天気
- 曇り後晴れ
ジョギング
日課
- (腕立て x 50 + 腹筋 x 50) x 3
今日のるびぃ ~ REx - Ruby Examination にチャレンジ (12) ~
REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.
$ ruby --version ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux] $ irb --version irb 0.9.6(09/06/30)
module_eval
以下のコードを実行するとどうなるか.
module Mod B = 100 def method 1000 end end Mod.module_eval do def self.method p B end end B = 10000 Mod.method
10000 が出力される
以下, irb にて確認.
irb(main):001:0> module Mod irb(main):002:1> B = 100 irb(main):003:1> irb(main):004:1* def method irb(main):005:2> 1000 irb(main):006:2> end irb(main):007:1> end => :method irb(main):008:0> irb(main):009:0* Mod.module_eval do irb(main):010:1* def self.method irb(main):011:2> p B irb(main):012:2> end irb(main):013:1> end => :method irb(main):014:0> irb(main):015:0* B = 10000 => 10000 irb(main):016:0> irb(main):017:0* Mod.method 10000 => 10000
以下, 解説より抜粋.
module_eval
にブロックを渡した際のネスト状態は[]
となり, メソッドはトップレベルに定義されることになる- トップレベルで定数を定義した場合は Object クラスの定数になる
- 設問では,
self.method
はブロックで渡されている為, トップレベルの定数を参照することになりMod.method
は10000
を返す
irb(main):001:0> module A; end => nil irb(main):002:0> A.module_eval do irb(main):003:1* p Module.nesting irb(main):004:1> end [] => [] irb(main):005:0> A.module_eval %Q{ irb(main):006:0" p Module.nesting irb(main):007:0" } [A] => [A] irb(main):008:0> A.module_eval do irb(main):009:1* p Module.nesting irb(main):010:1> end irb(main):011:0> B = "Hello, world" => "Hello, world" irb(main):012:0> p Object.const_get(:B) "Hello, world" => "Hello, world"
なるほどー, ブロックで渡した時と文字列で渡した時の違いってこれかなー.
ちなみに, class_eval
でも同様の事が言える.
irb(main):001:0> class C; end => nil irb(main):002:0> C.class_eval do irb(main):003:1* p Module.nesting irb(main):004:1> end [] => [] irb(main):009:0> C.class_eval %Q{ irb(main):010:0" p Module.nesting irb(main):011:0" } [C] => [C]
ということで, 以下のドキュメントの意味がシュッと頭に入ってくるような気がする.
- 文字列で定義した場合には, クラス又はモジュール定義式内の定数, クラス変数を参照する
- ブロックで定義した場合には, クラス又はモジュール定義外の定数, クラス変数を参照する
一応, 以下, ドキュメントより抜粋.
module_eval
に文字列を渡した場合の定数及びクラス変数のスコープはモジュール定義式内と同じスコープとなる- 対して,
module_eval
にブロックを渡した場合は, 定数とクラス変数のスコープはブロックの外側のスコープとなる - 尚, ローカル変数に関しては,
class_eval
及びmodule_eval
の外側と共有する
irb(main):001:0> class C irb(main):002:1> end => nil irb(main):003:0> a = 1 => 1 irb(main):004:0> C.class_eval %Q{ irb(main):005:0" def m irb(main):006:0" return :m, #{a} irb(main):007:0" end irb(main):008:0" } => :m irb(main):009:0> irb(main):010:0* p C.new.m [:m, 1] => [:m, 1]
フムフム...