[ANN]: Little NeoJSON Helper

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

[ANN]: Little NeoJSON Helper

Sean P. DeNigris
Administrator
"Assuming Neo-JSON-Core is loaded"
Gofer it
        smalltalkhubUser: 'SeanDeNigris' project: 'SeansPlayground';
        package: 'Neo-JSON-Utilities';
        load.

To aid in writing mappings, send "reader mapHelperFor: MyDomainClass", where MyDomainClass need not even exist. This will halt inside the mapping, and bring up an inspector on a NeoJSONMapHelper object.

From here, you can #generateInstVars to map the json keys to inst vars, translating underscores to camel case.

Then you can inspect #mappingSnippet, which will give you the code to replace "reader mapHelperFor: MyDomainClass" with the new mappings to inst vars. For example:
        mapper for: DoDropletSize do: [ :m |
                m
                        mapInstVars: #(name cpu slug memory id disk);
                        mapInstVar: #costPerHour to: #cost_per_hour;
                        mapInstVar: #costPerMonth to: #cost_per_month ].

It could be enhanced, especially with a UI to further customize the mappings (e.g. maybe you want to map the boolean "required" key to a more Smalltalkish "isRequired" inst var, but it makes the common cases a bit easier.

HTH :)
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sean P. DeNigris
Administrator
Sean P. DeNigris wrote
"Assuming Neo-JSON-Core is loaded"
To aid in writing mappings, send "reader mapHelperFor: MyDomainClass"
I improved the API a bit. Now, the mapping is done via class-side #addNeoJsonMapTo: aNeoJSONReader.
The default (defined in class) brings up the helper. So now you can write:
    MyClass addNeoJsonMapTo: aNeoJSONReader.

The first time you do this, you will get an inspector on the helper object, which you still send #generateInstVars.

But for the second step, you now send #generateMapping, which compiles MyClass class>>#addNeoJsonMapTo: with the necessary mapping.

If you're mapping a collection, you probably have to close the halt debugger now and restart, because the default behavior of inspecting the helper is cached in the reader. Otherwise, you can proceed and map the next class.

I like the class side methods because they decompose monolithic mapping declarations and can be reused.
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sean P. DeNigris
Administrator
Sean P. DeNigris wrote
I improved the API a bit. Now, the mapping is done via class-side #addNeoJsonMapTo: aNeoJSONReader.
Of course, if I had RTFM (more thoroughly), I would've noticed that Sven already implemented that ;) So the hook is simply a default Class>>#neoJsonMapping: which brings up the helper if no class-side mapping is defined.
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sean P. DeNigris
Administrator
In reply to this post by Sean P. DeNigris
Okay, here is version 0.1 - the most basic useful functionality to aid in writing mappings.

"Assuming Neo-JSON-Core is loaded"
Gofer it
        smalltalkhubUser: 'SeanDeNigris' project: 'SeansPlayground';
        package: 'Neo-JSON-Utilities';
        load.

Now if you:
        reader := NeoJSONReader on: entity contents readStream.
        reader nextAs: MyClass "(that does not implement MyClass class>>#neoJsonMapping:)".

You will get a debugger (which you probably want to close because the new mappings we create will not be activated as the helper hook is cached in the mappings) and a tree inspector on a NeoJSON model that you can customize, where:
- a NeoJSONObject represents each JSON dictionary; for the enclosing object, the schema is already set to MyClass (i.e. the argument to #nextAs:)
- a NeoJSONList represents each JSON list
- a NeoJSONValue represents all other values e.g. bools, nil, strings, numbers

Some useful things to do:
- For each NeoJSONObject that you want to map to a class, select it in the explorer and:
  self schema: MyOtherClass.
  self generateInstVars. "self explanatory?"
  self mappingSourceCode inspect. "see the neoJsonMapping: source that would be generated"
  self generateMapping. "compile class-side neoJsonMapping:"
- Select any field inside a NeoJSONObject that you want to map to an inst var with a different name and:
  self instVarName: #isSaved "(e.g. to map JSON fields_with_underscores to camelCase var names)"
- Specify the element type of a list by selecting it and:
  self elementSchema: MyListReturnType. "This will automatically set the schema to #ArrayOfMyListReturnType, but you can change that manually if you want by sending #schema:)

After customizing, sending #generateMapping to a NeoJSONObject should generate something like:
    neoJsonMapping: mapper
        mapper for: self do: [ :mapping |
                mapping mapInstVars: #(notes id).
                (mapping mapInstVar: #day) valueSchema: Date.
                (mapping mapInstVar: #events) valueSchema: #ArrayOfMyEvent.
                mapping mapInstVar: #isSaved to: #is_saved.
                (mapping mapInstVar: #timeSaved) valueSchema: DateAndTime ].

        mapper for: Date customDo: [ :mapping | ]. "now you specify how to convert the string to a Date"
        mapper for: #ArrayOfMyEvent customDo: [ :mapping |
                mapping listOfElementSchema: MyEvent ].
        mapper for: DateAndTime customDo: [ :mapping | ]. "same as Date above"

This started as a tiny little personal experiment that got away from me, ha ha, so there is no UI, tests, or doc (except for this post). MIT of course. Enjoy!
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

stepharo
sean

May be we can add that to the JSOn chapter.
Are you interested?

Stef

On 30/4/14 16:28, Sean P. DeNigris wrote:

> Okay, here is version 0.1 - the most basic useful functionality to aid in
> writing mappings.
>
> "Assuming Neo-JSON-Core is loaded"
> Gofer it
> smalltalkhubUser: 'SeanDeNigris' project: 'SeansPlayground';
> package: 'Neo-JSON-Utilities';
> load.
>
> Now if you:
> reader := NeoJSONReader on: entity contents readStream.
> reader nextAs: MyClass "(that does not implement MyClass
> class>>#neoJsonMapping:)".
>
> You will get a debugger (which you probably want to close because the new
> mappings we create will not be activated as the helper hook is cached in the
> mappings) and a tree inspector on a NeoJSON model that you can customize,
> where:
> - a NeoJSONObject represents each JSON dictionary; for the enclosing object,
> the schema is already set to MyClass (i.e. the argument to #nextAs:)
> - a NeoJSONList represents each JSON list
> - a NeoJSONValue represents all other values e.g. bools, nil, strings,
> numbers
>
> Some useful things to do:
> - For each NeoJSONObject that you want to map to a class, select it in the
> explorer and:
>    self schema: MyOtherClass.
>    self generateInstVars. "self explanatory?"
>    self mappingSourceCode inspect. "see the neoJsonMapping: source that would
> be generated"
>    self generateMapping. "compile class-side neoJsonMapping:"
> - Select any field inside a NeoJSONObject that you want to map to an inst
> var with a different name and:
>    self instVarName: #isSaved "(e.g. to map JSON fields_with_underscores to
> camelCase var names)"
> - Specify the element type of a list by selecting it and:
>    self elementSchema: MyListReturnType. "This will automatically set the
> schema to #ArrayOfMyListReturnType, but you can change that manually if you
> want by sending #schema:)
>
> After customizing, sending #generateMapping to a NeoJSONObject should
> generate something like:
>      neoJsonMapping: mapper
> mapper for: self do: [ :mapping |
> mapping mapInstVars: #(notes id).
> (mapping mapInstVar: #day) valueSchema: Date.
> (mapping mapInstVar: #events) valueSchema: #ArrayOfMyEvent.
> mapping mapInstVar: #isSaved to: #is_saved.
> (mapping mapInstVar: #timeSaved) valueSchema: DateAndTime ].
>
> mapper for: Date customDo: [ :mapping | ]. "now you specify how to convert
> the string to a Date"
> mapper for: #ArrayOfMyEvent customDo: [ :mapping |
> mapping listOfElementSchema: MyEvent ].
> mapper for: DateAndTime customDo: [ :mapping | ]. "same as Date above"
>
> This started as a tiny little personal experiment that got away from me, ha
> ha, so there is no UI, tests, or doc (except for this post). MIT of course.
> Enjoy!
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sean P. DeNigris
Administrator
I'd like for Sven to take a look and see if it's generally useful and well-designed, but sure...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sven Van Caekenberghe-2
It is on my list ...

On 01 May 2014, at 20:03, Sean P. DeNigris <[hidden email]> wrote:

> I'd like for Sven to take a look and see if it's generally useful and
> well-designed, but sure...
>
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/ANN-Little-NeoJSON-Helper-tp4756763p4757481.html
> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sven Van Caekenberghe-2
Hi Sean,

This has been on my list for quite some time, sorry about that - the problem was also that I do/did not really have a good opinion about this, see further.

On one hand, I am really happy that you produced this hack (in the good definition of the word: a neat trick to solve a problem). I am impressed by it, you mix what is available in NeoJSON with the dynamic abilities in Pharo to do something cool (much like coding in the debugger, or using available input to dynamically derive a mapping). You clearly got deep into it (carried away you said yourself) and you do understand NeoJSON very well.

But on the other hand, it took me quite some time, browsing your code intensively, reading your mail again and again, to even understand what you did, how it (could) work(s), the goals, the limitations - and I wrote NeoJSON. So the problem is, IMHO, that we cannot expect this to be explainable/understandable to others. This could maybe be fixed by writing more code, maybe some kind of GUI tool, more documentation - but then the question is, is it worth it ? does this really solve a common problem ?

It feels like an extension/add-on to me, not something to be part of the core of NeoJSON.

I just don't know, what do you think about it in retrospect ?

Sven

On 01 May 2014, at 20:26, Sven Van Caekenberghe <[hidden email]> wrote:

> It is on my list ...
>
> On 01 May 2014, at 20:03, Sean P. DeNigris <[hidden email]> wrote:
>
>> I'd like for Sven to take a look and see if it's generally useful and
>> well-designed, but sure...
>>
>>
>>
>> -----
>> Cheers,
>> Sean
>> --
>> View this message in context: http://forum.world.st/ANN-Little-NeoJSON-Helper-tp4756763p4757481.html
>> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>>
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sean P. DeNigris
Administrator
Sven Van Caekenberghe-2 wrote
I just don't know, what do you think about it in retrospect ?
Thanks for taking a look! I don't know either :)
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: [ANN]: Little NeoJSON Helper

Sven Van Caekenberghe-2
Let's classify it as a brilliant, advanced hack then ;-)
 
On 01 Jul 2014, at 03:54, Sean P. DeNigris <[hidden email]> wrote:

> Sven Van Caekenberghe-2 wrote
>> I just don't know, what do you think about it in retrospect ?
>
> Thanks for taking a look! I don't know either :)
>
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/ANN-Little-NeoJSON-Helper-tp4756763p4765873.html
> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>