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