从模块中访问包含类的命名空间
我正在研究一个模块,除其他外,它将为你混合它的类添加一些通用的’finder’类型function。 问题:出于方便和美观的原因,我想在类之外包含一些function,与类本身在同一范围内。
例如:
class User include MyMagicMixin end # Should automagically enable: User.name('Bob') # Returns first user named Bob Users.name('Bob') # Returns ALL users named Bob User(5) # Returns the user with an ID of 5 Users # Returns all users
我可以在这些方法中做function,没问题。 案例1( User.name('Bob')
)很简单。 但是,案例2-4需要能够在User
之外创建新的类和方法。 Module.included
方法允许我访问该类,但不允许访问其包含的范围。 在Class和Module上没有简单的“父”类型方法。 (对于命名空间,我的意思是,不是超类,也不是嵌套模块。)
我能想到的最好方法是在类的#name
上进行一些字符串解析,以打破其命名空间,然后将字符串转换回常量。 但这看起来很笨拙,鉴于这是Ruby,我觉得应该有更优雅的方式。
有没有人有想法? 或者我只是为了自己的利益而过于聪明?
在您的示例中, User
只是一个指向Class
对象的常量。 当包含MyMagicMixin
时,您可以轻松创建另一个常量指针:
module MyMagicMixin class <
当然,这不能回答你是否应该做这样的事情。
我倾向于过于聪明。
即使有一个优雅的解决方案, 在类中包含一个模块在类外创建类似乎也很奇怪。
这是邮件列表中有时会出现的问题。 这也是Rails中出现的问题。 正如您所怀疑的那样,解决方案基本上是Regexp。
但是,还有一个更基本的问题:在Ruby中,类没有名称! 一个类就像任何其他对象一样。 您可以将它分配给实例变量,局部变量,全局变量,常量,甚至不将其分配给任何东西。 Module#name
方法基本上只是一个方便的方法,它的工作原理如下:它查找定义的常量列表,直到找到一个指向接收器的常量。 如果找到一个,则返回它可以找到的第一个,否则返回nil
。
所以,这里有两种失败模式:
a = Class.new a.name # => nil B = a B.name # => "B" A = B A.name # => "B"
- 一个类可能根本没有名字
- 一个类可能有多个名称,但
Module#name
只返回它找到的第一个Module#name
现在,如果有人试图调用As
获取A
的列表,他们会惊讶地发现该方法不存在,但他们可以调用Bs
来获得相同的结果。
这实际上确实发生在现实中。 在MacRuby中,例如String.name
返回NSMutableString
, Hash.name
返回NSMutableDictionary
, Object.name
返回NSObject
。 这样做的原因是MacRuby将Ruby运行时和Objective-C运行时集成为一个,并且因为Objective-C可变字符串的语义与Ruby字符串相同,所以Ruby的字符串类的整个实现基本上是一行: String = NSMutableString
。 由于MacRuby位于Objective-C之上,这意味着Objective-C首先启动,这意味着NSMutableString
被插入到符号表中,这意味着它首先被Module#name
。