Réponses:
Le bloc que vous passez à define_method peut inclure certains paramètres. C'est ainsi que votre méthode définie accepte les arguments. Lorsque vous définissez une méthode, vous ne faites que surnommer le bloc et en garder une référence dans la classe. Les paramètres sont fournis avec le bloc. Alors:
define_method(:say_hi) { |other| puts "Hi, " + other }
... et si vous voulez des paramètres optionnels
class Bar
define_method(:foo) do |arg=nil|
arg
end
end
a = Bar.new
a.foo
#=> nil
a.foo 1
# => 1
... autant d'arguments que vous le souhaitez
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']
...combinaison de
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]
... tous
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
Mettre à jour
Ruby 2.0 a introduit le double splat **
(deux étoiles) qui ( je cite ) fait:
Ruby 2.0 a introduit des arguments de mots-clés et ** agit comme *, mais pour les arguments de mots-clés. Il renvoie un Hash avec des paires clé / valeur.
... et bien sûr, vous pouvez également l'utiliser dans la méthode define :)
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}
Exemple d'attributs nommés:
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}
J'essayais de créer un exemple avec un argument de mot-clé, un splat et un double splat tout en un:
define_method(:foo) do |variable1, variable2,*arg, i_will_not: 'work', **options, &block|
# ...
ou
define_method(:foo) do |variable1, variable2, i_will_not: 'work', *arg, **options, &block|
# ...
... mais cela ne fonctionnera pas, il semble qu'il y ait une limitation. Quand vous y réfléchissez, cela a du sens car l'opérateur splat "capture tous les arguments restants" et double splat "capture tous les arguments mot-clé restants", donc les mélanger casserait la logique attendue. (Je n'ai aucune référence pour prouver ce point doh!)
mise à jour 2018 août:
Article de synthèse: https://blog.eq8.eu/til/metaprogramming-ruby-examples.html
a.foo 1
place de foo 1
). Merci!
En plus de la réponse de Kevin Conner: les arguments de bloc ne prennent pas en charge la même sémantique que les arguments de méthode. Vous ne pouvez pas définir d'arguments par défaut ou bloquer des arguments.
Ceci n'est corrigé que dans Ruby 1.9 avec la nouvelle syntaxe alternative "stabby lambda" qui supporte la sémantique complète des arguments de méthode.
Exemple:
# 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' }
Avec la version 2.2, vous pouvez désormais utiliser des arguments de mots clés: https://robots.thoughtbot.com/ruby-2-keyword-arguments
define_method(:method) do |refresh: false|
..........
end