1

次のティータイマーコードには、SleepTimer内に「notify」を呼び出す「start」メソッドがあります。

  def start
    sleep minutes * 60
    notifier.notify("Tea is ready!")
  end

以下のコードを見ると、に通知メソッドがあり、に通知メソッドがあることがわかりclass StdioUiますmodule UiWithBeep。上記のstartメソッドは、のnotifyメソッドを呼び出しますmodule UiWithBeep。次に、'super'を介して、のnotifyメソッドを呼び出しますclass StdioUimodule UiWithBeep(効果は、「お茶の準備ができました」の前に「BEEP!」が聞こえるということです。)しかし、notifier.notifyがnotifyメソッドをではなくで呼び出す理由がわかりませんclass StdioUi最初の質問:一方の「通知」にもう一方の「通知」に行くことをどのようにして知るのですか。 SecondQuestionそして、私はスーパーを理解していますが、通知するように関係を確立するのclass StdioUiは、他の通知に対して「スーパー」です。説明してもらえますか

ティータイマー

class TeaClock
  attr_accessor :timer
  attr_accessor :ui

  def initialize(minutes)

    self.ui = StdioUi.new

    self.timer = SleepTimer.new(minutes, ui)
    init_plugins

  end

  def init_plugins
    puts "init plugins"
    @plugins = []
    ::Plugins.constants.each do |name|
      @plugins << ::Plugins.const_get(name).new(self)
    end
  end

  def start
    timer.start
  end
end

class StdioUi
  def notify(text)
    puts text
  end
end

SleepTimer = Struct.new(:minutes, :notifier) do
  def start
    sleep minutes * 60
    notifier.notify("Tea is ready!")
  end
end

module Plugins
  class Beep    
    def initialize(tea_clock)

      tea_clock.ui.extend(UiWithBeep)
    end

    module UiWithBeep
      def notify(*)         #gets called by notifier.notify("Tea is ready")
        puts "BEEP!"

        super               #calls notify in class StdioUi
      end
    end
  end
end

t = TeaClock.new(0.01).start
4

2 に答える 2

1

各クラスにはancestors、継承チェーンを表すというプロパティがあります。rubyは、継承された動作のリストを調べて、一致するメソッドを探します。見つかった場合は、指定されたパラメーターを使用して呼び出します。あなたがそれを呼ぶならば、superそれは次のマッチを探します。

1.9.3-p194 :003 > String.class.ancestors
 => [Class, Mocha::ClassMethods, Module, NewRelic::Agent::MethodTracer::InstanceMethods, NewRelic::Agent::MethodTracer::InstanceMethods::TraceExecutionScoped, NewRelic::Agent::MethodTracer::ClassMethods, NewRelic::Agent::MethodTracer::ClassMethods::AddMethodTracer, Mocha::ModuleMethods, ActiveSupport::Dependencies::ModuleConstMissing, Object, FactoryGirl::Syntax::Vintage, Metaclass::ObjectMethods, Mocha::ObjectMethods, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Dependencies::Loadable, FriendlyId::ObjectUtils, Kernel, BasicObject]
于 2012-10-17T19:21:47.620 に答える
1

:私はこの素晴らしい本、メタプログラミングRubyを推薦し続けます。この答えを作成している間、私はそれを調べていました。


したがって、ここでは、モジュールを使用してオブジェクトを拡張します。Rubyでは、オブジェクト拡張と呼ばれます。単純なケースでは、次のようにすべてが期待どおりに機能します。

module Foo
  def hello
    puts "foo"
  end
end

class Bar
end

bar = Bar.new
bar.extend Foo
bar.hello
# >> foo

クラス独自のメソッドが関係していると、事態は複雑になります。これは、同じ動作を示すスニペットの簡略化されたバージョンです。

module Foo
  def hello
    puts "foo"
    super
  end
end

class Bar
  def hello
    puts 'bar'
  end
end

bar = Bar.new
bar.extend Foo
bar.hello
# >> foo
# >> bar

rubyでメソッドを呼び出す場合、インタプリタは最初に呼び出すメソッドを見つける必要があります。これはメソッドルックアップと呼ばれます。ここで、インスタンスメソッドを定義すると、実際には、そのインスタンスではなく、クラスオブジェクトのメソッドになります。したがって、最初のスニペットのメソッドルックアップは次のようになります。

 1) bar instance => method hello not found here
 2) Bar class => method hello found

ただし、オブジェクトを拡張すると、メソッドはインスタンスのに挿入されますeigenclass。これは、インスタンスごとに一意の特別な「非表示」クラスです。そして実際には、メソッドルックアップは最初にそれを通過します。もう一度最初のスニペット:

 1) bar instance => method hello not found here
 2) bar's eigenclass => method hello not found here
 3) Bar class => method hello found

これで、メソッドルックアッププロセスの早い段階で表示されるため、:Foo.helloの代わりに呼び出される理由が明確になります。Bar.hello

 1) bar instance => method hello not found here
 2) bar's eigenclass => method hello found

私はいくつかの間違いを犯したかもしれませんが、これは大まかに起こることです。

于 2012-10-17T19:40:38.793 に答える