2016-04-14 5 views
4

Ich möchte ein Proc, das Lambda-Verhalten zeigt (Argumentüberprüfung), in eines konvertieren, das nicht funktioniert. Im Folgenden ist ein sehr konstruiertes Beispiel, aber es sollte den Punkt zu vermitteln:Ignoriere Lambda-Argumentprüfung

Das Ziel ist die Schaffung eines DSL, die etwa wie folgt aussieht:

NumberSeries.perform do 
    add first_series: -> { natural_numbers.take(10) }, 
     second_series: -> { fibonacci_numbers.take(10) } 
end 

Beachten Sie, dass natural_numbers und fibonacci_numbers nicht als Argumente übergeben im DSL. Die Implementierung von add etwa wie folgt aussieht:

NaturalNumbersFibonacciNumbers = Struct.new(:natural_numbers, :fibonacci_numbers) 
FAMOUS_NUMBER_SERIES = NaturalNumbersFibonacciNumbers. 
         new(natural_numbers, fibonacci_numbers) 

def add(first_series:, second_series:) 
    first_numbers = FAMOUS_NUMBER_SERIES.instance_eval(&first_series) 
    second_numbers = FAMOUS_NUMBER_SERIES.instance_eval(&second_series) 
    first_numbers.zip(second_numbers).map { |x, y| x + y } 
end 

Nun, wenn ich -> mit proc im DSL ersetzen, wird es funktionieren. Um jedoch die Lambda-Ausdrücke zu halten, würde ich

ArgumentError: wrong number of arguments (1 for 0)

bekommen als BasicObject#instance_eval selbst auf das Lambda liefert, aber das Lambda erwartet keine Argumente.


Ich will nicht Fiddle aus offensichtlichen Gründen verwenden.

+2

Does 'instance_exec' Arbeit statt - die Sie Argumente zu übergeben können (oder in diesem Fall nicht)? – matt

+0

Ich bin verwirrt. Warum definierst du nicht einfach dein DSL mit Procs? 'add first_series: proc {natural_numbers.take (10)}' ist genauso elegant. –

+0

@matt, yep, 'instance_exec' hat den Trick gemacht. Keine Ahnung, wie ich daran nicht gedacht habe. Auch wenn es die Frage nicht beantwortet, löst es das ursprüngliche Problem, also füge das als Antwort hinzu und wenn keiner weiß, wie es geht, werde ich es akzeptieren. – ndn

Antwort

1

instance_exec ist eine Alternative zu instance_eval, mit der Sie die an den Block übergebenen Parameter steuern können und den Empfänger nicht passieren, wie instance_eval tut. Sie können es als Behelfslösung für Ihr Problem verwenden, da es Ihnen ermöglicht Null args weitergeben müssen:

irb:108:0> Object.new.instance_eval &-> { puts "Hello" } 
ArgumentError: wrong number of arguments (given 1, expected 0) 
    from (irb):108:in `block in irb_binding' 
    from (irb):108:in `instance_eval' 
    from (irb):108 
    from /Users/matt/.rubies/ruby-2.3.0/bin/irb:11:in `<main>' 
irb:109:0> Object.new.instance_exec &-> { puts "Hello" } 
Hello 
=> nil