How to write out simple Json?
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like: { 'id'-> self id. 'name' -> self name } gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦. But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ } I thought it was simple to do this? Am I missing something obvious. Tim
STONJSON toString: { #id->1. #name->'tim' } asDictionary. JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it? E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â ) ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }. String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ]. I had thought maybe NeoJSON might help and put: String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ]. But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" }, So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string? Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like: Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3). And I guess at:is: can do the Association asDictionary thing? But I thought Neo might give me something like that, as it must be terribly common? Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config. ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself. String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ]. So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <tim@testit.works> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
As I merrily chat to myself - I noticed that STONWriter almost does what I need - it just complains in #writeAssociation: so I make a subclass STONJSONWriter and override: writeAssociation: association âdonât smack meâ¦. jsonMode ifTrue: [ self error: 'wrong object class for JSON mode' ]." self encodeKey: association key value: association value I get exactly what I would expect - valid Json from simple Collections, Associations and Array. So would it be handy to have such a writer in the image (or let STONWriter be more configurable for this?) Tim p.s. my finally example would then be: ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }. String streamContents: [ :stream | (STONJSONWriter on: (stream)) jsonMode: true; prettyPrint: true; writeList: ex ].
On 28 Feb 2019, at 13:45, Tim Mackinnon <tim@testit.works> wrote:
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config.
ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself.
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ].
So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <tim@testit.works> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
This is wrong !! Think about it, what would then happen with a mixed list ? { #key->#value. 1. true } That would generate invalid JSON.
On 28 Feb 2019, at 14:56, Tim Mackinnon <tim@testit.works> wrote:
As I merrily chat to myself - I noticed that STONWriter almost does what I need - it just complains in #writeAssociation: so I make a subclass STONJSONWriter and override:
writeAssociation: association âdonât smack meâ¦. jsonMode ifTrue: [ self error: 'wrong object class for JSON mode' ]." self encodeKey: association key value: association value
I get exactly what I would expect - valid Json from simple Collections, Associations and Array.
So would it be handy to have such a writer in the image (or let STONWriter be more configurable for this?)
Tim
p.s. my finally example would then be:
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONJSONWriter on: (stream)) jsonMode: true; prettyPrint: true; writeList: ex ].
On 28 Feb 2019, at 13:45, Tim Mackinnon <tim@testit.works> wrote:
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config.
ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself.
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ].
So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <tim@testit.works> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
Sven- thinking a bit more
On 28 Feb 2019, at 13:59, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
This is wrong !!
Think about it, what would then happen with a mixed list ?
{ #key->#value. 1. true }
That would generate invalid JSON.
I actually went and tried my little hack with your example and it gives the same error as STONWriter - so actually my proposal isnât so horrid as inferred⦠(but still not as knowledgable as everyone else on this for sure). As a reminder - I wanted a compact way to express the following (sort of like you would expect in Javascript) - ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> { 'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }. String streamContents: [ :stream | (STONJSONWriter on: stream) jsonMode: true; prettyPrint: true; nextPut: ex ]. My pragmatic changes were 2 methods as follows - writeAssociation: association self encodeKey: association key value: association value writeObject: anObject do: block jsonMode ifTrue: [ (anObject isKindOf: OrderedCollection) âso you donât have to asArray everywhere" ifTrue: [ ^self writeList: anObject ]. (anObject isKindOf: OrderedDictionary) âso you can output { } for libs that need it - does require asOrderedDictionary" ifTrue: [ ^self writeMap: anObject ]]. super writeObject: anObject do: block (And if you assume your using json - a class method on: writeStream ^ (super on: writeStream) jsonMode: true; prettyPrint: true; yourself
On 28 Feb 2019, at 22:35, Tim Mackinnon <tim@testit.works> wrote:
Sven- thinking a bit more
On 28 Feb 2019, at 13:59, Sven Van Caekenberghe <sven@stfx.eu> wrote:
This is wrong !!
Think about it, what would then happen with a mixed list ?
{ #key->#value. 1. true }
That would generate invalid JSON.
I actually went and tried my little hack with your example and it gives the same error as STONWriter - so actually my proposal isnât so horrid as inferred⦠(but still not as knowledgable as everyone else on this for sure).
Forget about the way you are trying to implement it, to what would { #key->#value. 1. true } be rendered in JSON ? { "key":"value", 1, true } or [ "key":"value", 1, true ] Both are illegal JSON.
On 1 Mar 2019, at 10:35, Sven Van Caekenberghe <sven@stfx.eu> wrote:
Forget about the way you are trying to implement it, to what would
{ #key->#value. 1. true }
be rendered in JSON ?
{ "key":"value", 1, true }
or
[ "key":"value", 1, true ]
Both are illegal JSON.
You didnât read what I said - with those 2 tiny changes - both of those given an exception just like STONJSON - the only difference is that I donât have to put asDictionary everywhere. Anyway - I think Iâve learned a lot from this discussion - and as Pharo is malleable I can do my little nasty subclass until I get burned and then I will probably adopt a proper Config object like Henrik mentioned ;) Just as a small additional question - when you do : ex := { #track->#pharo. #language->#smalltalk. #exercises->{ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } asDictionary } asDictionary. Am I right in thinking that with asDictionary the order wonât be deterministic (which is valid for JSON dictionaries, but annoying for diffing config files). This is why I was doing asOrderedDictionary as I though I had seen it change on me a few times when I was generating output. Tim
On 1 Mar 2019, at 12:32, Tim Mackinnon <tim@testit.works> wrote:
On 1 Mar 2019, at 10:35, Sven Van Caekenberghe <sven@stfx.eu> wrote:
Forget about the way you are trying to implement it, to what would
{ #key->#value. 1. true }
be rendered in JSON ?
{ "key":"value", 1, true }
or
[ "key":"value", 1, true ]
Both are illegal JSON.
You didnât read what I said - with those 2 tiny changes - both of those given an exception just like STONJSON - the only difference is that I donât have to put asDictionary everywhere.
Anyway - I think Iâve learned a lot from this discussion - and as Pharo is malleable I can do my little nasty subclass until I get burned and then I will probably adopt a proper Config object like Henrik mentioned ;)
Yes you can !
Just as a small additional question - when you do :
ex := { #track->#pharo. #language->#smalltalk. #exercises->{ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } asDictionary } asDictionary.
Am I right in thinking that with asDictionary the order wonât be deterministic (which is valid for JSON dictionaries, but annoying for diffing config files). This is why I was doing asOrderedDictionary as I though I had seen it change on me a few times when I was generating output.
Right, #asDictionary or #asOrderedDictionary both work, it is up to you. But, like you said, there is no order in JSON, although it can help in diffing.
Tim
What's missing is a "map" syntax. :) #{ 'track' -> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> #{ 'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } } The #{ } would be a mix of the existing { } construct, but somehow enforcing that elements return "association like" (#key and #value) and sends #asDictionary to the resulting collection. I cannot think of anything shorter than that except for what I use and was already suggested: ex := { #track->#pharo. #language->#smalltalk. #exercises->{ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } asDictionary } asDictionary. Regards, Esteban A. Maringolo El vie., 1 mar. 2019 a las 9:08, Sven Van Caekenberghe (<sven@stfx.eu>) escribió:
On 1 Mar 2019, at 12:32, Tim Mackinnon <tim@testit.works> wrote:
On 1 Mar 2019, at 10:35, Sven Van Caekenberghe <sven@stfx.eu> wrote:
Forget about the way you are trying to implement it, to what would
{ #key->#value. 1. true }
be rendered in JSON ?
{ "key":"value", 1, true }
or
[ "key":"value", 1, true ]
Both are illegal JSON.
You didnât read what I said - with those 2 tiny changes - both of those given an exception just like STONJSON - the only difference is that I donât have to put asDictionary everywhere.
Anyway - I think Iâve learned a lot from this discussion - and as Pharo is malleable I can do my little nasty subclass until I get burned and then I will probably adopt a proper Config object like Henrik mentioned ;)
Yes you can !
Just as a small additional question - when you do :
ex := { #track->#pharo. #language->#smalltalk. #exercises->{ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } asDictionary } asDictionary.
Am I right in thinking that with asDictionary the order wonât be deterministic (which is valid for JSON dictionaries, but annoying for diffing config files). This is why I was doing asOrderedDictionary as I though I had seen it change on me a few times when I was generating output.
Right, #asDictionary or #asOrderedDictionary both work, it is up to you.
But, like you said, there is no order in JSON, although it can help in diffing.
Tim
Of you load the JSON package from Squeaksource (http://www.squeaksource.com/JSON.html) You can do a JSON render: { 'track' -> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> { 'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } } and get a Json string or add e.g. Object>>#asJsonString ^JSON render: self Tim Mackinnon wrote
On 1 Mar 2019, at 10:35, Sven Van Caekenberghe <
sven@
> wrote:
Forget about the way you are trying to implement it, to what would
{ #key->#value. 1. true }
be rendered in JSON ?
{ "key":"value", 1, true }
or
[ "key":"value", 1, true ]
Both are illegal JSON.
You didnât read what I said - with those 2 tiny changes - both of those given an exception just like STONJSON - the only difference is that I donât have to put asDictionary everywhere.
Anyway - I think Iâve learned a lot from this discussion - and as Pharo is malleable I can do my little nasty subclass until I get burned and then I will probably adopt a proper Config object like Henrik mentioned ;)
Just as a small additional question - when you do :
ex := { #track->#pharo. #language->#smalltalk. #exercises->{ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } asDictionary } asDictionary.
Am I right in thinking that with asDictionary the order wonât be deterministic (which is valid for JSON dictionaries, but annoying for diffing config files). This is why I was doing asOrderedDictionary as I though I had seen it change on me a few times when I was generating output.
Tim
-- Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
Come on, no it does not. It generates invalid JSON (as it should, but doing so silently is wrong). Json render: { 'track' -> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> { 'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }. => '["track": "pharo","language": "smalltalk","exercises": ["slug": "hello","id": 55,"topics": ["a","b","c"]]]' You see this is wrong, do you ? BTW, the package you mentioned did not load in Pharo, it can if you make the following change: Json class>>#initialise "Json initialize." escapeArray := Array new: 128. (0 to: 31), #(127) do: [ :each | escapeArray at: each + 1 put: '\u', (each printStringHex padLeftTo: 4 with: $0) ]. { $" -> '\"'. $\ -> '\\'. Character backspace -> '\b'. Character lf -> '\n'. Character newPage -> '\f'. Character cr -> '\r'. Character tab -> '\t'. } do: [ :each | escapeArray at: each key asciiValue + 1 put: each value ].
On 2 Mar 2019, at 06:37, Paul DeBruicker <pdebruic@gmail.com> wrote:
Of you load the JSON package from Squeaksource (http://www.squeaksource.com/JSON.html)
You can do a
JSON render: { 'track' -> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> { 'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }
and get a Json string or add e.g.
Object>>#asJsonString ^JSON render: self
Tim Mackinnon wrote
On 1 Mar 2019, at 10:35, Sven Van Caekenberghe <
sven@
> wrote:
Forget about the way you are trying to implement it, to what would
{ #key->#value. 1. true }
be rendered in JSON ?
{ "key":"value", 1, true }
or
[ "key":"value", 1, true ]
Both are illegal JSON.
You didnât read what I said - with those 2 tiny changes - both of those given an exception just like STONJSON - the only difference is that I donât have to put asDictionary everywhere.
Anyway - I think Iâve learned a lot from this discussion - and as Pharo is malleable I can do my little nasty subclass until I get burned and then I will probably adopt a proper Config object like Henrik mentioned ;)
Just as a small additional question - when you do :
ex := { #track->#pharo. #language->#smalltalk. #exercises->{ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } asDictionary } asDictionary.
Am I right in thinking that with asDictionary the order wonât be deterministic (which is valid for JSON dictionaries, but annoying for diffing config files). This is why I was doing asOrderedDictionary as I though I had seen it change on me a few times when I was generating output.
Tim
-- Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
1. A JSON "object" corresponds to some kind of dictionary in Smalltalk. 2. {#a -> 1. #b -> 2} is NOT A DICTIONARY. It is an Array of Associations. 3. {#a -> 1. #b -> 2} asDictionary *is* a dictionary. 4. My Smalltalk allows #{#a -> 1. #b -> 2} -- how could I let it be less expressive than -- the language named for a snake? On Fri, 1 Mar 2019 at 02:57, Tim Mackinnon <tim@testit.works> wrote:
As I merrily chat to myself - I noticed that STONWriter almost does what I need - it just complains in #writeAssociation: so I make a subclass STONJSONWriter and override:
writeAssociation: association âdonât smack meâ¦. jsonMode ifTrue: [ self error: 'wrong object class for JSON mode' ]." self encodeKey: association key value: association value
I get exactly what I would expect - valid Json from simple Collections, Associations and Array.
So would it be handy to have such a writer in the image (or let STONWriter be more configurable for this?)
Tim
p.s. my finally example would then be:
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONJSONWriter on: (stream)) jsonMode: true; prettyPrint: true; writeList: ex ].
On 28 Feb 2019, at 13:45, Tim Mackinnon <tim@testit.works> wrote:
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config.
ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself.
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ].
So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <tim@testit.works> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
I really don't understand. JSON needs Dictionaries and Arrays (or other Sequenceable Collections). That has nothing to do with Pharo or how NeoJSON or STONJSON are implemented - it is what defines JSON. Of course, compatible objects work as well (NeoJSONObject is an example). You could make your own. Since there is no literal syntax in Pharo for a Dictionary, you have to write something like
{ #id->1. #name->'tim' } asDictionary
This has been discussed for years, I won't start that again. The above is short enough for me, but a bit of a pain when nesting. Part of the power of Pharo is a very simple syntax, we can express an awful lot with very few constructs. Your mapping examples won't work: you try to make something that is not a map but a list of associations into a map, that is simply not possible, sorry.
On 28 Feb 2019, at 14:45, Tim Mackinnon <tim@testit.works> wrote:
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config.
ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself.
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ].
So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <tim@testit.works> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
Tim Mackinnon wrote
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config.
ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself.
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ].
So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <
tim@
> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <
sven@
> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <
tim@
> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
The middle ground I've landed on is having a MySettings object, so I can write MySettings track: 'pharo'; language: 'smalltalk'; exercises: {'slug' -> 'hello'. 'id' -> 55. topics -> #('a' 'b' 'c')} and have the accessors for dictionaries convert them to such from arrays of associations. It's a bit more scaffolding, but is (imho) nicer to use elsewhere in the system (compared to a pure Dictionary). But then again, I haven't had a need for dictionaries in dictionaries so far... Cheers, Henry -- Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
I don't know if you really need OrderedDictionary or not. But I am a big fan of and use all the time simple Arrays or OrderedCollection of pairs. It is neat, clean and readable. ex := Dictionary newFromPairs: {    'track'. 'pharo.    'language'. 'smalltalk'.    'exercises'. Dictionary newFromPairs: {       'slug'. 'hello'.       'id'. 55.       'topics'. #('a' 'b' 'c')} In my app each individual level creates its own Dictionaries. I don't if such would be applicable for you. I have methods at each level which start like below. I don't know ahead of time whether or not I am receiving a Dictionary or an Array. I use this extensively for configuration that is readable and compact. I prefer this to the above when possible. And prefer pairs to associations. To my eyes it is cleaner. config := {    'track'. 'pharo.    'language'. 'smalltalk'.    'exercises'. {       'slug'. 'hello'.       'id'. 55.       'topics'. #('a' 'b' 'c')} myMethod: config    confd := config isDictionary       ifTrue: [ config ]       ifFalse: [ Dictionary newFromPairs: config ].       ... I use this also for JSON as I am using a REST API which receives JSON objects but it is also easy to pass in the necessary key:value pairs to the ZnClient. I don't know if this is of any value. But it is something I do extensively and pervasively in my app. I spent a lot of time thinking and iterating on how to handle large, complex, and nested configurations and enable them to be as clean, neat and concise as possible without limiting them in any foreseeable manner. Jimmie On 2/28/19 7:45 AM, Tim Mackinnon wrote:
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config.
ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself.
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ].
So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <tim@testit.works> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
I would use any of the following: ex := { #track->#pharo. #language->#smalltalk. #exercises->{ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } asDictionary } asDictionary. ex := { #track->#pharo. #language->#smalltalk. #exercises->({ #slug->'hello'. #id->55. #topics->#('a' 'b' 'c') } as: NeoJSONObject) } as: NeoJSONObject. ex := NeoJSONObject new track: #pharo; language: #smalltalk; exercises: (NeoJSONObject new slug: 'hello'; id: 55; topics: #('a' 'b' 'c')).
On 1 Mar 2019, at 05:01, Jimmie Houchin <jlhouchin@gmail.com> wrote:
I don't know if you really need OrderedDictionary or not. But I am a big fan of and use all the time simple Arrays or OrderedCollection of pairs. It is neat, clean and readable.
ex := Dictionary newFromPairs: { 'track'. 'pharo. 'language'. 'smalltalk'. 'exercises'. Dictionary newFromPairs: { 'slug'. 'hello'. 'id'. 55. 'topics'. #('a' 'b' 'c')}
In my app each individual level creates its own Dictionaries.
I don't if such would be applicable for you.
I have methods at each level which start like below. I don't know ahead of time whether or not I am receiving a Dictionary or an Array. I use this extensively for configuration that is readable and compact. I prefer this to the above when possible. And prefer pairs to associations. To my eyes it is cleaner.
config := { 'track'. 'pharo. 'language'. 'smalltalk'. 'exercises'. { 'slug'. 'hello'. 'id'. 55. 'topics'. #('a' 'b' 'c')}
myMethod: config confd := config isDictionary ifTrue: [ config ] ifFalse: [ Dictionary newFromPairs: config ]. ...
I use this also for JSON as I am using a REST API which receives JSON objects but it is also easy to pass in the necessary key:value pairs to the ZnClient.
I don't know if this is of any value. But it is something I do extensively and pervasively in my app. I spent a lot of time thinking and iterating on how to handle large, complex, and nested configurations and enable them to be as clean, neat and concise as possible without limiting them in any foreseeable manner.
Jimmie
On 2/28/19 7:45 AM, Tim Mackinnon wrote:
Just to add more flavour to this - it seems quite wordy that we have to do this (or equivalent) to write some config.
ex := OrderedDictionary new at: 'track' put: 'pharo'; at: 'language' put: 'smalltalk'; at: 'exercises' put: ( OrderedDictionary new at: 'slug' put: 'hello'; at: 'id' put: 55; at: 'topics' put: #('a' 'b' 'c'); yourself ); yourself.
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; mapInstVarsFor: Association; nextPut: ex ].
So Iâm still wondering the NeoJSONObjectMapping can do something easy for Association other than simply mapInstVars?
On 28 Feb 2019, at 13:36, Tim Mackinnon <tim@testit.works> wrote:
Hi Sven - is there no convenience shortcut we can use in our code to make this less wordy when we are specifying it?
E.g. the following is very convenient to write - but doesnât work (as you have $â and not $â )
ex := { 'track'-> 'pharo'. 'language' -> 'smalltalk'. 'exercises' -> {'slug' -> 'hello'. 'id' -> 55. 'topics' -> #('a' 'b' 'c') } }.
String streamContents: [ :stream | (STONWriter on: (stream)) prettyPrint: true; writeList: ex ].
I had thought maybe NeoJSON might help and put:
String streamContents: [ :stream | (NeoJSONWriter on: (stream)) prettyPrint: true; "mapInstVarsFor: Association;" nextPut: ex ].
But I get the error about missing an association mapping. If I uncomment that bit - I get things like: { "value" : âpharo" },
So is there a way I can write a simple mapper for Association that will write out the key in a string and the value in a string?
Iâm quite suprised we canât easily write out fragments of Json in our code in a light weight way? Or do I need to make a proper Config object and then teach it how to map properly such that rather than fiddling with our { x->y } dictionary sugar I do something like:
Config new at: âidâ is: 123; at: ânameâ is: âTimâ; at: âexercisesâ is: #(1 2 3).
And I guess at:is: can do the Association asDictionary thing?
But I thought Neo might give me something like that, as it must be terribly common?
Tim
On 28 Feb 2019, at 13:16, Sven Van Caekenberghe <sven@stfx.eu> wrote:
STONJSON toString: { #id->1. #name->'tim' } asDictionary.
JSON cannot deal with Associations by themselves.
On 28 Feb 2019, at 14:05, Tim Mackinnon <tim@testit.works> wrote:
I am stumped about how to write out some simple json (for a config file). I didn't think I need Neo, and STONJSON would be fine but it seems like creating items like:
{ 'id'-> self id. 'name' -> self name }
gives an error about the association. I think you have to do: { ('id'-> self id) asDictionary. ('name' -> self name) asDictionary } everywhereâ¦.
But when I switch over to NeoJsonWriter it also complains about Assocations too. I just want a simple output like: { "id" : 12, "name" : "timâ }
I thought it was simple to do this? Am I missing something obvious.
Tim
participants (7)
-
Esteban Maringolo -
Henrik Sperre Johansen -
Jimmie Houchin -
Paul DeBruicker -
Richard O'Keefe -
Sven Van Caekenberghe -
Tim Mackinnon