Ruby导入的方法总是私有的吗?

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

最好用一个例子来说明这一点:

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
将给出一个错误“':调用了私有方法“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的内容和位置仅在运行时已知,用户不知道。或者我可以找到文件中定义的方法或模块列表吗?