Jawaban:
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 }
... 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
Memperbarui
Ruby 2.0 memperkenalkan gambar percikan 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 percikan 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!)
perbarui 2018 Agustus:
Artikel ringkasan: https://blog.eq8.eu/til/metaprogramming-ruby-examples.html
a.foo 1
bukan foo 1
). Terima kasih!
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 di 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' }
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