Ruby导入的方法总是私有的吗?
最好用一个例子来说明这一点: file1.rb:Ruby导入的方法总是私有的吗?,ruby,visibility,require,public,access-specifier,Ruby,Visibility,Require,Public,Access Specifier,最好用一个例子来说明这一点: file1.rb: def foo puts 123 end module IncludesFoo def foo puts 123 end end file2.rb: class A require 'file1' end A.new.foo require 'file1.rb' class A include IncludesFoo end A.new.foo # => 123 将给出一个错误“':调用了私有方法“f
def foo
puts 123
end
module IncludesFoo
def foo
puts 123
end
end
file2.rb:
class A
require 'file1'
end
A.new.foo
require 'file1.rb'
class A
include IncludesFoo
end
A.new.foo
# => 123
将给出一个错误“':调用了私有方法“foo”
我可以通过执行A.new.send(“foo”)
来解决这个问题,但是有没有办法将导入的方法公开
编辑:为了澄清,我并不混淆包含和要求。另外,我不能使用普通包含(正如许多人正确指出的那样)的原因是,这是元编程设置的一部分。我需要允许用户在运行时添加功能;例如,他可以说“运行这个应用程序——包括file1.rb”,根据他在file1.rb中编写的代码,这个应用程序的行为会有所不同。对不起,我应该解释得更清楚些
编辑:在阅读了Jorg的答案后,我意识到我的代码并没有完全按照预期的那样运行,他完美地回答了我的(误导的)问题。我正在尝试做一些更类似于
str=(将整个file1.rb作为字符串)的事情;A.class\u exec(str)
在Ruby中这样做是不好的。尝试通过模块使用mixin:
file1.rb:
def foo
puts 123
end
module IncludesFoo
def foo
puts 123
end
end
file2.rb:
class A
require 'file1'
end
A.new.foo
require 'file1.rb'
class A
include IncludesFoo
end
A.new.foo
# => 123
Ruby中的全局过程并不是真正的全局过程。它们是方法,就像其他任何东西一样。特别是,当您定义看起来像全局过程的内容时,实际上是在定义
Object
的私有实例方法。由于Ruby中的每一段代码都是在对象的上下文中进行计算的,因此您可以像使用全局过程一样使用这些方法,因为self
是默认的接收者,self
是其类继承自object
的对象
那么这个,
# file1.rb
def foo
puts 123
end
实际上相当于
# file1.rb
class Object
private
def foo
puts 123
end
end
self.foo
现在您有了一个名为foo
的“全局过程”,您可以这样调用它:
foo
你之所以可以这样称呼它,是因为这个称呼实际上相当于
# file1.rb
class Object
private
def foo
puts 123
end
end
self.foo
而self
是在其祖先链中包含object
的对象,因此它继承了私有foo
方法
[注意:准确地说,私有方法不能用显式接收器调用,即使显式接收器是self
。因此,要真正学究,它实际上等同于self.send(:foo)
,而不是self.foo
]
您的文件2.rb
中的A.new.foo
是一个麻烦:您不妨尝试Object.new.foo
或[].foo
或42.foo
并获得相同的结果
顺便说一句:put
和require
本身就是这种“全局过程”的例子,它们实际上是对象
上的私有方法(或者更准确地说,它们是内核
上的私有方法,混合在对象
中)
另一方面:在类定义中调用require
,这是一种非常糟糕的风格,因为它使require
d代码看起来像是在类中以某种方式限定了作用域或名称空间,这当然是错误的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'
。这允许您使用本地代码(用于MRI、YARV、Rubinius、MacRuby或JRuby)、.jar
或.class
文件中的JVM字节代码(用于JRuby)、.dll
文件中的CIL字节代码(用于IronRuby)等替换Ruby文件,而无需更改任何require
调用
最后一点意见:规避访问保护的惯用方法是使用
send
,而不是instance\u eval
,即使用A.new.send(:foo)
而不是A.new.instance\u eval{foo}加载(“文件1”,A)
?()您是否尝试了A.new.instance_eval{foo}
?它对我不起作用(ruby 1.9.2)。你把require和include`混淆了吗?@andrewgrim不幸的是没有。我正在寻找一种廉价的方法来动态扩展程序。整个应用程序相当复杂,但基本上字符串“file1.rb”来自用户输入。“file1.rb”及其内容都来自用户输入,并动态加载。基本上,用户可以在运行时输入路径,应用程序将加载适当的ruby文件,该文件将更改现有功能,而无需重新启动等。抱歉,应该让这更清楚。谢谢!这个答案真的很完整,消除了我的误解——要求像C一样包含复制粘贴的文本。有没有办法将file1.rb的内容动态添加为类a的方法?file1的内容和位置仅在运行时已知,用户不知道。或者我可以找到文件中定义的方法或模块列表吗?