0

I'm playing Ruby game and got stuck at this :

Implement class Squirrel in a way below API will be supported.

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

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

I was experimenting with def find(&block) and saving it as Proc later, but it probably shouldn't be done this way. I'll appreciate any hints.

2
  • The exercise doesn't contain a method called find, why do you want to define it? Commented Aug 30, 2016 at 7:57
  • @Stefan: I think he meant fight Commented Aug 30, 2016 at 7:58

3 Answers 3

2

I'll appreciate any hints

Sure. fight should accept a block and instance_eval it. jump, kick and others should be methods on the same class.

Sign up to request clarification or add additional context in comments.

Comments

1

This is a rather standard metaprogramming technique that was popularized many years ago by the BlankSlate and XmlBase classes in Jim Weirich's builder Gem.

The main idea is to create a "blank slate" object, i.e. an object that has no methods, and then record all method calls on this object.

Here is one possible implementation:

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

Comments

0

Try instance_eval. And/or read this this: Change the context/binding inside a block in ruby

1 Comment

He didn't ask for a full solution. Just hints. You're taking all the fun away :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.