kiyoka.2011_09_29 RSSPLAIN

Related pages: !kiyoka.blog.list kiyoka.2011_09_30 !kiyoka.blog.2011_09
5555555555555555555555555555555455555555555555555555555555555554555555555555555555555555555555555555555555333335
5

[Ruby] Rubygems.orgから取得したgemでエラーが出るのはなぜか

5

rubygems_icon_128

5

ずっと前から自分が作ったgemが環境によってエラーになる原因が解析できずにいた。

5

やっと、tenderloveEXTことAaron Patterson氏が書かれたブログエントリでメカニズムが理解できた。

5

 

5

Aaron Patterson氏の説明を読み解く

5
 Shaving a YAML Yack EXT
5
 Have you ever seen this error?
5
 
5
 $ gem install rails --pre
5
 ERROR:  While executing gem ... (NameError)
5
   uninitialized constant Psych::Syck
5
 $
5
 
5
 Yes, I have too. Today we’re going to discuss the source of this error, and what we
5
 need to do to fix it.
5

 

5

やっぱり、誰もが同じエラーに遭遇していたのか。

5

自分の環境が悪いのかと思っていた。自分の環境はちょっと違うエラーメッセージだけど、原因は同梱のようだ。

5

結局RubyのYamlライブラリの互換性問題だった。

5

gemspecファイルの依存規則のところに'='イコールを使うとダメらしい。

5
Gem::Specification.new do |s|
5
  ...
5
  s.add_dependency('activesupport', '= 3.1.0')
5
  ..
5
end
5

 

5

上記のようなgemspecファイルを元に、gemパッケージが生成されるが、gemの中に格納されるmetafileはyaml形式となる。

5

gemパッケージ生成環境がPsychを使っている場合と、Syckを使っている場合で生成されるmetafile中の '='の扱いが異なる。

5

 

5

再現確認

4

メカニズムについては上記のAaron氏のブログエントリに書かれている通りなので、NGとOKパターンだけまとめると次のようになる。

5
 (1) OK ...   Syckで作ったgem =>  SyckライブラリがインストールされたRuby環境でmetafile(yaml)をパース
5
 (2) OK ...   Syckで作ったgem => PsychライブラリがインストールされたRuby環境でmetafile(yaml)をパース
5
 (3) OK ...  Psychで作ったgem => PsychライブラリがインストールされたRuby環境でmetafile(yaml)をパース
5
 (4) NG ...  Psychで作ったgem =>  SyckライブラリがインストールされたRuby環境でmetafile(yaml)をパース
5

 

5

NGの確認は自分のOSSパッケージsekka-0.9.3のパッケージをPsych環境で作った。gemspecには次のような行がある。

5
  gemspec.add_dependency( "nendo", "= 0.5.3" )
5

 

5

なお、gemをインストールした環境はlibyamlの入っていないRuby環境だ。そこではyaml parserはPSychではなくSyckが使われる。

5

このようにエラーメッセージが出る。

5
/tmp $ gem --version
5
Invalid gemspec in [/usr/local/stow/ruby-1.9.2-p290/lib/ruby/gems/1.9.1/specifications/sekka-0.9.3.gemspec]: Illformed requirement ["#<Syck::DefaultKey:0x00000102ca5258> 0.5.3"]
5
1.8.10
5

 

5

念のためSyck環境であることを確認。

5
/tmp $ ruby --version
5
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin10.8.0]
5
/tmp $ irb
5
irb(main):001:0> require 'yaml'
5
require 'yaml'
5
=> true
5
irb(main):002:0> YAML.dump [ '=' ]
5
YAML.dump [ '=' ]
5
=> "--- \n- \"=\"\n"
5
irb(main):003:0> YAML.load "---\n- =\n"
5
YAML.load "---\n- =\n"
5
=> [#<Syck::DefaultKey:0x00000101259de0>]
5
irb(main):004:0> 
5

 

5

 

5

rubygems.orgとの関係

4

Aaron氏のブログエントリでも書いてあるように、rubygems.orgはmarshalされたオブジェクトをユーザーに配布しているらしい。

5

上記の私の再現確認では、ローカルにあるgemファイルを使ってgem install していたが、rugygemsに登録した場合はrubygems.org内部のyamlパーサでパースしたmarshalオブジェクトが配布されるということだ。

5

現在rubygems.orgはSyckだそうで、これからPsychに差しかえるべく動いているとのこと。

5

つまり、Psyckでgemsでパッケージを作りrubygems.orgに登録すると上記のパターンで書いた(4)に該当する。

5

このとき、クライアント環境がどのような環境であろうとエラーが出るはず。これはマズい。

5

 

5
 Shaving a YAML Yack EXT
5
 How can we fix this?
5
 
5
 We have two ways to deal with this issue. The first way to deal with
5
 this issue is to upgrade rubygems. Rubygems contains code to work
5
 around the issue when installing gems. But it does not fix the issue.
5
 
5
 The only way we can fix this error for all users is to upgrade
5
 rubygems.org to use psych as the YAML parser. Upgrading rubygems.org
5
 will prevent the strange objects from entering marshal data sent to
5
 users.
5

 

5

 

5

 

5

回避方法 案1

5

gemspecはSyck環境でgemパッケージを作ってrubygems.orgに登録する。

5

Sekkaではこれまで、この方法を使っていた。

5

 

5

回避方法 案2

5

gemspecに、'='を使わない。かわり'>='を使う。

5

 

5

[SekkaのRakefile]

5

現状

5
  gemspec.add_dependency( "nendo", "= 0.5.3" )
5

回避策

5
  gemspec.add_dependency( "nendo", ">= 0.5.3" )
5

 

5

かなり姑息というか、本来行いたい指定とは違うのでちょっと不満がある。

5

Nendoのほうで下位互換性を壊すバージョンアップがあった場合Sekkaが動かなくなるという直接的な問題がある。

5

ただし、どんな環境でgemパッケージを作ってもよい。

5

 

5

 

5

まとめ

5

gemのinstall時のエラーは多くの人が遭遇しているはず。

5

メカニズムを理解すれば環境に依存しないgemを作れるが、スマートな解決方法は無い。

5

 

5

 

3

追記

3

実際に複数の環境でgemパッケージを作り、内容を貼りつけた。

3

「 kiyoka.2011_09_30[Ruby] Rubygems.orgから取得したgemでエラーが出るのはなぜか(追記)」

3

 

3

 

5

...comment disabled...