2008-09-18 14 views

Odpowiedz

168

Blok przekazywany do metody define_method może zawierać niektóre parametry. W ten sposób zdefiniowana metoda przyjmuje argumenty. Kiedy definiujesz metodę, tak naprawdę po prostu przezwiskasz blok i zachowujesz odniesienie do niego w klasie. Parametry pochodzą z bloku. Więc:

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

Dobrze, że to tylko sprawa czystej nieskażonej Beaty. Dobra robota, Kevin Costner. – Fuser97381

58

Oprócz odpowiedź Kevin Conner za: argumenty blokowych nie obsługują te same semantykę jako argumenty metod. Nie można definiować domyślnych argumentów ani argumentów blokowych.

Zostało to naprawione tylko w Rubim 1.9 z nową alternatywną składnią "skurczona lambda", która obsługuje semantykę pełnego argumentu metody.

Przykład:

# 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' } 
+3

Właściwie, uważam, że argumenty blokowe na module define_method do support splat mogą stanowić sposób na zdefiniowanie domyślnych argumentów. – Chinasaur

+1

Chinasaur ma poprawne argumenty bloków pozwalające na użycie ikon. Potwierdziłem to zarówno w Ruby 1.8.7, jak i 1.9.1. –

+0

Dzięki, zapomniałem o tym. Naprawiono teraz. –

74

... a jeśli chcesz opcjonalne parametry

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

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

... jak wiele argumentów, ile chcesz

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

... kombinacja

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] 

... wszyscy

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 

Aktualizacja

Ruby 2.0 wprowadzono podwójne ikona ** (dwie gwiazdki), która (I quote) robi:

Ruby 2.0 wprowadzone argumenty słów kluczowych i ** działa jak *, ale dla argumentów słów kluczowych. Zwraca Hash z parami klucz/wartość.

... i oczywiście można go używać na określenie metody zbyt :) przykład

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} 

Nazwany atrybuty:

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} 

starałem się tworzyć przykład ze słowem kluczowym argumentem, ikona w postaci splat i podwójnej: w jednym:

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

lub

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

... ale to nie zadziała, wygląda na to, że istnieje ograniczenie. Kiedy myślisz o tym ma sens, operatorem splat jest "przechwytywanie wszystkich pozostałych argumentów", a podwójna ikona to "przechwytywanie wszystkich pozostałych argumentów słów kluczowych", dlatego ich mieszanie przerwałoby oczekiwaną logikę. (Nie mam żadnego odniesienia, aby udowodnić ten punkt!)

+0

Ciekawe - w szczególności czwarty blok: działało na 1.8.7! Pierwszy blok nie działał w 1.8.7, a drugi blok ma literówkę (powinno to być 'a.foo 1' zamiast' foo 1'). Dzięki! –

+1

dzięki za opinie, poprawiono literówkę, ... Na Rubim 1.9.3 i 1.9.2 wszystkie przykłady działają i jestem przekonany, że również na 1.9.1 (ale nie spróbowałem) – equivalent8

+0

Połączyłem tę odpowiedź z przyjęta odpowiedź na http://stackoverflow.com/questions/4470108/when-monkey-patching-a-method-can-you-call-the-overridden-method-from-the-new-i, aby dowiedzieć się jak nadpisać (bez przesłonięcia) metoda w czasie wykonywania, która pobiera opcjonalne argumenty i blok i nadal może wywoływać oryginalną metodę z argumentami i blokiem. Ah, ruby. W szczególności musiałem zastąpić Savon :: Client.request w moim dev env dla pojedynczego wywołania API dla hosta, do którego mam dostęp tylko w produkcji. Twoje zdrowie! – pduey

Powiązane problemy