Spec Adapter Advice

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
19 messages Options
Reply | Threaded
Open this post in threaded view
|

Spec Adapter Advice

Rob Rothwell
Hello,

I have recently been lucky enough to get the Cocoa portion of Mars working on Pharo 5.0.  While there are some issues, it has a wonderful set of examples that allowed me create new Cocoa classes and delegate methods and see a straightforward path to learning how to use Coco widgets from Pharo.

I'd like to do that by creating appropriate Spec adapters, but unfortunately the new Spec booklet wasn't designed for that!

Can anyone give me any insight into creating (and using) a new Spec adapter?  Maybe just some high level steps to help me orient my investigation into how Spec works?

Thank you,

Rob


Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Peter Uhnak
Hi Rob,

I guess the best resource at the moment is to just look at existing adapters.

But here are some thoughts to get you started:

(Spec) ComposableModel has as its widget (Spec) Adapter
Adapter has as its widget the actual visual component, which currently means Morphic.


The simplest example: LabelModel

1. model to adapter

LabelModel is adapted by MorphicLabelAdapter:

you can see on the class side in method `defaultSpec`.
There is only `LabelAdapter` there because there is some extra mapping for some classes, but you can specify directly the class of the Adapter, so the following would work just as well:

LabelModel class>>defaultSpec
        <spec>
       
        ^ #(MorphicLabelAdapter
                adapt: #(model))


LabelModel -> LabelAdapter direct event propagation (pushing changes)

in Model world you can call changed:with: to execute code on the Adapter, e.g.

self changed: #emphasis: with: {emphasis}

which in turn will call the #emphasis: method on the LabelAdapter.

LabelModel -> LabelAdapter events (pulling changes)

preferred alternative is to do the opposite; properties of models are often held in ValueHolders, which can be observed on ValueChange, so the Adapter can register to event change and react on itself;

you can see this best in MorphicTabAdapter (but you will see that TabAdapter looks a bit different from the rest, because I was experimenting with cleaning up Adapters...)

2. adapter to morphic

Every adapter implements #buildWidget method that returns a Morphic Object.
Typically the adapter registers itself as the model of the adapter (so adapter's model is Spec, and Morphic's model is the adapter). This depends a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so there's no buildWidget, and it is in #buildWidgetWith:).

It is all kinds of messy, but if you have other widgets then it will be a good test how well Spec can handle it... or rather we'll see how it can be improved...

Peter



On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:

> Hello,
>
> I have recently been lucky enough to get the Cocoa portion of Mars working
> on Pharo 5.0.  While there are some issues, it has a wonderful set of
> examples that allowed me create new Cocoa classes and delegate methods and
> see a straightforward path to learning how to use Coco widgets from Pharo.
>
> I'd like to do that by creating appropriate Spec adapters, but
> unfortunately the new Spec booklet wasn't designed for that!
>
> Can anyone give me any insight into creating (and using) a new Spec
> adapter?  Maybe just some high level steps to help me orient my
> investigation into how Spec works?
>
> Thank you,
>
> Rob

Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Rob Rothwell
Hi Peter,

Thank you very much for that overview!

It looks like even just creating a window with no other widgets is sort of "hard-wired" to Morphic through ComposableModel>>defaultWindowModelClass, so maybe just overriding that and trying to create a Cocoa window model and adapter is the place to start.

I need to find a good starting point because you can't poke at the existing code too much since even the debugger is built with Spec!

It's pretty exciting, though, because it feels like all the right pieces are there and a lot of this could mostly be "just work" once I get going.

Thanks again,

Rob

On Thu, Apr 27, 2017 at 6:04 PM, Peter Uhnak <[hidden email]> wrote:
Hi Rob,

I guess the best resource at the moment is to just look at existing adapters.

But here are some thoughts to get you started:

(Spec) ComposableModel has as its widget (Spec) Adapter
Adapter has as its widget the actual visual component, which currently means Morphic.


The simplest example: LabelModel

1. model to adapter

LabelModel is adapted by MorphicLabelAdapter:

you can see on the class side in method `defaultSpec`.
There is only `LabelAdapter` there because there is some extra mapping for some classes, but you can specify directly the class of the Adapter, so the following would work just as well:

LabelModel class>>defaultSpec
        <spec>

        ^ #(MorphicLabelAdapter
                adapt: #(model))


LabelModel -> LabelAdapter direct event propagation (pushing changes)

in Model world you can call changed:with: to execute code on the Adapter, e.g.

self changed: #emphasis: with: {emphasis}

which in turn will call the #emphasis: method on the LabelAdapter.

LabelModel -> LabelAdapter events (pulling changes)

preferred alternative is to do the opposite; properties of models are often held in ValueHolders, which can be observed on ValueChange, so the Adapter can register to event change and react on itself;

you can see this best in MorphicTabAdapter (but you will see that TabAdapter looks a bit different from the rest, because I was experimenting with cleaning up Adapters...)

2. adapter to morphic

Every adapter implements #buildWidget method that returns a Morphic Object.
Typically the adapter registers itself as the model of the adapter (so adapter's model is Spec, and Morphic's model is the adapter). This depends a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so there's no buildWidget, and it is in #buildWidgetWith:).

It is all kinds of messy, but if you have other widgets then it will be a good test how well Spec can handle it... or rather we'll see how it can be improved...

Peter



