Что такое 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
метаклассом, виртуальным классом, одноэлементным классом или чем-то еще?
Ответы
Ответ 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
Возможно, не по имени, но вы сможете сказать, используя его, как любой массив, за исключением того, что вы можете передать ему аргументы командной строки. Попробуйте добавить что-то еще, чтобы увидеть, что происходит.