Глобальные процедуры в Ruby, не действительно глобальные процедуры. Это методы, как и все остальное. В частности, когда вы определяете, что выглядит как глобальной процедурой, вы являетесь фактически, определяя метод частного экземпляра Object
. Поскольку каждый фрагмент кода в Ruby оценивается в контексте объекта, это позволяет использовать эти методы, как если бы они были глобальными процедурами, поскольку self
является приемником по умолчанию, а self
- это объект, класс которого наследуется от Object
.
Итак, это:
# file1.rb
def foo
puts 123
end
фактически эквивалентно
# file1.rb
class Object
private
def foo
puts 123
end
end
Теперь у вас есть "глобальный порядок" под названием foo
, которую можно назвать так же, как это:
foo
Причина причина почему вы можете так назвать, в том, что этот вызов фактически эквивалентно
self.foo
и self
это объект, который включает в себя Object
в своей родословной цепи, таким образом, он наследует частный foo
метод.
[Примечание: частные методы не могут быть вызваны явным приемником, , даже если, что явный приемник - self
. Таким образом, чтобы быть действительно педантичный, это фактически эквивалентно self.send(:foo)
и не self.foo
]
A.new.foo
в вашем file2.rb
является отвлекающим маневром:. Вы могли бы точно так же попробовать Object.new.foo
или [].foo
или 42.foo
и получить тот же результат ,
Кстати: puts
и require
сами примеры таких «глобальных процедуры», которые на самом деле являются частными методами на Object
(точнее, они являются частными методами на Kernel
, которые смешивают в Object
).
На заметка на поля: это действительно плохой стиль, чтобы положить вызовы require
внутри определения класса, потому что это делает его похожим на require
д кода какой-то образом контекстном или пространства имен внутри класса, который, конечно, неверно. require
просто запускает код в файле, не более того.
Таким образом, в то время как
# file2.rb
class A
require 'file1.rb'
end
совершенно правильный код, он также очень запутанный. Гораздо лучше использовать следующий, семантический эквивалентный, код:
# file2.rb
require 'file1.rb'
class A
end
Таким образом, совершенно ясен читателю коды, file1.rb
никоим образом не контекстный или пространство имен внутри A
.
Кроме того, как правило, предпочтительно оставить расширение файла, то есть использовать require 'file1'
вместо require 'file1.rb'
. Это позволяет заменить файл Ruby на, например, собственный код (для MRI, YARV, Rubinius, MacRuby или JRuby), байт-код JVM в файле .jar
или .class
(для JRuby), байтовый код CIL в файле .dll
(для IronRuby) и т. Д., Без необходимости изменять любые ваши вызовы require
.
Один последний комментарий: идиоматический способ обойти защиту доступа является использование send
, не instance_eval
, то есть использовать A.new.send(:foo)
вместо A.new.instance_eval {foo}
.
Вы попробовали 'A.new.instance_eval {foo}'? Это не работает для меня (ruby 1.9.2). – knut
Вы сбиваете с толку 'require with' include'? –
@knut я сделал. Оно работает. – alexloh