0

我正在尝试向 Observable 添加一个方法,以便对于包含它的类,它可以调用observe_attribute :attribute将生成attribute=具有逻辑的方法的方法,以检查值是否已更改:

module Observable
  def observe_attribute(attribute)
    raise NameError, "#{self.class} does not contain #{attribute}" unless instance_variables.include? "@#{attribute}"
    eval %" def #{attribute}=(new_value) 
              unless @#{attribute} == new_value
                changed
                notify_observers
                puts 'ok'
              end
            end
         ";
  end
end

但是,对于以下类,最后一次调用会observe_attribute :att导致 NoMethodError,而注释掉的则不会:

class Test 
  include Observable

  def initialize
    @att = 3
    #observe_attribute :att
  end

  observe_attribute :att
end

为了使最后一次调用observe_attribute正常工作,我需要做什么?

4

1 回答 1

1

当您包含一个模块时,其中包含的方法被加载到方法的“实例”级别。

如果要将模块中的方法包含到 Class 范围内,则必须扩展模块。

或者,如果您需要两者,但您想将其打包为单个“包含”,您可以扩展您正在扩展的模块的“包含”方法,并通过从那里扩展和包含 2 个模块来使用它做一些魔术.

module Observable

  def self.included(other)
    other.send(:include, InstanceMethods)
    other.send(:extend, ClassMethods)
  end

  module InstanceMethods
    def some_helper
      puts "called some_helper"
    end
    def other_helper
      puts "called other_helper"
    end
  end

  module ClassMethods
    def observe_attribute(name)
      # do something useful, maybe in your case define the method
      define_method("#{name}=") do |val|
        puts "called #{name}= #{val}"
        # bla bla
        some_helper
        other_helper
        # end
        puts "done"
      end
    end
  end

end

class Foo
  include Observable
  observe_attribute :foo
end

现在你可以打电话...

o = Foo.new
o.foo = :bar

然后结果将是......

called foo= bar
called some_helper
called other_helper
done
于 2012-01-09T05:06:31.457 回答