Phrogz / NeatJSON

Pretty-print your JSON in Ruby, JS, or Lua with more power than JSON.stringify or JSON.pretty_generate
http://phrogz.net/JS/NeatJSON
MIT License
108 stars 19 forks source link

NeatJson sorts numerical strings to the beginning #9

Closed bwl21 closed 8 years ago

bwl21 commented 8 years ago

{ "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

Phrogz commented 8 years ago

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}
bwl21 commented 8 years ago

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)

Phrogz commented 8 years ago

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.

bwl21 commented 8 years ago

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 :-(

elia commented 8 years ago

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

bwl21 commented 8 years ago

@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.

elia commented 8 years ago

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

bwl21 commented 8 years ago

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"}
bwl21 commented 8 years ago

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

hmdne commented 3 years ago

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.

bwl21 commented 3 years ago

@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.