ようへいの日々精進XP

よかろうもん

2018 年 05 月 14 日(月)

ジョギング

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

夕飯

  • 山芋とピーマンに小麦粉をふって素揚げにしたら美味しかった
  • サーモンも軽く粉して素揚げ風で美味しかった

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (2) ~

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)

定数探索

次のプログラムを実行するとどうなるか.

class C
  CONST = "A"
end

module M
  CONST = "B"
end

module M
  class C
    CONST = "C"
  end
end

module M
  class C
    p CONST
  end
end

module M
  class C
    p CONST
    p ::C::CONST
    p ::M::CONST
  end
end

C

以下, irb による確認.

irb(main):001:0> class C
irb(main):002:1>   CONST = "A"
irb(main):003:1> end
=> "A"
irb(main):004:0> 
irb(main):005:0* module M
irb(main):006:1>   CONST = "B"
irb(main):007:1> end
=> "B"
irb(main):008:0> 
irb(main):009:0* module M
irb(main):010:1>   class C
irb(main):011:2>     CONST = "C"
irb(main):012:2>   end
irb(main):013:1> end
=> "C"
irb(main):014:0> 
irb(main):015:0* module M
irb(main):016:1>   class C
irb(main):017:2>     p CONST
irb(main):018:2>   end
irb(main):019:1> end
"C"
=> "C"

以下, メモ.

  • 冒頭の CM::C は別物となる
  • 設問の場合は M::C にある CONST が参照される為, C が表示される

ちなみに, 以下のように書くことで, 全ての定数を参照することが出来る.

irb(main):028:0> p M::C::CONST
"C"
=> "C"
irb(main):029:0> p ::C::CONST
"A"
=> "A"
irb(main):030:0> p ::M::CONST
"B"
=> "B"

オブジェクト指向, 定数探索

次のプログラムは "ABCDEFG" と表示するが, 同じ結果になる選択肢はどれか (複数選択).

module M
  CONST = "ABCDEFG"

  class C
    def awesome_method
      CONST
    end
  end
end

p M::C.new.awesome_method

一応, 上記のコードを irb で確認.

irb(main):001:0> module M
irb(main):002:1>   CONST = "ABCDEFG"
irb(main):003:1> 
irb(main):004:1*   class C
irb(main):005:2>     def awesome_method
irb(main):006:3>       CONST
irb(main):007:3>     end
irb(main):008:2>   end
irb(main):009:1> end
=> :awesome_method
irb(main):010:0> 
irb(main):011:0* p M::C.new.awesome_method
"ABCDEFG"
=> "ABCDEFG"

フムフム.

選択肢を見ていて, 随所に出てきていた class_eval が解らなかったので, 以下, ドキュメントより引用.

モジュールのコンテキストで文字列 expr またはモジュール自身をブロックパラメータとするブロックを 評価してその結果を返します。

モジュール内でメソッドを動的に定義する為に利用する...という解釈.

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> C.new.m
=> [:m, 1]

ナルホド...

class_eval の定数とローカル変数の参照については, 以下のように記載されている.

文字列が与えられた場合には、定数とクラス変数のスコープは自身のモジュール定義式内と同じスコープになります。 ブロックが与えられた場合には、定数とクラス変数のスコープはブロックの外側のスコープになります。

# 以下, ブロックが与えられたパターン 
class C
  CONST = "ABCDEFG"
end

module M
  C.class_eval do
    def awesome_method
      CONST
    end
  end
end
p C.new.awesome_method

# 以下, 文字列が与えられているパターン
class C
  CONST = "ABCDEFG"
end

module M
  C.class_eval(<<-CODE)
    def awesome_method
      CONST
    end
  CODE
end
p C.new.awesome_method

一見, 同じ結果になりそうな気がするけど, 以下のような違いがある.

  • ブロックが与えられたパターン
irb(main):012:0> p C.new.awesome_method
NameError: uninitialized constant M::CONST
        from (irb):8:in `awesome_method'
        from (irb):12
        from /usr/local/bin/irb:11:in `<main>'
  • 文字列が与えられているパターン
# 以下, 文字列が与えられているパターン
irb(main):012:0> p C.new.awesome_method
"ABCDEFG"
=> "ABCDEFG"

フムフム.

ちょっとスッキリしないけど...