On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:
> Hello,
>
> I have recently been lucky enough to get the Cocoa portion of Mars working
> on Pharo 5.0.  While there are some issues, it has a wonderful set of
> examples that allowed me create new Cocoa classes and delegate methods and
> see a straightforward path to learning how to use Coco widgets from Pharo.
>
> I'd like to do that by creating appropriate Spec adapters, but
> unfortunately the new Spec booklet wasn't designed for that!
>
> Can anyone give me any insight into creating (and using) a new Spec
> adapter?  Maybe just some high level steps to help me orient my
> investigation into how Spec works?
>
> Thank you,
>
> Rob


Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Ben Coman
Hi Dennis,

On Fri, Apr 28, 2017 at 7:09 AM, Rob Rothwell <[hidden email]> wrote:
Hi Peter,

Thank you very much for that overview!

It looks like even just creating a window with no other widgets is sort of "hard-wired" to Morphic through ComposableModel>>defaultWindowModelClass, so maybe just overriding that and trying to create a Cocoa window model and adapter is the place to start.

I need to find a good starting point because you can't poke at the existing code too much since even the debugger is built with Spec!

Would your remote IDE [1] be suitable to help Rob to hack around Spec without blowing up his IDE? 
But I think its only available on Pharo 6?


cheers -ben

 

It's pretty exciting, though, because it feels like all the right pieces are there and a lot of this could mostly be "just work" once I get going.

Thanks again,

Rob

On Thu, Apr 27, 2017 at 6:04 PM, Peter Uhnak <[hidden email]> wrote:
Hi Rob,

I guess the best resource at the moment is to just look at existing adapters.

But here are some thoughts to get you started:

(Spec) ComposableModel has as its widget (Spec) Adapter
Adapter has as its widget the actual visual component, which currently means Morphic.


The simplest example: LabelModel

1. model to adapter

LabelModel is adapted by MorphicLabelAdapter:

you can see on the class side in method `defaultSpec`.
There is only `LabelAdapter` there because there is some extra mapping for some classes, but you can specify directly the class of the Adapter, so the following would work just as well:

LabelModel class>>defaultSpec
        <spec>

        ^ #(MorphicLabelAdapter
                adapt: #(model))


LabelModel -> LabelAdapter direct event propagation (pushing changes)

in Model world you can call changed:with: to execute code on the Adapter, e.g.

self changed: #emphasis: with: {emphasis}

which in turn will call the #emphasis: method on the LabelAdapter.

LabelModel -> LabelAdapter events (pulling changes)

preferred alternative is to do the opposite; properties of models are often held in ValueHolders, which can be observed on ValueChange, so the Adapter can register to event change and react on itself;

you can see this best in MorphicTabAdapter (but you will see that TabAdapter looks a bit different from the rest, because I was experimenting with cleaning up Adapters...)

2. adapter to morphic

Every adapter implements #buildWidget method that returns a Morphic Object.
Typically the adapter registers itself as the model of the adapter (so adapter's model is Spec, and Morphic's model is the adapter). This depends a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so there's no buildWidget, and it is in #buildWidgetWith:).

It is all kinds of messy, but if you have other widgets then it will be a good test how well Spec can handle it... or rather we'll see how it can be improved...

Peter



On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:
> Hello,
>
> I have recently been lucky enough to get the Cocoa portion of Mars working
> on Pharo 5.0.  While there are some issues, it has a wonderful set of
> examples that allowed me create new Cocoa classes and delegate methods and
> see a straightforward path to learning how to use Coco widgets from Pharo.
>
> I'd like to do that by creating appropriate Spec adapters, but
> unfortunately the new Spec booklet wasn't designed for that!
>
> Can anyone give me any insight into creating (and using) a new Spec
> adapter?  Maybe just some high level steps to help me orient my
> investigation into how Spec works?
>
> Thank you,
>
> Rob



Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Stephane Ducasse-3
In reply to this post by Rob Rothwell
This is a cool news.
We could have a new adapter for Mars.
I'm really interested in getting this working. 

Stef

On Thu, Apr 27, 2017 at 11:10 PM, Rob Rothwell <[hidden email]> wrote:
Hello,

I have recently been lucky enough to get the Cocoa portion of Mars working on Pharo 5.0.  While there are some issues, it has a wonderful set of examples that allowed me create new Cocoa classes and delegate methods and see a straightforward path to learning how to use Coco widgets from Pharo.

I'd like to do that by creating appropriate Spec adapters, but unfortunately the new Spec booklet wasn't designed for that!

Can anyone give me any insight into creating (and using) a new Spec adapter?  Maybe just some high level steps to help me orient my investigation into how Spec works?

Thank you,

Rob



Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Denis Kudriashov
In reply to this post by Ben Coman
Hi Ben

2017-04-28 4:32 GMT+02:00 Ben Coman <[hidden email]>:

Would your remote IDE [1] be suitable to help Rob to hack around Spec without blowing up his IDE? 

Yes. But I think it is easy to just use Calypso tools to hack Spec. Calypso not depends on Spec. And it would be not a problem to break Spec based MessageBrowser.

To use remote tools generally refactorings should be fixed. Right now they are not working from remote browser.
 
But I think its only available on Pharo 6?

Yes.
 
Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Denis Kudriashov
In reply to this post by Peter Uhnak
From design point of view I think we should remove adapters at all. They bring parallel hierarchy which is always bad.
In fact they are not adapters. They are factories which creates backend views (morphs). And now there are completely no logic behind them: every adapter just passes state received from model to view instance.
I think full hierarchy of adapters can be easily substituted by single backend factory class like MorphicViewFactory. Every model will ask it to create concrete view instance. Actually I have another idea: we do not need this factory at all.

