Skip to content

backward incompat json 3 changes

trentm edited this page Apr 3, 2012 · 3 revisions

Care has been taken in json3 to not gratuitously change output behaviour: only where the utility was greatly improved and the expected usage of the old behaviour was rare.

Nomenclature: I use "json N" or "jsonN" to refer to "version N of the json tool". E.g. "json3" is the new version 3.x of the json tool from this repo and NOT some new version 3 of the JSON specification.

'-a' output differs if output mode is json

A new rule in json3 is that "json" mode output (via -j or -o json or -o json-N) is always actual JSON. This was not the case in json2 with array processing output via the -a option.

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json2 -aj name
"trent"
"ewan"
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -aj name
[
  {
    "name": "trent"
  },
  {
    "name": "ewan"
  }
]

Or without lookups it becomes a little more obvious why the json3 take on this is preferable:

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json2 -aj
{
  "name": "trent",
  "age": 38
}
{
  "name": "ewan",
  "age": 4
}
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -aj
[
  {
    "name": "trent",
    "age": 38
  },
  {
    "name": "ewan",
    "age": 4
  }
]

Note that the behaviour for the default "jsony" output mode is unchanged:

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json2 -a name
trent
ewan
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -a name
trent
ewan

-e CODE will automatically process each element of an input array

Executing code on the input with the -e CODE option has changed a bit in json3. In json2 you had to manually use '-a' to process each element of an input array:

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json2 -e 'age++'

/Users/trentm/tm/dotfiles/home/bin/json:671
        vm.runInNewContext(code, datum);
           ^
ReferenceError: age is not defined
    at evalmachine.<anonymous>:1:1
    at Socket.<anonymous> (/Users/trentm/tm/dotfiles/home/bin/json:671:12)
    at Socket.emit (events.js:64:17)
    at Pipe.onread (net.js:388:51)
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json2 -a -e 'age++'
{
  "name": "trent",
  "age": 39
}
{
  "name": "ewan",
  "age": 5
}

I believe that usage of -e CODE will be much more common on an input array than an input object, so in json3 -e CODE will automatically switch to array processing if the input is an array:

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -e 'age++'
[
  {
    "name": "trent",
    "age": 39
  },
  {
    "name": "ewan",
    "age": 5
  }
]

Note here that json3 doesn't suffer from the (often unwanted) side-effect of non-JSON output from json2's -a output. You can still use -a explicitly if you want that output:

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -e 'age++' -a
{
  "name": "trent",
  "age": 39
}
{
  "name": "ewan",
  "age": 5
}
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -e 'age++' -a age
39
5

A new -A option can be used to force processing an array as a single item:

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -A -e 'this[0].age++'
[
  {
    "name": "trent",
    "age": 39
  },
  {
    "name": "ewan",
    "age": 4
  }
]

To help understand the design a little bit: The new -c CODE option also automatically switches to array processing if the input is an array. However handling of LOOKUPS does NOT automatically switch to array process if the input is an array because that would have broken an important use case. As a result the following behave the same in json2 and json3:

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json2 0
{
  "name": "trent",
  "age": 38
}
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 0
{
  "name": "trent",
  "age": 38
}
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json2 -a name
trent
ewan
$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' | json3 -a name
trent
ewan