# 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
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.
3条答案
按热度按时间d6kp6zgx1#
没有也没有。
Ruby中唯一的可见性是public、protected和private。没有文件级可见性的概念。你也许可以“作弊”,然后做一些像这样的事情:
但这不是个好主意。不同目录下的同名文件 * 可能 * 有效。它也不是真正的可见性,而是在方法本身中强制实现它。
实际上,你应该让每个类都在自己的文件中。它使组织更好。此外,您不应该依赖于public/protected/private。你总是可以只使用
send
来调用私有方法,但是上面的 * 打破了 * 这个期望。如果你的代码的用户真的想用你的代码做一些事情,那么让他们做几乎没有什么,这就是动态语言的本质。如果你不记录一个方法,大多数用户甚至永远不会知道它的存在:P
。至于你的第二个问题,没有办法在同一个类中有两个同名的方法,但它们的可见性不同,第二个方法总是会覆盖原来的方法。你可以做一些类似于我上面所做的事情,并根据条件运行不同的代码,而不是提高,但如上所述,我真的不认为这是一个好主意。
bxpogfeg2#
1.在Object类中定义一个新的方法(类似于属性)。如果你不想搞砸Object类,你可以使用另一个名称,Foo应该继承这个类。
在file2.rb中,
3hvapo4f3#
是的,是的,从Ruby2开始。0.
Ruby实际上是关于对象的,而不是文件,所以你可能不应该这样做。一般来说,您应该只使用类和对象来完成您想要的任何事情。
然而,ruby * 确实 * 有一个机制来完成你的两个问题:refinements。
不幸的是,尽管ruby的改进已经有十年了,大多数开发人员仍然认为它们是实验性的和深奥的。自引入以来,精化已经以向后不兼容的方式进行了多次更改。更重要的是,它们可能会造成显著的性能损失。虽然我已经在一些简单的使用细化的代码上运行了基准测试,并且几乎没有看到性能影响,但是细化会破坏ruby的内部方法缓存,从而导致 * 非常 * 显著的速度唐斯(从ruby 3开始)。而且,据我所知,现有的JIT编译器甚至不尝试优化细化的方法调用。请参阅https://shopify.engineering/the-case-against-monkey-patching了解不这样做的其他原因。特别是,请阅读那篇文章中的“关于精化的说明”部分。
不管怎样,抛开所有这些警告和警告,下面是一个演示:
这是
ruby -I. unrefined.rb
的输出: