Je voudrais passer un argument (s) à une méthode en cours de définition en utilisant define_method, comment ferais-je cela?Comment passez-vous les arguments à define_method?
Répondre
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 nickname le bloc et gardez une référence dans la classe. Les paramètres viennent avec le bloc. Alors:
define_method(:say_hi) { |other| puts "Hi, " + other }
En plus de réponse de Kevin Conner: les arguments de bloc ne supportent pas la même sémantique que les arguments de méthode. Vous ne pouvez pas définir les arguments par défaut ou les arguments de blocage.
Ceci n'est corrigé que dans Ruby 1.9 avec la nouvelle syntaxe alternative "stabby lambda" qui prend en charge la sémantique d'argument de méthode complète.
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' }
En fait, je crois que les arguments de bloc sur define_method supportent splat, ce qui peut fournir un moyen de définir des arguments par défaut aussi. – Chinasaur
Chinasaur est correct sur les arguments de bloc permettant des splats. J'ai confirmé cela à la fois dans Ruby 1.8.7 et 1.9.1. –
Merci, j'ai oublié à ce sujet. Fixé maintenant –
... et si vous voulez des paramètres facultatifs
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 voulez
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
Mise à jour
Ruby 2.0 introduit deux floc **
(deux étoiles) qui (I quote) fait:
Ruby 2.0 introduit des arguments clés , et ** agit comme *, mais pour les arguments de mots-clés. Il renvoie un hachage avec des paires clé/valeur.
... et bien sûr, vous pouvez l'utiliser à définir dans la méthode aussi :)
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}
nommé attributs par exemple:
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}
je tentais de créer par exemple avec l'argument de mot-clé, splat et 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 prend tout son sens car l'opérateur splat "capture tous les arguments restants" et double splat "capture tous les arguments de mots-clés restants". Par conséquent, les mélanger briserait la logique attendue. (Je n'ai aucune référence pour prouver ce point doh!)
Intéressant - Spécialement le 4ème bloc: il a fonctionné sur 1.8.7! Le premier bloc n'a pas fonctionné en 1.8.7, et le deuxième bloc a une faute de frappe (devrait être 'a.foo 1' au lieu de' foo 1'). Merci! –
merci pour les commentaires, typo a été corrigé, ... Sur ruby 1.9.3 et 1.9.2 tous les exemples fonctionne et je suis positif que sur 1.9.1 aussi (mais n'a pas essayé) – equivalent8
J'ai combiné cette réponse avec le réponse acceptée à http://stackoverflow.com/questions/4470108/when-monkey-patching-a-method-can-you-call-the-overridden-method-from-the-new-i pour comprendre comment écraser (pas override) une méthode à l'exécution qui prend des arguments optionnels et un bloc et qui peut toujours appeler la méthode d'origine avec les arguments et le bloc. Ah, rubis. Plus précisément, j'avais besoin de remplacer Savon :: Client.request dans mon dev env pour un seul appel API vers un hôte auquel je ne peux accéder qu'en production. À votre santé! – pduey
Avec 2.2 vous pouvez maintenant utiliser des arguments clés: https://robots.thoughtbot.com/ruby-2-keyword-arguments
define_method(:method) do |refresh: false|
..........
end
Eh bien, c'est juste une chose de pure Beaty pure. Beau travail, Kevin Costner. – Fuser97381