2011-09-12 17 views
17
>> string = '#{var}' 
=> "\#{var}" 

>> proc = Proc.new { |var| string } 
=> #<Proc:[email protected](pry):6> 

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

Nie do końca tego, czego chcę. Cudzysłowie string w wyniku oczywistej undefined local variable.Jak zrobić "późny" interpolacja ciągów w Ruby

+0

Co jest w przypadku użycia do tego? To brzmi jak bardzo dziwna rzecz do zrobienia. –

+1

Tak ... jestem znany moich bizzare potrzeb. Dla tych dwóch linii jest bardziej DRY https://github.com/pjg/dotfiles/blob/5ae2e0c5a80be8b31d729d0739eb667fa99e5212/.pryrc#L46 –

+0

Myślę, że coś takiego istnieje w Ruby Facets. –

Odpowiedz

17

Chociaż jest to możliwe, to nie będzie działać, jak masz zamiar tu bez konieczności korzystania eval i generalnie jest to zły pomysł, jeśli istnieje alternatywa. Dobrą wiadomością jest to, że masz kilka opcji.

Najprostszym jest użycie sprintf formatowanie, które jest jeszcze łatwiejsze dzięki metodzie String#%:

string = '%s' 

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

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

To jest naprawdę niezawodny sposób jako coś który obsługuje metodę .to_s zadziała i nie spowoduje Wszechświat imploduje, jeśli zawiera kod wykonywalny.

+9

'String #%' obsługuje również parametry nazwane z Hash jako argumentem, co bardzo zbliża je do mocy natywnej interpolacji napisów. –

+0

Generalnie używam go w stylu C ze względu na jego kompaktowość, ale jak zauważyłeś, robi to o wiele więcej. – tadman

+0

To ładnie działa ładnie :) Thx! –

4

Współpracuje z eval:

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

(Jeśli ufasz wartość ciąg.)

+1

Kiedy cytujesz cytaty, prawdopodobnie powinieneś wyrazić to używając singli lub '% q []' like: '% q [" # {string} "]' aby uniknąć wszystkich okropnych ucieczek. – tadman

+0

Hmm ... Wygląda 'eval' prac. Ale może jest inny sposób? –

+0

@tadman nie interpoluje # {string}, a następnie – arnaud576875

0

Czy trzeba zdefiniować ciąg interpolacja-łożyskowy spoza Proc?

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

To byłby najczystszy sposób, jak sądzę.

+0

Widzę, że to nie działa w twoim konkretnym przykładzie ... ale nadal może odnosić się do innych podobnych sytuacji. Postawię lepszą odpowiedź osobno. –

1

Możesz osiągnąć pożądaną suszę, tworząc funkcję "curried" (tj. Proc, która zwraca Proc), gdzie funkcja wewnętrzna zawiera łańcuch bazowy ze zmiennymi dla każdej części, która się różni.

Popraw mnie jeśli się mylę, ale w kodzie za swoim komentarzem linku, jedyną różnicą pomiędzy tymi dwoma strunami jest pojedynczy znak na końcu. (Nawet jeśli nie jest, nadal możesz użyć tej techniki, aby osiągnąć ten sam cel.) Możesz utworzyć Proc, który zwraca Proca, która zawiera twój ciąg, następnie wywołaj zewnętrzną Proc dwa razy dla twoich dwóch znaków kończących:

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> " 
+0

To jest dość skomplikowane :) Pomaga mi interpolacja za pomocą zaakceptowanych odpowiedzi. –

19

W moim przypadku potrzebowałem konfiguracji przechowywanej w yml, z interpolacją, ale która jest interpolowana tylko wtedy, gdy jej potrzebuję. Przyjęta odpowiedź z Proc wydawała mi się zbyt skomplikowana.

W Ruby 1.8.7 można użyć składni % następująco:

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

Przy użyciu co najmniej rubinowy 1.9.x (lub Ruby 1.8.7 z i18n) istnieje alternatywny środek czyszczący:

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

my_template % { adjective: "nice", super: "woah" } 
=> "This is a nice verb, woah!"