代码之家  ›  专栏  ›  技术社区  ›  SFEley

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

  •  3
  • SFEley  · 技术社区  · 15 年前

    我正在开发一个模块,其中包括将一些通用的“finder”类型功能添加到您将其混合到的类中。问题:出于方便和美观的考虑,我想包含一些功能 外部 类,与类本身在同一范围内。

    例如:

    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
    

    我可以做这个功能 在内部 这些方法,没问题。案例1 User.name('Bob') 很容易。然而,案例2–4要求能够在外部创建新的类和方法 User . 这个 Module.included 方法允许我访问该类,但不能访问其包含范围。在类或模块上看不到简单的“parent”类型方法。(对于名称空间,我是说,不是超类,也不是嵌套模块。)

    我认为最好的方法是对类的 #name 将其名称空间拆分,然后将字符串转换回常量。但这看起来很笨拙,考虑到这是红宝石,我觉得应该有一个更优雅的方式。

    有人有主意吗?还是我太聪明了?

    3 回复  |  直到 15 年前
        1
  •  1
  •   James A. Rosen    15 年前

    在你的例子中, User 只是一个常数,指向 Class 对象。您可以轻松创建 另一个 MyMagicMixin 包括:

    module MyMagicMixin
      class <<self
        def self.included(klass)
          base.extend MyMagicMixin::ClassMethods
          create_pluralized_alias(klass)
        end
    
        private
    
        def create_pluralized_alias(klass)
          fq_name = klass.to_s
          class_name = fq_name.demodulize
          including_module = fq_name.sub(Regexp.new("::#{class_name}$", ''))
          including_module = including_module.blank? ? Object : including_module.constantize
          including_module.const_set class_name.pluralize, klass
        end
      end
    
      module ClassMethods
        # cass methods here
      end
    end
    

    当然这不能回答你 应该 做这样的事。

        2
  •  3
  •   jrallison    15 年前

    我倾向于太聪明。

    即使有一个优雅的解决方案,包含一个模块似乎也很奇怪 里面 创建类的类 外部 全班同学。

        3
  •  2
  •   Jörg W Mittag    15 年前

    这个问题有时会出现在邮件列表中。这也是rails中出现的一个问题。解决方案是,正如您已经怀疑的,基本上是regexp咀嚼。

    然而,还有一个更基本的问题:在ruby中,类没有名字!类和其他类一样只是一个对象。你可以把它赋给一个实例变量,一个局部变量,一个全局变量,一个常量,甚至不把它赋给任何东西 完全 . 这个 Module#name 方法基本上只是一个方便的方法,其工作方式如下:它查看已定义常量的列表,直到找到指向接收器的常量。如果它找到一个,它会返回它能找到的第一个,否则它会返回 nil .

    这里有两种失效模式:

    a = Class.new
    a.name # => nil
    B = a
    B.name # => "B"
    A = B
    A.name # => "B"
    
    • 类可能根本没有名称
    • 一个类可能有多个名称,但是 模块名 只会返回找到的第一个

    如果有人打电话来 As 获取 A 他们会很惊讶地发现这个方法不存在,但是他们可以调用 Bs 而是得到同样的结果。

    这个 实际上发生在现实中。例如,在macruby中 String.name 收益率 NSMutableString , Hash.name 收益率 NSMutableDictionary Object.name 收益率 NSObject . 原因是macruby将ruby运行时和objective-c运行时集成为一个,并且由于objective-c可变字符串的语义与ruby字符串相同,ruby的string类的整个实现本质上是一行: String = NSMutableString . 由于macruby位于objective-c之上,这意味着objective-c首先启动,这意味着 可修改的字符串 首先插入到符号表中,这意味着它将 建立 首先由 模块名 .

    推荐文章