ruby -文件私有方法

l7wslrjt  于 2023-04-29  发布在  Ruby
关注(0)|答案(3)|浏览(104)

在ruby中,有没有一种方法可以定义一个方法,它对文件(或模块)中的每个类都是可见的,但对需要该文件的文件却不可见?
相关的,但不完全相同的:我们可以重新定义一个方法(例如标准库中的一个类的方法),使得这个重新定义只在当前文件中可见吗?所有其他文件应查看原始定义。

d6kp6zgx

d6kp6zgx1#

没有也没有。
Ruby中唯一的可见性是public、protected和private。没有文件级可见性的概念。你也许可以“作弊”,然后做一些像这样的事情:

# 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

但这不是个好主意。不同目录下的同名文件 * 可能 * 有效。它也不是真正的可见性,而是在方法本身中强制实现它。
实际上,你应该让每个类都在自己的文件中。它使组织更好。此外,您不应该依赖于public/protected/private。你总是可以只使用send来调用私有方法,但是上面的 * 打破了 * 这个期望。如果你的代码的用户真的想用你的代码做一些事情,那么让他们做几乎没有什么,这就是动态语言的本质。如果你不记录一个方法,大多数用户甚至永远不会知道它的存在:P
至于你的第二个问题,没有办法在同一个类中有两个同名的方法,但它们的可见性不同,第二个方法总是会覆盖原来的方法。你可以做一些类似于我上面所做的事情,并根据条件运行不同的代码,而不是提高,但如上所述,我真的不认为这是一个好主意。

bxpogfeg

bxpogfeg2#

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.
3hvapo4f

3hvapo4f3#

是的,是的,从Ruby2开始。0.
Ruby实际上是关于对象的,而不是文件,所以你可能不应该这样做。一般来说,您应该只使用类和对象来完成您想要的任何事情。
然而,ruby * 确实 * 有一个机制来完成你的两个问题:refinements
不幸的是,尽管ruby的改进已经有十年了,大多数开发人员仍然认为它们是实验性的和深奥的。自引入以来,精化已经以向后不兼容的方式进行了多次更改。更重要的是,它们可能会造成显著的性能损失。虽然我已经在一些简单的使用细化的代码上运行了基准测试,并且几乎没有看到性能影响,但是细化会破坏ruby的内部方法缓存,从而导致 * 非常 * 显著的速度唐斯(从ruby 3开始)。而且,据我所知,现有的JIT编译器甚至不尝试优化细化的方法调用。请参阅https://shopify.engineering/the-case-against-monkey-patching了解不这样做的其他原因。特别是,请阅读那篇文章中的“关于精化的说明”部分。
不管怎样,抛开所有这些警告和警告,下面是一个演示:

# refine_file_scoped_methods.rb
using(Module.new do
  refine Object do
    def hello_file! = puts "In refined file:   hello world! :)"
  end
  refine Integer do
    def + rhs
      return super unless self == 2 && rhs == 2
      5
    end
  end
end)

class Integer
  def plus_two = self + 2
end

hello_file!
puts "In refined file:   2 + 2      = #{2 + 2}"
puts "In refined file:   2.plus_two = #{2.plus_two}"
# unrefined.rb
require_relative "refine_file_scoped_methods"

begin
  hello_file!
rescue NoMethodError
  puts "In unrefined file: No hello...  :("
end

puts "In unrefined file: 2 + 2      = #{2 + 2}"
puts "In unrefined file: 2.plus_two = #{2.plus_two}"

这是ruby -I. unrefined.rb的输出:

$ ruby -I. unrefined.rb
In refined file:   hello world! :)
In refined file:   2 + 2      = 5
In refined file:   2.plus_two = 5
In unrefined file: No hello...  :(
In unrefined file: 2 + 2      = 4
In unrefined file: 2.plus_two = 5

相关问题