before_session hook failed: ArgumentError: invalid byte sequence in Windows-31J
これにイラっときた人は少なくない筈
非Windows環境ならば、UTF-8で統一すれば大分減るはずですが
事の発端
binding.pry の直前に日本語コメントが入ってて表示できなかった
何度もこの問題(default_external と別エンコードのファイルの読み込みに失敗する)に直面して
正直疲れたので、いっそハックしてしまおう
対策
.pryrc
require 'nkf'
# Fix IO
module IO_NKF
def read(path, length = nil, offset = 0, opts = {})
keys = opts.keys
return super unless (keys & %i[encoding external_encoding binmode]).empty?
return super if keys.include?(:mode) && opts[:mode].include?(':')
NKF_read path, length, offset, opts
end
def NKF_read(path, length = nil, offset = 0, opts = {})
len = length || 1024
enc = NKF_guess path, [1024, len].min, offset
read path, length, offset, NKF_opts(enc, opts)
end
def readlines(path, rs, limit, opts={})
keys = opts.keys
return super unless (keys & %i[encoding external_encoding binmode]).empty?
return super if keys.include?(:mode) && opts[:mode].include?(':')
NKF_readlines(path, rs, limit, opts)
end
def readlines(path, rs = $/, opts = {})
keys = opts.keys
return super unless (keys & %i[encoding external_encoding binmode]).empty?
return super if keys.include?(:mode) && opts[:mode].include?(':')
NKF_readlines(path, rs, opts)
end
def NKF_readlines(path, rs, limit, opts)
bin = binread(path, [1024, limit].min)
encode = NKF.guess bin
readlines path, rs, limit, NKF_opts(encode, opts)
end
def NKF_readlines(path, rs = $/, opts = {})
enc = NKF_guess path
readlines path, rs, NKF_opts(enc, opts)
end
def NKF_guess(path, limit = 1024, offset = 0)
encode = NKF.guess binread(path, limit, offset)
case encode
when NKF::JIS then nil
when NKF::EUC then Encoding::EUCJP
when NKF::SJIS then Encoding::CP932
when NKF::UNKNOWN then nil
when NKF::UTF8 then Encoding::UTF_8
when NKF::UTF16 then Encoding::UTF_16
end
end
def NKF_opts(enc, opts = {})
opts.dup.tap{|o|
o[:external_encoding] = enc
}
end
end
# クラスメソッドをprependする方法ってこれでいいのかな
IO.singleton_class.class_eval { self.prepend(IO_NKF) }
Encoding.default_internal ||= Encoding::UTF_8
コレをpryrcに仕込めば、コードの文字コードに左右されにくくなります
後でGem化してみるかも
既知の問題点
- JISと判別された場合どうすりゃいいんだろう
- BOM 非対応
- UTF32 非対応
最後に
File.read(path) を外部ファイルの読み込みに使ってる人は爆発しろエンコーディングを設定する必要がないのかきちんと考えてください