Skip to content

Replace OpenStruct with hash-backed Context (v4.0.0)#225

Open
crisnahine wants to merge 1 commit into
collectiveidea:masterfrom
crisnahine:master
Open

Replace OpenStruct with hash-backed Context (v4.0.0)#225
crisnahine wants to merge 1 commit into
collectiveidea:masterfrom
crisnahine:master

Conversation

@crisnahine

@crisnahine crisnahine commented Mar 6, 2026

Copy link
Copy Markdown

Summary

  • Replaces Interactor::Context < OpenStruct with a plain hash-backed implementation
  • Removes the ostruct runtime dependency entirely
  • Bumps version to 4.0.0 (semver major — breaking change)

Motivation

OpenStruct was deprecated in Ruby 3.2+ and may be removed in a future Ruby version. This change eliminates the deprecation warning and future-proofs the gem with zero runtime dependencies.

What changed

lib/interactor/context.rb

  • Context now inherits from Object instead of OpenStruct
  • Hash-backed @table store with method_missing for dynamic accessors
  • Implements [], []=, to_h, ==, inspect, to_s explicitly
  • Compatible with Ruby 1.9+ (uses plain Hash#each, not transform_keys)

interactor.gemspec

  • Removed spec.add_dependency "ostruct"
  • Version bumped to 4.0.0

lib/interactor.rb

  • Fixed pre-existing StandardRB Lint/IdentityComparison warning (object_id !=!equal?)

spec/interactor/context_spec.rb

  • Added spec asserting Context.superclass == Object to lock in the new contract
  • Updated send(:table) internal accessor test to use public to_h

Breaking changes

  • context.is_a?(OpenStruct) now returns false
  • OpenStruct-only methods (each_pair, marshal_dump, marshal_load) are no longer available

Migration: If your code does not check is_a?(OpenStruct) or call OpenStruct-specific methods, no changes are required.

Test results

111 examples, 0 failures
StandardRB: no offenses

Upgrades

@genaromadrid

Copy link
Copy Markdown

Having this would also make the gem much faster as OpenStruct is known to have performance issues.
What do you think @gaffneyc?

OpenStruct is deprecated on Ruby 3.2+ and leaves the default gems in
Ruby 4.0. Reimplement Interactor::Context as a plain hash-backed object
and drop the ostruct runtime dependency.

- Context inherits from Object and stores attributes in an @table hash
  with method_missing accessors. All documented public API is preserved:
  build, [], []=, to_h, ==, success?, failure?, fail!, called!,
  rollback!, _called, deconstruct_keys, and dynamic getters/setters.
- respond_to_missing? reports true only for setters and already-set
  keys, so the context never advertises implicit conversions
  (to_ary/to_hash/to_str) that method_missing would answer with nil.
- initialize_copy gives dup/clone an independent store instead of
  aliasing the original's hash.
- A reader called with arguments raises ArgumentError, matching a real
  zero-arity accessor.
- Bump the version to 4.0.0. Breaking: Context is no longer
  is_a?(OpenStruct) and OpenStruct-only methods (each_pair, marshal_dump,
  marshal_load) are gone.
- Fix the Lint/IdentityComparison warning in Interactor#run.

118 examples, 0 failures; standardrb clean.
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