Skip to content

Move Rails-compatible methods to lib/rails; date deprecations - #326

Merged
trans merged 3 commits into
mainfrom
claude/github-connector-capabilities-4qcre6
Sep 27, 2026
Merged

trans merged 3 commits into
mainfrom
claude/github-connector-capabilities-4qcre6

Conversation

@trans

@trans trans commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

First step of separating the methods Facets borrowed from ActiveSupport from the ones Facets endorses as its own. The per-file decisions came from a triage of all 40 Facets files that overlap with ActiveSupport 8.1.

1. New lib/rails tree (f9f1fa6)

These files move to lib/rails/facets/, with their tests and demos under test/rails and demo/rails:

  • hash/symbolize_keys, hash/stringify_keys, hash/to_options, hash/slice
  • array/extract_options
  • module/mattr, module/cattr, class/cattr, cattr
  • file/atomic_write
  • date (previously in lib/standard)

lib/rails is added to the gem's require_paths, so require 'facets/hash/slice' and friends still work.

Also in this commit:

  • lib/rails is added to .index, Indexfile, etc/test.rb and the Rakefile, which gains test:rails and qed:rails tasks.
  • MANIFEST has the moved paths relocated. It was already out of date before this PR and mast wasn't available to regenerate it, so only the moved entries were edited.
  • Fix: hash/to_options only loaded symbolize_keys and never defined Hash#to_options. It now aliases to_options and to_options! as Rails does, and has a new test.

2. Deprecations get a removal date (aa011ae)

Each of these now names 2027-09-30 in its @deprecated note and in its warning:

  • Kernel#returning
  • Module#alias_method_chain
  • Array#uniq_by!
  • Enumerable#uniq_by
  • Kernel#silence_stream
  • Facets' fallback Time#to_time, which is only defined when date isn't loaded

The first four already warned; they only gain the date.

silence_stream: Rails removed it in 5.0 because reopening STDOUT/STDERR affects every thread in the process. Its logic now lives in Kernel#silence, and silently, silence_stderr and silence_stdout call silence, so they keep working without a warning. silence_stream warns and then delegates to silence. The docs for silence now say it affects the whole process.

3. Warning for Rails methods loaded by require 'facets' (65d5b5f)

require 'facets' (and facets/essentials) still provides Hash#slice!, #symbolize_keys, #stringify_keys, #to_options and Array#extract_options!, but will stop after 2027-09-30. Instead of loading those files outright, the loaders now call Facets.rails_bridge, which defines a small stub for each method. The first call to a stub:

  1. warns, naming the file to require,
  2. loads that file, which replaces the stub,
  3. retries the call.
warning: Hash#slice! will no longer be loaded by `require 'facets'` after 2027-09-30. Add `require 'facets/hash/slice'` to keep using it.
  • Each method warns at most once per process.
  • Requiring the file directly avoids the stub and the warning entirely.
  • If a method is already defined when require 'facets' runs, for example by ActiveSupport, it is left alone and not stubbed.
  • The set of methods require 'facets' defines is unchanged, apart from the new Facets.rails_bridge and the to_options fix.

Testing

  • rake test: 1,252 tests, all passing: the previous 1,248, 2 new to_options tests and 2 new rails_bridge tests.
  • rake qed: 153 demos with 8 failures and 2 errors. Those same failures were already there before these changes, so nothing new.
  • Ran by hand:
    • silence, silently, silence_stderr and silence_stream: the output is hidden inside the block and comes back afterwards, and only silence_stream warns.
    • The bridge stubs: each warns once, then works normally, and there's no warning when the file is required directly.
  • I didn't run the experimental JRuby job locally. It already fails on main because URI.hash_to_query comes out private on JRuby 10.1 (see the comment on Simplify block default passing in cattr and mattr #325).

🤖 Generated with Claude Code

https://claude.ai/code/session_01E2Njj4j1r9twkVcXsMySLW

Facets carries a number of methods borrowed from ActiveSupport that it
doesn't endorse as its own. They now live in a separate lib/rails tree
(lib/rails/facets/...), with their tests and demos under test/rails and
demo/rails:

  hash/symbolize_keys, hash/stringify_keys, hash/to_options, hash/slice,
  array/extract_options, module/mattr, module/cattr, class/cattr, cattr,
  file/atomic_write, and the standard facets/date extensions.

lib/rails is added to the gem's require_paths, so require paths are
unchanged. The core loaders (facets/hash, facets/array, facets/essentials)
still require the moved files, so `require 'facets'` loads the same
methods as before.

Also fixes hash/to_options, which only loaded symbolize_keys and never
defined Hash#to_options or #to_options!.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2Njj4j1r9twkVcXsMySLW
Give every deprecated method a removal date, both in its @deprecated
note and in its warning:

  Kernel#returning, Module#alias_method_chain, Array#uniq_by!,
  Enumerable#uniq_by, Kernel#silence_stream, and Facets' fallback
  Time#to_time (only defined when 'date' isn't loaded).

Rails removed silence_stream in 5.0 because reopening STDOUT/STDERR
isn't thread-safe. Its logic now lives in Kernel#silence, which
silently, silence_stderr and silence_stdout call, so those keep working
without a warning. silence_stream warns and delegates to silence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2Njj4j1r9twkVcXsMySLW

trans commented Sep 27, 2026

Copy link
Copy Markdown
Member Author

CI status: all required jobs pass (Ruby 3.1–3.4, head, TruffleRuby). The only red check is the experimental Ruby jruby on ubuntu job, and it isn't caused by this PR.

  • It's the same error main already has: private method 'hash_to_query' called for module URI at lib/standard/facets/uri.rb:28 (see the comment on Simplify block default passing in cattr and mattr #325). This PR doesn't touch uri.rb.
  • On JRuby, 1,245 of this PR's 1,250 tests pass: 4 are pending and this is the only error. So the moved lib/rails files and their tests work on JRuby too.
  • No fix exists yet; it needs its own change to uri/query.rb.

Generated by Claude Code

`require 'facets'` still provides the lib/rails methods (Hash#slice!,
#symbolize_keys, #stringify_keys, #to_options, Array#extract_options!),
but will stop after 2027-09-30. Instead of loading them outright, the
core loaders now define stubs via Facets.rails_bridge. The first call
warns and names the file to require, loads the real file (replacing the
stub), and retries the call.

Requiring the file directly skips the stub and the warning, and methods
that are already defined, e.g. by ActiveSupport, are left alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2Njj4j1r9twkVcXsMySLW
@trans
trans merged commit 1da7a2d into main Sep 27, 2026
12 of 14 checks passed
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