Skip to content

Conversation

@etiennebarrie
Copy link
Contributor

Builds on #903.

While working on #903, I realized JSON::Coder wasn't respecting the depth it's given:

$ ruby -rjson -e 'puts JSON::Coder.new(object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 1).dump(foo: 42)' \
> -e 'puts JSON::State.new(object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 1).generate(foo: 42)'
{
  "foo": 42
}
{
    "foo": 42
  }

This is not ideal, for example a user could want to emit pretty generated JSON, using Russian-doll caching and JSON::Fragment (or a custom solution). To me it's a bug, so I just fixed it, now that generate_json_data has its own depth it's pretty straightforward: etiennebarrie/json@move-depth-to-generate_json_data...etiennebarrie:json:respect-coder-depth

@etiennebarrie etiennebarrie changed the title Respect coder depth Respect Coder depth Nov 25, 2025
@byroot
Copy link
Member

byroot commented Nov 26, 2025

This needs rebasing now.

That said, it never occurred to me that depth could be used as a configuration for pretty printing purposes. But if it works, why not.

@byroot
Copy link
Member

byroot commented Nov 26, 2025

Testing old versions, seems like this never really worked?

gem "json", "2.2.0"
require 'json'

puts "JSON::VERSION: #{JSON::VERSION}"
puts JSON.generate({ foo: 1 }, object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 4)
$ ruby /tmp/test.rb
JSON::VERSION: 2.2.0
{
          "foo": 1
        }

Coder currently ignores its depth and always resets it to 0 when
generating a new JSON document.
@etiennebarrie
Copy link
Contributor Author

Testing old versions, seems like this never really worked?

I'm not sure what you mean, your example shows that JSON.generate always respected depth?

@byroot
Copy link
Member

byroot commented Nov 27, 2025

your example shows that JSON.generate always respected depth?

Look at the opening braces. It's not respecting the depth. But the rest yes.

@etiennebarrie
Copy link
Contributor Author

The opening brace being on the first character is expected, because the enclosing code should be already indenting that part. For example, to go from a fragment with depth 1 to an Array:

puts "[\n  #{JSON.generate({ foo: 1 }, object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 1)}\n]"
[
  {
    "foo": 1
  }
]

@byroot
Copy link
Member

byroot commented Nov 27, 2025

Ah right, that makes sense.

@byroot byroot merged commit 9c36681 into ruby:master Nov 27, 2025
37 checks passed
@etiennebarrie
Copy link
Contributor Author

etiennebarrie commented Nov 27, 2025

Another example, using the generator to do the Array part instead of String interpolation:

gem "json", ARGV.first
require 'json'

puts "JSON::VERSION: #{JSON::VERSION}"

cache_miss = 0
cache = Hash.new do |h, k|
  cache_miss += 1
  h[k] = Fragment.new(JSON.pretty_generate({ foo: k }, depth: 1))
end

class Fragment
  def initialize(fragment)
    @fragment = fragment
  end

  def to_json(*)
    @fragment
  end
end

puts JSON.pretty_generate((1..3).map(&cache))
puts "miss:#{cache_miss}"
cache_miss = 0
puts JSON.pretty_generate((1..3).map(&cache))
puts "miss:#{cache_miss}"

This works all the way to ruby 2.7 for example:

$ cat test.rb | container run --rm -i ruby:2.7 ruby
JSON::VERSION: 2.3.0             
[
  {
    "foo": 1
  },
  {
    "foo": 2
  },
  {
    "foo": 3
  }
]
miss:3
[
  {
    "foo": 1
  },
  {
    "foo": 2
  },
  {
    "foo": 3
  }
]
miss:0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants