Antworten:
Der Block, den Sie an define_method übergeben, kann einige Parameter enthalten. So akzeptiert Ihre definierte Methode Argumente. Wenn Sie eine Methode definieren, benennen Sie den Block wirklich nur mit einem Spitznamen und behalten einen Verweis darauf in der Klasse. Die Parameter werden mit dem Block geliefert. So:
define_method(:say_hi) { |other| puts "Hi, " + other }
... und wenn Sie optionale Parameter wünschen
class Bar
define_method(:foo) do |arg=nil|
arg
end
end
a = Bar.new
a.foo
#=> nil
a.foo 1
# => 1
... so viele Argumente wie Sie wollen
class Bar
define_method(:foo) do |*arg|
arg
end
end
a = Bar.new
a.foo
#=> []
a.foo 1
# => [1]
a.foo 1, 2 , 'AAA'
# => [1, 2, 'AAA']
...Kombination von
class Bar
define_method(:foo) do |bubla,*arg|
p bubla
p arg
end
end
a = Bar.new
a.foo
#=> wrong number of arguments (0 for 1)
a.foo 1
# 1
# []
a.foo 1, 2 ,3 ,4
# 1
# [2,3,4]
... alle von ihnen
class Bar
define_method(:foo) do |variable1, variable2,*arg, &block|
p variable1
p variable2
p arg
p block.inspect
end
end
a = Bar.new
a.foo :one, 'two', :three, 4, 5 do
'six'
end
Aktualisieren
Ruby 2.0 hat Double Splat **
(zwei Sterne) eingeführt, was ( ich zitiere ) Folgendes bewirkt:
Ruby 2.0 führte Schlüsselwortargumente ein und ** verhält sich wie *, jedoch für Schlüsselwortargumente. Es gibt einen Hash mit Schlüssel / Wert-Paaren zurück.
... und natürlich kannst du es auch in der Methode define verwenden :)
class Bar
define_method(:foo) do |variable1, variable2,*arg,**options, &block|
p variable1
p variable2
p arg
p options
p block.inspect
end
end
a = Bar.new
a.foo :one, 'two', :three, 4, 5, ruby: 'is awesome', foo: :bar do
'six'
end
# :one
# "two"
# [:three, 4, 5]
# {:ruby=>"is awesome", :foo=>:bar}
Beispiel für benannte Attribute:
class Bar
define_method(:foo) do |variable1, color: 'blue', **other_options, &block|
p variable1
p color
p other_options
p block.inspect
end
end
a = Bar.new
a.foo :one, color: 'red', ruby: 'is awesome', foo: :bar do
'six'
end
# :one
# "red"
# {:ruby=>"is awesome", :foo=>:bar}
Ich habe versucht, ein Beispiel mit Schlüsselwortargument, Splat und Double Splat in einem zu erstellen:
define_method(:foo) do |variable1, variable2,*arg, i_will_not: 'work', **options, &block|
# ...
oder
define_method(:foo) do |variable1, variable2, i_will_not: 'work', *arg, **options, &block|
# ...
... aber das wird nicht funktionieren, es sieht so aus, als gäbe es eine Einschränkung. Wenn Sie darüber nachdenken, ist dies sinnvoll, da der splat-Operator "alle verbleibenden Argumente erfasst" und double splat "alle verbleibenden Schlüsselwortargumente erfasst", sodass das Mischen dieser Argumente die erwartete Logik brechen würde. (Ich habe keinen Hinweis, um diesen Punkt zu beweisen, doh!)
Update 2018 August:
Zusammenfassender Artikel: https://blog.eq8.eu/til/metaprogramming-ruby-examples.html
a.foo 1
anstelle von sein foo 1
). Vielen Dank!
Zusätzlich zu Kevin Conners Antwort: Blockargumente unterstützen nicht dieselbe Semantik wie Methodenargumente. Sie können keine Standardargumente definieren oder Argumente blockieren.
Dies wird nur in Ruby 1.9 mit der neuen alternativen Syntax "stabby lambda" behoben, die die vollständige Semantik von Methodenargumenten unterstützt.
Beispiel:
# Works
def meth(default = :foo, *splat, &block) puts 'Bar'; end
# Doesn't work
define_method :meth { |default = :foo, *splat, &block| puts 'Bar' }
# This works in Ruby 1.9 (modulo typos, I don't actually have it installed)
define_method :meth, ->(default = :foo, *splat, &block) { puts 'Bar' }
Mit 2.2 können Sie jetzt Schlüsselwortargumente verwenden: https://robots.thoughtbot.com/ruby-2-keyword-arguments
define_method(:method) do |refresh: false|
..........
end