Phrogz / NeatJSON

Pretty-print your JSON in Ruby, JS, or Lua with more power than JSON.stringify or JSON.pretty_generate

Home Page:http://phrogz.net/JS/NeatJSON

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

NeatJson sorts numerical strings to the beginning

bwl21 opened this issue · comments

{ "d": "10", "1":30 ,"a":10}

yields

{"1":30 ,"d":"10" ,"a":10}

It changes the sequence of the properties if the key is a string representing a number

What you are seeing is not the fault of NeatJSON. It is the fact that Objects in JavaScript do not guarantee key order. Observe the way Node.js represents your object:

$ node
> o = { "d": "10", "1":30 ,"a":10}
{ '1': 30, d: '10', a: 10 }

The order in which Node chooses to enumerate the properties is the order I show them in (unless the sorted:true option is passed).

For more details, see Does JavaScript Guarantee Object Property Order?.


Note that this works just fine in Ruby, where Hash keys do preserve insertion order (from Ruby v1.9 on):

$ irb
o = { d:"10", "1"=>30, a:10 }
#=> {:d=>"10", "1"=>30, :a=>10} 

require 'neatjson'
puts JSON.neat_generate(o)
#=> {"d":"10","1":30,"a":10}

As I mentioned, I use neatjson with Opal, so your statement is reasonable. Opal transpiles to javascript. Nevertheless for my application, maintaining the sequence of keys is still an issue.

I even think, if we could add an option which provides an intended sort order (if not apply json_schema)

I'd be willing to review a pull request that included an option for explicit, specific ordering of object keys.

You might petition the Opal team to consider an option to "transpile" Ruby hashes to Javascript Map objects, which preserve ordering.

I have created an initial try for epxlicit sort: see the test in https://github.com/bwl21/NeatJSON/blob/feature/explicit_sort/test/tests.rb

I have also impelemented it the branch https://github.com/bwl21/NeatJSON/blob/feature/explicit_sort

the option has to provide two arrays with sort keys. the keys which are not explicitly specified are sorted between the keys of the first and the second array.

What do you think? I will not be able to implement this in JS :-(

Opal member here — Forgive me if I'm missing context but I just skimmed through the issue and I don't know enough about this project

I just wanted to clarify that even if opal uses JS objects as its Hash hash-table implementation, key order is still guaranteed by the presence of an array of keys.

In light of that it maybe makes sense to use the ruby version of this library and compile it to javascript instead of using the JS implementation. Of course the usual caveats applies (Strings are immutable, String == Symbol, etc.).

@Phrogz if you want help in setting up an opal test runner I'll be happy to help

@elia this issue is with the ruby version compiled via Opal. I tried to run the test with Opal but fail. It is a static require so it should work.

NeatJSON>cd test
NeatJSON/test>Opal test_neatjson.rb
/Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/path_reader.rb:12:in `initialize': No such file or directory - ../lib/neatjson (Errno::ENOENT)
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/path_reader.rb:12:in `open'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/path_reader.rb:12:in `read'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/builder.rb:117:in `read'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/builder.rb:127:in `process_require'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/builder.rb:42:in `block in build_str'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/builder.rb:42:in `map'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/builder.rb:42:in `build_str'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/cli.rb:110:in `block in build'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/cli.rb:157:in `evals_or_file'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/cli.rb:109:in `build'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/cli.rb:119:in `compiled_source'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/cli.rb:85:in `run_code'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/lib/opal/cli.rb:69:in `run'
        from /Library/Ruby/Gems/2.0.0/gems/opal-0.9.0/bin/opal:22:in `<top (required)>'
        from /usr/local/bin/Opal:23:in `load'
        from /usr/local/bin/Opal:23:in `<main>'
NeatJSON/test>

It would be great if you could have a look into this such that we can sort out Opal issues.

You need to add --gem GEMNAME to add the gem's lib paths

It indeed seems to be an issue of Opal, it creates numerical keys instead of string keys. I tried with opal-repl

>> a=JSON.parse(%Q{{"a" : "1", "2" : "2"}})
=> {"2"=>"2", "a"=>"1"}

It happens in the JS - version as well, ( try on http://phrogz.net/JS/neatjson/neatjson.html)

commented

I don't know if this is still important for you, but I made a https://github.com/hmdne/minijson JSON parser for Opal. We are pondering integrating it, I plan to expand it a little bit more to be closer to MRI's JSON, but in the meantime you can use it.

@hmdne thanks for the hint. The issue is somewhat old and I worked around it by adding a sort routine which handles all keys as non numerical string. By this I achieve a reproducible alphabetic order of the keys.

Nevertheless the issue is important and I will keep an eye on it.