2009-03-14 21 views
14

Tengo un script de Ruby que utiliza la interpolación de cadenas para generar mensajes de error.Interpolación de cadenas cuando no se utiliza una cadena literal

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

Otro programador apareció e intentó externalizar los literales de cadena a un archivo de configuración separado. Por supuesto, él no obtiene la sustitución.

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

He mirado alrededor, pero no pudo llegar a nada mejor que la conversión a sprintf cuerdas y el uso de printf.

¿Alguien sabe cómo hacer que la sustitución # {} funcione en cadenas que no son literales de comillas dobles en el script de Ruby?

Respuesta

20

En realidad Ruby tiene una funcionalidad muy similar a la del ejemplo de Juan Python:

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

Esto también es útil si su argumento es una constante de matriz. Si tiene que usar # {} interpolación estilo se puede utilizar eval:

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

El enfoque eval va a ser mucho más lento que el uso de la interpolación% estilo, por lo que es una solución de compromiso.

+0

¡Vaya! Estoy corregido. Eliminaré mi respuesta. –

+0

Sí, esperaba encontrar una manera que no lo involucrara modificando las cuerdas. No es gran cosa, pero después de que me preguntó por él, tenía que ver si había una forma de hacer que la sustitución # {} funcionara sin estar en una cadena literal. Parecía que debería haber una manera. –

+0

@John: No hay problema si tengo un dólar por cada pequeño error ... (En realidad no sabía que Python hizo esto tampoco);) @Mike: Actualicé mi respuesta con información sobre cómo hacer esto usando # { } estilo de interpolación –

1

Así es como lo hago, solo para que conste. Un poco más claro.

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

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

Pero, honestamente, es decir tales un hack. A menos que tengas una buena razón para usar una cadena, utiliza un proceso en su lugar. Siempre trato de usar rubí simple en lugar de evaluar cadenas.

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

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

Sí, ciertamente estoy de acuerdo en que el uso de eval es algo que tendería a evitar. Si esto fuera parte de un "sistema" más grande que necesitara una estrategia de error, probablemente acondicionaría la solución de plantillas o convertiría cada mensaje en un Proc (solución interesante por cierto). Probablemente usemos eval. –

2

Sugiero que nos fijamos en Liquid templating language que proporciona características más potentes (por ejemplo, puede hacer referencia a los parámetros por su nombre). El ejemplo anterior se vería así:

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

gracias, eso es bueno saberlo. Es un poco más de lo que creo que queremos agregar a lo que en realidad es un guión bastante simple (no estoy exactamente seguro de por qué se sintieron obligados a externalizar las cadenas para que sea honesto). –

Cuestiones relacionadas