3

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

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

4

2 回答 2

8

没有也没有。

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

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

于 2012-05-10T14:11:18.340 回答
1
  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
    

    在文件 2.rb 中,

    require_relative 'file1'
    Foo.new.bar
    #output: Method bar is called outside the definition file.
    
于 2012-05-10T14:14:05.560 回答