Question

Je voudrais passer un argument à une méthode définie avec define_method, comment ferais-je cela?

Était-ce utile?

La solution

Le bloc que vous passez à define_method peut inclure certains paramètres. C'est comme ça que votre méthode définie accepte les arguments. Lorsque vous définissez une méthode, vous ne faites que nommer le bloc et conserver une référence à celui-ci dans la classe. Les paramètres viennent avec le bloc. Donc:

define_method(:say_hi) { |other| puts "Hi, " + other }

Autres conseils

... et si vous souhaitez 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 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 éclatement ** (deux étoiles) qui ( je cite ) fait:

  

Ruby 2.0 a introduit les arguments de mots clés et ** agit comme *, mais pour les arguments de mots clés. Il retourne un hachage avec des paires clé / valeur.

... et vous pouvez bien sûr l'utiliser aussi 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 mot clé argument, 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 y avoir 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 de mot clé restants". donc les mélanger briserait 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

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 ni d’arguments de blocage.

Ceci n’est corrigé que dans Ruby 1.9 avec la nouvelle alternative "stabby lambda". syntaxe qui prend en charge la sémantique des arguments 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' }

Avec 2.2, vous pouvez maintenant utiliser des arguments de mots clés: https://robots.thoughtbot.com/ruby-2-keyword-arguments

define_method(:method) do |refresh: false|
  ..........
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top