为什么模块内部的 ruby 类 不能具有与常规 类 相同的作用域?
Why can't ruby classes inside modules have the same scope as regular classes?
我有一个内部有 class 的模块,但我发现如果不指定模块路径,内部的 class 无法访问封闭模块中的任何方法。
另一种看待它的方式是 module_function 似乎没有带入 class。
示例:
module MyMod
def meaning
42
end
class Foo
def initialize
puts "New Foo"
puts "I can call #{MyMod.meaning} from here"
puts "But I can't get to #{meaning} from here"
end
end
def go
puts "I can get to #{meaning} from here"
bar = Foo.new
end
module_function :go, :meaning
go
end
如果你运行这个,你会在“但我不能...”行中得到一个错误:
undefined local variable or method `meaning'
但是如果去掉整个文件周围的MyMod位,访问外层方法就没有问题了。
是否有一种无需提供完整路径即可访问这些内容的简单方法?
(我挑剔不包括完整路径的原因之一是因为我正在使用 http://redshift.sourceforge.net/script/ 来创建我可以实例化的 ruby 脚本 - 但它们不会有一个清晰简单的名称,如 'MyMod',我可以将其添加到路径中,实际上我必须传递范围,即使它只是 class)
的封闭范围
由于 Ruby 名称解析和方法查找的方式有效。当您在任何地方写 x
时,Ruby 将按以下顺序:
寻找一个x
局部变量
在self.class
中寻找x
方法
在self.superclass
中寻找x
方法
重复步骤 3 直到 superclass
为 nil
Ruby 将在 class 层级中向上移动
试图找到方法 x
直到达到 BasicObject
.
调用method_missing
它的默认行为是引发您遇到的错误。
MyMod
仅包含 Foo
,它不是 Foo
的 class 层次结构的一部分。这就是找不到方法的原因。
I have a module with a class inside,
不,你不知道。您有一个模块 definition,里面有 class definition,但是 不会使 class 一个嵌套的 class。 Ruby 没有嵌套 classes.
Ruby不是Beta, Scala, or Newspeak,Ruby.
中没有嵌套的class
嵌套模块或 class 定义 到另一个模块或 class 定义中 不会 创建嵌套关系在两个 classes / 模块之间。它只会使 常量 引用外部 class/ 模块命名空间的 class / 模块部分。
也就是说
没有区别
module Foo
class Bar
end
end
和
class Quux
end
module Foo
Bar = Quux
end
只嵌套常量,不常量引用的对象
but I find that the class inside can't reach any of the methods in the enclosing module without specifying the module path.
正是因为没有“封闭模块”。有一个词法封闭模块定义,但不在[之间创建任何形式的关系=16=] class 和 MyMod
模块。
Another way to look at it is that the module_function doesn't seem to carry into the class.
老实说,我不明白你的意思,一个方法“携带到 class”是什么意思,但是 Module#module_function
is not magic. It does exactly what the documentation says it does: it takes an instance method of the module, copies it as an instance method of the singleton class of the module, and makes the original instance method private
.
你可以阅读 its specification in the Ruby/Spec, it is fairly simple. Also, the Rubinius source code, both the basic version for booting the Rubinius kernel and the full version 相当可读。
最后,Module#module_function
确实比
做的不多
class Module
def module_function(*meths)
meths.each do |meth|
define_singleton_method(meth, &instance_method(meth).bind(self))
private meth
end
self
end
end
If you run this, you get an error on the "But I can't..." line of:
undefined local variable or method `meaning'
原因很简单:class Foo
及其任何超classes 都没有该名称的任何方法,所以 当然 你得到一个例外。
But if you remove the MyMod bits around the whole file, it has no problem accessing the outer method.
没有“外法”。 Ruby 没有类似 Beta 的嵌套 classes。这才是你误会的根本原因。您希望 Ruby 表现得像 Beta,但事实并非如此。 Ruby 从任何语言中汲取灵感,最值得注意的是(按重要性大致排序)Smalltalk、Lisp、Perl 和 Clu,但 Beta 不在其中。
这在这里工作的原因完全不同:
def meaning
42
end
class Foo
def initialize
meaning
end
end
在顶层定义的方法隐式定义为 Object
. This is because the 的私有实例方法。由于Foo
继承自Object
,方法查找最终会找到Object
中定义的meaning
方法。
Is there an easy way to make these accessible without having to give the full path?
继承。例如,Module#append_features
, which is called by Module#include
使模块成为包含 class 的超级 class,因此模块的所有实例方法都成为方法查找祖先链的一部分。
旁白:如果没有嵌套,那么 Module::nesting
有什么作用?嗯,是的,这是一个不幸的命名方法。术语“嵌套 class”或“嵌套模块”在 OO 中具有明确定义的含义,一直追溯到 Beta。但是这种方法是关于一种完全不同的嵌套:
指模块definitions的lexical嵌套,not嵌套模块 本身 .
例如,这些模块定义都定义了完全相同的模块,但是定义text有不同的嵌套:
module Foo
module Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar, Foo]
end
end
end
end
module Foo
module Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar, Foo]
end
end
end
module Foo
module Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo]
end
end
end
module Foo::Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar]
end
end
end
module Foo
module Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo]
end
end
module Foo::Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz]
end
end
module Foo::Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar]
end
end
module Foo::Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux]
end
同样,这纯粹是词法模块定义的嵌套。模块本身没有嵌套;在所有这些情况下,模块本身都是相同的。这种嵌套 仅 影响 常量查找 。
查找常量 ,然后 向上 继承链。
还有一个可以嵌套的实例:blocks create nested 词法作用域,而所有其他词法作用域(脚本,模块/class定义,和方法定义)不要嵌套。换句话说,块和 只有块 可以访问其封闭词法范围的局部变量(和 self
)。
我有一个内部有 class 的模块,但我发现如果不指定模块路径,内部的 class 无法访问封闭模块中的任何方法。
另一种看待它的方式是 module_function 似乎没有带入 class。
示例:
module MyMod
def meaning
42
end
class Foo
def initialize
puts "New Foo"
puts "I can call #{MyMod.meaning} from here"
puts "But I can't get to #{meaning} from here"
end
end
def go
puts "I can get to #{meaning} from here"
bar = Foo.new
end
module_function :go, :meaning
go
end
如果你运行这个,你会在“但我不能...”行中得到一个错误:
undefined local variable or method `meaning'
但是如果去掉整个文件周围的MyMod位,访问外层方法就没有问题了。
是否有一种无需提供完整路径即可访问这些内容的简单方法?
(我挑剔不包括完整路径的原因之一是因为我正在使用 http://redshift.sourceforge.net/script/ 来创建我可以实例化的 ruby 脚本 - 但它们不会有一个清晰简单的名称,如 'MyMod',我可以将其添加到路径中,实际上我必须传递范围,即使它只是 class)
的封闭范围由于 Ruby 名称解析和方法查找的方式有效。当您在任何地方写 x
时,Ruby 将按以下顺序:
寻找一个
x
局部变量在
中寻找self.class
x
方法在
中寻找self.superclass
x
方法重复步骤 3 直到
superclass
为nil
Ruby 将在 class 层级中向上移动 试图找到方法
x
直到达到BasicObject
.调用
method_missing
它的默认行为是引发您遇到的错误。
MyMod
仅包含 Foo
,它不是 Foo
的 class 层次结构的一部分。这就是找不到方法的原因。
I have a module with a class inside,
不,你不知道。您有一个模块 definition,里面有 class definition,但是 不会使 class 一个嵌套的 class。 Ruby 没有嵌套 classes.
Ruby不是Beta, Scala, or Newspeak,Ruby.
中没有嵌套的class嵌套模块或 class 定义 到另一个模块或 class 定义中 不会 创建嵌套关系在两个 classes / 模块之间。它只会使 常量 引用外部 class/ 模块命名空间的 class / 模块部分。
也就是说
没有区别module Foo
class Bar
end
end
和
class Quux
end
module Foo
Bar = Quux
end
只嵌套常量,不常量引用的对象
but I find that the class inside can't reach any of the methods in the enclosing module without specifying the module path.
正是因为没有“封闭模块”。有一个词法封闭模块定义,但不在[之间创建任何形式的关系=16=] class 和 MyMod
模块。
Another way to look at it is that the module_function doesn't seem to carry into the class.
老实说,我不明白你的意思,一个方法“携带到 class”是什么意思,但是 Module#module_function
is not magic. It does exactly what the documentation says it does: it takes an instance method of the module, copies it as an instance method of the singleton class of the module, and makes the original instance method private
.
你可以阅读 its specification in the Ruby/Spec, it is fairly simple. Also, the Rubinius source code, both the basic version for booting the Rubinius kernel and the full version 相当可读。
最后,Module#module_function
确实比
class Module
def module_function(*meths)
meths.each do |meth|
define_singleton_method(meth, &instance_method(meth).bind(self))
private meth
end
self
end
end
If you run this, you get an error on the "But I can't..." line of:
undefined local variable or method `meaning'
原因很简单:class Foo
及其任何超classes 都没有该名称的任何方法,所以 当然 你得到一个例外。
But if you remove the MyMod bits around the whole file, it has no problem accessing the outer method.
没有“外法”。 Ruby 没有类似 Beta 的嵌套 classes。这才是你误会的根本原因。您希望 Ruby 表现得像 Beta,但事实并非如此。 Ruby 从任何语言中汲取灵感,最值得注意的是(按重要性大致排序)Smalltalk、Lisp、Perl 和 Clu,但 Beta 不在其中。
这在这里工作的原因完全不同:
def meaning
42
end
class Foo
def initialize
meaning
end
end
在顶层定义的方法隐式定义为 Object
. This is because the Foo
继承自Object
,方法查找最终会找到Object
中定义的meaning
方法。
Is there an easy way to make these accessible without having to give the full path?
继承。例如,Module#append_features
, which is called by Module#include
使模块成为包含 class 的超级 class,因此模块的所有实例方法都成为方法查找祖先链的一部分。
旁白:如果没有嵌套,那么 Module::nesting
有什么作用?嗯,是的,这是一个不幸的命名方法。术语“嵌套 class”或“嵌套模块”在 OO 中具有明确定义的含义,一直追溯到 Beta。但是这种方法是关于一种完全不同的嵌套:
指模块definitions的lexical嵌套,not嵌套模块 本身 .
例如,这些模块定义都定义了完全相同的模块,但是定义text有不同的嵌套:
module Foo
module Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar, Foo]
end
end
end
end
module Foo
module Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar, Foo]
end
end
end
module Foo
module Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo]
end
end
end
module Foo::Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar]
end
end
end
module Foo
module Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo]
end
end
module Foo::Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz]
end
end
module Foo::Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar]
end
end
module Foo::Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux]
end
同样,这纯粹是词法模块定义的嵌套。模块本身没有嵌套;在所有这些情况下,模块本身都是相同的。这种嵌套 仅 影响 常量查找 。
查找常量
还有一个可以嵌套的实例:blocks create nested 词法作用域,而所有其他词法作用域(脚本,模块/class定义,和方法定义)不要嵌套。换句话说,块和 只有块 可以访问其封闭词法范围的局部变量(和 self
)。