2009-03-14 14 views
14

Ho uno script Ruby che utilizza l'interpolazione stringa per creare messaggi di errore.Interpolazione stringa quando non si utilizza una stringa letterale

p "#{vName} is not a defined variable" => 'xxx is not a defined variable' 

Un altro programmatore è arrivato e ha tentato di esternalizzare i valori letterali delle stringhe in un file di configurazione separato. Certo, non ottiene la sostituzione.

p err_string_from_config => '#{vName} is not a defined variable' 

Ho guardato intorno, ma non poteva venire in mente nulla di meglio che la conversione in sprintf stringhe e l'utilizzo di printf.

Qualcuno sa come ottenere la sostituzione # {} per lavorare su stringhe che non sono letterali con doppia virgoletta all'interno dello script Ruby?

risposta

20

In realtà Ruby ha funzionalità molto simili a esempio di Giovanni Python:

$ irb 
>> greeting = 'hello %s, my name is %s!' 
>> interpolated = greeting % ['Mike', 'John'] 
=> "hello Mike, my name is John!" 
>> 

Questo è utile anche se il tuo argomento è una costante di matrice. Se è necessario utilizzare # {} stile di interpolazione è possibile utilizzare eval:

>> greeting = 'hi #{name}' # notice name is not defined yet 
>> name = "mike" 
>> eval '"' + greeting + '"' 

L'approccio eval sta per essere molto più lento rispetto all'utilizzo% stile di interpolazione, quindi è un trade-off.

+0

Whoops! Sono corretto. Toglierò la mia risposta. –

+0

Sì, speravo di trovare un modo per non coinvolgerlo nella modifica delle stringhe. Non è un grosso problema, ma dopo averlo chiesto, ho dovuto vedere se c'era un modo per far funzionare la sostituzione # {} senza che fosse in una stringa letterale. Sembrava che dovesse esserci un modo. –

+0

@John: Nessun problema se avessi un dollaro per ogni piccolo errore ... (In realtà non sapevo che Python lo facesse);) @Mike: Ho aggiornato la mia risposta con informazioni su come farlo usando # {{ } interpolazione di stile. –

1

Ecco come lo faccio, solo per la cronaca. Un po 'più chiaro.

gief = '#{later} please' 
later = "later" 

puts eval(%Q["#{gief}"]) 
# => later please 

Ma, onestamente, questo è quali un hack. A meno che tu non abbia una buona ragione per usare una stringa, usa invece un proc. Cerco sempre di usare un semplice rubino invece di valutare le corde.

gief = Proc.new {|l| "#{l} please" } 
later = "later" 

puts gief.call(later) 
# => later please 
+0

Sì, certamente tendo ad essere d'accordo sul fatto che l'uso di eval è qualcosa che tenderei ad evitare. Se questo fosse parte di un "sistema" più ampio che necessitava di una strategia di errore, probabilmente condirò la soluzione dei modelli o trasformerò ciascun messaggio in un Proc (soluzione interessante tra l'altro). Probabilmente useremo eval. –

2

io suggerisco di guardare in Liquid templating language che fornisce funzionalità più potenti (ad esempio è possibile fare riferimento i parametri per nome). L'esempio precedente sarebbe:

greeting = Liquid::Template.parse("hello {{your_name}}, my name is {{my_name}}!") 
interpolated = greeting.render('your_name' => 'Mike', 'my_name' => 'John') 
# => "hello Mike, my name is John!" 
+0

grazie, è bello sapere. È un po 'più di quello che penso vogliamo aggiungere in quello che è davvero uno script abbastanza semplice (non sono esattamente sicuro del motivo per cui si sono sentiti in dovere di esternalizzare le stringhe perché fosse onesto). –

Problemi correlati