Project

General

Profile

Actions

Bug #20871

closed

Including methods in Enumerable doesn't make them available in Array

Added by sanderd17 (Sander Deryckere) 13 days ago. Updated about 14 hours ago.

Status:
Feedback
Assignee:
-
Target version:
-
[ruby-core:119751]

Description

Today, our CI pipeline started failing after the automatic update from v3.3.5 to v3.3.6.

After researching, it turned out that our core extensions to the Array class weren't loaded anymore.

The core-extensions code looks like this:


module CoreExt
  module Enumerable
    def average
      sum(&:to_f) / count if any?
    end

    # def ...
  end
end

Enumerable.include CoreExt::Enumerable

After some debugging, it turned out that the average method was included in the instance_methods of Enumerable, but not in the instance_methods of Array.

Explicitly adding Array.include CoreExt::Enumerable fixes CI for our case.

The very strange thing is that it only happens on a release branch we are still maintaining. It doesn't happen on our main development branch (which also updated to v3.3.6 today). I have been unable to find the difference between both branches so far (they diverged a couple of months ago, but the base system is still regularly updated on both, and pretty similar).

After some digging around, I assume this commit is related to our issue: https://github.com/ruby/ruby/commit/edeb0319f7a95dfe3f9b895bcf32371dd8514726

Updated by sanderd17 (Sander Deryckere) 13 days ago

Forgot to mention.

We use the parallel_tests gem to speed up our specs in CI.

On my local environment, with synchronous tests, I haven't been able to reproduce the same behaviour either.

Updated by jeremyevans0 (Jeremy Evans) about 18 hours ago

  • Status changed from Open to Feedback

The example works as expected on Ruby 3.3.6. It seems unlikely the commit you are referencing is related, because the commits fixes an issue where the method cache is not updated on a change, it wouldn't cause the method not to show up at all. Are you able to provide a self-contained reproducible example for this issue?

Updated by rolf (Rolf T) about 16 hours ago · Edited

We are running into the exact same problem. I was not able to reproduce it except as part of a Rails application. Maybe that's not exactly helpful, but hopefully this helps zoom in further on the issue. The problem seems to be introduced in Ruby 3.3.6.

A working reproduction is here: https://github.com/rolftimmermans/ruby-20871

module Ext
  def foo
    "foo"
  end
end

Enumerable.include(Ext)

With Ruby 3.3.6 via irb there seems to be no issue:

% irb                    
irb(main):001> RUBY_VERSION
=> "3.3.6"
irb(main):002> require_relative "lib/ext"
=> true
irb(main):003> [].foo
=> "foo"

With Ruby 3.3.6 via Rails console the bug manifests itself:

% rails c
Loading development environment (Rails 7.1.5)
irb(main):001> RUBY_VERSION
=> "3.3.6"
irb(main):002> require_relative "lib/ext"
=> true
irb(main):003> [].foo
(irb):3:in `<main>': undefined method `foo' for an instance of Array (NoMethodError)

[].foo
  ^^^^

With Ruby 3.3.5 via Rails console everything is working fine:

% rails c     
/Users/rolftimmermans/.rubies/ruby-3.3.5/lib/ruby/3.3.0/json/generic_object.rb:2: warning: /Users/rolftimmermans/.rubies/ruby-3.3.5/lib/ruby/3.3.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.
Loading development environment (Rails 7.1.5)
irb(main):001> RUBY_VERSION
=> "3.3.5"
irb(main):002> require_relative "lib/ext"
=> true
irb(main):003> [].foo
=> "foo"

Updated by rolf (Rolf T) about 14 hours ago · Edited

I managed to narrow it down a bit further. With the versions specified in https://github.com/rolftimmermans/ruby-20871/blob/main/Gemfile.lock:

% irb
irb(main):001> require "active_support"
irb(main):002> require "active_support/json/decoding"
irb(main):003> 
irb(main):004* class Foo
irb(main):005*   include Enumerable
irb(main):006> end
irb(main):007> 
irb(main):008* module Ext
irb(main):009*   def foo
irb(main):010*     "foo"
irb(main):011*   end
irb(main):012> end
irb(main):013> 
irb(main):014> Enumerable.include(Ext)
irb(main):015> 
=> Enumerable
irb(main):016> [].foo
(irb):16:in `<main>': undefined method `foo' for an instance of Array (NoMethodError)

[].foo
  ^^^^
	from <internal:kernel>:187:in `loop'
	from /Users/rolftimmermans/.gem/ruby/3.3.6/gems/irb-1.14.1/exe/irb:9:in `<top (required)>'
	from /Users/rolftimmermans/.rubies/ruby-3.3.6/bin/irb:25:in `load'
	from /Users/rolftimmermans/.rubies/ruby-3.3.6/bin/irb:25:in `<main>'
Actions

Also available in: Atom PDF

Like1
Like0Like0Like0Like1