Techioz Blog

Ruby では (通常は ) に何が提供されますか?

概要

私は Ruby のメタプログラミングをもう少しよく理解しようとしており、やりたいことの回避策はありますが、それをできるだけきれいにしたいと考えています。

簡単に言うと、モジュールを含むクラスが特定のメソッドを定義しているかどうかを確認したいと思います。

irb(main):058:1* module A
irb(main):059:2*   def self.included(base)
irb(main):060:2*     puts base.singleton_method(:singleton_test)
irb(main):061:1*   end
irb(main):062:0> end
:included
irb(main):063:1* class B
irb(main):064:1*   include A
irb(main):065:2*   def self.singleton_test
irb(main):066:2*     puts "hi"
irb(main):067:1*   end
irb(main):068:0> end

これにより、次のようなものが出力されると予想されます。

#<メソッド: B.singleton_test() (irb):95>

ただし、次のことはできません。

(irb):60:in `singleton_method': undefined singleton method `singleton_test' for `B' (NameError)

    puts base.singleton_method(:singleton_test)
             ^^^^^^^^^^^^^^^^^

これは、付属のフックが呼び出されたときにシングルトン メソッドがまだベースにバインドされていないためだと思われます。

このパターンで singleton_test が定義されているかどうかを確認するにはどうすればよいでしょうか?

PS おそらく、これは、シングルトンまたはインスタンスにかかわらず、モジュール A が含まれる時点でベースのメソッド定義で発生するようであることにも注目する価値があるかもしれません。

解決策

単純な注文の問題です。

Ruby は (ほとんどの場合) 左から右、上から下に評価されます。

class B
  include A

  def self.singleton_test
    puts('hi')
  end
end

ご覧のとおり、インクルードはメソッド定義の前に来ます。 2 つを入れ替える必要があります。

class B
  def self.singleton_test
    puts('hi')
  end

  include A
  # #<Method: B.singleton_test() ./test.rb:2>
end