如何在Ruby中创建一个执行先前给定块的方法?

时间:2017-09-26 09:52:57

标签: ruby metaprogramming eigenclass

我有一个为子类化而构建的类。

class A
  def initialize(name)
  end

  def some
    # to define in subclass
  end
end

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

在我的用例中,我不想创建一个子类,因为我只需要一个实例。因此,我会更改initialize方法以支持以下用法。

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

我如何支持上述用法?

BTW:我发现了以下Ruby 1.8.7项目的解决方案,但它们看起来很尴尬。

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 个答案:

答案 0 :(得分:3)

您可以将block argument存储在实例变量中,稍后将call存储在其中:

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

  def some
    @block.call
  end
end

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

您还可以将参数传递到块中:

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

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

instance_exec接收器上下文中的块:

class A
  # ...

  def some
    instance_exec(&@block)
  end
end

允许您绕过封装:

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