Now Spec allows very restricted relationship between model and view. We can only have single kind of view per model (MorphicAdapterBindings defines this relation). There is no way to use different kind of views for same model in single application.
Maybe current design tried to address this issue. But it not works. And interesting that all Spec based tools do not require such kind of flexibility which means that it is not really an issue. 

Now you can imaging that if we always use same view class for same model class then we can directly ask model to instantiate view. Message can be backend specific like createMorphicView: and we need hierarchy of backends here which will choose appropriate message.

P.S. Every time I read word model in Spec I feel something bad. It should be named to presenter. But it is quite difficult due to compatibility. And I am not sure that others agree with this.

2017-04-28 0:04 GMT+02:00 Peter Uhnak <[hidden email]>:
Hi Rob,

I guess the best resource at the moment is to just look at existing adapters.

But here are some thoughts to get you started:

(Spec) ComposableModel has as its widget (Spec) Adapter
Adapter has as its widget the actual visual component, which currently means Morphic.


The simplest example: LabelModel

1. model to adapter

LabelModel is adapted by MorphicLabelAdapter:

you can see on the class side in method `defaultSpec`.
There is only `LabelAdapter` there because there is some extra mapping for some classes, but you can specify directly the class of the Adapter, so the following would work just as well:

LabelModel class>>defaultSpec
        <spec>

        ^ #(MorphicLabelAdapter
                adapt: #(model))


LabelModel -> LabelAdapter direct event propagation (pushing changes)

in Model world you can call changed:with: to execute code on the Adapter, e.g.

self changed: #emphasis: with: {emphasis}

which in turn will call the #emphasis: method on the LabelAdapter.

LabelModel -> LabelAdapter events (pulling changes)

preferred alternative is to do the opposite; properties of models are often held in ValueHolders, which can be observed on ValueChange, so the Adapter can register to event change and react on itself;

you can see this best in MorphicTabAdapter (but you will see that TabAdapter looks a bit different from the rest, because I was experimenting with cleaning up Adapters...)

2. adapter to morphic

Every adapter implements #buildWidget method that returns a Morphic Object.
Typically the adapter registers itself as the model of the adapter (so adapter's model is Spec, and Morphic's model is the adapter). This depends a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so there's no buildWidget, and it is in #buildWidgetWith:).

It is all kinds of messy, but if you have other widgets then it will be a good test how well Spec can handle it... or rather we'll see how it can be improved...

Peter



On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:
> Hello,
>
> I have recently been lucky enough to get the Cocoa portion of Mars working
> on Pharo 5.0.  While there are some issues, it has a wonderful set of
> examples that allowed me create new Cocoa classes and delegate methods and
> see a straightforward path to learning how to use Coco widgets from Pharo.
>
> I'd like to do that by creating appropriate Spec adapters, but
> unfortunately the new Spec booklet wasn't designed for that!
>
> Can anyone give me any insight into creating (and using) a new Spec
> adapter?  Maybe just some high level steps to help me orient my
> investigation into how Spec works?
>
> Thank you,
>
> Rob


Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Peter Uhnak
In reply to this post by Rob Rothwell
Hi Rob,

> I need to find a good starting point because you can't poke at the existing
> code too much since even the debugger is built with Spec!

I don't know what Pharo you are on, but this is not the case. Debugger itself is based on Glamour (there used to be SpecDebugger, but it is no longer used).

What is blowing up on you is the predebugger window, which is in Spec. You can disable this in your settings or by calling

GTGenericStackDebugger alwaysOpenFullDebugger: true

this will skip the debugger.

