Pytanie Interpolacja łańcuchowa, gdy nie jest używana literał łańcuchowy


Mam skrypt Ruby, który używał interpolacji ciągów do budowania komunikatów o błędach.

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

Pojawił się inny programista i próbował przekazać ciągi literałów do oddzielnego pliku konfiguracyjnego. Oczywiście nie otrzymuje substytucji.

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

Rozglądałem się, ale nie mogłem wymyślić nic lepszego niż konwersja na ciągi sprintf i używanie printf.

Czy ktoś wie, jak uzyskać podstawienie # {} do pracy na ciągach, które nie są literałami podwójnego cudzysłowu w skrypcie Ruby?


14
2018-03-14 15:47


pochodzenie




Odpowiedzi:


W rzeczywistości Ruby ma funkcjonalność bardzo podobną do przykładu Pythona Johna:

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

Jest to również użyteczne, jeśli argument jest stałą tablicową. Jeśli musisz użyć interpolacji stylu # {}, możesz użyć eval:

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

Podejście eval będzie znacznie wolniejsze niż przy użyciu interpolacji% style, więc jest to kompromis.


21
2018-03-14 16:21



Whoops! Poprawiono mnie. Usuwam moją odpowiedź. - John Feminella
Tak, miałem nadzieję znaleźć sposób, który nie wymagałby od niego modyfikowania strun. To nie jest wielka sprawa, ale po tym, jak zapytał o to, musiałem sprawdzić, czy istnieje sposób na zastąpienie # {}, nie będąc w dosłownym łańcuchu. Wydawało się, że powinien być jakiś sposób. - Mike Cargal
@John: Nie ma problemu, gdybym miał dolara za każdy mały błąd ... (właściwie nie wiedziałem, że Python to zrobił);) @Mike: Zaktualizowałem swoją odpowiedź informacją, jak to zrobić, używając stylu # {} interpolacja. - Mark A. Nicolosi
Dzięki, nie pomyślał o tym, jak używać eval i owijać podwójne cytaty. - Mike Cargal


Proponuję, żebyś na to spojrzał Płynny język szablonów który zapewnia bardziej zaawansowane funkcje (np. możesz odwoływać się do parametrów według nazwy). Poprzedni przykład wygląda następująco:

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!"

2
2018-03-14 17:35



dzięki, o tym dobrze. To trochę więcej, niż myślę, że chcemy dodać do tego, co jest naprawdę dość prostym skryptem (nie jestem do końca pewien, dlaczego czuli się zmuszeni do eksternalizacji tych łańcuchów, żeby było szczere). - Mike Cargal


Oto, jak to robię, tylko dla nagrania. Trochę jaśniejsze imo.

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

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

Ale szczerze mówiąc taki hack. Jeśli nie masz naprawdę dobrego powodu, aby użyć ciągu, użyj zamiast tego proc. Zawsze staram się używać zwykłego rubinu zamiast oceny ciągów.

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

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

1
2018-03-14 16:57



Tak, z pewnością zgadzam się, że używanie eval jest czymś, czego chciałbym uniknąć. Jeśli byłby częścią większego "systemu", który wymagałby strategii błędu, prawdopodobnie zwróciłbym uwagę na szablonowe rozwiązanie lub przekształcenie każdej wiadomości w Proc (ciekawe rozwiązanie). Prawdopodobnie użyjemy eval. - Mike Cargal