Göran Thank you for this illustration. http://goran.krampe.se/blog/Squeak/Tirade.rdoc I understand that 1) the Tirade parser parses a subset of regular Smalltalk messages. 2) the receiver is not given as it is assumed to be always the Tirade parser object. 3) the Tirade parser acts like a builder for objects? 4) It solves problems JSON and STON do not. I think this idea is very worth to pursue. --Hannes On 4/25/12, Göran Krampe <goran@krampe.se> wrote:
On 04/24/2012 07:28 PM, Dale Henrichs wrote:
Sven,
For tODE I am very interested having something with this kind of potential ... shipping "real" ST objects back and forth between Amber and Pharo or GemStone has some real appeal...
So Goran, the STON format looks somewhat similar to Tirade ... what would Tirade look like for the same data set?
Hmmm, let's see.
| TestDomainObject { | #created : DateAndTime [ '2012-02-14T16:40:15+01:00' ], | #modified : DateAndTime [ '2012-02-14T16:40:18+01:00' ], | #integer : 39581, | #float : 73.84789359463944, | #description : 'This is a test', | #color : #green, | #tags : [ | #two, | #beta, | #medium | ], | #bytes : ByteArray [ 'afabfdf61d030f43eb67960c0ae9f39f' ], | #boolean : false | }
It is an interesting question since Tirade is not meant to be parsed by a generic parser like JSON or STON. Tirade is a series of Smalltalk messages (unary or keyword) with arguments limited to literals (although with some subtle additions to regular Smalltalk literals, like for example Associations).
These messages give Tirade semantics and thus we do not normally add "types" to the Tirade input.
So the above could be encoded as a single Tirade message like this:
created: '2012-02-14T16:40:15+01:00' modified: '2012-02-14T16:40:18+01:00' integer: 39581 float: 73.84789359463944 description: 'This is a test' color: #green tags: #(two beta medium) bytes: 'afabfdf61d030f43eb67960c0ae9f39f' boolean: false.
Note that the above syntactically is a regular Smalltalk keyword message with no receiver to the left and ended with a "." (mandatory in Tirade). Also, the tags could also be represented as {#two . #beta . #medium} but although the syntax is like dynamic arrays in Pharo that does not mean expressions are allowed in Tirade - only literals.
Normally there would be a subclass of TiradeReader that implements the above message and then does the appropriate instantiations for #created, #modified and #bytes given the string input for those arguments. This method could look something like this (just pseudo code):
created: created modified: modified integer: int float: float description: description color: color tags: tags bytes: bytes boolean: boolean
result := TestDomainObject new created: (TimeStamp fromString: created); modified: (TimeStamp fromString: modified). result integer: int; float: float; description: description; color: color; tags: tags; bytes: bytes asByteArray; boolean: boolean
If one instead uses a plain TiradeParser to parse the above it will of course not have an implementation of the above method and will instead by default produce an OrderedCollection of "messages" where each message is an Association with the keyword selector as key and an array of arguments as the value. So running TiradeParser>>parse: on the above input gives:
an OrderedCollection(#created:modified:integer:float:description:color:tags:bytes:boolean:->#('2012-02-14T16:40:15+01:00' '2012-02-14T16:40:18+01:00' 39581 73.84789359463944 'This is a test' #green #(true #beta #medium) 'afabfdf61d030f43eb67960c0ae9f39f' false))
Finally a totally different approach is to encode the above object as a nested array with Associations, thus mimicking JSON/STON and it could look like this:
testdomainobject: { #created -> '2012-02-14T16:40:15+01:00'. #modified -> '2012-02-14T16:40:18+01:00'. #integer -> 39581. #float -> 73.84789359463944. #description -> 'This is a test'. #color -> #green. #tags -> #(two beta medium). #bytes -> 'afabfdf61d030f43eb67960c0ae9f39f'. #boolean -> false }.
NOTE: The -> syntax is added to Tirade as a "literal syntax" although it is in fact a binary message in Pharo. This will create an Array with Associations in it.
Again, if the reader implements the selector #testdomainobject: it will know what to do with the argument. Again, using only TiradeParser it would parse into:
an OrderedCollection(#testdomainobject:->{((Array new: 9) at: 1 put: (#created->'2012-02-14T16:40:15+01:00'); at: 2 put: (#modified->'2012-02-14T16:40:18+01:00'); at: 3 put: (#integer->39581); at: 4 put: (#float->73.84789359463944); at: 5 put: (#description->'This is a test'); at: 6 put: (#color->#green); at: 7 put: (#tags->#(true #beta #medium )); at: 8 put: (#bytes->'afabfdf61d030f43eb67960c0ae9f39f'); at: 9 put: (#boolean->false); yourself)})
Oh, funky. Obviously that is how print-it behaves on an Array of Assocations :)
Hopefully this gives a better idea of how Tirade works. Again, the three articles on Tirade from my blog explains more details:
http://goran.krampe.se/blog/Squeak/Tirade.rdoc http://goran.krampe.se/blog/Squeak/Tirade2.rdoc http://goran.krampe.se/blog/Squeak/Tirade3.rdoc
NOTE: The part on "receiver juggling" was way crazy, forget that :)
regards, Göran