Skip to content

Facets 4.0.0

Latest

Choose a tag to compare

@trans trans released this 27 Sep 23:43
· 2 commits to main since this release
c0f9429

A major release, because it changes behavior: Kernel#try! is now
the lenient variant and #try is strict, require 'facets' no longer
loads Kernel#with, and non-core "Railisms" move to the new lib/rails
area (still loaded by require 'facets' with a warning until 2027-09-30).
Every deprecation now names that same removal date.

Changes:

  • Breaking

    • Kernel#try! now returns nil when the receiver doesn't respond to the
      method (or it is private), instead of raising NoMethodError. #try
      stays strict. This is deliberately the opposite of ActiveSupport, which
      since Rails 4.0 makes #try lenient and #try! strict. In Ruby the bang
      marks the more dangerous method, and quietly ignoring a missing method is
      the dangerous behavior. The docs no longer claim ActiveSupport
      compatibility.
    • require 'facets' no longer loads Kernel#with, since a global with
      breaks other libraries' methods of that name, such as RSpec's
      receive(...).with (#290). It is still available, deprecated, with
      require 'facets/kernel/with'.
    • Kernel#try no longer calls private methods. It now behaves exactly like
      a normal call or &., raising NoMethodError for them.
  • Enhancements

    • New lib/rails library for Rails-compatible methods that Facets carries
      but doesn't endorse as its own: Hash#symbolize_keys/#stringify_keys,
      Hash#to_options, Hash#slice!, Array#extract_options!,
      Module#mattr_*/#cattr_*, File.atomic_write and the facets/date
      extensions. Require paths are unchanged (require 'facets/hash/slice'
      still works), and require 'facets' still provides the same methods.
  • Deprecations

    • require 'facets' will stop providing the lib/rails methods after
      2027-09-30. Until then, the first call to one of them through
      require 'facets' warns and names the file to require. Requiring that
      file directly avoids the warning.
    • Kernel#returning, Module#alias_method_chain, Array#uniq_by!,
      Enumerable#uniq_by, Kernel#silence_stream and Facets' fallback
      Time#to_time are scheduled for removal after 2027-09-30. Each warns
      with its replacement and the removal date.
    • Every existing deprecation now names a removal date, 2027-09-30, in its
      @deprecated note and its warning. String#upper_camelcase/
      #lower_camelcase, Kernel#equate?, facets/kernel/tee and
      Interval#each(n, d) were deprecated in docs only (or "will be") and
      now warn as well.
    • Kernel#with is deprecated in favor of instance_eval, also for removal
      after 2027-09-30. Rails 7.1's unrelated Object#with (which temporarily
      sets attributes) was silently replaced by it when both were loaded.
    • Kernel#silence now does the stream silencing itself; silently,
      silence_stderr and silence_stdout use it and do not warn.
  • Bug Fixes

    • Hash#to_options and #to_options! now exist. facets/hash/to_options
      only loaded symbolize_keys and never defined the aliases.
    • Module#alias_module_function now aliases the singleton method directly.
      On JRuby, the singleton method module_function created turned private
      when aliased again, which broke URI.hash_to_query under the test suite.
    • Dir.recurse and Dir.ls_r once again return an Array that leaves out
      the starting directory. Deprecating them in favor of Dir.find had
      quietly changed both.
    • Enumerable::Argumentable#min and #max now pass their arguments to
      #each, as documented, rather than to Ruby's own min(n)/max(n).
    • String#similarity now divides the shared length by the longer string's
      length, not length + 1, so 9 of 10 matching characters score 0.9 as its
      docs said (it gave 0.818). Scores for non-identical strings rise slightly.
    • require 'facets' no longer crashes on Ruby 4.1, which removed
      ObjectSpace._id2ref. ObjectSpace[] is only defined where _id2ref
      exists.
    • Kernel#silence now supports :verbose/:warnings and :debug, as its
      docs always said, instead of raising NoMethodError. They set $VERBOSE
      to nil and $DEBUG to false within the block.
  • Internal

    • Run the qed demos in CI.
    • Remove leftover build files that nothing reads anymore: MANIFEST,
      Assembly (Detroit), .index, Indexfile and lib/core/facets.yml.
      The Rakefile takes its version from Facets::VERSION (.index still said
      3.1.1), and rake package no longer needs the mast and index tools.
    • The gemspec reads its version from Facets::VERSION, so the version now
      lives in one place, lib/core/facets/version.rb.
    • Fix the qed demos, which had 8 failures and 2 errors. Most were stale
      expectations (Array#from, #step, #arrange, String#similarity)
      and the date demo held pasted irb output.
    • CONTRIBUTING.md explains the test stack (RubyTest, Lemon, AE and QED)
      and the @uncommon convention.
    • The String#trim demo no longer drops random cases, so the QED
      assertion count is the same on every run.