继承我所拥有/想要的东西:
module Observable
def observers; @observers; end
def trigger(event, *args)
good = true
return good unless (@observers ||= {})[event]
@obersvers[event].each { |e| good = false and break unless e.call(self, args) }
good
end
def on(event, &block)
@obersvers ||= {}
@obersvers[event] ||= []
@observers[event] << block
end
end
class Item < Thing
include Observable
def pickup(pickuper)
return unless trigger(:before_pick_up, pickuper)
pickuper.add_to_pocket self
trigger(:after_pick_up, pickuper)
end
def drop(droper)
return unless trigger(:before_drop, droper)
droper.remove_from_pocket self
trigger(:after_drop, droper)
end
# Lots of other methods
end
# How it all should work
Item.new.on(:before_pickup) do |item, pickuper|
puts "Hey #{pickuper} thats my #{item}"
return false # The pickuper never picks up the object
end
在开始尝试使用Ruby创建游戏时,我认为如果它可以基于观察者和事件的全部,那就太棒了。问题是必须编写所有这些触发器似乎是一种浪费,因为它似乎是很多重复的代码。我觉得必须有一些元编程方法来包装具有功能的方法。
理想的Sceanrio:
class CustomBaseObject
class << self
### Replace with correct meta magic
def public_method_called(name, *args, &block)
return unless trigger(:before_+name.to_sym, args)
yield block
trigger(:after_+name.to_sym, args)
end
###
end
end
然后我的所有对象都继承自Class
。
我还不熟悉Ruby更高级的元编程主题,因此任何有关此类事物的知识都会很棒。
答案 0 :(得分:6)
在元编程魔法的帮助下,有几种方法可以做到这一点。例如,您可以定义如下方法:
def override_public_methods(c)
c.instance_methods(false).each do |m|
m = m.to_sym
c.class_eval %Q{
alias #{m}_original #{m}
def #{m}(*args, &block)
puts "Foo"
result = #{m}_original(*args, &block)
puts "Bar"
result
end
}
end
end
class CustomBaseObject
def test(a, &block)
puts "Test: #{a}"
yield
end
end
override_public_methods(CustomBaseObject)
foo = CustomBaseObject.new
foo.test(2) { puts 'Block!' }
# => Foo
Test: 2
Block!
Bar
在这种情况下,您可以使用instance_methods
计算出类中定义的所有必需方法,然后覆盖它们。
另一种方法是使用所谓的'hook'方法:
module Overrideable
def self.included(c)
c.instance_methods(false).each do |m|
m = m.to_sym
c.class_eval %Q{
alias #{m}_original #{m}
def #{m}(*args, &block)
puts "Foo"
result = #{m}_original(*args, &block)
puts "Bar"
result
end
}
end
end
end
class CustomBaseObject
def test(a, &block)
puts "Test: #{a}"
yield
end
include Overrideable
end
当您included
该模块时,将调用此模块中定义的include
挂钩。这要求您include
在类定义结尾处的模块,因为included
应该知道所有已定义的方法。我认为这很难看:))