7

ruby での改良の現在の実装に関する非常に優れたドキュメントが http://ruby-doc.org//core-2.2.0/doc/syntax/refinements_rdoc.htmlにありますが、奇妙なケースがいくつかあります。

まず、include module直交してusing moduleいます (1 つはモジュールのインスタンス メソッドを含み、もう 1 つはリファインメントをアクティブにします)。しかし、絞り込みモジュール自体を含めるトリックがあります。「 絞り込みを使用するよりも Ruby クラスをモジュールに変換する方法が優れていますか?」を参照してください。.

def to_module(klass)
  Module.new do
    #note that we return the refinement module itself here
    return refine(klass) {
      yield if block_given?
    }
  end
end

class Base
  def foo
    "foo"
  end
end
class Receiver
  include to_module(Base) {
    def foo
      "refined " + super
    end
  }
end
Receiver.new.foo #=> "refined foo"

using奇妙なことに、この改良モジュールは!では使用できません。

m=to_module(Base) {}
m.class #=> Module
using m    
#=>TypeError: wrong argument type Class (expected Module)

したがって、洗練モジュールの囲みモジュールでのみ作業を使用します。次に、 https://www.new-bamboo.coのように Proc をソースに戻すことに頼らずに、上記の yield トリックを使用して Proc を渡して (ブロックのみを受け入れても) 洗練させたいと考えました 。 .uk/blog/2014/02/05/refinements-under-the-knife/ . ただしyield、インクルードの例のように使用しても機能しません。

def ref_module1(klass)
  Module.new do
    refine(klass) {
      yield
    }
  end
end

class Receiver1
  using ref_module1(Base) {
    def foo
      "refined " + super
    end
  }
  def bar
    Base.new.foo
  end
end
Receiver1.new.bar #=> NoMethodError: super: no superclass method `foo'

Receiver1 は依然として Bar#foo を使用しており、洗練されたメソッドを使用していないことがわかります。module_evalただし、代わりに使用できます。

def ref_module2(klass,&b)
  Module.new do
    refine(klass) {
      module_eval(&b)
    }
  end
end

class Receiver2
  using ref_module2(Base) {
    def foo
      "refined " + super
    end
  }
  def bar
    Base.new.foo
  end
end
Receiver2.new.bar #=> "refined foo"

module_evalメソッドではなく、なぜここで機能するのかよくわかりませんyield。改良ブロック内では、'default_definee' が改良モジュールであるためmodule_eval、'default_definee' をself='改良モジュール' に配置しても影響を受けません。実際、冒頭の「include」の例では、module_evalor を直接使用しても同じ結果が得られyieldます。

誰でもこの動作を説明できますか?

4

1 に答える 1