2012-12-19 11 views
9

sono in grado di definire un metodo come questo:Come definire un metodo in ruby ​​usando splat e un hash opzionale allo stesso tempo?

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

Ma questo rende il hash_params argomento obbligatorio. Questi non funzionano neanche:

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

C'è un modo per renderlo opzionale?

+0

Quale versione di Ruby stai usando? –

+0

La domanda non è chiara. Se esegui 'test (id, hash1)', stai aspettando 'ary = [hash1]; hash = nil' o 'ary = []; hash = hash1'? Qual è la regola che determina quale scegliere? – sawa

risposta

10

Non puoi farlo. Devi pensare a come Ruby sarebbe in grado di determinare cosa appartiene a *ary e cosa appartiene all'hash opzionale. Dato che Ruby non può leggere la tua mente, la combinazione di argomenti di cui sopra (splat + opzionale) è impossibile da risolvere logicamente.

O si deve riorganizzare le argomentazioni:

def test(id, h, *a) 

Nel qual caso h non sarà facoltativa. Oppure programmalo manualmente:

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 ha ragione. Solo uno dei parametri può avere l'operatore splat. Gli argomenti vengono assegnati ai parametri non splattati prima da sinistra a destra. Gli argomenti rimanenti vengono assegnati al parametro splat.

Si può fare come suggerisce. È anche possibile fare questo:

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 

Ecco alcune piste IRB campione:

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 

Forse, dovrei aggiungere. È possibile avere un parametro opzionale come ultimo parametro, ma deve essere un blocco/proc.

Ad esempio:

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

Ecco alcune chiamate di esempio:

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

Sì, vero. Sebbene 'h = nil' o' h = {} 'ha senso solo se chiami' test' con 'test (123)', perché in tutti gli altri casi devi fornire il valore a 'h' manualmente quando si chiama 'test'. Ruby non accetta 'test (123,, qualcosa, altro)'. – Casper

+1

In base alla sua domanda, 'test (123)' potrebbe essere una chiamata valida. –

3

Oltre a caspers answer:

È possibile utilizzare un parametro di spruzzi e verificare, se l'ultimo parametro è un hash. Quindi si prende l'hash come impostazioni.

Un esempio di codice:

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) 

risultato è:

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

Questo farà problemi, se la matrice-parametro deve contenere un hash in ultima posizione.

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

Risultato:

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

Si potrebbe (mis-) utilizzare il blocco opzionale alla fine dell'elenco dei parametri:

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

Soluzione interessante ... :) –

12

V'è il supporto per questo nella ActiveSupport attraverso la utilizzo dell'estensione dell'array extract_options!.

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

Se l'ultimo elemento è un hash, allora sarà pop dalla matrice e restituirlo, altrimenti restituirà un hash vuoto, che è tecnicamente lo stesso di quello che si vuole (*args, opts={}) da fare.

ActiveSupport Array#extract_options!

Problemi correlati