0

我今天从@avdi 的 Ruby Tapas 节目中获得了以下代码:

module Eventful
  def self.included(other)
    other.extend(Macros)
  end
  def add_listener(listener)
    (@listeners ||= []) << listener
  end
  def notify_listeners(event, *args)
    (@listeners || []).each do |listener|
      listener.public_send("on_#{event}", *args)
    end
  end

  module Macros
    def event(name)
      module_eval(%Q{
        def #{name}(*args)
          notify_listeners(:#{name}, *args)
        end
      })
    end
  end
end

class Dradis
  include Eventful
  event :new_contact
end

class ConsoleListener
  def on_new_contact(direction, range)
    puts "DRADIS contact! #{range} kilometers, bearing #{direction}"
  end
end

dradis = Dradis.new
dradis.add_listener(ConsoleListener.new)
dradis.new_contact(120, 23000)

我了解事件和侦听器以及观察者模式的概念,但不明白这种语法是如何/为什么起作用的,也没有在任何手册中看到它。类Dradis有这个:

 event :new_contact

起初,我认为这event是一个方法,:new_contact是一个参数,所以我会调用event的一个实例Dradis,例如:

dradis = Dradis.new
dradis.event

而是在类似new_contact的实例上调用Dradis

dradis = Dradis.new
dradis.add_listener(ConsoleListener.new)
dradis.new_contact(120, 23000)

并触发event宏模块中的方法。

谁能解释为什么它会这样工作?调用:new_contact实例dradis来触发事件方法?

4

2 回答 2

1

我没看那集,但是看,它就在那里。

  module Macros
    def event(name)
      module_eval(%Q{
        def #{name}(*args)
          notify_listeners(:#{name}, *args)
        end
      })
    end
  end

event是一种方法,它定义了另一个方法 ( new_contact),该方法notify_listenersEventful.

并触发宏模块中的事件方法

不正确。该方法很久以前就完成了它的工作,它不会再次被调用。它使用module_eval/生成了一个新方法def,而新方法 ( new_contact) 就是被调用的方法。

当类被解析和加载时,理解event方法只运行一次是很重要的。Dradis它不会在Dradis.

于 2012-11-23T22:13:59.793 回答
1

Several separated features of ruby is used: In the line event :new_contact the "evnet" is class method (http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_classes.html#UE).

Usually class methods are defined by:

  class A
    def A.my_class_method
     #code
    end
  end
  A.my_class_method #executing class_method

or

  class A
    def <<self   #usefull when you want delare several class methods
      def A.my_class_method
        #code
      end
    end
  end
  A.my_class_method #executing class_method

In the code the method is included by the module Macros.

The key thing is, that (class method) event is dynamicaly creating new (instance) method (in this case new_contact) The name of the method is passed as argument to event). And this method providing calling of the listener.

Can anyone explain why it works like this? calling :new_contact on an instance dradis to trigger the event method?

This is by the dynammically created method new_contact which is calling notify_listeners(:#{name}, *args)

于 2012-11-23T22:54:56.417 回答