> On 28 Sep 2017, at 16:55, Ron Teitelbaum <[email protected]> wrote: > > Hi All, > > To solve this problem I do this: > > replaceTokensIn: aString > ^self tokens inject: aString into: [:str :assoc | > ((str explode: assoc key) mergeDelimited: assoc value value)]. > > tokens is a collection of key value pairs. > > aString := 'Dear {!user}'. > > self tokens: {'{!user}' -> [self user]}. > > self replaceTokensIn: aString. > > I like using the blocks because they can be almost anything and since they > are defined by the developer the security issue goes away. It's not a > streaming solution which would be nice for a much longer text and it does > rewrite the string for every token.
I think I understand what you mean. When there is no #evaluate: involved, there is no risk. #explode: and #mergeDelimited: are not standard messages though ... > On Thu, Sep 28, 2017 at 10:27 AM, [email protected] <[email protected]> > wrote: > We also have > http://norbert.hartl.name/blog/2013/10/03/mustache-templates-for-smalltalk/ > > Phil > > On Thu, Sep 28, 2017 at 4:20 PM, Sven Van Caekenberghe <[email protected]> wrote: > 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 > > > >
