Как сделать «позднюю» интерполяцию строк в Ruby

17
>> string = '#{var}'
=> "\#{var}"

>> proc = Proc.new { |var| string }
=> #<Proc:0xb717a8c4@(pry):6>

>> proc.call(123)
=> "\#{var}"

Не то, что я хочу. Двойные кавычки вокруг string приводят к очевидному undefined local variable .

    
задан Paweł Gościcki 12.09.2011 в 20:51
источник

5 ответов

17

Хотя это возможно, он не будет работать так, как вы намереваетесь здесь, не используя eval , и, как правило, это плохая идея, если есть альтернатива. Хорошая новость заключается в том, что у вас есть несколько вариантов.

Наиболее простым является использование форматирования sprintf , которое упрощается с помощью метода String#% :

string = '%s'

proc = Proc.new { |var| string % var }

proc.call(123)
# => "123"

Это действительно надежный метод, так как все, что поддерживает метод .to_s , будет работать и не вызовет юниоризацию, если он содержит исполняемый код.

    
ответ дан tadman 12.09.2011 в 20:59
источник
19

В моем случае мне нужна конфигурация, хранящаяся внутри yml, с интерполяцией, но которая только интерполируется, когда мне это нужно. Принятый ответ с Proc казался мне слишком сложным.

В ruby ​​1.8.7 вы можете использовать синтаксис % следующим образом:

"This is a %s verb, %s" % ["nice", "woaaaah"]

При использовании по крайней мере рубина 1.9.x (или рубина 1.8.7 с i18n) существует более чистая альтернатива:

my_template = "This is a %{adjective} verb, %{super}!"

my_template % { adjective: "nice", super: "woah" }
=> "This is a nice verb, woah!"
    
ответ дан nathanvda 20.08.2013 в 14:37
источник
4

Он работает с eval:

proc = Proc.new { |var| eval(%Q{"#{string}"}) }

(Если вы доверяете значению string .)

    
ответ дан arnaud576875 12.09.2011 в 20:57
источник
1

Вы можете достичь СУХОЙ, которую вы ищете, создавая функцию «curried» (то есть: Proc, которая возвращает Proc), где внутренняя функция содержит базовую строку с переменными для каждой части, которая отличается.

Исправьте меня, если я ошибаюсь, но в вашем коде за вашей прокомментированной ссылкой единственная разница между двумя строками - это один символ в конце. (Даже если это не так, вы можете использовать эту технику для достижения той же цели). Вы можете создать Proc, который возвращает Proc, который содержит вашу строку, затем дважды вызовите внешний Proc для двух ваших завершающих символов:

rails_root = "whatever" # Not variant for the string
rails_env_prompt = "whatever" #not variant for the string

spec = Proc.new { |tail_char| 
  Proc.new {|obj, nest_level, *| 
    "#{rails_root} #{rails_env_prompt} #{obj}:#{nest_level}#{tail_char} "
  }
}

Pry.config.prompt = [ spec.call(">"), spec.call("*") ]  

Pry.config.prompt[0].call("My obj", "My Nest Level")
# result: "whatever whatever My obj:My Nest Level> "
    
ответ дан Craig Walker 02.04.2013 в 20:18
источник
0

Вам нужно определить строку, несущую интерполяцию вне вашего Proc?

proc = Proc.new { |var| "#{var}" }
proc.call(123) # "123"

Это было бы самым чистым способом, я думаю.

    
ответ дан Craig Walker 02.04.2013 в 19:58
источник