3

次のような DSL のような Ruby コードがあります。

Activity.new('20-06-2012') do
  Eat.log do |l|
    l.duration = 0.30
    l.priority = 5
  end
  Work.log do |l|
    l.duration = 2
    l.priority = 3
  end
end

log() メソッドが呼び出されるたびに、メソッドに渡されたブロックを使用して Log オブジェクトが (舞台裏で) インスタンス化されます (ブロックは Log オブジェクトのコンストラクターに渡されます)。私の質問は、log() メソッドからのすべての戻り値を収集する方法はありますか? 上記の例では、最も外側のブロックの戻り値は、log() への最後の呼び出しです。しかし、最後の結果だけでなく、すべての呼び出し結果を配列で取得したいと考えています。

ありがとう!

4

6 に答える 6

3

内部 DSL は依然として Ruby に似すぎているため、次のようにリファクタリングできます。

activity '20-06-2012' do
  log :eat do
    duration 0.30
    priority 5
  end
  log :work do
    duration 2
    priority 3
  end
end

ここで呼び出しをキャプチャしinstance_eval、値を内部配列に蓄積します。これは通常の DSL のものです。

于 2012-06-20T17:26:18.877 に答える
1

新しいオブジェクトなどを作成ActivityLogし、初期化子からブロックに渡しActivityます。

Activity.new('20-06-2012') do |log|
  log.eat do |l|
    l.duration = 0.30
    l.priority = 5
  end
  log.work do |l|
    l.duration = 2
    l.priority = 3
  end
end

ログの種類が少ない場合は、それらをActivityLog( ActivityLog#eatActivityLog#workなど) に追加します。対応するオブジェクト ( EatWork) を初期化し、受信したブロックでそのログ メソッドを呼び出します。

次のステップとして、それらを配列に追加して反復し、ActivityLog#initialize各メソッドを動的に作成することができます。

怠惰な方法は、任意のメソッドを受け入れ、それをクラス定数に変換してから上記の手順を実行する を用意ActivityLogすることです。method_missing通常、デバッグが難しくなり、ロガーに対応しないオブジェクトのメソッドを呼び出すと、誤解を招く例外が発生する可能性がありmethods、オブジェクトに対して呼び出して、リストされているメソッドを確認できないため、これは悪いことです。

それが役立つことを願っています。

于 2012-06-20T17:31:31.963 に答える
1

ブロックの最後のステートメントは常に戻り値です。lブロックの最後のステートメントとしてユーザーに強制的に記述させたくない場合lは、ブロックの戻り値の代わりに、インスタンスに対して行われた変更 (それが何であれ) を使用する必要があります。別のオプションは、lオブジェクトのセッター動作を変更して、割り当て時にすべての値の配列を返すことですが、コードによっては最初のオプションを使用しますが、次のようになります。

class Log
  attr_accessor :duration, :priority
  def initialize(block)
    block.call(self)
  end
end

Log.new proc{ |l| l.duration = 0.3; l.priority = 5 }
# => #<Log:0x000000029d8030 @duration=0.3, @priority=5>
于 2012-06-20T17:16:45.210 に答える
0

を使用しreturn、各ブロックをコンマで区切ります。

Activity.new('20-06-2012') do
  return_value = Eat.log do |l|
    l.duration = 0.30
    l.priority = 5
  end, Work.log do |l|
    l.duration = 2
    l.priority = 3
  end
return return_value #redundant
end

コンマで区切られた複数の値を返すと、Ruby はそれらを 1 つの配列に結合します。

于 2012-06-20T17:13:29.737 に答える
0

André のアプローチは機能しますが、あまり読みやすくありません。1 か月かそこらで戻ってきた場合、そこに隠れているコンマを見つけるのは難しいです。

個人的には、配列コレクションをより明示的にします。

Activity.new('20-06-2012') do
  logs = []
  logs << Eat.log do |l|
    l.duration = 0.30
    l.priority = 5
  end
  logs << Work.log do |l|
    l.duration = 2
    l.priority = 3
  end
  logs
end

このように、コードを見て、その動作を読み間違えることは非常に困難です。

于 2012-06-20T17:16:15.093 に答える
0

ログ構造が単純で一貫している場合 (およびその場合のみ)、次のような方法で問題を解決できます。

Activity.new('20-06-2012') do
  logs = {
    Eat => {:duration => 0.30, :priority => 5},
    Work => {:duration => 2, :priority => 3}
  }

  logs.map do |log_type, log_data|
    log_type.log do |l|
      l.duration = log_data[:duration]
      l.priority = log_data[:priority]
    end
  end
end

これがあなたの構造に適合するかどうか、また十分に読みやすいかどうかについては、自分で判断する必要があります。

于 2012-06-20T17:22:30.567 に答える