Skip to content

Wish: Remove "forced" dependency from ostruct #988

Description

@phorsuedzie

Ruby's core makes some effort to squeeze ostruct / OpenStruct out of the code. The gem 'json', promoted to a default gem now, is no exception to this. Any require "ostruct" there has been transformed into conditional code (see MRI 3.3 => 3.4).

  1. OpenStruct itself is monkey-patched only with an active require 'json/add/ostruct' (see e.g. https://rubyapi.org/3.4/o/openstruct)
  2. JSON::GenericObject is only an autoload. Which works even if require 'ostruct' would raise a LoadError.

Best if Oj would be able to drop s.add_runtime_dependency 'ostruct', '>= 0.2'. And run any require 'ostruct' only if "actively demanded" ...

  • ... by Oj.add_to_json() (if this continues to promise that OpenStruct is patched as a default). Note: if OpenStruct is passed as an argument, there is no need to require it.
  • ... because JSON::GenericObject is (auto-)loaded. Could even be, that Oj doesn't need to define JSON::GenericObject at all anymore (for a modern Ruby). AFAICS, the default json gem's JSON::GenericObject is
    • unconditionally available (at least for the lowest MRI version supported (RBX might be different): https://github.com/ruby/ruby/blob/ruby_2_4/ext/json/lib/json/generic_object.rb)
    • "demands" only an autoload declaration (which is set up by json gem's require "json", i.e. Oj would have to declare something similar; to require "json/generic_object" directly works immediately), and
    • the code of generic_object.rb calls nothing but methods from JSON, which are mimicked by Oj (AFAICS).

Activity

  1. ohler55 commented on Jan 13, 2026

    @ohler55
    Owner

    I'll remove the dependency and see if that breaks anything. It might be an issue with earlier ruby versions.

  2. JulianBoralli commented on Feb 4, 2026

    @JulianBoralli

    I am running ruby 4.0.1 and got this warning when I upgraded OJ to 3.16.14:

    warning: ostruct used to be loaded from the standard library, but is not part of the default gems since Ruby 4.0.0.
    You can add ostruct to your Gemfile or gemspec to fix this error.

    I just added ostruct to my Gemfile for now.

  3. franzliedke commented on Feb 5, 2026

    @franzliedke

    Also got the same warning on Ruby 3.4 after upgrading to the latest oj release.

    It includes the following line. 😇

    Also please contact the author of oj-3.16.14 to request adding ostruct into its gemspec.

    Historic reference: #928.

  4. phorsuedzie commented on Feb 5, 2026

    @phorsuedzie
    Author

    Also please contact the author of oj-3.16.14 to request adding ostruct into its gemspec.

    FYI: This is only one of the possible options. This wish is about a different approach: to not "actively" require "ostruct" unconditonally. Hopefully similar to how the standard json gem doesn't require it actively anymore, nowadays. Given ruby core learned that OpenStruct is broken by design and should be avoided. If the "surrounding" ruby code never accesses OpenStruct, it should also not be loaded just because oj is used.

    TL;DR: The goal should be:

    • for a Gemfile with gem oj, and
    • code that accesses Oj (Oj.load, Oj.dump, Oj::ParseError)
    • then still no warning about ostruct used to be loaded from the standard library.

    Whether one needs to add gem "ostruct" (only) if (e.g.) require "oj/mimic" is called, remains open.
    People which access JSON::GenericObject actively can likely be expected to provide its prerequisite. And/or it is not anymore oj's responsibility to provide a copy of the code of the json gem here.

  5. imran-iq commented on Feb 5, 2026

    @imran-iq

    (hi just another person with the message that popped up for ruby 4)

    This wish is about a different approach: to not "actively" require "ostruct" unconditonally. Hopefully similar to how the standard json gem doesn't require it actively anymore, nowadays.

    https://github.com/ruby/json/blob/b11ce01ca6bb47c0f1aab1e72f293af70978711d/lib/json/add/ostruct.rb#L5-L8

    looks like we can catch the LoadError and its already guarded for here:

    if Object.const_defined?('OpenStruct')

    but looks like this might need to be changed:

    class GenericObject < OpenStruct

  6. zarqman commented on Feb 5, 2026

    @zarqman

    Like others, I'm running into the missing ostruct dependency warning here as well. Ruby 3.4.7.

    ~/.rvm/gems/ruby-3.4.7@main/gems/oj-3.16.14/lib/oj/mimic.rb:4: warning: ~/.rvm/rubies/ruby-3.4.7/lib/ruby/3.4.0/ostruct.rb was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0.
    You can add ostruct to your Gemfile or gemspec to silence this warning.
    Also please contact the author of oj-3.16.14 to request adding ostruct into its gemspec.
    

    @ohler55, as you suggested could happen, dropping ostruct does appear to be an issue with at least some Ruby versions.

    This is, at least in part, because require 'ostruct' happens during default usage of the gem. Note the dependency/require chain:

    gem 'oj'
    => bundler calls  require 'oj'
      => oj.rb:11
        require 'oj/mimic'
          => mimic.rb:5
            require 'ostruct'
    

    That means that ostruct is a default requirement of the gem, same as bigdecimal, because oj/mimic is always required.

    The ostruct gem (v0.6.3) is nearly 500 lines, so it's not just a shim (at least not on all versions of Ruby supported by Oj, which is back to Ruby 2.7). I'm not entirely understanding why ostruct needs to be removed, but perhaps I'm missing something.

    @phorsuedzie, you wrote "The goal should be ... then still no warning about ostruct used to be loaded from the standard library." Wouldn't this best be solved by indeed making ostruct a dependency, exactly as those warning say?

    Regardless, I'd suggest reintroducing the dependency on ostruct for Oj's 3.16.x series, unless it's possible to eliminate all warnings on all of Oj's supported versions of Ruby (2.7..4.0).

    Then, if there's a compelling reason to remove ostruct, it either needs to wait until older Rubies are dropped (which I recognize is going to be a while), or Oj needs to detect when the loaded gemspecs are missing 'ostruct' (if !Gem.loaded_specs['ostruct'] ... perhaps) and then display an error with the specific instruction to add gem 'ostruct' to the app's own Gemfile. I'd argue either of these belongs in a v4 release, or possibly v3.17, depending on semver adherence.

    PS: @ohler55, been using Oj a long time--thanks for the time and effort you've generously given to all of us these many years.

  7. ohler55 commented on Feb 6, 2026

    @ohler55
    Owner

    Ok, reverting back to include the dependency. Will deal with the desire to remove that dependency at a later date.

  8. ohler55 commented on Feb 6, 2026

    @ohler55
    Owner

    rubygems is acting up and not accepting a release push. Oj is tagged though so you are welcome to fetch directly.

  9. ohler55 commented on Feb 6, 2026

    @ohler55
    Owner

    Ok, released

  10. JulianBoralli commented on Feb 6, 2026

    @JulianBoralli

    Ok, released

    Just tested, all good. @ohler55 Really appreciate you maintaining Oj.

  11. phorsuedzie commented on Mar 18, 2026

    @phorsuedzie
    Author

    Wouldn't this best be solved by indeed making ostruct a dependency, exactly as those warning say?

    With the current implementation, this is what is needed. The actual wish is to be able to use oj with a Gemfile.lock that doesn't include ostruct anymore (because ruby itself nowadays "dislikes" OpenStruct because of "questionable design").

    Which would need to change the implementation, so that it does not anymore require "ostruct" if oj gets loaded, or that if still does, then it rescues from a LoadError (see ruby's packaged json gem).

    And maybe one simple solution to not anymore access OpenStruct from within this gem's code is to not anymore include a (more or less outdated) copy of the ::JSON::GenericObject, but (only then) simply require "json/generic_object", and have the including application care about the (additional) dependencies: json and ostruct.

  12. ohler55 commented on Mar 18, 2026

    @ohler55
    Owner

    I'll reopen the issue.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions