【问题标题】:ruby - File-private methodsruby - 文件私有方法
【发布时间】:2012-05-19 02:28:55
【问题描述】:

在 ruby​​ 中,有没有办法定义一个方法,该方法对文件(或模块)中的每个类都可见,但对需要该文件的文件不可见?

相关,但不完全相同:我们能否重新定义一个方法(例如标准库类中的一个方法),使得该重新定义仅在当前文件中可见?所有其他文件应查看原始定义。

【问题讨论】:

  • 只是想知道为什么需要它?它在任何情况下真的有用吗?
  • 嗯,封装总是一件好事。如果您正在编写一个库,您不希望用户开始弄乱内部结构。尽管如此,让其他实现类使用您的私有方法可能会很有用。在 C++ 中,您有朋友类来执行此操作,在 Java 中,默认可见性是“包保护”。至于重新定义,我主要是想避免命名空间冲突。我可能想在库类中添加一些功能,但如果每个人和他们的朋友都在自己的库中这样做,就会出现混乱。

标签: ruby visibility


【解决方案1】:

没有也没有。

Ruby 中唯一的可见性是公共的、受保护的和私有的。没有文件级可见性的概念。你也许可以“作弊”,然后做这样的事情:

# In some file foobar.rb

class Foo
  def to_bar
    Bar.new.file_private
  end
end

class Bar
  def file_private
    raise unless caller[0].split(':')[0] == __FILE__
  end
end
# In IRB or some other file

Foo.new.to_bar  #=> nil
Bar.new.file_private  #=> RuntimeError

但这是个坏主意。不同目录中的同名文件可能工作。它也不是真正的可见性,而是在方法本身中强制执行。

不过,实际上,您应该将每个类都放在自己的文件中。它使组织更好。此外,您不应依赖公共/受保护/私有。你总是可以只使用send 来调用私有方法,但是上面的打破这个期望。如果您的代码的用户真的想对您的代码做某事,那么让他们做几乎没有什么,这就是动态语言的本质。如果您不记录方法,大多数用户甚至都不会知道它的存在:P

关于你的第二个问题,没有办法在同一个类中有两个同名的方法具有不同的可见性,第二个方法总是会覆盖原来的。你可以做一些类似于我上面所做的事情,并根据条件运行不同的代码而不是引发,但如上所述,我真的不认为这是一个好主意。

【讨论】:

    【解决方案2】:
    1. 在 Object 类中定义一个新方法(如属性)。如果不想弄乱 Object 类,可以使用其他名称,而 Foo 应该继承该类。

      class Object
        @@file_only_methods = []
      
        def file_only(method_name)
          method_name = method_name.to_sym
          new_method_name = "file_only_#{method_name}".to_sym
          self.send(:alias_method, new_method_name, method_name)
          self.send(:undef_method, method_name)
          self.send(:private, new_method_name)
          @@file_only_methods << method_name
        end
      
      
        def method_missing(method_name, *arg, &block)
          if @@file_only_methods.include? method_name
            if __FILE__ == $0
              self.send("file_only_#{method_name}".to_sym,*arg,&block)
            else
              raise "Method #{method_name} is called outside the definition file."
            end
          else
            raise "Method #{method_name} does not exist."
          end
        end
      end
      
      class Foo
        def bar
          puts 'bar method'
        end
        file_only :bar
      end
      
      Foo.new.bar
      #output:bar method
      Foo.new.x
      #output:no method
      

      在file2.rb中,

      require_relative 'file1'
      Foo.new.bar
      #output: Method bar is called outside the definition file.
      

    【讨论】:

    • 这些都不起作用,因为条件是在类加载的上下文中运行的,而不是执行方法。每个方法要么总是私有的,要么永远不会是私有的/别名的。
    • @Norswap, @AndrewMarshall:第一个在没有改变任何东西的情况下工作。文件1测试线:Foo.new.bar,输出为bar method。文件 2:require_relative 'file1';Foo.new.bar;,它给出了错误:调用了私有方法。今晚我将测试第二个
    • 但是如果我在与Foo 相同的文件中创建另一个类,并使用调用Foo.new.bar 的方法,我会得到“NoMethodError: private method `bar' called”。
    • @AndrewMarshall 现在怎么样?我将旧方法别名为新方法,取消定义旧方法,并屏蔽新方法,并使用method_missing 进行实际调用。
    猜你喜欢
    • 2013-11-10
    • 2014-07-26
    • 2015-12-08
    • 2013-05-06
    • 1970-01-01
    • 2017-09-17
    • 2011-05-16
    • 2010-09-24
    • 2019-03-10
    相关资源
    最近更新 更多