Подтвердить что ты не робот

Что такое ARGF.class в Ruby 1.9?

В Ruby 1.8.7 документация не отображает ARGF под классы и модули, а ARGF не является классом или модуль:

ARGF.class # => Object

В Ruby 1.9.3 документация имеет ARGF под классами и модулями, но я вижу это:

ARGF.class # => ARGF.class
ARGF.superclass # => NoMethodError: undefined method `superclass' for ARGF:ARGF.class
ARGF.class.superclass # => Object
  • Почему документация Ruby 1.9 размещает ARGF как класс, когда фактический класс - это что-то еще? Или это одно и то же?
  • Является ли ARGF.class метаклассом, виртуальным классом, одноэлементным классом или чем-то еще?
4b9b3361

Ответ 1

ARGF реализован в C, и вы можете делать в нем странные вещи. Класс ARGF определяется там первым. Он не задан ни одной константой в Ruby, но его имя имеет значение "ARGF.class". Тогда константа ARGF устанавливается в экземпляр этого класса.

rb_cARGF = rb_class_new(rb_cObject);
rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
/* ... */
argf = rb_class_new_instance(0, 0, rb_cARGF);
rb_define_global_const("ARGF", argf);

Вот код Ruby, который делает примерно то же самое.

argf_class = Class.new
def argf_class.name
  "ARGF.class"
end
argf = argf_class.new
ARGF = argf

Это не выглядит разумным в Ruby, но в C это нормально. Хотя, я думаю, класс может быть установлен в ARGFClass как NilClass, TrueClass, FalseClass, так что это не путает.

Я не знаю историю изменений. Я думаю, что люди Ruby Core хотели получить ARGF в документах, и это был самый простой способ. (RDoc не может показывать документацию для одиночных объектов.)

Ответ 2

Кажется правильным, что ARGF не является классом или модулем.

class ARGF
end
# => TypeError: ARGF is not a class

module ARGF
end
# => TypeError: ARGF is not a module

В документации перечислены ARGF под классом, но кроме этого, он не говорит, что это класс. Вероятно, не предполагалось, что ARGF обрабатывается как класс, и неверно, чтобы документация была указана как таковая. Это ошибка документации.

Он выглядит как ARGF, если единственный экземпляр определенного класса, которому не хватает литерала, и единственный способ ссылаться на него - вызвать ARGF.class.

ARGF.class.class
# => Class

ARGF.class.ancestors
# => [ARGF.class, Enumerable, Object, Kernel, BasicObject]

Обычное отношение между классом и его экземпляром выполняется для ARGF.class и ARGF.

ARGF.is_a?(ARGF.class)
# => true

ARGF.kind_of?(ARGF.class)
# => true

Ответ 3

Если мы захватим объекты и посмотрим на них, используя только чистый Ruby, мы увидим несколько вещей:

1.9.3 (Object#main):0 > ARGFClass = ARGF.class                                                                                                                                      
=> ARGF.class
1.9.3 (Object#main):0 > ARGFClass.name                                                                                                                                              
=> "ARGF.class"
1.9.3 (Object#main):0 > ARGFClass.class                                                                                                                                             
=> Class
1.9.3 (Object#main):0 > ARGFClass.superclass                                                                                                                                        
=> Object
1.9.3 (Object#main):0 > ARGFClass.ancestors                                                                                                                                         
=> [ARGF.class,
    Enumerable,
    Object,
    JSON::Ext::Generator::GeneratorMethods::Object,
    PP::ObjectMixin,
    Kernel,
    BasicObject]

По какой-то причине разработчики явно установили значение class.name для возврата ARGF.class, что обычно является необычным, но используется внутри Ruby для констант, к которым никогда не следует обращаться напрямую.

Мы можем создавать объекты с ARGFClass точно так же, как и любой другой класс. Это означает, что это настоящий класс Ruby:

1.9.3 (Object#main):0 > argfinstance = ARGFClass.new                                                                                                                                
=> ARGF
1.9.3 (Object#main):0 > argfinstance.inspect                                                                                                                                        
=> "ARGF"

Он не просто возвращает синглтон при вызове #new:

1.9.3 (Object#main):0 > argfinstance == ARGF                                                                                                                                        
=> false
1.9.3 (Object#main):0 > argfinstance.object_id                                                                                                                                      
=> 70346556507420
1.9.3 (Object#main):0 > ARGF.object_id                                                                                                                                              
=> 70346552343460

Разработчики Ruby намеренно назвали ARGF.class таким образом, что на него нельзя ссылаться напрямую по имени, но он является реальным классом, а ARGF является реальным объектом.

Он имеет множество тех же методов, что и объект ввода-вывода, и фактически определен в исходном файле io.c. Он также имеет смешанный модуль Enumerable, поэтому он поддерживает все функциональные возможности каждого/инъекции/карты.

edit: В документации есть список ARGF как класс. Тем не менее, на самом деле это константа, ссылающаяся на экземпляр singleton класса с нечетным именем ARGF.class.

Ссылки

Ответ 4

ARGF - это класс Array. см. примеры https://github.com/DouglasAllen/Ruby_core_ri_doc/tree/master/ARGF Возможно, не по имени, но вы сможете сказать, используя его, как любой массив, за исключением того, что вы можете передать ему аргументы командной строки. Попробуйте добавить что-то еще, чтобы увидеть, что происходит.