2012-12-19 9 views
9

jestem w stanie określić metodę tak:Jak zdefiniować metodę w ruby ​​za pomocą ikonki i opcjonalnego skrótu w tym samym czasie?

def test(id, *ary, hash_params) 
    # Do stuff here 
end 

Ale to sprawia, że ​​hash_params argumentem obowiązkowe. Te też nie działają:

def t(id, *ary, hash_params=nil) # SyntaxError: unexpected '=', expecting ')' 
def t(id, *ary, hash_params={}) # SyntaxError: unexpected '=', expecting ')' 

Czy istnieje sposób na uczynienie go opcjonalnym?

+0

Którą wersję Ruby używasz? –

+0

Pytanie nie jest jasne. Jeśli wykonasz 'test (id, hash1)', czy spodziewasz się 'ary = [hash1]; hash = nil' lub 'ary = []; hash = hash1'? Jaka jest reguła, która decyduje o wyborze? – sawa

Odpowiedz

10

Nie możesz tego zrobić. Musisz zastanowić się, w jaki sposób Ruby byłby w stanie określić, co należy do *ary i co należy do opcjonalnego skrótu. Ponieważ Ruby nie może odczytać twojego umysłu, powyższa kombinacja argumentów (splat + opcjonalnie) jest niemożliwa do rozwiązania logicznego.

albo trzeba zmienić swoje argumenty:

def test(id, h, *a) 

W takim przypadku h nie będzie opcjonalna. Lub zaprogramuj go ręcznie:

def test(id, *a) 
    h = a.last.is_a?(Hash) ? a.pop : nil 
    # ^^ Or whatever rule you see as appropriate to determine if h 
    # should be assigned a value or not. 
1

@Casper ma rację. Tylko jeden z parametrów może mieć operatora splat. Argumenty są przypisywane do niepodzielonych parametrów od lewej do prawej. Pozostałe argumenty zostaną przypisane do parametru splat.

Możesz zrobić, jak sugeruje. Można też to zrobić:

def test(id,h={},*a) 
    # do something with id 
    # if not h.empty? then do something with h end 
    # if not a.empty? then do something with a end 
end 

Oto kilka przykładowych tras IRB:

001 > def test (id, h={}, *a) 
002?> puts id.inspect 
003?> puts h.inspect 
004?> puts a.inspect 
005?> end 
=> nil 
006 > test(1,2,3,4) 
1 
2 
[3, 4] 
=> nil 
007 > test(1,{"a"=>1,"b"=>2},3,4) 
1 
{"a"=>1, "b"=>2} 
[3, 4] 
=> nil 
008 > test(1,nil,3,4) 
1 
nil 
[3, 4] 
=> nil 

Może dodam. Możesz mieć opcjonalny parametr jako ostatni parametr, ale musi to być blok/proc.

Na przykład:

def test(a,*b, &c) 
    puts a.inspect 
    puts b.inspect 
    c.call if not c.nil? 
end 

Oto niektóre połączenia przykładowe:

006 > test(1,2,3) 
1 
[2, 3] 
=> nil 
007 > test(1,2,3) {puts "hello"} 
1 
[2, 3] 
hello 
=> nil 
+0

Tak, prawda. Chociaż 'h = nil' lub' h = {} 'ma sens tylko wtedy, gdy chcesz wywołać' test' z 'test (123)', ponieważ we wszystkich innych przypadkach musisz podać wartość 'h' ręcznie podczas wywoływania 'testu'. Ruby nie zaakceptuje 'testu (123,, somehing, else)'. – Casper

+1

Na podstawie jego pytania, 'test (123)' może być prawidłowym połączeniem. –

3

oprócz caspers answer:

można użyć parametru powitalny i sprawdź, czy ostatni parametr jest hasz. Następnie bierzesz hasz jako ustawienia.

przykład kodu:

def test(id, *ary) 
    if ary.last.is_a?(Hash) 
    hash_params = ary.pop 
    else 
    hash_params = {} 
    end 
    # Do stuff here 

    puts "#{id}:\t#{ary.inspect}\t#{hash_params.inspect}" 
end 


test(1, :a, :b) 
test(2, :a, :b, :p1 => 1, :p2 => 2) 
test(3, :a, :p1 => 1, :p2 => 2) 

Wynik jest:

1: [:a, :b] {} 
2: [:a, :b] {:p1=>1, :p2=>2} 
3: [:a] {:p1=>1, :p2=>2} 

To sprawi problemów, jeśli tablica parametr powinien zawierać skrót na ostatniej pozycji.

test(5, :a, {:p1 => 1, :p2 => 2}) 
test(6, :a, {:p1 => 1, :p2 => 2}, {}) 

Wynik:

5: [:a] {:p1=>1, :p2=>2} 
6: [:a, {:p1=>1, :p2=>2}] {} 
2

Mogłeś (nie-) użyć opcjonalnego bloku na końcu listy parametrów:

def test(id,*ary, &block) 
    if block_given? 
    opt_hash = block.call 
    p opt_hash 
    end 
    p id 
    p ary 
end 

test(1,2,3){{:a=>1,:b=>2}} 
# output: 
# {:a=>1, :b=>2} #Hurray! 
# 1 
# [2, 3] 
+0

Ciekawe rozwiązanie ... :) –

12

nie ma wsparcia dla tego w ActiveSupport poprzez użycie rozszerzenia tablicy extract_options!.

def test(*args) 
    opts = args.extract_options! 
end 

Jeśli ostatni element jest hash, to będzie pop go z tablicy i zwraca go, w przeciwnym razie zwróci pusty hash, który jest technicznie tak samo jak to, co chcesz (*args, opts={}) zrobić.

ActiveSupport Array#extract_options!