我正在玩Ruby游戏并且陷入困境:
支持以低于API的方式实施类
Squirrel
。squirrel = Squirrel.new squirrel.fight do jump kick punch jump end squirrel.actions #=> ['jump', 'kick', 'punch', 'jump']
我正在试验def find(&block)
并稍后将其保存为Proc,但它可能不应该以这种方式完成。我会感激任何提示。
答案 0 :(得分:2)
我会感激任何提示
不确定。 fight
应该接受一个阻止并instance_eval
。 jump
,kick
和其他人应该是同一个班级的方法。
答案 1 :(得分:1)
这是一种相当标准的元编程技术,多年前由BlankSlate
的XmlBase
宝石中的Jim Weirich和builder
类推广。
主要思想是创建一个“空白平板”对象,即没有方法的对象,然后在该对象上记录所有方法调用。
以下是一种可能的实施方式:
class Squirrel
class Recorder < BasicObject
(instance_methods + private_instance_methods).each(&method(:undef_method))
def method_missing(method) @actions << method.to_s end
end
attr_reader :actions, :recorder
private
attr_writer :actions, :recorder
def initialize
self.actions = []
self.recorder = Recorder.allocate
Object.public_instance_method(:instance_variable_set).bind(recorder).(:@actions, actions)
end
public def fight(&block)
BasicObject.public_instance_method(:instance_eval).bind(recorder).(&block)
end
end
require 'minitest/autorun'
describe Squirrel do
before do @squirrel = Squirrel.new end
describe '#fight' do
it 'should record its actions' do
@squirrel.fight do jump; kick; punch; jump end
@squirrel.actions.must_equal %w[jump kick punch jump]
end
end
end
答案 2 :(得分:0)
试试instance_eval
。和/或读这个:
Change the context/binding inside a block in ruby