How to create a method that executes a previously given block in Ruby?

44 Views Asked by At

I have a class that was built for subclassing.

class A
  def initialize(name)
  end

  def some
    # to define in subclass
  end
end

# usage
p A.new('foo').some
#=> nil

In my use case, I don't want to create a subclass since I need just one instance. Therefore, I'll change the initialize method to support the following usage.

p A.new('foo') { 'YEAH' }.some
#=> YEAH

How could I support the usage above?


BTW: I found the following solutions for a Ruby 1.8.7 project, but they look awkward to me.

class A
  def singleton_class
    class << self; self; end
  end

  def initialize(name, &block)
    @name = name
    self.singleton_class.send(:define_method, :some) { block.call } if block_given?
  end

  def some
    # to define in subclass
  end
end
1

There are 1 best solutions below

0
On BEST ANSWER

You can store the block argument in an instance variable and call it later on:

class A
  def initialize(name, &block)
    @name  = name
    @block = block
  end

  def some
    @block.call
  end
end

A.new('foo') { 'YEAH' }.some
#=> "YEAH"

You can also pass arguments into the block:

class A
  # ...
  def some
    @block.call(@name)
  end
end

A.new('foo') { |s| s.upcase }.some
#=> "FOO"

Or instance_exec the block in the context of the receiver:

class A
  # ...

  def some
    instance_exec(&@block)
  end
end

Which allows you to bypass encapsulation:

A.new('foo') { @name.upcase }.some
#=> "FOO"