> On 29 Sep 2017, at 06:40, Hernán Morales Durand <[email protected]> 
> wrote:
> 
> Hi Sven,
> 
> Is this one the similar to the #evaluate in
> http://www.squeaksource.com/evaluablestrings ?

Haha, yes that is exactly the same trick.
Lukas & Philippe back in 2005, duh.

> Cheers,
> 
> Hernán
> 
> 
> 2017-09-28 11:20 GMT-03:00 Sven Van Caekenberghe <[email protected]>:
>> Hi,
>> 
>> I got into a little office discussion about string interpolation as it is 
>> done in different programming languages.
>> 
>> In Pharo we have String>>#format: which is pretty nice. It works as follows:
>> 
>> | x y |
>> x := 123.
>> y := #foo.
>> 'x={1} and y={2}' format: { x. y }.
>> 
>> It is also possible to use a dictionary with keys, like this:
>> 
>> | x y |
>> x := 123.
>> y := #foo.
>> 'x={x} and y={y}' format: { #x->x. #y->y } asDictionary.
>> 
>> But this is not true string interpolation as described in [ 
>> https://en.wikipedia.org/wiki/String_interpolation ]. The idea is to write 
>> the value generating expressions directly inside the strings.
>> 
>> Since in Pharo we add features not by extending the syntax but by adding 
>> messages I wondered if it could be done for string interpolation. The goal 
>> is to make the following work:
>> 
>> | x y |
>> x := 123.
>> y := #foo.
>> 'It seems x equals {x} and y equals {y} while Pi is still {Float pi}' 
>> interpolate.
>> 
>> => 'It seems x equals 123 and y equals foo while Pi is still 
>> 3.141592653589793'
>> 
>> Here is the implementation I came up with:
>> 
>> String>>#interpolate
>>  "Format the receiver by interpolating the evaluation of expressions
>>  in between curly brackets in the context of the sender as in the following 
>> 3 oneline examples.
>>  'Today is {Date today}' interpolate.
>>  | x | x := 123. 'x equals {x} and pi equals {Float pi}' interpolate.
>>  'In {#strings} you can escape \{ by prefixing it with \\' interpolate."
>> 
>>  | senderContext |
>>  senderContext := thisContext sender.
>>  ^ self class new: self size streamContents: [ :out | | stream |
>>      stream := self readStream.
>>      [ stream atEnd ] whileFalse: [ | currentChar |
>>        (currentChar := stream next) == ${
>>          ifTrue: [ | expression result |
>>            expression := stream upTo: $}.
>>            result := Compiler new
>>              evaluate: expression in: senderContext to: nil notifying: nil 
>> ifFail: [ ^ nil ] logged: false.
>>            out nextPutAll: result asString ]
>>          ifFalse: [
>>            currentChar == $\
>>              ifTrue: [ stream atEnd ifFalse: [ out nextPut: stream next ] ]
>>              ifFalse: [ out nextPut: currentChar ] ] ] ]
>> 
>> It is a hack that could certainly be improved. And there is of course an 
>> obvious security problem.
>> 
>> Thoughts ?
>> 
>> Sven
>> 
>> 
> 


Reply via email to