Jes
Jes

Reputation: 343

Ruby exercise - block to array

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.

Upvotes: 0

Views: 78

Answers (3)

Jörg W Mittag
Jörg W Mittag

Reputation: 369633

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

Upvotes: 1

Felixyz
Felixyz

Reputation: 19143

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

Upvotes: 0

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230561

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.

Upvotes: 2

Related Questions