Tôi muốn chuyển một đối số cho một phương thức được xác định bằng cách sử dụng define_method, tôi sẽ làm như thế nào?Làm thế nào để bạn vượt qua đối số để define_method?
Trả lời
Khối bạn vượt qua để define_method có thể bao gồm một số thông số. Đó là cách phương thức được định nghĩa của bạn chấp nhận các đối số. Khi bạn xác định một phương thức, bạn thực sự chỉ cần đặt tên cho khối đó và giữ một tham chiếu đến nó trong lớp. Các tham số đi kèm với khối. Vì vậy:
define_method(:say_hi) { |other| puts "Hi, " + other }
Ngoài câu trả lời của Kevin Conner: đối số khối không hỗ trợ cùng ngữ nghĩa làm đối số phương pháp. Bạn không thể xác định đối số mặc định hoặc chặn đối số.
Điều này chỉ được sửa trong Ruby 1.9 với cú pháp thay thế mới "stabby lambda" hỗ trợ ngữ nghĩa đối số đầy đủ.
Ví dụ:
# 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' }
Trên thực tế, tôi tin rằng các đối số khối trên define_method làm hỗ trợ splat, mà có thể cung cấp một cách vòng-a-bout để xác định đối số mặc định quá. – Chinasaur
Chinasaur là chính xác về các đối số khối cho phép các biểu tượng. Tôi đã xác nhận điều này trong cả Ruby 1.8.7 và 1.9.1. –
Cảm ơn, tôi đã quên mất điều này. Đã sửa lỗi. –
... và nếu bạn muốn thông số tùy chọn
class Bar
define_method(:foo) do |arg=nil|
arg
end
end
a = Bar.new
a.foo
#=> nil
a.foo 1
# => 1
... như nhiều lập luận như bạn muốn
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']
... kết hợp của
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]
... tất cả trong số họ
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
Cập nhật
của Ruby 2.0 giới thiệu đôi splat **
(hai ngôi sao) mà (I quote) thực hiện: đối số từ khóa
của Ruby 2.0 giới thiệu và ** hoạt động như *, nhưng đối với đối số từ khóa. Nó trả về một Hash với các cặp khóa/giá trị.
... và tất nhiên bạn có thể sử dụng nó trong xác định phương pháp quá :)
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}
Đặt tên thuộc tính ví dụ:
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}
Tôi đã cố gắng để tạo ra ví dụ với lập luận từ khóa, splat và double splat tất cả trong một:
define_method(:foo) do |variable1, variable2,*arg, i_will_not: 'work', **options, &block|
# ...
hoặc
define_method(:foo) do |variable1, variable2, i_will_not: 'work', *arg, **options, &block|
# ...
... nhưng điều này sẽ không hoạt động, có vẻ như có giới hạn. Khi bạn nghĩ về nó có ý nghĩa như toán tử splat là "nắm bắt tất cả các đối số còn lại" và splat kép là "nắm bắt tất cả các đối số từ khóa còn lại" do đó trộn chúng sẽ phá vỡ logic dự kiến. (Tôi không có bất kỳ tham chiếu nào để chứng minh điểm này!)
Thú vị - đặc biệt khối thứ tư: nó đã hoạt động trên 1.8.7! Khối đầu tiên không hoạt động trong 1.8.7 và khối thứ hai có lỗi đánh máy (phải là 'a.foo 1' thay vì' foo 1'). Cảm ơn! –
cảm ơn phản hồi, lỗi đánh máy đã được sửa, ... Trên ruby 1.9.3 và 1.9.2 tất cả các ví dụ hoạt động và tôi tích cực là trên 1.9.1 quá (nhưng không thử) – equivalent8
Tôi kết hợp câu trả lời này với chấp nhận câu trả lời tại http://stackoverflow.com/questions/4470108/when-monkey-patching-a-method-can-you-call-the-overridden-method-from-the-new-i để tìm cách ghi đè (không ghi đè lên) một phương thức trong thời gian chạy có các tham số tùy chọn và một khối và vẫn có thể gọi phương thức gốc với các tham số và khối. Ah, ruby. Cụ thể, tôi cần ghi đè Savon :: Client.request trong env dev của tôi cho một cuộc gọi API đến một máy chủ mà tôi có thể truy cập chỉ trong sản xuất. Chúc mừng! – pduey
Với 2.2 bây giờ bạn có thể sử dụng đối số từ khóa: https://robots.thoughtbot.com/ruby-2-keyword-arguments
define_method(:method) do |refresh: false|
..........
end
Đó chỉ là một điều tuyệt đối không được pha trộn. Làm tốt lắm, Kevin Costner. – Fuser97381