有选择地允许类使用其他人的私有类方法或等效的解决方案

时间:2012-12-08 03:32:22

标签: ruby class-method private-methods

在我的项目Bar中,我有这个类Foo,其实例代表唯一的,命名的真实世界对象。这些实例的引用分散在我项目中的数据结构周围,但是,我还决定通过它们的名称来访问它们。为此,Foo类本身跟踪其实例,如

module Bar
  class Foo
    attr_reader :name

    def initialize( name )
      @name = name
    end

    def self.new *args, &block
      new_instance = super
      n_i_name = new_instance.name
      ( @instances ||= {} ).merge! new_instance => n_i_name
      return new_instance
    end

    def inspect; "Foo instance #{name}" end
  end
end

现在这是一种常见的模式。通常,要访问实例,可以在Foo

中建立公共类方法
class << Bar::Foo
  def instance( i )
    case i
    when self then i
    else @instances.rassoc( i ).first end
  end
end

i = Bar::Foo.new "John Smith"
#=> Foo instance John Smith
i.object_id
#=> 68997470
Bar::Foo.instance( "John Smith" ).object_id
#=> 68997470

但问题是,Bar模块下有命名实例的类比类,例如Bar::BazBar::Quux等等,需要访问Foo实例和名称彼此。所以我认为按照名称访问每个其他实例的方式保持顺序是Bar模块本身的责任,我在其中创建了公共模块方法:

module Bar
  # Foo method blah blah blah...
  def self.Foo( i ); Foo.instance i end

  # Baz method blah blah blah...
  def self.Baz( i ); Baz.instance i end

  # Quux method blah blah blah...
  def self.Quux( i ); Quux.instance i end
end

每当班级FooBazQuux相互引用时,他们都会使用Bar.Foo( "John Smith" )样式调用,这也可以通过其唯一名称引用这些实例。现在我的问题是,这对我来说似乎仍然不是100%的犹太人。当我运行rdocBar模块创建文档时,公共类方法#Foo#Baz#Quux将其添加到文档中。但这些并不是真正意图成为用户界面的一部分。所以我有以下选项,每个选项都有问题:

  1. 在用户界面中加入#Foo#Baz#Quux问题:用户并不真正需要它们;我不打算在UI中设置它们。

  2. 向他们添加# :nodoc:指令,以防止rdoc记录他们。 问题:感觉不对。它与Bar.Foo不同,并且朋友被排除在用户界面之外。感觉更像是他们仍然是UI的一部分,但没有文档,秘密。我不希望这样。

  3. 使用#private_class_method将其声明为私有。但是,即使实例#Foo#Baz#Quux在正常操作期间按名称相互访问,它们也必须使用Bar.send :Foo, "John Smith"样式。

  4. 问题:选项3似乎最无害。但是,它仍然不完美。理想情况下,我希望以这种方式保护方法Bar.FooBar.BazBar.Quux,这些人可以通过简单地调用Bar.Foo "John Smith"来通过名称互相调用,而用户必须使用Bar.send :Foo, "John Smith",并且不会为用户记录这些模块方法。还有什么其他选择,如果有的话,我必须达到这种状态吗?有没有办法有选择地允许某些类随意使用别人的私有方法?另外,我没有使用受保护的类方法的经验,这可能是一个解决方案吗?感谢您花时间阅读本文。

1 个答案:

答案 0 :(得分:1)

查看Understanding private methods in Ruby并搜索SO以获取私人/受保护,有很多材料需要阅读。

受保护的类方法:

class Foo
    class << self
        def prot
            puts "self.prot"
        end
        protected :prot
    end
...

Bar::Foo.prot #=> protected method `prot' called for Bar::Foo:Class (NoMethodError)