Ruby 3.0 changes how methods of subclassed core classes work.
First of all, most likely you shouldn’t inherit from Ruby’s core classes. But if you still want to do it, it’s better to know what was changed in Ruby 3.0.
Before Ruby 3.0 return values of core classes methods like e.g
Array#rotate were inconsistent. Here’s what I mean:
class Foo < Array
foo = Foo.new
foo.rotate.class # => Array
class Bar < String
bar = Bar.new
bar.upcase.class # => Bar
As you can see in the first example
Foo#rotate returns the instance of Array class and
Bar#upcase returns the instance of Bar class. Personally, I'd prefer if Ruby would always return an instance of subclass but if you check this discussion it becomes pretty clear that it's hard to make it work properly for all cases and it's better to always return an instance of the original class.
So that’s what was done in Ruby 3.0! You can check these Pull Requests here and here with the changes. Now all
Array methods always return instances of the original class, not the subclass.
The way I learned about this change was failing Enumerize build. Enumerize is a gem for enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper/Sequel support. And a class that powers enumerated value is a subclass of String core class. So before you could just write something like
user.role # => admin'role = user.role.upcase # => 'ADMIN'
role.class # => Enumerize::Value
where the role is an enumerated field, you would get upcased value of
Enumerize::Value instance. But with Ruby 3.0 changes it becomes
String instance. It means you can't use any
Enumerize methods on that value anymore. It's not a big deal in terms of
Enumerize usage since in most cases you don't apply any String's methods on it but would be good to make it not depend on the fact that
Enumerize::Value is a subclass of Ruby's