Class::new
и Class#new
одинаковы.
Как и методы new
в других классах (String.new
, Array.new
и т. Д.), Class.new
разрешается до Class#new
. Классы Ruby обычно не предоставляют свой собственный метод класса new
. Мы можем легко подтвердить это, заменив Class#new
:
String.new #=> ""
Array.new #=> []
Class.new #=> #<Class:0x00007fef2517f5e0>
class Class
def new(*args)
"it's me, Class#new"
end
end
String.new #=> "it's me, Class#new"
Array.new #=> "it's me, Class#new"
Class.new #=> "it's me, Class#new"
Исходная реализация Class#new
создает новый объект, вызывая метод allocate
получателя и вызывая метод initialize
этого объекта (передавая аргументы), что-то вроде:
class Class
def new(*args, &block)
obj = allocate
obj.send(:initialize, *args, &block)
obj
end
end
Итак, Class#new
- это простой шаблонный метод - фактическая работа выполняется allocate
и initialize
.
Мы можем определить разницу, проверив initialize
- ее владельцем является Class
для Class#initialize
, но BasicObject
для их экземпляров:
Class.instance_method(:initialize).owner
#=> Class
Class.new.instance_method(:initialize).owner
#=> BasicObject
Путаница проистекает из документации, которая показывает #initialize
как ::new
(что удобно, потому что мы обычно вызываем new
и редко, если вообще когда-либо, вызываем initialize
напрямую). Поэтому, если вы откроете документы для Class::new
и нажмете «toogle source» , вы посмотрите на реализацию для Class#initialize
(или rb_class_initialize
, как она вызывается в C)
Единственный известный мне класс, который фактически переопределяет метод класса new
, это Struct
, то есть Struct::new
:
Struct.method(:new).owner #=> #<Class:Struct>
Struct.method(:new).super_method #=> #<Method: Class#new>