it-swarm-id.com

Bagaimana Anda mengoper argumen ke define_method?

Saya ingin meneruskan argumen ke metode yang didefinisikan menggunakan define_method, bagaimana saya melakukannya?

150
Sixty4Bit

Blok yang Anda lewati ke define_method dapat menyertakan beberapa parameter. Begitulah cara Anda mendefinisikan metode menerima argumen. Ketika Anda mendefinisikan sebuah metode, Anda benar-benar hanya menjuluki blok dan menyimpan referensi di kelas. Parameter datang dengan blok. Begitu:

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

... dan jika Anda menginginkan parameter opsional

 class Bar
   define_method(:foo) do |arg=nil|                  
     arg                                                                                          
   end   
 end

 a = Bar.new
 a.foo
 #=> nil
 a.foo 1
 # => 1

... Argumen sebanyak yang Anda inginkan

 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']

... kombinasi dari

 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]

... mereka semua

 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

Pembaruan

Ruby 2.0 memperkenalkan splat ganda ** (dua bintang) yang ( saya kutip ):

Ruby 2.0 memperkenalkan argumen kata kunci, dan ** bertindak seperti *, tetapi untuk argumen kata kunci. Ini mengembalikan hash dengan pasangan kunci/nilai.

... dan tentu saja Anda dapat menggunakannya dalam metode define juga :)

 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}

Contoh atribut yang dinamai:

 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}

Saya mencoba membuat contoh dengan argumen kata kunci, splat, dan double splat semuanya dalam satu:

 define_method(:foo) do |variable1, variable2,*arg, i_will_not: 'work', **options, &block|
    # ...

atau

 define_method(:foo) do |variable1, variable2, i_will_not: 'work', *arg, **options, &block|
    # ...

... tapi ini tidak akan berhasil, sepertinya ada batasan. Ketika Anda berpikir tentang hal itu masuk akal karena operator percikan adalah "menangkap semua argumen yang tersisa" dan splat ganda adalah "menangkap semua argumen kata kunci yang tersisa" karena itu pencampuran mereka akan mematahkan logika yang diharapkan. (Saya tidak punya referensi untuk membuktikan hal ini, doh!)

pembaruan 2018 Agustus:

Artikel ringkasan: https://blog.eq8.eu/til/metaprogramming-Ruby-examples.html

84
equivalent8

Selain jawaban Kevin Conner: argumen blok tidak mendukung semantik yang sama dengan argumen metode. Anda tidak dapat mendefinisikan argumen default atau memblokir argumen.

Ini hanya diperbaiki dalam Ruby 1.9 dengan sintaks "stabby lambda" alternatif baru yang mendukung semantik argumen metode penuh.

Contoh:

# 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' }
59
Jörg W Mittag

Dengan 2.2 Anda sekarang dapat menggunakan argumen kata kunci: https://robots.thoughtbot.com/Ruby-2-keyword-arguments

define_method(:method) do |refresh: false|
  ..........
end
7
akostadinov