Skip to content

Add JSON::Any wrapper around JSON::Any#inspect output#15979

Merged
straight-shoota merged 1 commit intocrystal-lang:masterfrom
jneen:bugfix.json-any-inspect
Sep 11, 2025
Merged

Add JSON::Any wrapper around JSON::Any#inspect output#15979
straight-shoota merged 1 commit intocrystal-lang:masterfrom
jneen:bugfix.json-any-inspect

Conversation

@jneen
Copy link
Contributor

@jneen jneen commented Jul 15, 2025

Fixes #6213
See also #15953

This approach is admittedly a bit of a hack, and would benefit from Fiber-local variables other than what can be stored in exec_recursive_hash.

@jneen jneen force-pushed the bugfix.json-any-inspect branch 2 times, most recently from f15c9b9 to 2cf6531 Compare July 15, 2025 17:11
@jneen
Copy link
Contributor Author

jneen commented Jul 15, 2025

Rebased since I was out of date.

@jneen jneen force-pushed the bugfix.json-any-inspect branch from 2cf6531 to 9c1a31d Compare July 15, 2025 17:15
@jneen
Copy link
Contributor Author

jneen commented Jul 15, 2025

Added some more spec coverage to ensure state is reset at the end.

@jneen
Copy link
Contributor Author

jneen commented Jul 16, 2025

I'm realizing we should probably do the same for YAML::Any

@jneen
Copy link
Contributor Author

jneen commented Jul 17, 2025

Okay so the real proper Object Oriented Approved way to do this is to modify Array#inspect and Hash#inspect to use double recursion.

Essentially this would mean defining something like:

class Object
  def inspect_recursive(io : IO) : Nil
    inspect(io)
  end
end

and having all recursive calls to #inspect such as in Array and Hash use this indirect method instead:

class Array
  def inspect(io : IO) : Nil
    # ...
    join io, ", ", &.inspect_recursive(io)
  end
end

Then classes like JSON::Any could specify separate behaviour on the two.

This is a much deeper-reaching change though, so I'd like thoughts on whether this stack-flag hack is preferable to that.

@jneen
Copy link
Contributor Author

jneen commented Jul 17, 2025

I had a thought that we could use #to_s as a bit of a hack:

class Any
  def inspect(io : IO)
    io << "JSON::Any("
    to_s(io)
    io << ')'
  end

  def to_s(io : IO)
    @raw.to_s(io)
  end
end

but unfortunately Array#to_s calls into #inspect on its elements, which I suppose makes sense?

@jneen jneen force-pushed the bugfix.json-any-inspect branch from 9c1a31d to 11d52e1 Compare July 18, 2025 19:21
@jneen
Copy link
Contributor Author

jneen commented Jul 18, 2025

rebased.

@jneen
Copy link
Contributor Author

jneen commented Jul 18, 2025

I presume for the YAML case we want this to show up in error messages as well?

      expect_raises(KeyError, %(Missing hash key: YAML::Any(nil))) do
        any[YAML::Any.new(nil)]
      end

@straight-shoota
Copy link
Member

Hm, not sure about the error in YAML::Any[].
It's probably not necessary to spell out the wrapper type because x and YAML::Any.new(x) behave identical in this method. It doesn't matter whether the value is raw or wrapped.

@straight-shoota straight-shoota changed the title add JSON::Any(...) to JSON::Any#inspect Add JSON::Any wrapper around JSON::Any#inspect output Aug 5, 2025
@straight-shoota straight-shoota added this to the 1.18.0 milestone Sep 9, 2025
@straight-shoota straight-shoota merged commit ca23c0b into crystal-lang:master Sep 11, 2025
38 checks passed
@straight-shoota straight-shoota changed the title Add JSON::Any wrapper around JSON::Any#inspect output Add JSON::Any, YAML::Any wrapper around Any#inspect output Oct 9, 2025
@straight-shoota straight-shoota changed the title Add JSON::Any, YAML::Any wrapper around Any#inspect output Add JSON::Any wrapper around JSON::Any#inspect output Oct 9, 2025
@straight-shoota
Copy link
Member

We're still missing the same for YAML::Any. It feels a bit weird to release this only for JSON::Any, but it's impossible to merge in time for the new release. We could consider pulling this change and re-introducing it afterwards, together with YAML::Any.

It should be fine to have only this in 1.18 and follow up with YAML::Any in 1.19, though.

@ysbaddaden
Copy link
Collaborator

It should be fine to have only this in 1.18 and follow up with YAML::Any in 1.19, though.

👍

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JSON::Any#inspect should include JSON::Any in its output

5 participants