gpt4 book ai didi

Ruby:在事件触发器中自动包装方法

转载 作者:数据小太阳 更新时间:2023-10-29 08:28:48 25 4
gpt4 key购买 nike

这是我拥有/想要的:

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 创建游戏时,我认为如果它可以完全基于观察者和事件,那就太好了。问题是必须编写所有这些触发器似乎是一种浪费,因为它似乎有很多重复的代码。我觉得一定有一些元编程方法可以用功能包装方法。

理想场景:

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

然后我的所有对象都继承自这个

我对 Ruby 的更高级的元编程主题仍然是新手,所以任何关于此类事物的知识都会很棒。

最佳答案

在元编程魔法的帮助下,有多种方法可以做到这一点。例如,您可以像这样定义一个方法:

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 钩子(Hook)定义在这个模块中,当您include 那个模块时调用。这要求您在类定义的末尾 include 模块,因为 included 应该知道所有已经定义的方法。我觉得它很丑:)

关于Ruby:在事件触发器中自动包装方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8316228/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com