Rails3 で RDoc ドキュメント生成時に invalid byte sequence in UTF-8 エラーが出た場合の対応
日本語でコメントを記述したプログラムを利用して RDoc ドキュメントを生成するときに、
下記のようなエラーが出て途中で止まってしまうことがあります。
$ rdoc -c UTF-8 -U Parsing sources... Before reporting this, could you check that the file you're documenting compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if fed invalid programs. The internal error was: (ArgumentError) invalid byte sequence in UTF-8 uh-oh! RDoc had a problem: invalid byte sequence in UTF-8 run with --debug for full backtrace
これは、ドキュメントを生成する際に RDoc の内部で 1024byte 毎にファイルを区切っていて、
1024byte の部分がちょうど日本語 UTF-8 の 3byte の中になってしまった場合にエラーになるようです。
実験として、下記のような model を作成してみました。
# coding: utf-8 # #= エラー再現確認用モデル # # 1024byte の部分が日本語だった場合の実験用モデル # class Mail < ActiveRecord::Base # # 1024byte の部分が、日本語 UTF8 の 1 文字の途中だった場合は # rdoc -c UTF-8 -U を実行した際にエラーとなって rdoc が生成できないみたい。 # この実験のために日本語をたくさん書いてエラーを再現してみようと思います。 # ここまで書いてまだ半分の 512byte まで到達していなくてちょっとびっくり。 # 意味の無い文書を長く書くことも結構難しいですね。 # ここで色々なことを書いておけば SEO でヒットするキーワードが多くなるかなとか # 適当なことを考えながら淡々と文章を書き続けています。 # # あとちょっとで 1024byte にまで届きそう! # がんばれ俺!負けるな俺! # この行がちょうど 1024byte になるのでここで打ち止め! end
そして /usr/local/lib/ruby/gems/1.9.1/gems/rdoc-2.5.11/lib/rdoc/parser.rb の
def self.binary? に下記のような修正を加えてみます。
def self.binary?(file) s = File.read(file, 1024) or return false set_encoding(s) p s # この行を状況確認用に追加 if s[0, 2] == Marshal.dump('')[0, 2] then true elsif file =~ /erb\.rb$/ then false elsif s.scan(/<%|%>/).length >= 4 || s.index("\x00") then true elsif 0.respond_to? :fdiv then s.count("^ -~\t\r\n").fdiv(s.size) > 0.3 else # HACK 1.8.6 (s.count("^ -~\t\r\n").to_f / s.size) > 0.3 end end
そして rdoc -c UTF-8 -U を実行すると下記のようなエラーで止まります。
(読みやすいように改行を加えています)
"# coding: utf-8\n#\n#= エラー再現確認用モデル\n#\n# 1024byte の部分が日本語だった場合の実験用モデル \n#\n\n\nclass Mail < ActiveRecord::Base\n #\n # 1024byte の部分が、日本語 UTF8 の 1 文字の途中だっ た場合は\n # rdoc -c UTF-8 -U を実行した際にエラーとなって rdoc が生成できないみたい。\n # この実験 のために日本語をたくさん書いてエラーを再現してみようと思います。\n # ここまで書いてまだ半分の 512byte まで到達していなくてちょっとびっくり。\n # 意味の無い文書を長く書くことも結構難しいですね 。\n # ここで色々なことを書いておけば SEO でヒットするキーワードが多くなるかなとか\n # 適当なことを考えながら 淡々と文章を 書き続けています。\n #\n # あとちょっとで 1024byte にまで届きそう!\n # がんばれ俺! 負けるな俺!\n # この行がちょうど 1024byte になるのでここで打ち止\xE3" Before reporting this, could you check that the file you're documenting compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if fed invalid programs. The internal error was: (ArgumentError) invalid byte sequence in UTF-8 uh-oh! RDoc had a problem: invalid byte sequence in UTF-8 run with --debug for full backtrace
rdoc 生成時の app/models/mail.rb のファイルサイズは 1034byte です。
なので utf-8 を 1 文字 3byteで最後から逆算していくと、
下記のように "打ち止め!" の "め" の部分がちょうど 1024byte 目から始まってしまっています。
byte | char ---------------- 1015〜1017 | 打 1018〜1020 | ち 1021〜1023 | 止 1024〜1026 | め 1027〜1029 | ! 1030 | \n 1031 | e 1032 | n 1033 | d 1034 | \n
というわけで、こういったケースはプログラム内の先頭や途中に適当に半角文字を追加して、
日本語が 1024byte にぶつからないように微調整してあげることでエラーが出ないようになります。
あぁ、日本語ってめんどくさい、、、