微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ruby – 如何在特征类中使模块常量也可见?

我创建了一个包含常量NAME和方法hello的模块.如果类包含模块,则两个定义应在不同范围内可见.

module A
  NAME = 'otto'
  def self.included(base)
    base.extend(ClassMethods)
  end

  def hello(name = 'world')
    self.class.hello(name)
  end

  module ClassMethods
    def hello(name = 'world')
      "Hello #{name}!"
    end
  end
end

class B
  include A

  def instance_scope
    p [__method__,hello(NAME)]
  end

  def self.class_scope
    p [__method__,hello(NAME)]
  end

  class << self
    def eigen_scope
      p [__method__,hello(NAME)]
    end
  end
end

B.new.instance_scope
B.class_scope
B.eigen_scope

#=> script.rb:34:in `eigen_scope': uninitialized constant Class::NAME (NameError)
    from script.rb:41

但是该常量在本征类的实例方法范围中是不可见的,类<<自. 有没有办法使模块更健壮,并在上面的错误范围内提供常量?

解决方法

class << self
  def eigen_scope
    p [__method__,hello(self::NAME)]
    #=> [:eigen_scope,"Hello otto!"]
  end
end

为什么self :: NAME有效?

> A :: NAME将是最简单的硬编码版本.
> B :: NAME也可以,因为B包括A.
>在eigen_scope里面,self是B,所以self :: NAME也可以
> self :: NAME也可以在self.class_scope中使用
> self :: NAME在instance_scope中不起作用:B实例不是类/模块.

为什么NA​​ME不起作用?

Here一个非常好的解释.

constant lookup searches for constants that are defined in
Module.nesting,Module.nesting.first.ancestors,and
Object.ancestors if Module.nesting.first is nil or a module

self在class_scope和eigen_scope中是相同的.

尽管如此,Module.nesting是不同的:

> [B]用于class_scope
> [#< Class:B>,B]用于eigen_scope

所以Module.nesting.first.ancestors是:

> class_scope的[B,A,Object,Kernel,BasicObject]
eigen_scope的[#< Class:B>,A :: ClassMethods,#< Class:Object>,#< Class:BasicObject>,Class,Module,BasicObject]

A没有被搜索,但是A :: ClassMethods!

所以你可以定义:

module A
  module ClassMethods
    NAME = 'Bob'
  end
end

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