> On 28 Sep 2017, at 18:08, Ron Teitelbaum <[email protected]> wrote:
>
> Sorry, I tried to have them included at one point on squeak but I was talked
> down.
>
> I use them a lot! They work with other things besides strings.
In Pharo we have #join: and #split:
$| join: #('Foo' 'Bar').
=> 'Foo|Bar'
$| split: 'Foo|Bar'.
=> an OrderedCollection('Foo' 'Bar')
Not 100% the same, but quite close. Handy indeed.
> Collection >> explode: aDelimiter
> "explode the collection into a collection of collections broken by
> aDelimiter"
> "(#(#(1 2) #(3 4)) mergeDelimited: Character tab ) explode: Character
> tab = an OrderedCollection(#(1 2) #(3 4))
> 'abcdef' explode: 'cd' = an OrderedCollection('ab' 'ef')"
> | resultCollection starting aDelimiterPosition aDelimiterSize |
> self ifEmpty: [^self].
> resultCollection := OrderedCollection new.
> aDelimiterSize := aDelimiter isCollection ifTrue: [aDelimiter size]
> ifFalse: [1].
> starting := 1.
> [aDelimiterPosition := aDelimiter isCollection ifTrue: [self
> indexOfSubCollection: aDelimiter startingAt: starting] ifFalse: [self
> indexOf: aDelimiter startingAt: starting ifAbsent: [0]].
> aDelimiterPosition > 0] whileTrue: [
> resultCollection add: (self copyFrom: starting to:
> aDelimiterPosition - 1).
> starting := aDelimiterPosition + aDelimiterSize.
> ].
> resultCollection add: (self copyFrom: starting to: self size).
> ^resultCollection
>
> Collection >> mergeDelimited: anObject
> "return to reciever a collection with each element concatenated to
> remove imbeded collections"
> "#(#(1 2) #(3 4)) mergeDelimited: Character tab = #(1 2 Character tab 3
> 4), #('ab' 'cd') mergeDelimited: Character cr = 'ab
> cd' "
> | returnCollection aSeperator |
> self ifEmpty: [^self].
> aSeperator := anObject isCollection ifTrue: [anObject] ifFalse: [Array
> with: anObject].
> returnCollection := self first species new.
> self copy from: 1 to: self size -1 do: [:a |
> a ifNotNil: [
> returnCollection := returnCollection, a, aSeperator
> ].
> ].
> ^returnCollection, self last
>
> On Thu, Sep 28, 2017 at 11:25 AM, Sven Van Caekenberghe <[email protected]> wrote:
>
>
> > On 28 Sep 2017, at 17:13, Thierry Goubier <[email protected]> wrote:
> >
> >
> >
> > 2017-09-28 17:08 GMT+02:00 Sven Van Caekenberghe <[email protected]>:
> >
> >
> > > On 28 Sep 2017, at 16:58, [email protected] wrote:
> > >
> > > I stand corrected.
> > >
> > > Nuclear style feature then.
> > >
> > > 'Let me get out of here {Smalltalk snapshot:false andQuit: true}. BOOM'
> > > interpolate
> > >
> > > Feels like
> > >
> > > STR='sudo reboot'; $(STR)
> > >
> > > in bash when one is sudoer.
> >
> > Yeah, but it is always the original programmer who writes the template
> > (including the 'Smalltalk snapshot:false andQuit: true' and the 'sudo
> > reboot' in you examples), you would not do that for any good reason.
> >
> > Typically, you would write something like
> >
> > 'My name is {firstname} {lastname}' interpolate.
> >
> > in a method of an object with firstname and lastname as instance variables.
> > To access the binding, #evaluate: is used. Though a malicious person could
> > enter 'Smalltalk snapshot:false andQuit: true' as name, it is not that
> > expression that gets evaluated. So in that respect there is no risk.
> >
> > The risk would be when the template string itself would be (partially)
> > based on used input.
> >
> > which is easy to overlook:
> >
> > aString interpolate
> >
> > People are on average a bit more carefull when they use #compile: or
> > #evaluate:.
> >
> > Thierry
>
> 100% correct, hence my warning.
>
> > > Phil
> > >
> > > On Thu, Sep 28, 2017 at 4:43 PM, Sven Van Caekenberghe <[email protected]>
> > > wrote:
> > >
> > >
> > > > On 28 Sep 2017, at 16:27, [email protected] wrote:
> > > >
> > > > We also have
> > > > http://norbert.hartl.name/blog/2013/10/03/mustache-templates-for-smalltalk/
> > > >
> > > > Phil
> > >
> > > Yes, Mustache is a cool templating engine, but it is similar to #format:
> > > not to #interpolate. With true string interpolation, you do not provide a
> > > context, you just write the expressions inline. Compare the following two:
> > >
> > > 'Today is {1} format: { Date today }.
> > >
> > > 'Today is { Date today }' interpolate.
> > >
> > > > 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
> > > >
> > > >
> > > >
> > >
> > >
> > >
>
>
>
>