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 <[hidden email]> 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 <[hidden email]> wrote: > > STONJSON toString: { #id->1. #name->'tim' } asDictionary. > > JSON cannot deal with Associations by themselves. > >> On 28 Feb 2019, at 14:05, Tim Mackinnon <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote: >> >> STONJSON toString: { #id->1. #name->'tim' } asDictionary. >> >> JSON cannot deal with Associations by themselves. >> >>> On 28 Feb 2019, at 14:05, Tim Mackinnon <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote: >>> >>> STONJSON toString: { #id->1. #name->'tim' } asDictionary. >>> >>> JSON cannot deal with Associations by themselves. >>> >>>> On 28 Feb 2019, at 14:05, Tim Mackinnon <[hidden email]> 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 >>> >>> >> >> > > |
In reply to this post by Tim Mackinnon
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote: >>> >>> STONJSON toString: { #id->1. #name->'tim' } asDictionary. >>> >>> JSON cannot deal with Associations by themselves. >>> >>>> On 28 Feb 2019, at 14:05, Tim Mackinnon <[hidden email]> 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 >>> >>> >> >> > > |
In reply to this post by Tim Mackinnon
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote: >>>> >>>> STONJSON toString: { #id->1. #name->'tim' } asDictionary. >>>> >>>> JSON cannot deal with Associations by themselves. >>>> >>>>> On 28 Feb 2019, at 14:05, Tim Mackinnon <[hidden email]> 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 >>>> >>>> >>> >>> >> >> > > |
In reply to this post by Tim Mackinnon
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 <[hidden email]> 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: |
In reply to this post by Tim Mackinnon
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 |
In reply to this post by Sven Van Caekenberghe-2
Sven- thinking a bit more
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 |
In reply to this post by Tim Mackinnon
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 <[hidden email]> 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 <[hidden email]> wrote: >>> >>> STONJSON toString: { #id->1. #name->'tim' } asDictionary. >>> >>> JSON cannot deal with Associations by themselves. >>> >>>> On 28 Feb 2019, at 14:05, Tim Mackinnon <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote: >>>> >>>> STONJSON toString: { #id->1. #name->'tim' } asDictionary. >>>> >>>> JSON cannot deal with Associations by themselves. >>>> >>>>> On 28 Feb 2019, at 14:05, Tim Mackinnon <[hidden email]> 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 >>>> >>> >> > |
In reply to this post by Tim Mackinnon
> On 28 Feb 2019, at 22:35, Tim Mackinnon <[hidden email]> wrote: > > Sven- thinking a bit more > >> On 28 Feb 2019, at 13:59, Sven Van Caekenberghe <[hidden email]> 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. |
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 <[hidden email]> wrote: > > > >> On 1 Mar 2019, at 10:35, Sven Van Caekenberghe <[hidden email]> 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 (<[hidden email]>) escribió: > > > > > On 1 Mar 2019, at 12:32, Tim Mackinnon <[hidden email]> wrote: > > > > > > > >> On 1 Mar 2019, at 10:35, Sven Van Caekenberghe <[hidden email]> 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 > > |
In reply to this post by Tim Mackinnon
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 <[hidden email]> 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 |
Free forum by Nabble | Edit this page |