2016-08-30 2 views
0

я играю игру Руби и застрял на это:рубин упражнения - блок для массива

Реализовать класс Squirrel таким образом, ниже API будет поддерживаться.

squirrel = Squirrel.new 
squirrel.fight do 
    jump 
    kick 
    punch 
    jump 
end 

squirrel.actions #=> ['jump', 'kick', 'punch', 'jump'] 

Я экспериментировал с def find(&block) и сохранив его как Proc позже, но это, вероятно, не должно быть сделано таким образом. Буду признателен за любые намеки.

+0

упражнение не содержит метод, называемый 'find', почему вы хотите, чтобы определить это? – Stefan

+0

@Stefan: Я думаю, он имел в виду 'fight' –

ответ

2

Я признателен за любые подсказки

Конечно. fight должен принять блок и instance_eval он. jump, kick и другие должны быть методы одного класса.

0

Пробег: instance_eval. И/или прочитать это: Change the context/binding inside a block in ruby

+1

Он не просил полного решения. Просто намеки. Вы устраиваете все самое интересное :) –

+0

К сожалению, вы правы. Исправьте это, спасибо! – Felixyz

1

Это довольно стандартный метод метапрограммированием, который популяризировал много лет назад в BlankSlate и XmlBase классов в Jim Weirich «s builder Gem.

Основная идея - создать объект «пустой сланец», то есть объект, который не имеет методов, а затем записывать все вызовы методов для этого объекта.

Вот одна из возможных реализаций:

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 
Смежные вопросы