Pharo-users
By thread
pharo-users@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
June 2017
- 100 participants
- 622 messages
Re: [Pharo-users] How to deploy headless app without changes and source files?
by Andreas Sunardi
I had my changes and sources files in the bundle but has their write
permission removed, and that causes the error. Simply deploying the tool
without the changes file seems to fix it. Pharo5 doesn't complain if the
changes file isn't there.
However, without the sources file, I get this warning that pharo cannot
locate the sources file. Including the sources file in the deployed tool is
fine with me.
So, I think that's my solution. Thanks!
On Mon, Jun 5, 2017 at 5:07 PM, Andreas Sunardi <a.sunardi(a)gmail.com> wrote:
> I found this StackOverflow question:
> https://stackoverflow.com/questions/14737695/is-it-
> possible-to-deploy-a-pharo-image-without-changes-and-
> sources-files/14747328
>
> and this older forum thread:
> https://www.mail-archive.com/pharo-project@lists.gforge.
> inria.fr/msg21170.html
>
> I'm using Pharo5.0 and neither of these options is available anymore. What
> is the new way to do this?
>
> --
> Andreas Sunardi
>
June 6, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Ben Coman
On Tue, Jun 6, 2017 at 5:11 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
wrote:
> Tx ben.
> When I see all this complexity for something that looks not that complex:
> I prefer to pass the class and get done.
> May be I missed something obvious... but when I see something too complex
> I start to get worried.
>
> I think that thinking about the contract between classes at runtime is
> important and to me a MovieLister should be using at runtime and instance
> of the *Finder*
> Now needing an extra class just to set this should really be evaluated
> with the tradeoff: "flexibility win" (our simple solution is still really
> flexible - I decide when I want to pass the correct finder) vs. the code
> and conceptual bloat.
>
>
> I'm happy not to face the hyper super over engineering of Java "solutions".
>
> I like the "Of course this just shifts the burden a tad, we still have to
> get the locator into the lister"
> but the solution is super simple let us use another "Singleton and a
> Factory...." :)
>
> Stef
>
> On Mon, Jun 5, 2017 at 8:43 PM, Ben Coman <btc(a)openinworld.com> wrote:
>
>>
>>
>> On Tue, Jun 6, 2017 at 1:26 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
>> wrote:
>>
>>> Thanks for the answer Ben and Stephane.
>>>
>>> I already read A Mentoring Course on Smalltalk, Valloud, there is
>>> nothing there I could use in this case :( . I will look after for The
>>> Design Patterns Smalltalk Companion. Most of the sources provided I already
>>> know of or went in the same lines lines of what I have already found.
>>>
>>> About TDD, I am experienced with the discipline and have tested it on
>>> Pharo living system already, but I could not understand how this is related
>>> with object wiring, DI and service locator.
>>>
>>
>> I guess I don't properly understand your need and those topics. That was
>> my quick pass. Now if I take the time to actually read Fowler's long
>> article
>>
>> "the inversion is about how they lookup a plugin implementation ... to
>> ensure that any user of a plugin follows some convention that allows a
>> separate assembler module to inject the implementation into the lister."
>>
>> "The basic idea of the Dependency Injection is to have a separate object,
>> an assembler, that populates a field in the lister class with an
>> appropriate implementation for the finder interface. There are three main
>> styles of dependency injection. The names I'm using for them are
>> Constructor Injection, Setter Injection, and Interface Injection."
>>
>> Now there was too much syntactical noise in those Java examples for me to
>> think clearly, so I converted them all to Smalltalk.
>>
>>
>> ##CONSTRUCTOR INJECTION
>>
>> Object subclass: MovieLister
>> instanceVariables: 'finder'
>>
>>
>> MovieLister class >> newWith: aFinder
>> ^ self basicNew initializeWith: aFinder
>>
>> MovieLister >> initializeWith: aFinder
>> finder := aFinder
>>
>>
>> ColonMovieFinder class >> newWith: aFilename
>> ^ self basicNew initializeWith: aFilename
>>
>> ColonMovieFinder >> initializeWith: aFilename
>> filename := aFilename.
>>
>>
>> ConstructorInjectionContainer >> new
>> container := DefaultContainer new. "the article doesn't specify
>> where this comes from"
>> finderParams := ConstantParameter newWith: 'movies1.txt'.
>> container registerComponentInterface: MovieFinderInterface
>> implementation: ColonMovieFinder
>> params: finderParams.
>> container registerComponentImplementation: MovieLister
>> ^container
>>
>> to be used like this...
>> ConstructorInjectionTest >> testWithContainer
>> container := ConstructorInjectionContainer new.
>> lister := container getComponentInstance( MovieLister ).
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>> The article poorly defines registerComponentXXX: or getComponentInstance:
>> methods, so I don't dwell on them. I presume its little relevant to the
>> main theme.
>>
>>
>> ##SETTER INJECTION
>>
>> MovieLister >> setFinder: aFinder
>> finder := aFinder.
>>
>> ColonMovieFinder >> setFilename: aFilename
>> filename := aFilename.
>>
>> SetterInjectionTest >> testWithConfigurationFile
>> ctx := SomeXmlApplicationConfiguration on: 'config.xml'.
>> lister := ctx getConfigOf: 'MovieLister'.
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>>
>> ##INTERFACE INJECTION
>>
>> MovieLister >> injectFinder: aFinder
>> finder := aFinder
>>
>> ColonMovieFinder >> injectFilename: aFilename
>> filename := aFilename
>>
>> InterfaceInjectionTest >> configureContainer
>> container := InterfaceInjectionContainer new.
>> self registerComponents.
>> self registerInjectors.
>> container start.
>>
>> InterfaceInjectionTest >> registerComponents
>> container registerComponent: 'MovieLister' with: MovieLister.
>> container registerComponent: 'MovieFinder' with: ColonMovieFinder.
>>
>> InterfaceInjectionTest >> registerInjectors
>> container registerInjector: Injector with: (container lookup:
>> 'MovieFinder').
>> container registerInjector: InjectorFinderFilename with:
>> FinderFilenameInjector new.
>>
>> ColonMovieFinder >> inject: anObject
>> anObject injectFinder: self.
>>
>> FinderFilenameInjector >> inject: anObject
>> anObject injectFilename: 'movies1.txt'.
>>
>> InterfaceInjectionTester >> testInterface
>> self configureContainer.
>> lister := container lookup: 'MovieLister'.
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>> The article doesn't define InterfaceInjectionContainer, but I guess it
>> could look like this...
>>
>> InterfaceInjectionContainer >> registerComponent: componentName with:
>> aComponent
>> container ifNil: [ container := Dictionary new].
>> container at: componentName put: aComponent
>>
>> InterfaceInjectionContainer >> lookup: componentName
>> ^ container at: componentName
>>
>>
>> ##SERVICE LOCATOR
>>
>> "The basic idea behind a service locator is to have an object that knows
>> how to get hold of all of the services that an application might need. So a
>> service locator for this application would have a method that returns a
>> movie finder when one is needed. Of course this just shifts the burden a
>> tad, we still have to get the locator into the lister"
>>
>> MovieLister >> initialize
>> finder := ServiceLocator movieFinder.
>>
>>
>> Object subclass: ServiceLocator
>> instanceVariable: 'movieFinder'
>> classVariable: 'SoleInstance'
>>
>> ServiceLocator class >> load: aServiceLocator
>> SoleInstance := aServiceLocator
>>
>> ServiceLocator class >> soleInstance
>> ^ SoleInstance
>>
>> ServiceLocator class >> movieFinder
>> ^ self soleInstance movieFinder
>>
>> ServiceLocator >> movieFinder
>> ^movieFinder
>>
>>
>> ServiceLocatorTest >> configure
>> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
>> newWith: 'movies1.txt'))
>>
>>
>> ServiceLocator class >> newWith: aMovieFinder
>> ^ self basicNew initializeWithFinder: aMovieFinder
>>
>> ServiceLocator >> initializeWithFinder: aMovieFinder
>> movieFinder := aMovieFinder
>>
>>
>> ServiceLocatorTest >> testSimple
>> self configure.
>> lister := MovieLister new.
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>> So it seems that a service locator is just a Singleton pattern having a
>> class variable for each service of interest ??
>>
>
It was late and I mispoke here, of course this should have said...
* a Singleton pattern having an instance variable for each service of
interest
* a Singleton pattern having a getter method (with hidden implementation) for
each service of interest
> So in good faith** I ask... "Is it any more complicated than that?"
>>
>> **Since its taken me a couple of hours to convert the Java to this point
>> so I stopped reading to seek your feedback.
>>
>
but I'll add, it was so much simpler to understand without all that Java
typing boiler plate.
cheers -ben
> Is that enough insight to adapt to your needs, or is there something else
>> further down the article that invalidates my analysis?
>>
>>
>>
>>
>>
>>>
>>> From ben:
>>>
>>> "I'm not really familiar with IoC or DI patterns, so just taking your
>>>> example at face value, in Pharo I'd do...
>>>>
>>>> MovieLister>>moviesDirectedBy: director
>>>> allMovies := finder allMovies.
>>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>>> "although typically #getDirector would be renamed #director"
>>>>
>>>> MovieLister>>finder: movieFinder
>>>> finder := movieFinder.
>>>>
>>>> to be used like this...
>>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
>>>> 'movies1.txt').
>>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>
>>>
>>
>> So per Fowler, the above is equivalent to "Setter Injection with Spring"
>>
>>
>>>
>>> and Stephane:
>>>
>>> Why don't you simply pass the class and use that class in your
>>>> MovieLister?
>>>>
>>>> MovieLister new
>>>> finderClass: MySuperCoolFinderClass
>>>>
>>>> ...
>>>> MovieLister finder
>>>> finderClass new .....
>>>>
>>>> What is wrong with that.
>>>
>>>
>>> That was what I meant when I said: "I know that in Smalltalk I can make
>>> MovieLister to receive, upon construction, a class representing MovieFinder
>>> and call it construction message.". The code I had in mind is a bit of
>>> mix from the one provided by you both:
>>>
>>> MovieLister>>moviesDirectedBy: director
>>> allMovies := finder allMovies.
>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>> "although typically #getDirector would be renamed #director"
>>>
>>> MovieLister>>finder: aMovieFinderBuilder
>>> finder := aMovieFinderClass new.
>>>
>>> to be used like this...
>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder
>>> builderOn: 'movies1.txt').
>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>
>>> But that means I will have to wire dependencies by hand whenever I
>>> create a MovieLister and seek through code when and if those dependencies
>>> change. When there are lot's of dependencies it's is a considerable and
>>> tedious work. Let's see an image from Fowlers article:
>>>
>>> [image: Inline image 1]
>>>
>>> In this case, the service locator provides me with an instance and I
>>> configure the instance in the assembler, the scheme is alike for an IoC,
>>> and that would mean my implementation could be like this:
>>>
>>>
>>> MovieLister>>moviesDirectedBy: director
>>> allMovies := finder allMovies.
>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>> "although typically #getDirector would be renamed #director"
>>>
>>> MovieLister>>initialize
>>> finder := ServiceLocator locate: FinderClass <--- This would
>>> bring the instance of finder class configured by the assembler
>>>
>>
>> No, like this...
>> finder := ServiceLocation movieFinder.
>>
>> Now if you want to store a class rather than an instance as I did higher
>> up, you just do this...
>>
>> Object subclass: ServiceLocator
>> instanceVariable: 'movieFinderClass'
>> classVariable: 'SoleInstance'
>>
>> ServiceLocator class >> movieFinder
>> ^ self soleInstance movieFinderClass new
>>
>>
>>
>>>
>>>
>>> to be used like this...
>>> lister := MovieLister new.
>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>
>>> and the assembler:
>>>
>>> Assember class>>configure:
>>> aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
>>> FinderClass
>>>
>>
>> Assembler class>>configure
>> ServiceLocator load:
>> (ServiceLocator new
>> movieFinder: (ColonMovieFinder newWith: 'movies1.txt')
>> otherService: MyCustomService new)
>>
>>
>>>
>>> My assembler and service locator could be even more elaborated, and
>>> provide a different MovieFinder in test scope, for different classes or
>>> wharever.
>>>
>>
>> Really, the test should not be updating the class variable global like
>> this...
>> ServiceLocatorTest >> configure
>> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
>> newWith: 'movies1.txt'))
>>
>> you probably want something like (its rough but shows the point...)
>> Object subclass: #MovieLister
>> instanceVariables: 'serviceLocator'
>>
>> MovieLister >> initialize
>> serviceLocator ifNil: [ serviceLocator := ServiceLocator soleInstance
>> ].
>> finder := serviceLocator movieFinder.
>>
>> MovieLister class >> newWithServiceLocator: aServiceLocator
>> ^ (self basicNew initializeWithServiceLocator: aServiceLocator)
>> initialize.
>>
>> MovieLister >> initializeWithServiceLocator: aServiceLocator
>> serviceLocator := aServiceLocator
>>
>> ServiceLocatorTest >> testSimple2
>> lister := MovieLister newWithServiceLocator: (ServiceLocator newWith:
>> (ColonMovieFinder newWith: 'movies1.txt')).
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>>
>> cheers -ben
>>
>>
>>>
>>> It is a little convenience for Smalltalk, I will give that, but I was
>>> wandering if there was something alike in Pharo, by your answers I assuming
>>> there is nothing like that.
>>>
>>>
>>>
>>> On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <
>>> stepharo.self(a)gmail.com> wrote:
>>>
>>>> Why don't you simply pass the class and use that class in your
>>>> MovieLister?
>>>>
>>>> MovieLister new
>>>> finderClass: MySuperCoolFinderClass
>>>>
>>>> ...
>>>> MovieLister finder
>>>> finderClass new .....
>>>>
>>>> What is wrong with that.
>>>>
>>>> If you do not want to have a reference at runtime to a Finder then you
>>>> need to use announcement and registration.
>>>>
>>>> Stef
>>>>
>>>>
>>>>
>>>> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <
>>>> vitormcruz(a)gmail.com> wrote:
>>>> > Hello,
>>>> >
>>>> > I would like to know how people in Pharo ecosystem do to deal with
>>>> object
>>>> > wiring, as described by Marting Fowler in
>>>> > https://martinfowler.com/articles/injection.html#FormsOfDepe
>>>> ndencyInjection:
>>>> >
>>>> > "A common issue to deal with is how to wire together different
>>>> elements: how
>>>> > do you fit together this web controller architecture with that
>>>> database
>>>> > interface backing when they were built by different teams with little
>>>> > knowledge of each other."
>>>> >
>>>> > He gives an example, I will leave it in java as it is simple enough to
>>>> > understand:
>>>> >
>>>> > "class MovieLister...
>>>> >
>>>> > public Movie[] moviesDirectedBy(String arg) {
>>>> > List allMovies = finder.findAll();
>>>> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
>>>> > Movie movie = (Movie) it.next();
>>>> > if (!movie.getDirector().equals(arg)) it.remove();
>>>> > }
>>>> > return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>>>> >
>>>> > }"
>>>> >
>>>> > The question is how to provide the finder object in a decoupled
>>>> matter, a
>>>> > naive approach would be:
>>>> >
>>>> > " private MovieFinder finder;
>>>> >
>>>> > public MovieLister() {
>>>> > finder = new ColonDelimitedMovieFinder("movies1.txt");
>>>> >
>>>> > }"
>>>> >
>>>> > Which couples the MovieLister to the specific
>>>> ColonDelimitedMovieFinder
>>>> > class.
>>>> >
>>>> > Fowler explains how to decouple using an IoC framework or a Service
>>>> Locator.
>>>> > In Java and .Net IoC is used most of the time. I Googled how this
>>>> problem is
>>>> > approached in Smalltalk/Pharo, and I generally I found answers "that
>>>> is easy
>>>> > to do in Smalltalk, so there is no need of a framework", what I miss
>>>> is a
>>>> > description on *how* to do that:
>>>> >
>>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>>> > https://stackoverflow.com/questions/2684326/is-there-a-depen
>>>> dency-injection-framework-for-smalltalk
>>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>>> /347477#347477
>>>> >
>>>> > I know that in Smalltalk I can make MovieLister to receive, upon
>>>> > construction, a class representing MovieFinder and call it
>>>> construction
>>>> > message. As long an object that responds to this message is provided,
>>>> I can
>>>> > create as many derivations I want and the MovieLister will be
>>>> decoupled from
>>>> > the MovieFinder. That way, however, I still have to wire things by
>>>> hand, and
>>>> > I am not sure if this is what I am supposed to do in order to solve
>>>> the
>>>> > decouple problem.
>>>> >
>>>> > Can you explain me how this is done in Pharo? It's is usually wiring
>>>> by
>>>> > hand? Is there a simple construction that deals with the wiring
>>>> problem that
>>>> > I cannot foresee?
>>>> >
>>>> > Thanks in advance,
>>>> > Vitor
>>>> >
>>>> >
>>>> >
>>>>
>>>>
>>>
>>
>
June 6, 2017
How to deploy headless app without changes and source files?
by Andreas Sunardi
I found this StackOverflow question:
https://stackoverflow.com/questions/14737695/is-it-possible-to-deploy-a-pha…
and this older forum thread:
https://www.mail-archive.com/pharo-project@lists.gforge.inria.fr/msg21170.h…
I'm using Pharo5.0 and neither of these options is available anymore. What
is the new way to do this?
--
Andreas Sunardi
June 6, 2017
Re: [Pharo-users] Saving selected changes in Monticello
by Andreas Sunardi
I definitely will check Komitter and I can use and fallback to Ben's
method. Thank you to all of you.
On Mon, Jun 5, 2017 at 12:58 AM, Peter Uhnak <i.uhnak(a)gmail.com> wrote:
> Komitter could indeed help you, see https://www.peteruhnak.com/
> blog/2016/08/12/fine-grained-committing-and-extending-nautilus/
>
> Peter
>
> On Mon, Jun 05, 2017 at 08:27:23AM +0200, serge.stinckwich(a)gmail.com
> wrote:
> > Kommiter available in default image allows you do cherry pick quite
> easily.
> >
> > Envoyé de mon iPhone
> >
> > > Le 5 juin 2017 à 07:14, Ben Coman <btc(a)openinworld.com> a écrit :
> > >
> > >
> > >
> > >> On Mon, Jun 5, 2017 at 10:12 AM, Andreas Sunardi <a.sunardi(a)gmail.com>
> wrote:
> > >> I have a half done changes in my image, but I need to distribute the
> other changes that are done. I thought I was going to do this all at once,
> but now I realize I should split this into 2 commit versions.
> > >>
> > >> Is there a way in Monticello to say save my changes, but not this and
> that changes? I can't seem to find it nor in books. How do people deal with
> this situation?
> > >
> > > AFAIK, Monticello cannot cherry pick. One work around is probably
> something like...
> > > 1. Save the mcz locally
> > > 2. Merge back into a fresh image selecting only the bits you want.
> > > 3. Save as a second mcz.
> > > One issue is that the second mcz will have the first mcz as an
> ancestor, so before 2 you might create a new changeset to file out after 2,
> and load that into a second new image. yuck!
> > >
> > > Another alternative might be to use Tools > ChangeSorter to move the
> code you want to exclude from the mcz to a changeset, file that out and
> then revert that code in the image. After save the package to a mcz, reload
> the changeset.
> > >
> > > cheers -ben
>
>
June 5, 2017
Re: [Pharo-users] STON Question
by Offray Vladimir Luna Cárdenas
Ok Stef. Happy that we're exploring different paths ;-).
Cheers,
Offray
On 05/06/17 13:56, Stephane Ducasse wrote:
> Hi offray
>
> Thanks but pillar ha a conf since several years and it is working
> well. Now I'm revisiting the implementation of cocoon
> because I want to have it simpler independent of magritte and better
> tested.
>
> Now I just want to add a new functionality to output a configuration
> file from the
> objects and in Pillar the configuration objects hold more complex
> ***objects***.
> So just taking the object and turning it in ston does not work.
>
> Stef
>
> On Mon, Jun 5, 2017 at 6:23 PM, Offray Vladimir Luna Cárdenas
> <offray.luna(a)mutabit.com <mailto:offray.luna@mutabit.com>> wrote:
>
> Hi,
>
> Maybe what I'm doing in Grafoscopio could help.
>
> I have a %metadata node which contains all configuration options
> for the production of the document (as shown in the image below).
> Exporting a document consist in looking for these nodes while
> traversing the notebook tree and applying that options in the
> proper place. You can see the source code of the current notebook
> STON file at [1], the exported markdown file at [2] and the
> exported PDF at [3]. As you can see I have pretty good control of
> the configuration of the document using this option (and a single
> place to manage all, without endless small files and folders for a
> document, but event that exporting options as split folders and
> docs, could be added also).
>
> [1]
> http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1
> <http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1>
> [2]
> http://mutabit.com/repos.fossil/grafoscopio/artifact?name=59245142cf93590b&…
> <http://mutabit.com/repos.fossil/grafoscopio/artifact?name=59245142cf93590b&…>
> [3]
> http://mutabit.com/repos.fossil/grafoscopio/doc/tip/Docs/En/Books/Manual/ma…
> <http://mutabit.com/repos.fossil/grafoscopio/doc/tip/Docs/En/Books/Manual/ma…>
>
>
>
> Cheers,
>
> Offray
>
>
> On 05/06/17 01:58, Stephane Ducasse wrote:
>> Sven I know what Ston is :)
>>
>> Now Pillar dev used Ston as input and it works. Then with some
>> hooks they let the user convert the strings
>> into specific objects and this is ok.
>> Now I want to add export in Ston and for configurations I need to
>> control for the application and not as a ston object the value saved.
>> For example a file reference should not be just a file reference
>> in Ston but
>> a string relative the the baseDirectory of the configuration.
>>
>> So I thought that I can build a hook and control the call to Ston
>> (convert the object before to the correct values) and export.
>> It should be working now doing this I found myself redoing the
>> output of Ston.
>> So I will do it. Then I thought that may be I could reuse this
>> logic.
>>
>> Stef
>>
>>
>>
>> On Sun, Jun 4, 2017 at 11:49 PM, Sven Van Caekenberghe
>> <sven(a)stfx.eu <mailto:sven@stfx.eu>> wrote:
>>
>> Stef,
>>
>> STON is like FUEL, it can write any object to a stream and
>> read it back. Although you can customise how this is done,
>> only one way of doing so is supported (i.e. you cannot change
>> the format for each application).
>>
>> People have used STON for various applications now, including
>> for configuration stuff (because it is a textual format that
>> is easy to read).
>>
>> I would suggest you just try to see what your config looks
>> like once you have the objects in Pharo.
>>
>> STON toStringPretty: myConfig.
>>
>> Then we can see how to tune the representation.
>>
>> Sven
>>
>> > On 4 Jun 2017, at 22:58, Stephane Ducasse
>> <stepharo.self(a)gmail.com <mailto:stepharo.self@gmail.com>> wrote:
>> >
>> > Hi sven
>> >
>> > I'm working on a new configuration frameworks similar to
>> the one use pillar.conf.
>> >
>> > So basically I have
>> >
>> > ston := '{
>> > "newLine":#unix,
>> > "separateOutputFiles":true
>> > }'.
>> > and I want to recreate it.
>> >
>> > So I did
>> >
>> > Object >> toConfigurationString
>> >
>> > ^ STON toString: self
>> >
>> > SimpleConfiguration >> exportStream
>> >
>> > ^ String streamContents: [ :str |
>> > str << '{' .
>> > self propertiesKeysAndValuesDo: [ :key :value|
>> > str << key toConfigurationString.
>> > str << ':'.
>> > str << value toConfigurationString.
>> > str << ','.
>> > str lf.
>> > ].
>> > str << '}'.
>> > str contents
>> > ]
>> >
>> > The idea is that for special configuration values people
>> should be able to define
>> > how to go from the object to configuration.
>> > For example for some FileReference I want to have just the
>> path up to the baseDirectory.
>> >
>> > Now I wonder if I could not better reuse ston.
>> > I saw the stonOn:
>> > but I did not look further because I was wondering how the
>> writer where passed.
>> >
>> > Any feedback is welcome.
>> >
>> > Stef (now bed time).
>> >
>>
>>
>>
>
>
June 5, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Stephane Ducasse
Tx ben.
When I see all this complexity for something that looks not that complex: I
prefer to pass the class and get done.
May be I missed something obvious... but when I see something too complex I
start to get worried.
I think that thinking about the contract between classes at runtime is
important and to me a MovieLister should be using at runtime and instance
of the *Finder*
Now needing an extra class just to set this should really be evaluated with
the tradeoff: "flexibility win" (our simple solution is still really
flexible - I decide when I want to pass the correct finder) vs. the code
and conceptual bloat.
I'm happy not to face the hyper super over engineering of Java "solutions".
I like the "Of course this just shifts the burden a tad, we still have to
get the locator into the lister"
but the solution is super simple let us use another "Singleton and a
Factory...." :)
Stef
On Mon, Jun 5, 2017 at 8:43 PM, Ben Coman <btc(a)openinworld.com> wrote:
>
>
> On Tue, Jun 6, 2017 at 1:26 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
> wrote:
>
>> Thanks for the answer Ben and Stephane.
>>
>> I already read A Mentoring Course on Smalltalk, Valloud, there is
>> nothing there I could use in this case :( . I will look after for The
>> Design Patterns Smalltalk Companion. Most of the sources provided I already
>> know of or went in the same lines lines of what I have already found.
>>
>> About TDD, I am experienced with the discipline and have tested it on
>> Pharo living system already, but I could not understand how this is related
>> with object wiring, DI and service locator.
>>
>
> I guess I don't properly understand your need and those topics. That was
> my quick pass. Now if I take the time to actually read Fowler's long
> article
>
> "the inversion is about how they lookup a plugin implementation ... to
> ensure that any user of a plugin follows some convention that allows a
> separate assembler module to inject the implementation into the lister."
>
> "The basic idea of the Dependency Injection is to have a separate object,
> an assembler, that populates a field in the lister class with an
> appropriate implementation for the finder interface. There are three main
> styles of dependency injection. The names I'm using for them are
> Constructor Injection, Setter Injection, and Interface Injection."
>
> Now there was too much syntactical noise in those Java examples for me to
> think clearly, so I converted them all to Smalltalk.
>
>
> ##CONSTRUCTOR INJECTION
>
> Object subclass: MovieLister
> instanceVariables: 'finder'
>
>
> MovieLister class >> newWith: aFinder
> ^ self basicNew initializeWith: aFinder
>
> MovieLister >> initializeWith: aFinder
> finder := aFinder
>
>
> ColonMovieFinder class >> newWith: aFilename
> ^ self basicNew initializeWith: aFilename
>
> ColonMovieFinder >> initializeWith: aFilename
> filename := aFilename.
>
>
> ConstructorInjectionContainer >> new
> container := DefaultContainer new. "the article doesn't specify where
> this comes from"
> finderParams := ConstantParameter newWith: 'movies1.txt'.
> container registerComponentInterface: MovieFinderInterface
> implementation: ColonMovieFinder
> params: finderParams.
> container registerComponentImplementation: MovieLister
> ^container
>
> to be used like this...
> ConstructorInjectionTest >> testWithContainer
> container := ConstructorInjectionContainer new.
> lister := container getComponentInstance( MovieLister ).
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
> The article poorly defines registerComponentXXX: or getComponentInstance:
> methods, so I don't dwell on them. I presume its little relevant to the
> main theme.
>
>
> ##SETTER INJECTION
>
> MovieLister >> setFinder: aFinder
> finder := aFinder.
>
> ColonMovieFinder >> setFilename: aFilename
> filename := aFilename.
>
> SetterInjectionTest >> testWithConfigurationFile
> ctx := SomeXmlApplicationConfiguration on: 'config.xml'.
> lister := ctx getConfigOf: 'MovieLister'.
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
>
> ##INTERFACE INJECTION
>
> MovieLister >> injectFinder: aFinder
> finder := aFinder
>
> ColonMovieFinder >> injectFilename: aFilename
> filename := aFilename
>
> InterfaceInjectionTest >> configureContainer
> container := InterfaceInjectionContainer new.
> self registerComponents.
> self registerInjectors.
> container start.
>
> InterfaceInjectionTest >> registerComponents
> container registerComponent: 'MovieLister' with: MovieLister.
> container registerComponent: 'MovieFinder' with: ColonMovieFinder.
>
> InterfaceInjectionTest >> registerInjectors
> container registerInjector: Injector with: (container lookup:
> 'MovieFinder').
> container registerInjector: InjectorFinderFilename with:
> FinderFilenameInjector new.
>
> ColonMovieFinder >> inject: anObject
> anObject injectFinder: self.
>
> FinderFilenameInjector >> inject: anObject
> anObject injectFilename: 'movies1.txt'.
>
> InterfaceInjectionTester >> testInterface
> self configureContainer.
> lister := container lookup: 'MovieLister'.
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
> The article doesn't define InterfaceInjectionContainer, but I guess it
> could look like this...
>
> InterfaceInjectionContainer >> registerComponent: componentName with:
> aComponent
> container ifNil: [ container := Dictionary new].
> container at: componentName put: aComponent
>
> InterfaceInjectionContainer >> lookup: componentName
> ^ container at: componentName
>
>
> ##SERVICE LOCATOR
>
> "The basic idea behind a service locator is to have an object that knows
> how to get hold of all of the services that an application might need. So a
> service locator for this application would have a method that returns a
> movie finder when one is needed. Of course this just shifts the burden a
> tad, we still have to get the locator into the lister"
>
> MovieLister >> initialize
> finder := ServiceLocator movieFinder.
>
>
> Object subclass: ServiceLocator
> instanceVariable: 'movieFinder'
> classVariable: 'SoleInstance'
>
> ServiceLocator class >> load: aServiceLocator
> SoleInstance := aServiceLocator
>
> ServiceLocator class >> soleInstance
> ^ SoleInstance
>
> ServiceLocator class >> movieFinder
> ^ self soleInstance movieFinder
>
> ServiceLocator >> movieFinder
> ^movieFinder
>
>
> ServiceLocatorTest >> configure
> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
> newWith: 'movies1.txt'))
>
>
> ServiceLocator class >> newWith: aMovieFinder
> ^ self basicNew initializeWithFinder: aMovieFinder
>
> ServiceLocator >> initializeWithFinder: aMovieFinder
> movieFinder := aMovieFinder
>
>
> ServiceLocatorTest >> testSimple
> self configure.
> lister := MovieLister new.
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
> So it seems that a service locator is just a Singleton pattern having a
> class variable for each service of interest ??
> So in good faith** I ask... "Is it any more complicated than that?"
>
> **Since its taken me a couple of hours to convert the Java to this point
> so I stopped reading to seek your feedback.
> Is that enough insight to adapt to your needs, or is there something else
> further down the article that invalidates my analysis?
>
>
>
>
>
>>
>> From ben:
>>
>> "I'm not really familiar with IoC or DI patterns, so just taking your
>>> example at face value, in Pharo I'd do...
>>>
>>> MovieLister>>moviesDirectedBy: director
>>> allMovies := finder allMovies.
>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>> "although typically #getDirector would be renamed #director"
>>>
>>> MovieLister>>finder: movieFinder
>>> finder := movieFinder.
>>>
>>> to be used like this...
>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
>>> 'movies1.txt').
>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>
>>
>
> So per Fowler, the above is equivalent to "Setter Injection with Spring"
>
>
>>
>> and Stephane:
>>
>> Why don't you simply pass the class and use that class in your
>>> MovieLister?
>>>
>>> MovieLister new
>>> finderClass: MySuperCoolFinderClass
>>>
>>> ...
>>> MovieLister finder
>>> finderClass new .....
>>>
>>> What is wrong with that.
>>
>>
>> That was what I meant when I said: "I know that in Smalltalk I can make
>> MovieLister to receive, upon construction, a class representing MovieFinder
>> and call it construction message.". The code I had in mind is a bit of
>> mix from the one provided by you both:
>>
>> MovieLister>>moviesDirectedBy: director
>> allMovies := finder allMovies.
>> ^ allMovies select: [ :movie | movie getDirector = director ].
>> "although typically #getDirector would be renamed #director"
>>
>> MovieLister>>finder: aMovieFinderBuilder
>> finder := aMovieFinderClass new.
>>
>> to be used like this...
>> lister := MovieLister new finder: (ColonDelimitedMovieFinder
>> builderOn: 'movies1.txt').
>> movies := lister moviesDirectedBy: 'Tarantino'."
>>
>> But that means I will have to wire dependencies by hand whenever I create
>> a MovieLister and seek through code when and if those dependencies change.
>> When there are lot's of dependencies it's is a considerable and tedious
>> work. Let's see an image from Fowlers article:
>>
>> [image: Inline image 1]
>>
>> In this case, the service locator provides me with an instance and I
>> configure the instance in the assembler, the scheme is alike for an IoC,
>> and that would mean my implementation could be like this:
>>
>>
>> MovieLister>>moviesDirectedBy: director
>> allMovies := finder allMovies.
>> ^ allMovies select: [ :movie | movie getDirector = director ].
>> "although typically #getDirector would be renamed #director"
>>
>> MovieLister>>initialize
>> finder := ServiceLocator locate: FinderClass <--- This would bring
>> the instance of finder class configured by the assembler
>>
>
> No, like this...
> finder := ServiceLocation movieFinder.
>
> Now if you want to store a class rather than an instance as I did higher
> up, you just do this...
>
> Object subclass: ServiceLocator
> instanceVariable: 'movieFinderClass'
> classVariable: 'SoleInstance'
>
> ServiceLocator class >> movieFinder
> ^ self soleInstance movieFinderClass new
>
>
>
>>
>>
>> to be used like this...
>> lister := MovieLister new.
>> movies := lister moviesDirectedBy: 'Tarantino'."
>>
>> and the assembler:
>>
>> Assember class>>configure:
>> aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
>> FinderClass
>>
>
> Assembler class>>configure
> ServiceLocator load:
> (ServiceLocator new
> movieFinder: (ColonMovieFinder newWith: 'movies1.txt')
> otherService: MyCustomService new)
>
>
>>
>> My assembler and service locator could be even more elaborated, and
>> provide a different MovieFinder in test scope, for different classes or
>> wharever.
>>
>
> Really, the test should not be updating the class variable global like
> this...
> ServiceLocatorTest >> configure
> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
> newWith: 'movies1.txt'))
>
> you probably want something like (its rough but shows the point...)
> Object subclass: #MovieLister
> instanceVariables: 'serviceLocator'
>
> MovieLister >> initialize
> serviceLocator ifNil: [ serviceLocator := ServiceLocator soleInstance
> ].
> finder := serviceLocator movieFinder.
>
> MovieLister class >> newWithServiceLocator: aServiceLocator
> ^ (self basicNew initializeWithServiceLocator: aServiceLocator)
> initialize.
>
> MovieLister >> initializeWithServiceLocator: aServiceLocator
> serviceLocator := aServiceLocator
>
> ServiceLocatorTest >> testSimple2
> lister := MovieLister newWithServiceLocator: (ServiceLocator newWith:
> (ColonMovieFinder newWith: 'movies1.txt')).
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
>
> cheers -ben
>
>
>>
>> It is a little convenience for Smalltalk, I will give that, but I was
>> wandering if there was something alike in Pharo, by your answers I assuming
>> there is nothing like that.
>>
>>
>>
>> On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <stepharo.self(a)gmail.com
>> > wrote:
>>
>>> Why don't you simply pass the class and use that class in your
>>> MovieLister?
>>>
>>> MovieLister new
>>> finderClass: MySuperCoolFinderClass
>>>
>>> ...
>>> MovieLister finder
>>> finderClass new .....
>>>
>>> What is wrong with that.
>>>
>>> If you do not want to have a reference at runtime to a Finder then you
>>> need to use announcement and registration.
>>>
>>> Stef
>>>
>>>
>>>
>>> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
>>> wrote:
>>> > Hello,
>>> >
>>> > I would like to know how people in Pharo ecosystem do to deal with
>>> object
>>> > wiring, as described by Marting Fowler in
>>> > https://martinfowler.com/articles/injection.html#FormsOfDepe
>>> ndencyInjection:
>>> >
>>> > "A common issue to deal with is how to wire together different
>>> elements: how
>>> > do you fit together this web controller architecture with that database
>>> > interface backing when they were built by different teams with little
>>> > knowledge of each other."
>>> >
>>> > He gives an example, I will leave it in java as it is simple enough to
>>> > understand:
>>> >
>>> > "class MovieLister...
>>> >
>>> > public Movie[] moviesDirectedBy(String arg) {
>>> > List allMovies = finder.findAll();
>>> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
>>> > Movie movie = (Movie) it.next();
>>> > if (!movie.getDirector().equals(arg)) it.remove();
>>> > }
>>> > return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>>> >
>>> > }"
>>> >
>>> > The question is how to provide the finder object in a decoupled
>>> matter, a
>>> > naive approach would be:
>>> >
>>> > " private MovieFinder finder;
>>> >
>>> > public MovieLister() {
>>> > finder = new ColonDelimitedMovieFinder("movies1.txt");
>>> >
>>> > }"
>>> >
>>> > Which couples the MovieLister to the specific ColonDelimitedMovieFinder
>>> > class.
>>> >
>>> > Fowler explains how to decouple using an IoC framework or a Service
>>> Locator.
>>> > In Java and .Net IoC is used most of the time. I Googled how this
>>> problem is
>>> > approached in Smalltalk/Pharo, and I generally I found answers "that
>>> is easy
>>> > to do in Smalltalk, so there is no need of a framework", what I miss
>>> is a
>>> > description on *how* to do that:
>>> >
>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>> > https://stackoverflow.com/questions/2684326/is-there-a-depen
>>> dency-injection-framework-for-smalltalk
>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>> /347477#347477
>>> >
>>> > I know that in Smalltalk I can make MovieLister to receive, upon
>>> > construction, a class representing MovieFinder and call it construction
>>> > message. As long an object that responds to this message is provided,
>>> I can
>>> > create as many derivations I want and the MovieLister will be
>>> decoupled from
>>> > the MovieFinder. That way, however, I still have to wire things by
>>> hand, and
>>> > I am not sure if this is what I am supposed to do in order to solve the
>>> > decouple problem.
>>> >
>>> > Can you explain me how this is done in Pharo? It's is usually wiring by
>>> > hand? Is there a simple construction that deals with the wiring
>>> problem that
>>> > I cannot foresee?
>>> >
>>> > Thanks in advance,
>>> > Vitor
>>> >
>>> >
>>> >
>>>
>>>
>>
>
June 5, 2017
Re: [Pharo-users] STON Question
by Stephane Ducasse
Hi offray
Thanks but pillar ha a conf since several years and it is working well. Now
I'm revisiting the implementation of cocoon
because I want to have it simpler independent of magritte and better tested.
Now I just want to add a new functionality to output a configuration file
from the
objects and in Pillar the configuration objects hold more complex
***objects***.
So just taking the object and turning it in ston does not work.
Stef
On Mon, Jun 5, 2017 at 6:23 PM, Offray Vladimir Luna Cárdenas <
offray.luna(a)mutabit.com> wrote:
> Hi,
>
> Maybe what I'm doing in Grafoscopio could help.
>
> I have a %metadata node which contains all configuration options for the
> production of the document (as shown in the image below). Exporting a
> document consist in looking for these nodes while traversing the notebook
> tree and applying that options in the proper place. You can see the source
> code of the current notebook STON file at [1], the exported markdown file
> at [2] and the exported PDF at [3]. As you can see I have pretty good
> control of the configuration of the document using this option (and a
> single place to manage all, without endless small files and folders for a
> document, but event that exporting options as split folders and docs, could
> be added also).
> [1] http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1
> [2] http://mutabit.com/repos.fossil/grafoscopio/artifact?
> name=59245142cf93590b&txt=1
> [3] http://mutabit.com/repos.fossil/grafoscopio/doc/tip/
> Docs/En/Books/Manual/manual.pdf
>
>
>
> Cheers,
>
> Offray
>
>
> On 05/06/17 01:58, Stephane Ducasse wrote:
>
> Sven I know what Ston is :)
>
> Now Pillar dev used Ston as input and it works. Then with some hooks they
> let the user convert the strings
> into specific objects and this is ok.
> Now I want to add export in Ston and for configurations I need to control
> for the application and not as a ston object the value saved.
> For example a file reference should not be just a file reference in Ston
> but
> a string relative the the baseDirectory of the configuration.
>
> So I thought that I can build a hook and control the call to Ston (convert
> the object before to the correct values) and export.
> It should be working now doing this I found myself redoing the output of
> Ston.
> So I will do it. Then I thought that may be I could reuse this logic.
>
> Stef
>
>
>
> On Sun, Jun 4, 2017 at 11:49 PM, Sven Van Caekenberghe <sven(a)stfx.eu>
> wrote:
>
>> Stef,
>>
>> STON is like FUEL, it can write any object to a stream and read it back.
>> Although you can customise how this is done, only one way of doing so is
>> supported (i.e. you cannot change the format for each application).
>>
>> People have used STON for various applications now, including for
>> configuration stuff (because it is a textual format that is easy to read).
>>
>> I would suggest you just try to see what your config looks like once you
>> have the objects in Pharo.
>>
>> STON toStringPretty: myConfig.
>>
>> Then we can see how to tune the representation.
>>
>> Sven
>>
>> > On 4 Jun 2017, at 22:58, Stephane Ducasse <stepharo.self(a)gmail.com>
>> wrote:
>> >
>> > Hi sven
>> >
>> > I'm working on a new configuration frameworks similar to the one use
>> pillar.conf.
>> >
>> > So basically I have
>> >
>> > ston := '{
>> > "newLine":#unix,
>> > "separateOutputFiles":true
>> > }'.
>> > and I want to recreate it.
>> >
>> > So I did
>> >
>> > Object >> toConfigurationString
>> >
>> > ^ STON toString: self
>> >
>> > SimpleConfiguration >> exportStream
>> >
>> > ^ String streamContents: [ :str |
>> > str << '{' .
>> > self propertiesKeysAndValuesDo: [ :key :value|
>> > str << key toConfigurationString.
>> > str << ':'.
>> > str << value toConfigurationString.
>> > str << ','.
>> > str lf.
>> > ].
>> > str << '}'.
>> > str contents
>> > ]
>> >
>> > The idea is that for special configuration values people should be able
>> to define
>> > how to go from the object to configuration.
>> > For example for some FileReference I want to have just the path up to
>> the baseDirectory.
>> >
>> > Now I wonder if I could not better reuse ston.
>> > I saw the stonOn:
>> > but I did not look further because I was wondering how the writer where
>> passed.
>> >
>> > Any feedback is welcome.
>> >
>> > Stef (now bed time).
>> >
>>
>>
>>
>
>
June 5, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Ben Coman
On Tue, Jun 6, 2017 at 1:26 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
wrote:
> Thanks for the answer Ben and Stephane.
>
> I already read A Mentoring Course on Smalltalk, Valloud, there is nothing
> there I could use in this case :( . I will look after for The Design
> Patterns Smalltalk Companion. Most of the sources provided I already know
> of or went in the same lines lines of what I have already found.
>
> About TDD, I am experienced with the discipline and have tested it on
> Pharo living system already, but I could not understand how this is related
> with object wiring, DI and service locator.
>
I guess I don't properly understand your need and those topics. That was
my quick pass. Now if I take the time to actually read Fowler's long
article
"the inversion is about how they lookup a plugin implementation ... to
ensure that any user of a plugin follows some convention that allows a
separate assembler module to inject the implementation into the lister."
"The basic idea of the Dependency Injection is to have a separate object,
an assembler, that populates a field in the lister class with an
appropriate implementation for the finder interface. There are three main
styles of dependency injection. The names I'm using for them are
Constructor Injection, Setter Injection, and Interface Injection."
Now there was too much syntactical noise in those Java examples for me to
think clearly, so I converted them all to Smalltalk.
##CONSTRUCTOR INJECTION
Object subclass: MovieLister
instanceVariables: 'finder'
MovieLister class >> newWith: aFinder
^ self basicNew initializeWith: aFinder
MovieLister >> initializeWith: aFinder
finder := aFinder
ColonMovieFinder class >> newWith: aFilename
^ self basicNew initializeWith: aFilename
ColonMovieFinder >> initializeWith: aFilename
filename := aFilename.
ConstructorInjectionContainer >> new
container := DefaultContainer new. "the article doesn't specify where
this comes from"
finderParams := ConstantParameter newWith: 'movies1.txt'.
container registerComponentInterface: MovieFinderInterface
implementation: ColonMovieFinder
params: finderParams.
container registerComponentImplementation: MovieLister
^container
to be used like this...
ConstructorInjectionTest >> testWithContainer
container := ConstructorInjectionContainer new.
lister := container getComponentInstance( MovieLister ).
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
The article poorly defines registerComponentXXX: or getComponentInstance:
methods, so I don't dwell on them. I presume its little relevant to the
main theme.
##SETTER INJECTION
MovieLister >> setFinder: aFinder
finder := aFinder.
ColonMovieFinder >> setFilename: aFilename
filename := aFilename.
SetterInjectionTest >> testWithConfigurationFile
ctx := SomeXmlApplicationConfiguration on: 'config.xml'.
lister := ctx getConfigOf: 'MovieLister'.
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
##INTERFACE INJECTION
MovieLister >> injectFinder: aFinder
finder := aFinder
ColonMovieFinder >> injectFilename: aFilename
filename := aFilename
InterfaceInjectionTest >> configureContainer
container := InterfaceInjectionContainer new.
self registerComponents.
self registerInjectors.
container start.
InterfaceInjectionTest >> registerComponents
container registerComponent: 'MovieLister' with: MovieLister.
container registerComponent: 'MovieFinder' with: ColonMovieFinder.
InterfaceInjectionTest >> registerInjectors
container registerInjector: Injector with: (container lookup:
'MovieFinder').
container registerInjector: InjectorFinderFilename with:
FinderFilenameInjector new.
ColonMovieFinder >> inject: anObject
anObject injectFinder: self.
FinderFilenameInjector >> inject: anObject
anObject injectFilename: 'movies1.txt'.
InterfaceInjectionTester >> testInterface
self configureContainer.
lister := container lookup: 'MovieLister'.
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
The article doesn't define InterfaceInjectionContainer, but I guess it
could look like this...
InterfaceInjectionContainer >> registerComponent: componentName with:
aComponent
container ifNil: [ container := Dictionary new].
container at: componentName put: aComponent
InterfaceInjectionContainer >> lookup: componentName
^ container at: componentName
##SERVICE LOCATOR
"The basic idea behind a service locator is to have an object that knows
how to get hold of all of the services that an application might need. So a
service locator for this application would have a method that returns a
movie finder when one is needed. Of course this just shifts the burden a
tad, we still have to get the locator into the lister"
MovieLister >> initialize
finder := ServiceLocator movieFinder.
Object subclass: ServiceLocator
instanceVariable: 'movieFinder'
classVariable: 'SoleInstance'
ServiceLocator class >> load: aServiceLocator
SoleInstance := aServiceLocator
ServiceLocator class >> soleInstance
^ SoleInstance
ServiceLocator class >> movieFinder
^ self soleInstance movieFinder
ServiceLocator >> movieFinder
^movieFinder
ServiceLocatorTest >> configure
ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
newWith: 'movies1.txt'))
ServiceLocator class >> newWith: aMovieFinder
^ self basicNew initializeWithFinder: aMovieFinder
ServiceLocator >> initializeWithFinder: aMovieFinder
movieFinder := aMovieFinder
ServiceLocatorTest >> testSimple
self configure.
lister := MovieLister new.
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
So it seems that a service locator is just a Singleton pattern having a
class variable for each service of interest ??
So in good faith** I ask... "Is it any more complicated than that?"
**Since its taken me a couple of hours to convert the Java to this point so
I stopped reading to seek your feedback.
Is that enough insight to adapt to your needs, or is there something else
further down the article that invalidates my analysis?
>
> From ben:
>
> "I'm not really familiar with IoC or DI patterns, so just taking your
>> example at face value, in Pharo I'd do...
>>
>> MovieLister>>moviesDirectedBy: director
>> allMovies := finder allMovies.
>> ^ allMovies select: [ :movie | movie getDirector = director ].
>> "although typically #getDirector would be renamed #director"
>>
>> MovieLister>>finder: movieFinder
>> finder := movieFinder.
>>
>> to be used like this...
>> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
>> 'movies1.txt').
>> movies := lister moviesDirectedBy: 'Tarantino'."
>
>
So per Fowler, the above is equivalent to "Setter Injection with Spring"
>
> and Stephane:
>
> Why don't you simply pass the class and use that class in your MovieLister?
>>
>> MovieLister new
>> finderClass: MySuperCoolFinderClass
>>
>> ...
>> MovieLister finder
>> finderClass new .....
>>
>> What is wrong with that.
>
>
> That was what I meant when I said: "I know that in Smalltalk I can make
> MovieLister to receive, upon construction, a class representing MovieFinder
> and call it construction message.". The code I had in mind is a bit of
> mix from the one provided by you both:
>
> MovieLister>>moviesDirectedBy: director
> allMovies := finder allMovies.
> ^ allMovies select: [ :movie | movie getDirector = director ].
> "although typically #getDirector would be renamed #director"
>
> MovieLister>>finder: aMovieFinderBuilder
> finder := aMovieFinderClass new.
>
> to be used like this...
> lister := MovieLister new finder: (ColonDelimitedMovieFinder
> builderOn: 'movies1.txt').
> movies := lister moviesDirectedBy: 'Tarantino'."
>
> But that means I will have to wire dependencies by hand whenever I create
> a MovieLister and seek through code when and if those dependencies change.
> When there are lot's of dependencies it's is a considerable and tedious
> work. Let's see an image from Fowlers article:
>
> [image: Inline image 1]
>
> In this case, the service locator provides me with an instance and I
> configure the instance in the assembler, the scheme is alike for an IoC,
> and that would mean my implementation could be like this:
>
>
> MovieLister>>moviesDirectedBy: director
> allMovies := finder allMovies.
> ^ allMovies select: [ :movie | movie getDirector = director ].
> "although typically #getDirector would be renamed #director"
>
> MovieLister>>initialize
> finder := ServiceLocator locate: FinderClass <--- This would bring
> the instance of finder class configured by the assembler
>
No, like this...
finder := ServiceLocation movieFinder.
Now if you want to store a class rather than an instance as I did higher
up, you just do this...
Object subclass: ServiceLocator
instanceVariable: 'movieFinderClass'
classVariable: 'SoleInstance'
ServiceLocator class >> movieFinder
^ self soleInstance movieFinderClass new
>
>
> to be used like this...
> lister := MovieLister new.
> movies := lister moviesDirectedBy: 'Tarantino'."
>
> and the assembler:
>
> Assember class>>configure:
> aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
> FinderClass
>
Assembler class>>configure
ServiceLocator load:
(ServiceLocator new
movieFinder: (ColonMovieFinder newWith: 'movies1.txt')
otherService: MyCustomService new)
>
> My assembler and service locator could be even more elaborated, and
> provide a different MovieFinder in test scope, for different classes or
> wharever.
>
Really, the test should not be updating the class variable global like
this...
ServiceLocatorTest >> configure
ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
newWith: 'movies1.txt'))
you probably want something like (its rough but shows the point...)
Object subclass: #MovieLister
instanceVariables: 'serviceLocator'
MovieLister >> initialize
serviceLocator ifNil: [ serviceLocator := ServiceLocator soleInstance ].
finder := serviceLocator movieFinder.
MovieLister class >> newWithServiceLocator: aServiceLocator
^ (self basicNew initializeWithServiceLocator: aServiceLocator)
initialize.
MovieLister >> initializeWithServiceLocator: aServiceLocator
serviceLocator := aServiceLocator
ServiceLocatorTest >> testSimple2
lister := MovieLister newWithServiceLocator: (ServiceLocator newWith:
(ColonMovieFinder newWith: 'movies1.txt')).
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
cheers -ben
>
> It is a little convenience for Smalltalk, I will give that, but I was
> wandering if there was something alike in Pharo, by your answers I assuming
> there is nothing like that.
>
>
>
> On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
>
>> Why don't you simply pass the class and use that class in your
>> MovieLister?
>>
>> MovieLister new
>> finderClass: MySuperCoolFinderClass
>>
>> ...
>> MovieLister finder
>> finderClass new .....
>>
>> What is wrong with that.
>>
>> If you do not want to have a reference at runtime to a Finder then you
>> need to use announcement and registration.
>>
>> Stef
>>
>>
>>
>> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
>> wrote:
>> > Hello,
>> >
>> > I would like to know how people in Pharo ecosystem do to deal with
>> object
>> > wiring, as described by Marting Fowler in
>> > https://martinfowler.com/articles/injection.html#FormsOfDepe
>> ndencyInjection:
>> >
>> > "A common issue to deal with is how to wire together different
>> elements: how
>> > do you fit together this web controller architecture with that database
>> > interface backing when they were built by different teams with little
>> > knowledge of each other."
>> >
>> > He gives an example, I will leave it in java as it is simple enough to
>> > understand:
>> >
>> > "class MovieLister...
>> >
>> > public Movie[] moviesDirectedBy(String arg) {
>> > List allMovies = finder.findAll();
>> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
>> > Movie movie = (Movie) it.next();
>> > if (!movie.getDirector().equals(arg)) it.remove();
>> > }
>> > return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>> >
>> > }"
>> >
>> > The question is how to provide the finder object in a decoupled matter,
>> a
>> > naive approach would be:
>> >
>> > " private MovieFinder finder;
>> >
>> > public MovieLister() {
>> > finder = new ColonDelimitedMovieFinder("movies1.txt");
>> >
>> > }"
>> >
>> > Which couples the MovieLister to the specific ColonDelimitedMovieFinder
>> > class.
>> >
>> > Fowler explains how to decouple using an IoC framework or a Service
>> Locator.
>> > In Java and .Net IoC is used most of the time. I Googled how this
>> problem is
>> > approached in Smalltalk/Pharo, and I generally I found answers "that is
>> easy
>> > to do in Smalltalk, so there is no need of a framework", what I miss is
>> a
>> > description on *how* to do that:
>> >
>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>> > https://stackoverflow.com/questions/2684326/is-there-a-depen
>> dency-injection-framework-for-smalltalk
>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>> /347477#347477
>> >
>> > I know that in Smalltalk I can make MovieLister to receive, upon
>> > construction, a class representing MovieFinder and call it construction
>> > message. As long an object that responds to this message is provided, I
>> can
>> > create as many derivations I want and the MovieLister will be decoupled
>> from
>> > the MovieFinder. That way, however, I still have to wire things by
>> hand, and
>> > I am not sure if this is what I am supposed to do in order to solve the
>> > decouple problem.
>> >
>> > Can you explain me how this is done in Pharo? It's is usually wiring by
>> > hand? Is there a simple construction that deals with the wiring problem
>> that
>> > I cannot foresee?
>> >
>> > Thanks in advance,
>> > Vitor
>> >
>> >
>> >
>>
>>
>
June 5, 2017
Re: [Pharo-users] STON Question
by Offray Vladimir Luna Cárdenas
Hi,
Maybe what I'm doing in Grafoscopio could help.
I have a %metadata node which contains all configuration options for the
production of the document (as shown in the image below). Exporting a
document consist in looking for these nodes while traversing the
notebook tree and applying that options in the proper place. You can see
the source code of the current notebook STON file at [1], the exported
markdown file at [2] and the exported PDF at [3]. As you can see I have
pretty good control of the configuration of the document using this
option (and a single place to manage all, without endless small files
and folders for a document, but event that exporting options as split
folders and docs, could be added also).
[1] http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1
[2]
http://mutabit.com/repos.fossil/grafoscopio/artifact?name=59245142cf93590b&…
[3]
http://mutabit.com/repos.fossil/grafoscopio/doc/tip/Docs/En/Books/Manual/ma…
Cheers,
Offray
On 05/06/17 01:58, Stephane Ducasse wrote:
> Sven I know what Ston is :)
>
> Now Pillar dev used Ston as input and it works. Then with some hooks
> they let the user convert the strings
> into specific objects and this is ok.
> Now I want to add export in Ston and for configurations I need to
> control for the application and not as a ston object the value saved.
> For example a file reference should not be just a file reference in
> Ston but
> a string relative the the baseDirectory of the configuration.
>
> So I thought that I can build a hook and control the call to Ston
> (convert the object before to the correct values) and export.
> It should be working now doing this I found myself redoing the output
> of Ston.
> So I will do it. Then I thought that may be I could reuse this logic.
>
> Stef
>
>
>
> On Sun, Jun 4, 2017 at 11:49 PM, Sven Van Caekenberghe <sven(a)stfx.eu
> <mailto:sven@stfx.eu>> wrote:
>
> Stef,
>
> STON is like FUEL, it can write any object to a stream and read it
> back. Although you can customise how this is done, only one way of
> doing so is supported (i.e. you cannot change the format for each
> application).
>
> People have used STON for various applications now, including for
> configuration stuff (because it is a textual format that is easy
> to read).
>
> I would suggest you just try to see what your config looks like
> once you have the objects in Pharo.
>
> STON toStringPretty: myConfig.
>
> Then we can see how to tune the representation.
>
> Sven
>
> > On 4 Jun 2017, at 22:58, Stephane Ducasse
> <stepharo.self(a)gmail.com <mailto:stepharo.self@gmail.com>> wrote:
> >
> > Hi sven
> >
> > I'm working on a new configuration frameworks similar to the one
> use pillar.conf.
> >
> > So basically I have
> >
> > ston := '{
> > "newLine":#unix,
> > "separateOutputFiles":true
> > }'.
> > and I want to recreate it.
> >
> > So I did
> >
> > Object >> toConfigurationString
> >
> > ^ STON toString: self
> >
> > SimpleConfiguration >> exportStream
> >
> > ^ String streamContents: [ :str |
> > str << '{' .
> > self propertiesKeysAndValuesDo: [ :key :value|
> > str << key toConfigurationString.
> > str << ':'.
> > str << value toConfigurationString.
> > str << ','.
> > str lf.
> > ].
> > str << '}'.
> > str contents
> > ]
> >
> > The idea is that for special configuration values people should
> be able to define
> > how to go from the object to configuration.
> > For example for some FileReference I want to have just the path
> up to the baseDirectory.
> >
> > Now I wonder if I could not better reuse ston.
> > I saw the stonOn:
> > but I did not look further because I was wondering how the
> writer where passed.
> >
> > Any feedback is welcome.
> >
> > Stef (now bed time).
> >
>
>
>
June 5, 2017