2011-10-06 20 views
8

Recentemente ho avuto alcuni problemi nel far funzionare correttamente un percorso. La soluzione si è rivelata semplice, ma ho avuto un problema inaspettato che mi ha impedito di raggiungerlo. La seguente riga, incluso in un modello di erb, funziona perfettamente:Spaziatura tra parentesi in Ruby

<%= button_to "Confirm delivery", delivery_confirm_path(@delivery) %> 

Questo non lo fa:

<%= button_to "Confirm delivery", delivery_confirm_path (@delivery) %> 

Sembra spaziatura prima della parentesi di apertura non è consentita in questo caso. L'errore che ottengo è questo:

/app/views/deliveries/_delivery_buttons.html.erb:22: syntax error, 
unexpected tLPAREN_ARG, expecting keyword_do or '{' or '(' 
...ivery", delivery_confirm_path (@delivery));@output_buffer... 
...        ^

Qualcuno può spiegare perché questo causa un errore?

EDIT: per informazioni, questo è di Ruby 1.9.2 e Rails 3.0.9, su Windows 7 a 64-bit

+2

http://www.justskins.com/forums/ruby-1-8-space-122361.html – Gazler

+0

Sembra come una limitazione della lingua. Hai trovato una soluzione alternativa, non vedo perché dovevi metterlo come domanda. – Candide

+0

@Gazler +1, ottimo collegamento con un post dello stesso Matz! –

risposta

6

Chiunque che mette uno spazio prima di un parametro-list parentesi ottiene ciò che meritano, che dico!

Il problema è che sta chiudendo la chiamata a button_to nel secondo esempio (spazio prima delle parentesi) e non sa cosa fare dopo.

+0

Nel tuo commento alla risposta di Sebastien, dici che è documentato quando puoi usare uno spazio. Avete qualche link ad esso? Il commento di Gazler si collega a una risposta piuttosto definitiva di Matz, ma non ho visto dove è documentato che la spaziatura sia importante. – asc99c

+1

@ asc99c Mi riferivo al libro O'Reilly The Ruby Programming Language, sezione 2.1.6.2, "Spaces and method invocations".La regola generale: non mettere uno spazio prima di un metodo e il suo paren di apertura :) Non parla nel libro del perché e fornisce un esempio diverso di rottura. –

-1

Non è possibile utilizzare uno spazio tra una funzione e le sue argomentazioni. In effetti, in rails il motore parser vuole la parentesi della funzione subito dopo la sua chiamata. Questa è la vita dei binari.

Spero di aiutarti.

Grazie

+1

Non è forse la "vita da rubino"? – christianblais

+4

Questo non è corretto; le * circostanze * in base alle quali è possibile, e non possono, utilizzare uno spazio, sono documentate. 'puts (" ciao ")', per esempio, funziona bene. –

+0

Puoi ** usare uno spazio tra una funzione e i suoi argomenti, in Ruby, e anche in Rails. Questi tutti producono lo stesso risultato: 'mette "hi"' 'puts ("hi")' 'puts ("hi")' 'mette "hi"' –

4

Non sono sicuro se questo è il modo in cui il parser di Ruby funziona, ma penso in questo modo: La virgola prima dello delivery_confirm_path ha precedenza più alta delle parentesi, a meno che non si liberi dello spazio.

Il parser vede la chiamata metodo come questo:

button_to "Confirm delivery", delivery_confirm_path 

In altre parole, delivery_confirm_path viene analizzato come una chiamata metodo senza argomenti. Ma poi il parser vede il penzoloni (@delivery) e non è una sintassi valida perché segue la chiamata al metodo button_to. E 'come se tu avessi questa sintassi non valida:

button_to("Confirm delivery", delivery_confirm_path) (@delivery) 

si può evitare la virgola-la precedenza in questo modo invece:

button_to "Confirm delivery", (delivery_confirm_path (@delivery)) 

ma di solito è più facile da rimuovere solo lo spazio.

Il principio da ricordare è che se c'è uno spazio prima delle parentesi con una chiamata al metodo, le parentesi vengono utilizzate come raggruppamento, e non come parentesi chiamata a metodo.

Ecco alcuni esempi per aiutare. Io uso il seguente metodo nei miei esempi:

def foo(*args); puts args.inspect; true; end 

Se siete su Ruby 1.9, ti suggerisco di accendere gli avvertimenti durante l'esecuzione degli esempi: $-w = true. Questo mostrerà warning: (...) interpreted as grouped expression se hai spazio prima delle parentesi.

Queste due linee sono sintatticamente equivalenti:

foo (1) 
foo 1 

Questo perché (1) come espressione raggruppato è solo 1.

A cosa serve raggruppare?

Una ragione è solo per una maggiore leggibilità. Potresti considerare più facile capire con paren- in questa espressione contro:

foo (2 + 3) 
foo 2 + 3 

Un'altra ragione è la precedenza. Diciamo che ho un'operazione di precedenza bassa, come l'operatore and. Poiché la chiamata al metodo ha precedenza più elevata, lo and viene valutato dopo la chiamata. Questo stampa [2] e restituisce 3:

foo 2 and 3 # same as foo(2) and 3, i.e. true and 3 

Ma questa stampa [3] e restituisce true:

foo (2 and 3) # the grouped expr returns 3, which is passed to foo 

Si noti tuttavia che l'esempio and è un po 'artificiosa, perché rubino non consente la rimozione del precedente spazio. (Non sono sicuro del perché, dal momento che && è consentito invece di and.) Ma tu hai l'idea.

foo(2 and 3) # syntax error - but why?? I still don't understand. 
foo(2 && 3) # works fine. This is strangely inconsistent. 

Questo dimostra che la rimozione lo spazio prima di una chiamata di metodo eleverà la precedenza metodo di chiamata sopra una virgola:

foo 1, foo 2 # syntax error; the 2 is dangling 
foo 1, foo(2) # ok 

Un altro punto è liste di argomenti.

foo 2, 3 # both are treated as args to the method call 
foo (2, 3) # syntax error, because "2, 3" is grouped as an expression, but is not a valid one 
Problemi correlati