But keep in mind that other tools might be using spec too (like the Browser window that opens when you are listing senders/implementors.

overriding the #windowClass (or whatever the name was) is a good start.

(also FML because apparently I've deleted my image with my spec changes by accident -_-)

Peter

>
> It's pretty exciting, though, because it feels like all the right pieces
> are there and a lot of this could mostly be "just work" once I get going.
>
> Thanks again,
>
> Rob
>
> On Thu, Apr 27, 2017 at 6:04 PM, Peter Uhnak <[hidden email]> wrote:
>
> > Hi Rob,
> >
> > I guess the best resource at the moment is to just look at existing
> > adapters.
> >
> > But here are some thoughts to get you started:
> >
> > (Spec) ComposableModel has as its widget (Spec) Adapter
> > Adapter has as its widget the actual visual component, which currently
> > means Morphic.
> >
> >
> > The simplest example: LabelModel
> >
> > 1. model to adapter
> >
> > LabelModel is adapted by MorphicLabelAdapter:
> >
> > you can see on the class side in method `defaultSpec`.
> > There is only `LabelAdapter` there because there is some extra mapping for
> > some classes, but you can specify directly the class of the Adapter, so the
> > following would work just as well:
> >
> > LabelModel class>>defaultSpec
> >         <spec>
> >
> >         ^ #(MorphicLabelAdapter
> >                 adapt: #(model))
> >
> >
> > LabelModel -> LabelAdapter direct event propagation (pushing changes)
> >
> > in Model world you can call changed:with: to execute code on the Adapter,
> > e.g.
> >
> > self changed: #emphasis: with: {emphasis}
> >
> > which in turn will call the #emphasis: method on the LabelAdapter.
> >
> > LabelModel -> LabelAdapter events (pulling changes)
> >
> > preferred alternative is to do the opposite; properties of models are
> > often held in ValueHolders, which can be observed on ValueChange, so the
> > Adapter can register to event change and react on itself;
> >
> > you can see this best in MorphicTabAdapter (but you will see that
> > TabAdapter looks a bit different from the rest, because I was experimenting
> > with cleaning up Adapters...)
> >
> > 2. adapter to morphic
> >
> > Every adapter implements #buildWidget method that returns a Morphic Object.
> > Typically the adapter registers itself as the model of the adapter (so
> > adapter's model is Spec, and Morphic's model is the adapter). This depends
> > a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so
> > there's no buildWidget, and it is in #buildWidgetWith:).
> >
> > It is all kinds of messy, but if you have other widgets then it will be a
> > good test how well Spec can handle it... or rather we'll see how it can be
> > improved...
> >
> > Peter
> >
> >
> >
> > On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:
> > > Hello,
> > >
> > > I have recently been lucky enough to get the Cocoa portion of Mars
> > working
> > > on Pharo 5.0.  While there are some issues, it has a wonderful set of
> > > examples that allowed me create new Cocoa classes and delegate methods
> > and
> > > see a straightforward path to learning how to use Coco widgets from
> > Pharo.
> > >
> > > I'd like to do that by creating appropriate Spec adapters, but
> > > unfortunately the new Spec booklet wasn't designed for that!
> > >
> > > Can anyone give me any insight into creating (and using) a new Spec
> > > adapter?  Maybe just some high level steps to help me orient my
> > > investigation into how Spec works?
> > >
> > > Thank you,
> > >
> > > Rob
> >
> >

Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Peter Uhnak
In reply to this post by Denis Kudriashov
On Fri, Apr 28, 2017 at 11:50:48AM +0200, Denis Kudriashov wrote:

> In fact they are not adapters. They are factories which creates backend
> views (morphs). And now there are completely no logic behind them: every
> adapter just passes state received from model to view instance.

This depends heavily on what the respective APIs provide.

In TabAdapter I connect SpecTab and MorphicTab directly, so it no longer lives during runtime.

In LabelAdapter the emphasis is being transcoded from symbol to random numbers (so this is not simple delegation)
In MenuItemAdapter you can see much more behavior.

So the naming is appropriate, but it is overall poorly connected.

> Now Spec allows very restricted relationship between model and view. We can
> only have single kind of view per model (MorphicAdapterBindings defines
> this relation). There is no way to use different kind of views for same
> model in single application.

As I've shown in my previous answer this is not the case. The connection is done via the class-side spec method where you can specify any class at all; MorphicAdapterBindings is just a convenience, you can put there whatever you want.

Likewise when you are composing widgets, you can specify what layout to use, something like (don't remember the precise naming out of my head)

^ SpecRowLayout composed add: #textModel withSpec: #cocoaSpec

> But it not works.

I've used it several times so it does work, if you had troubles then maybe it doesn't work with all models.

> Now you can imaging that if we always use same view class for same model
> class then we can directly ask model to instantiate view. Message can be
> backend specific like createMorphicView: and we need hierarchy of backends
> here which will choose appropriate message.

Which is exactly what we do not want, to directly bind model to the view; but I feel I am missing your point, can you rephrase it please?

>
> P.S. Every time I read word model in Spec I feel something bad. It should
> be named to presenter. But it is quite difficult due to compatibility. And
> I am not sure that others agree with this.

When you go the the internals, then depending on the context spec can mean: spec layout, adapter, spec model; and in some parts all contexts overlap, so it's fun to read. :)


Now Pharo 7 will have new SpecInterpreter (it took me two weeks and I've created two extra tools to understand the old one and there are still some special exceptions), so then we can rethink the way it is done.

Peter

>
> 2017-04-28 0:04 GMT+02:00 Peter Uhnak <[hidden email]>:
>
> > Hi Rob,
> >
> > I guess the best resource at the moment is to just look at existing
> > adapters.
> >
> > But here are some thoughts to get you started:
> >
> > (Spec) ComposableModel has as its widget (Spec) Adapter
> > Adapter has as its widget the actual visual component, which currently
> > means Morphic.
> >
> >
> > The simplest example: LabelModel
> >
> > 1. model to adapter
> >
> > LabelModel is adapted by MorphicLabelAdapter:
> >
> > you can see on the class side in method `defaultSpec`.
> > There is only `LabelAdapter` there because there is some extra mapping for
> > some classes, but you can specify directly the class of the Adapter, so the
> > following would work just as well:
> >
> > LabelModel class>>defaultSpec
> >         <spec>
> >
> >         ^ #(MorphicLabelAdapter
> >                 adapt: #(model))
> >
> >
> > LabelModel -> LabelAdapter direct event propagation (pushing changes)
> >
> > in Model world you can call changed:with: to execute code on the Adapter,
> > e.g.
> >
> > self changed: #emphasis: with: {emphasis}
> >
> > which in turn will call the #emphasis: method on the LabelAdapter.
> >
> > LabelModel -> LabelAdapter events (pulling changes)
> >
> > preferred alternative is to do the opposite; properties of models are
> > often held in ValueHolders, which can be observed on ValueChange, so the
> > Adapter can register to event change and react on itself;
> >
> > you can see this best in MorphicTabAdapter (but you will see that
> > TabAdapter looks a bit different from the rest, because I was experimenting
> > with cleaning up Adapters...)
> >
> > 2. adapter to morphic
> >
> > Every adapter implements #buildWidget method that returns a Morphic Object.
> > Typically the adapter registers itself as the model of the adapter (so
> > adapter's model is Spec, and Morphic's model is the adapter). This depends
> > a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so
> > there's no buildWidget, and it is in #buildWidgetWith:).
> >
> > It is all kinds of messy, but if you have other widgets then it will be a
> > good test how well Spec can handle it... or rather we'll see how it can be
> > improved...
> >
> > Peter
> >
> >
> >
> > On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:
> > > Hello,
> > >
> > > I have recently been lucky enough to get the Cocoa portion of Mars
> > working
> > > on Pharo 5.0.  While there are some issues, it has a wonderful set of
> > > examples that allowed me create new Cocoa classes and delegate methods
> > and
> > > see a straightforward path to learning how to use Coco widgets from
> > Pharo.
> > >
> > > I'd like to do that by creating appropriate Spec adapters, but
> > > unfortunately the new Spec booklet wasn't designed for that!
> > >
> > > Can anyone give me any insight into creating (and using) a new Spec
> > > adapter?  Maybe just some high level steps to help me orient my
> > > investigation into how Spec works?
> > >
> > > Thank you,
> > >
> > > Rob
> >
> >

Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Denis Kudriashov

2017-04-28 12:26 GMT+02:00 Peter Uhnak <[hidden email]>:
> backend specific like createMorphicView: and we need hierarchy of backends
> here which will choose appropriate message.

Which is exactly what we do not want, to directly bind model to the view; but I feel I am missing your point, can you rephrase it please?

This is exactly what I mean. Now there is no cases where anybody defines special adapter for existing model. And you can't do it because then you will need modify global MorphicAdapterBindings to specify new morph class.
And my sentence was: if we now live with that then we can simplify design a lot by directly asking model for a view. It will be still platform independent because concrete backend will use specific message like createMorphicView or createCocoaView.
Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Denis Kudriashov
In reply to this post by Peter Uhnak

2017-04-28 12:26 GMT+02:00 Peter Uhnak <[hidden email]>:
> In fact they are not adapters. They are factories which creates backend
> views (morphs). And now there are completely no logic behind them: every
> adapter just passes state received from model to view instance.

This depends heavily on what the respective APIs provide.

In TabAdapter I connect SpecTab and MorphicTab directly, so it no longer lives during runtime.

In LabelAdapter the emphasis is being transcoded from symbol to random numbers (so this is not simple delegation)
In MenuItemAdapter you can see much more behavior.

All they do is asking model about set of options. For example menu adapter ask 
 self model autoRefresh ifTrue: ifFalse:
And this logic can be moved to model itself and represented by different model classes if necessary. (I talk about model as a presenter)
Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Denis Kudriashov
In reply to this post by Denis Kudriashov

2017-04-28 12:59 GMT+02:00 Denis Kudriashov <[hidden email]>:
2017-04-28 12:26 GMT+02:00 Peter Uhnak <[hidden email]>:
> backend specific like createMorphicView: and we need hierarchy of backends
> here which will choose appropriate message.

Which is exactly what we do not want, to directly bind model to the view; but I feel I am missing your point, can you rephrase it please?

This is exactly what I mean. Now there is no cases where anybody defines special adapter for existing model. And you can't do it because then you will need modify global MorphicAdapterBindings to specify new morph class.
And my sentence was: if we now live with that then we can simplify design a lot by directly asking model for a view. It will be still platform independent because concrete backend will use specific message like createMorphicView or createCocoaView.

And it is not too far from supporting multiple view. 
Imaging that we have ItemSelectionModel. It can be shown as comboBox, radio button group or list. In spec methods ( #defaultSpec) we can use logical name for views: #comboBoxView, #radioGroupView, #listView. Then spec interpreter will call this methods on current backend which will return view instances. MorphicBackend will return concrete morph instances. Then view will be passed to model for initialisation:

view := backend perform: spec viewName.
model showItemsOn: view.
view layoutWith: spec layout.

Example is of course simplistic but I hope it shows that we can model spec without extra adapter component.
Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Rob Rothwell
In reply to this post by Peter Uhnak
Hi Peter,

Thanks again for the advice. I've reduced my number of infinite loops and crashes by creating copies of pertinent classes and using them for testing, but I have quickly learned to save my image after inserting a halt anywhere!

The parallel Spec implementation conversation is interesting too, but unfortunately I don't understand enough to participate very much yet.

However, I have discovered by creating new ComposableModel, WindowModel, and MorphicWindowAdapter classes that even the SpecInterpreter itself is hard-wired to use Morphic.

If you take a look at 

WindowModel>>privateAdapterFromModel: aModel withSpec: aSpec
"apparently when looking at the implementation, it does not return a widget but an adapter so it should be called adapter :)"
self halt.
^ SpecInterpreter private_buildWidgetFor: self withSpec: aSpec.

You see from the correct comment that an adapter is created during this operation, which I think (I'm not that far yet) comes from 

SpecInterpreter class>>defaultBindings
^ MorphicAdapterBindings new

In other words, I think that regardless of WindowModel class>>adapterName (and presumably all other "Model" classes, the actual adapter used is at present determined by the SpecInterpreter via MorphicAdapterBindings>>initializeBindings.

You can set the bindings on the class side, but I currently don't see a way to say "open this spec using these bindings."  In other words, something like:

MyApplication new openWithSpecAndBindings: MorphicAdapterBindings.

or simply

MyApplication openAsMorphicSpec, MyApplication openAsCocoaSpec, etc...

It's starting to make some sense at a high level, though.  Eventually I'll find a spot where I can create a CocoaWindow and start figuring out the minimum interface requirements!

Take care,

Rob






On Fri, Apr 28, 2017 at 6:13 AM, Peter Uhnak <[hidden email]> wrote:
Hi Rob,

> I need to find a good starting point because you can't poke at the existing
> code too much since even the debugger is built with Spec!

I don't know what Pharo you are on, but this is not the case. Debugger itself is based on Glamour (there used to be SpecDebugger, but it is no longer used).

What is blowing up on you is the predebugger window, which is in Spec. You can disable this in your settings or by calling

GTGenericStackDebugger alwaysOpenFullDebugger: true

this will skip the debugger.

But keep in mind that other tools might be using spec too (like the Browser window that opens when you are listing senders/implementors.

overriding the #windowClass (or whatever the name was) is a good start.

(also FML because apparently I've deleted my image with my spec changes by accident -_-)

Peter

>
> It's pretty exciting, though, because it feels like all the right pieces
> are there and a lot of this could mostly be "just work" once I get going.
>
> Thanks again,
>
> Rob
>
> On Thu, Apr 27, 2017 at 6:04 PM, Peter Uhnak <[hidden email]> wrote:
>
> > Hi Rob,
> >
> > I guess the best resource at the moment is to just look at existing
> > adapters.
> >
> > But here are some thoughts to get you started:
> >
> > (Spec) ComposableModel has as its widget (Spec) Adapter
> > Adapter has as its widget the actual visual component, which currently
> > means Morphic.
> >
> >
> > The simplest example: LabelModel
> >
> > 1. model to adapter
> >
> > LabelModel is adapted by MorphicLabelAdapter:
> >
> > you can see on the class side in method `defaultSpec`.
> > There is only `LabelAdapter` there because there is some extra mapping for
> > some classes, but you can specify directly the class of the Adapter, so the
> > following would work just as well:
> >
> > LabelModel class>>defaultSpec
> >         <spec>
> >
> >         ^ #(MorphicLabelAdapter
> >                 adapt: #(model))
> >
> >
> > LabelModel -> LabelAdapter direct event propagation (pushing changes)
> >
> > in Model world you can call changed:with: to execute code on the Adapter,
> > e.g.
> >
> > self changed: #emphasis: with: {emphasis}
> >
> > which in turn will call the #emphasis: method on the LabelAdapter.
> >
> > LabelModel -> LabelAdapter events (pulling changes)
> >
> > preferred alternative is to do the opposite; properties of models are
> > often held in ValueHolders, which can be observed on ValueChange, so the
> > Adapter can register to event change and react on itself;
> >
> > you can see this best in MorphicTabAdapter (but you will see that
> > TabAdapter looks a bit different from the rest, because I was experimenting
> > with cleaning up Adapters...)
> >
> > 2. adapter to morphic
> >
> > Every adapter implements #buildWidget method that returns a Morphic Object.
> > Typically the adapter registers itself as the model of the adapter (so
> > adapter's model is Spec, and Morphic's model is the adapter). This depends
> > a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so
> > there's no buildWidget, and it is in #buildWidgetWith:).
> >
> > It is all kinds of messy, but if you have other widgets then it will be a
> > good test how well Spec can handle it... or rather we'll see how it can be
> > improved...
> >
> > Peter
> >
> >
> >
> > On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:
> > > Hello,
> > >
> > > I have recently been lucky enough to get the Cocoa portion of Mars
> > working
> > > on Pharo 5.0.  While there are some issues, it has a wonderful set of
> > > examples that allowed me create new Cocoa classes and delegate methods
> > and
> > > see a straightforward path to learning how to use Coco widgets from
> > Pharo.
> > >
> > > I'd like to do that by creating appropriate Spec adapters, but
> > > unfortunately the new Spec booklet wasn't designed for that!
> > >
> > > Can anyone give me any insight into creating (and using) a new Spec
> > > adapter?  Maybe just some high level steps to help me orient my
> > > investigation into how Spec works?
> > >
> > > Thank you,
> > >
> > > Rob
> >
> >


Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Ben Coman


On Sat, Apr 29, 2017 at 4:20 AM, Rob Rothwell <[hidden email]> wrote:
Hi Peter,

Thanks again for the advice. I've reduced my number of infinite loops and crashes by creating copies of pertinent classes and using them for testing, but I have quickly learned to save my image after inserting a halt anywhere!

Its a bit of a trick to learn to change the wheels on the car while its still driving, but also very useful.
Try using #haltOnce instead.

cheers -ben
 

The parallel Spec implementation conversation is interesting too, but unfortunately I don't understand enough to participate very much yet.

However, I have discovered by creating new ComposableModel, WindowModel, and MorphicWindowAdapter classes that even the SpecInterpreter itself is hard-wired to use Morphic.

If you take a look at 

WindowModel>>privateAdapterFromModel: aModel withSpec: aSpec
"apparently when looking at the implementation, it does not return a widget but an adapter so it should be called adapter :)"
self halt.
^ SpecInterpreter private_buildWidgetFor: self withSpec: aSpec.

You see from the correct comment that an adapter is created during this operation, which I think (I'm not that far yet) comes from 

SpecInterpreter class>>defaultBindings
^ MorphicAdapterBindings new

In other words, I think that regardless of WindowModel class>>adapterName (and presumably all other "Model" classes, the actual adapter used is at present determined by the SpecInterpreter via MorphicAdapterBindings>>initializeBindings.

You can set the bindings on the class side, but I currently don't see a way to say "open this spec using these bindings."  In other words, something like:

MyApplication new openWithSpecAndBindings: MorphicAdapterBindings.

or simply

MyApplication openAsMorphicSpec, MyApplication openAsCocoaSpec, etc...

It's starting to make some sense at a high level, though.  Eventually I'll find a spot where I can create a CocoaWindow and start figuring out the minimum interface requirements!

Take care,

Rob






On Fri, Apr 28, 2017 at 6:13 AM, Peter Uhnak <[hidden email]> wrote:
Hi Rob,

> I need to find a good starting point because you can't poke at the existing
> code too much since even the debugger is built with Spec!

I don't know what Pharo you are on, but this is not the case. Debugger itself is based on Glamour (there used to be SpecDebugger, but it is no longer used).

What is blowing up on you is the predebugger window, which is in Spec. You can disable this in your settings or by calling

GTGenericStackDebugger alwaysOpenFullDebugger: true

this will skip the debugger.

But keep in mind that other tools might be using spec too (like the Browser window that opens when you are listing senders/implementors.

overriding the #windowClass (or whatever the name was) is a good start.

(also FML because apparently I've deleted my image with my spec changes by accident -_-)

Peter

>
> It's pretty exciting, though, because it feels like all the right pieces
> are there and a lot of this could mostly be "just work" once I get going.
>
> Thanks again,
>
> Rob
>
> On Thu, Apr 27, 2017 at 6:04 PM, Peter Uhnak <[hidden email]> wrote:
>
> > Hi Rob,
> >
> > I guess the best resource at the moment is to just look at existing
> > adapters.
> >
> > But here are some thoughts to get you started:
> >
> > (Spec) ComposableModel has as its widget (Spec) Adapter
> > Adapter has as its widget the actual visual component, which currently
> > means Morphic.
> >
> >
> > The simplest example: LabelModel
> >
> > 1. model to adapter
> >
> > LabelModel is adapted by MorphicLabelAdapter:
> >
> > you can see on the class side in method `defaultSpec`.
> > There is only `LabelAdapter` there because there is some extra mapping for
> > some classes, but you can specify directly the class of the Adapter, so the
> > following would work just as well:
> >
> > LabelModel class>>defaultSpec
> >         <spec>
> >
> >         ^ #(MorphicLabelAdapter
> >                 adapt: #(model))
> >
> >
> > LabelModel -> LabelAdapter direct event propagation (pushing changes)
> >
> > in Model world you can call changed:with: to execute code on the Adapter,
> > e.g.
> >
> > self changed: #emphasis: with: {emphasis}
> >
> > which in turn will call the #emphasis: method on the LabelAdapter.
> >
> > LabelModel -> LabelAdapter events (pulling changes)
> >
> > preferred alternative is to do the opposite; properties of models are
> > often held in ValueHolders, which can be observed on ValueChange, so the
> > Adapter can register to event change and react on itself;
> >
> > you can see this best in MorphicTabAdapter (but you will see that
> > TabAdapter looks a bit different from the rest, because I was experimenting
> > with cleaning up Adapters...)
> >
> > 2. adapter to morphic
> >
> > Every adapter implements #buildWidget method that returns a Morphic Object.
> > Typically the adapter registers itself as the model of the adapter (so
> > adapter's model is Spec, and Morphic's model is the adapter). This depends
> > a lot on the API of morphic. (in TabAdapter I'm overriding adapt: so
> > there's no buildWidget, and it is in #buildWidgetWith:).
> >
> > It is all kinds of messy, but if you have other widgets then it will be a
> > good test how well Spec can handle it... or rather we'll see how it can be
> > improved...
> >
> > Peter
> >
> >
> >
> > On Thu, Apr 27, 2017 at 05:10:39PM -0400, Rob Rothwell wrote:
> > > Hello,
> > >
> > > I have recently been lucky enough to get the Cocoa portion of Mars
> > working
> > > on Pharo 5.0.  While there are some issues, it has a wonderful set of
> > > examples that allowed me create new Cocoa classes and delegate methods
> > and
> > > see a straightforward path to learning how to use Coco widgets from
> > Pharo.
> > >
> > > I'd like to do that by creating appropriate Spec adapters, but
> > > unfortunately the new Spec booklet wasn't designed for that!
> > >
> > > Can anyone give me any insight into creating (and using) a new Spec
> > > adapter?  Maybe just some high level steps to help me orient my
> > > investigation into how Spec works?
> > >
> > > Thank you,
> > >
> > > Rob
> >
> >



Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Peter Uhnak
In reply to this post by Rob Rothwell
On Fri, Apr 28, 2017 at 04:20:57PM -0400, Rob Rothwell wrote:
> Hi Peter,
>
> However, I have discovered by creating new ComposableModel, WindowModel,
> and MorphicWindowAdapter classes that even the SpecInterpreter itself is
> hard-wired to use Morphic.

No, it is not. It has hard wired bindings from certain names to morphic adapters, but only if you don't actually specify the target calss.
In other words, if in your #specLayout you specify a name that has a binding, then the binding will be used; if there is no such binding, then the class will be instantiated directly.

So for example if you specify:
* LabelAdapter -> there is binding from LabelAdapter to MorphicLabelAdapter, so MorphicLabelAdapter will be instantiated
* MorphicLabelAdapter -> there are no bindings for this name, so it will be instantiated directly
* CocoaLabelAdapter -> there are no bindings for this name, so it will be instantiated directly

>
> If you take a look at
>
> WindowModel>>privateAdapterFromModel: aModel withSpec: aSpec
> "apparently when looking at the implementation, it does not return a widget
> but an adapter so it should be called adapter :)"
> self halt.
> ^ SpecInterpreter private_buildWidgetFor: self withSpec: aSpec.
>
> You see from the correct comment that an adapter is created during this
> operation, which I think (I'm not that far yet) comes from

This comment just adds more confusion to people that don't understand what is going on. From Spec perspective widget is the same as adapter (so the name is just fine), and during SpecInterpreter execution both adapter and the final widgets are created. The naming is not wrong, but the same word (widget) means different things in different contexts, so it is confusing.

>
> SpecInterpreter class>>defaultBindings
> ^ MorphicAdapterBindings new
>
> In other words, I think that regardless of WindowModel class>>adapterName
> (and presumably all other "Model" classes, the actual adapter used is at
> present determined by the SpecInterpreter via
> MorphicAdapterBindings>>initializeBindings.

You should go re-read my original answer where I explained how you can do exactly that...

>
> You can set the bindings on the class side, but I currently don't see a way
> to say "open this spec using these bindings."  In other words, something
> like:
>
> MyApplication new openWithSpecAndBindings: MorphicAdapterBindings.

#openWithSpecLayout:
#buildWithSpecLayout:
and in layout #add:withSpec:

See the spec booklet section 4.3. where you can see how #add:withSpec: can be used (I've also mentioned this in one of the previous comments)

Peter

Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Denis Kudriashov
Hi

2017-04-29 20:36 GMT+02:00 Peter Uhnak <[hidden email]>:
No, it is not. It has hard wired bindings from certain names to morphic adapters, but only if you don't actually specify the target calss.
In other words, if in your #specLayout you specify a name that has a binding, then the binding will be used; if there is no such binding, then the class will be instantiated directly.

So for example if you specify:
* LabelAdapter -> there is binding from LabelAdapter to MorphicLabelAdapter, so MorphicLabelAdapter will be instantiated
* MorphicLabelAdapter -> there are no bindings for this name, so it will be instantiated directly
* CocoaLabelAdapter -> there are no bindings for this name, so it will be instantiated directly

But we should not reference directly platform specific widgets when we define spec layout. Otherwise we will be forced to copy every layout method (like #defaultSpec) for each platform.
And it breaks goal of Spec to be able open application with different backends without code modification.

I am sure you know what I wrote. So probably I not understand what you mean.
Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Denis Kudriashov
In reply to this post by Peter Uhnak

2017-04-29 20:36 GMT+02:00 Peter Uhnak <[hidden email]>:
>
> You can set the bindings on the class side, but I currently don't see a way
> to say "open this spec using these bindings."  In other words, something
> like:
>
> MyApplication new openWithSpecAndBindings: MorphicAdapterBindings.

#openWithSpecLayout:
#buildWithSpecLayout:
and in layout #add:withSpec:

How it will allow open MessageBrowser (based on Spec) on cocoa backend?

Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Peter Uhnak
In reply to this post by Denis Kudriashov
On Sat, Apr 29, 2017 at 09:22:46PM +0200, Denis Kudriashov wrote:

> Hi
>
> 2017-04-29 20:36 GMT+02:00 Peter Uhnak <[hidden email]>:
>
> > No, it is not. It has hard wired bindings from certain names to morphic
> > adapters, but only if you don't actually specify the target calss.
> > In other words, if in your #specLayout you specify a name that has a
> > binding, then the binding will be used; if there is no such binding, then
> > the class will be instantiated directly.
> >
> > So for example if you specify:
> > * LabelAdapter -> there is binding from LabelAdapter to
> > MorphicLabelAdapter, so MorphicLabelAdapter will be instantiated
> > * MorphicLabelAdapter -> there are no bindings for this name, so it will
> > be instantiated directly
> > * CocoaLabelAdapter -> there are no bindings for this name, so it will be
> > instantiated directly
> >
>
> But we should not reference directly platform specific widgets when we
> define spec layout. Otherwise we will be forced to copy every layout method
> (like #defaultSpec) for each platform.
> And it breaks goal of Spec to be able open application with different
> backends without code modification.
>
> I am sure you know what I wrote. So probably I not understand what you mean.

I was describing how it is possible to do it _now_, not how it ideally should be done (because there's no other way right now)... we will change this, because we will also need a better way for Bloc.

So Pharo7 again :)

Peter

Reply | Threaded
Open this post in threaded view
|

Re: Spec Adapter Advice

Peter Uhnak
In reply to this post by Denis Kudriashov
On Sat, Apr 29, 2017 at 09:24:28PM +0200, Denis Kudriashov wrote:

> 2017-04-29 20:36 GMT+02:00 Peter Uhnak <[hidden email]>:
>
> > >
> > > You can set the bindings on the class side, but I currently don't see a
> > way
> > > to say "open this spec using these bindings."  In other words, something
> > > like:
> > >
> > > MyApplication new openWithSpecAndBindings: MorphicAdapterBindings.
> >
> > #openWithSpecLayout:
> > #buildWithSpecLayout:
> > and in layout #add:withSpec:
>
>
> How it will allow open MessageBrowser (based on Spec) on cocoa backend?

You would need to add cocoa-based layout for every model in the chain and then cross-reference them via #add:withSpec:, annoying, but should be possible.

Peter