从模块中访问包含类的命名空间

我正在研究一个模块,除其他外,它将为你混合它的类添加一些通用的’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返回NSMutableStringHash.name返回NSMutableDictionaryObject.name返回NSObject 。 这样做的原因是MacRuby将Ruby运行时和Objective-C运行时集成为一个,并且因为Objective-C可变字符串的语义与Ruby字符串相同,所以Ruby的字符串类的整个实现基本上是一行: String = NSMutableString 。 由于MacRuby位于Objective-C之上,这意味着Objective-C首先启动,这意味着NSMutableString被插入到符号表中,这意味着它首先被Module#name