Rubyのブロック内のコンテキスト/バインディングを変更する

概要

Ruby には次のように動作する DSL があります。

desc 'list all todos'
command :list do |c|
  c.desc 'show todos in long form'
  c.switch :l
  c.action do |global,option,args|
    # some code that's not relevant to this question
  end
end

desc 'make a new todo'
command :new do |c|
  # etc.
end

開発者仲間は、コマンド ブロックに c を渡す必要がないように DSL を拡張して、c を必要としないように提案しました。すべてのために 内部のメソッド。おそらく彼は、次のコードを同じように動作させることができるとほのめかしました。

desc 'list all todos'
command :list do
  desc 'show todos in long form'
  switch :l
  action do |global,option,args|
    # some code that's not relevant to this question
  end
end

desc 'make a new todo'
command :new do
  # etc.
end

コマンドのコードは次のようになります

def command(*names)
  command = make_command_object(..)
  yield command                                                                                                                      
end

いくつかのことを試しましたが、動作させることができませんでした。コマンド ブロック内のコードのコンテキスト/バインディングをデフォルトとは異なるものに変更する方法がわかりませんでした。

これが可能かどうか、またどのようにすればよいかについて何かアイデアはありますか?

解決策

このコードを貼り付けます:

  def evaluate(&block)
    @self_before_instance_eval = eval "self", block.binding
    instance_eval &block
  end

  def method_missing(method, *args, &block)
    @self_before_instance_eval.send method, *args, &block
  end

詳細については、この非常に優れた記事を参照してください。