我有一个内部有类的模块,但我发现如果不指定模块路径,内部类无法访问封闭模块中的任何方法。
另一种看待它的方法是 module_function 似乎没有带入类中。
例子:
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
Run Code Online (Sandbox Code Playgroud)
如果运行此命令,您会在“但是我不能...”行中收到错误:
undefined local variable or method `meaning'
Run Code Online (Sandbox Code Playgroud)
但是,如果删除整个文件周围的 MyMod 位,则访问外部方法就没有问题。
有没有一种简单的方法可以让这些访问而无需提供完整路径?
(我对不包含完整路径吹毛求疵的原因之一是因为我使用http://redshift.sourceforge.net/script/来创建我可以实例化的 ruby 脚本 - 而且它们没有清晰而简单的名称,例如“MyMod”,我可以将其添加到路径中,实际上我必须传递范围,即使它只是类的封闭范围)
我有一个模块,里面有一个类,
不,你不知道。您有一个模块定义,其中包含一个类定义,但这并不会使该类成为嵌套类。Ruby 没有嵌套类。
Ruby 不是Beta、Scala或Newspeak,Ruby 中没有嵌套类。
将模块或类定义嵌套在另一个模块或类定义内不会在两个类/模块之间创建嵌套关系。它仅使常量引用外部类/模块名称空间的类/模块部分。
换句话说,两者之间没有区别
module Foo
class Bar
end
end
Run Code Online (Sandbox Code Playgroud)
和
class Quux
end
module Foo
Bar = Quux
end
Run Code Online (Sandbox Code Playgroud)
仅嵌套常量,而不嵌套常量引用的对象。
但我发现如果不指定模块路径,内部类就无法访问封闭模块中的任何方法。
正是因为没有“封闭模块”。有一个词法封闭的模块定义,但不会在Foo类和模块之间创建任何形式的关系MyMod。
另一种看待它的方法是 module_function 似乎没有带入类中。
老实说,我不明白你的意思,“带入类”的方法意味着什么,但这Module#module_function不是魔法。它的作用完全按照文档所述:它采用模块的实例方法,将其复制为模块的单例类的实例方法,并生成原始实例方法private。
你可以在 Ruby/Spec 中阅读它的规范,它相当简单。此外,Rubinius源代码、用于启动 Rubinius 内核的基本版本和完整版本都具有相当的可读性。
最后,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
Run Code Online (Sandbox Code Playgroud)
如果运行此命令,您会在“但是我不能...”行中收到错误:
Run Code Online (Sandbox Code Playgroud)undefined local variable or method `meaning'
原因很简单:该类Foo及其任何超类都没有任何该名称的方法,因此您当然会遇到异常。
但是,如果删除整个文件周围的 MyMod 位,则访问外部方法就没有问题。
不存在“外法”。Ruby 没有类似 Beta 的嵌套类。这才是造成你误解的根本原因。您期望 Ruby 表现得像 Beta,但事实并非如此。Ruby 从任何语言中汲取灵感,最引人注目的是(按重要性的粗略顺序排列)Smalltalk、Lisp、Perl 和 Clu,但 Beta 并不在其中。
这在这里有一个完全不同的原因:
undefined local variable or method `meaning'
Run Code Online (Sandbox Code Playgroud)
在顶层定义的方法被隐式定义为 的私有实例方法Object。这是因为顶层的默认定义::Object是。由于Foo继承自Object,方法查找最终会找到meaning中定义的方法Object。
有没有一种简单的方法可以让这些访问而无需提供完整路径?
遗产。例如,Module#append_features由 调用Module#include,使该模块成为包含类的超类,因此该模块的所有实例方法都成为方法查找祖先链的一部分。
旁白:如果没有嵌套,那会Module::nesting做什么呢?嗯,是的,这是一个不幸命名的方法。术语“嵌套类”或“嵌套模块”在 OO 中具有明确定义的含义,可以一直追溯到 Beta。但这种方法是一种完全不同的嵌套:
它指的是模块定义的词法嵌套,而不是模块本身的嵌套。
例如,这些模块定义都定义了完全相同的模块,但定义文本具有不同的嵌套:
def meaning
42
end
class Foo
def initialize
meaning
end
end
Run Code Online (Sandbox Code Playgroud)
同样,这纯粹是模块定义的词法嵌套。模块本身没有嵌套;在所有这些情况下,模块本身都是相同的。这种嵌套仅影响常量查找。
常量首先在封闭的模块定义中按词法向外查找,然后在继承链中向上查找。
还有另一种情况可以嵌套:块创建嵌套的词法作用域,而所有其他词法作用域(脚本、模块/类定义和方法定义)不嵌套。换句话说,块和只有块可以访问self其封闭词法范围的局部变量(和)。