Hi,
I'm trying to wrap my head around Magritte but I am failing hard... Imagine I have object with three attributes. ~~~~~~~~~~~~~~~~~~~ Object subclass: #Person instanceVariableNames: 'name age email' ~~~~~~~~~~~~~~~~~~~ Now the normal way would be to add magritte descriptions... ~~~~~~~~~~~~~~~~~~~ Person>>descriptionEmail <magritteDescription> ^ MAStringDescription new label: 'Email'; accessor: #email; beRequired; yourself ~~~~~~~~~~~~~~~~~~~ etc for the rest... And now if I want to manipulate it I would do... ~~~~~~~~~~~~~~~~~~~ |p| p := Person new name: 'Someone'; email: '[hidden email]'; age: 20. p asMagritteMorph addButtons; openInWindow. ~~~~~~~~~~~~~~~~~~~ So far so simple... however what I don't understand: 1. What if I want to have different descriptions for the same attribute? For example in some views the email is required and in others it is not. 2. Must the description be part of the object? Maybe I am still not fully committed to the having massive protocols with tons of extension methods instead of externalizing the code to separate adapters and whatnot. 3. What if I want only partial rendering? For example in one view I want to be able to edit only name and age, and in another one all three. Since #asMagritteMorph collects everything I don't see how I can customize this. Now I do expect that all these things are possible, however as I'm just starting with Magritte it's a lot of information and concepts to absorb... so any help is appreciated. Also, is there maintained Magritte-Spec? I've seen something by Sean, but it's from 2013 with a single-ish commit. Thanks, Peter |
On 21-09-15 02:46, Peter Uhnák wrote:
> So far so simple... however what I don't understand: > > 1. What if I want to have different descriptions for the same attribute? > For example in some views the email is required and in others it is not. asMagritteMorph is just the quick and dirty variant for straightforward situations. > 2. Must the description be part of the object? Yes. Single responsibility principle applied. > Maybe I am still not fully committed to the having massive protocols > with tons of extension methods instead of externalizing the code to > separate adapters and whatnot. Ahum, that is exactly what Magritte does, while reusing the smalltalk tools. For very large domain models (more than several hundred domain classes), you'll be able to do better using a dynamic object model, and then you'll have to develop browsers, editors and inspectors for that. > 3. What if I want only partial rendering? > For example in one view I want to be able to edit only name and age, > and in another one all three. > Since #asMagritteMorph collects everything I don't see how I can customize this. asMagritteMorph provides the default. On Object it is defined as Object>>asMagritteMorph self magritteDescription asMorphOn: self Object>>magritteDescription ^ self basicMagritteDescription Object>>basicMagritteDescription ^ MAPragmaBuilder for: self which collects all descriptions and puts them in the container described by Object>descriptionContainer "Return the default description container." <magritteContainer> ^ MAPriorityContainer new label: self class label; yourself. The nice thing about a MA(Priority)Container is that it supports a large part of the collection protocol, so you can just do Person>>asNameMagritteMorph ^(self magritteDescription select: [:each | each label = 'Name']) asMorphOn: self So you'd define all possible descriptions you want on the domain object itself, possibly using extension methods, and override #asMagritteMorph to only return the default descriptions. For complex dependencies with extensions, use a smarter MAPragmaBuilder subclass that makes decisions based on which extensions are loaded. You also want to take a look at reference. In the Seaside generation that is used like MAInternalEditorComponent>>buildComponent ^ self value isNil ifFalse: [ (self magritteDescription reference asComponentOn: self value) setParent: self; yourself ] so that provides an extension point for nested objects. I don't see it used in Magritte-Morph > Also, is there maintained Magritte-Spec? I've seen something by Sean, > but it's from 2013 with a single-ish commit. I don't know if it needs more. Nothing changed in the spec interface since then, did there? Stephan |
Thank you Stephan, I think the image is becoming much clearer.
However I still don't understand how SRP applies here: > Person>>asNameMagritteMorph > ^(self magritteDescription select: [:each | each label = 'Name']) > asMorphOn: self Surely this is responsibility of the tool that needs it, no? Otherwise the Person class would have to describe every single possible scenario. Or maybe the tool would puts this into an extension protocol, which while visually places the code to Person class is actually separated (because it's part of another repository). > >> Also, is there maintained Magritte-Spec? I've seen something by Sean, >> but it's from 2013 with a single-ish commit. > > > I don't know if it needs more. Nothing changed in the spec interface since > then, did there? The Magritte-Spec seems to be just an experiment (with three classes) and it breaks Magritte-Morphic. Also I know I have changed Spec interface in the last year alone and as far as I can tell there was a lot work done in before. In any case I can always use asMagritteMorph morph asSpecAdapter in the meantime and maybe stitch together a Spec version once I am comfortable with Magritte. Thanks! Peter |
On 21-09-15 12:09, Peter Uhnák wrote:
> Thank you Stephan, I think the image is becoming much clearer. > > However I still don't understand how SRP applies here: > >> Person>>asNameMagritteMorph >> ^(self magritteDescription select: [:each | each label = 'Name']) >> asMorphOn: self > > Surely this is responsibility of the tool that needs it, no? No. It is a domain model. The person class is an information holder/structurer (Object Design, Roles, Responsibilities, and Collaborations), describing all possible uses, the user selects the one it needs. If the morph you need depends on the context in which it is shown, you might want to add a Person>>asMagritteMorphFrom: aDomainContext ^(aDomainContext magritteDescriptionFor: self magritteDescription) asMorphOn: self and do the selection on the other side > Otherwise the Person class would have to describe every single > possible scenario. Not the scenario, but the possible combinations yes. > Or maybe the tool would puts this into an extension protocol, which > while visually places the code to Person class is actually separated > (because it's part of another repository). For optional parts that works well, especially using MAObject subclasses with the dictionary based properties. > In any case I can always use asMagritteMorph morph asSpecAdapter in > the meantime and maybe stitch together a Spec version once I am > comfortable with Magritte. That sounds like the right order. |
In reply to this post by Peter Uhnak
Peter Uhnák <[hidden email]> writes: > ~~~~~~~~~~~~~~~~~~~ > Person>>descriptionEmail > <magritteDescription> > ^ MAStringDescription new > label: 'Email'; > accessor: #email; > beRequired; > yourself > ~~~~~~~~~~~~~~~~~~~ to complement Stephan's answer, you can add properties to your description that you use to filter them when building the morphs. For example: Person>>descriptionEmail <magritteDescription> ^ MAStringDescription new label: 'Email'; accessor: #email; beRequired; shouldBeShownInTheBasicView: true; yourself Then, when building the morph, you can #select: on 'shouldBeShownInTheBasicView' value. -- Damien Cassou http://damiencassou.seasidehosting.st "Success is the ability to go from one failure to another without losing enthusiasm." --Winston Churchill |
Free forum by Nabble | Edit this page |