我想知道的是,我在Groovy中看到的ExpandoMetaClasses是否存在某种等价性。我一直在阅读有关Open Classes但我无法确定Ruby允许类修改的范围。
借用上面博客中的一个例子,在Groovy中,我可以修改Java的String类,并像这样添加一个方法:
String.metaClass.shout = {->
return delegate.toUpperCase()
}
println "Hello MetaProgramming".shout()
// output
// HELLO METAPROGRAMMING
我认为 Ruby会让你重新定义这个类并且可能是别名(请帮助澄清我此时的误解):
class String
def foo
"foo"
end
end
puts "".foo # prints "foo"
在Groovy中,有一些方法可以将核心Java库方法重新定义为使用Categories的单个实例或一组实例,这与我在Ruby中定义为mixins的方式类似。
将开放类的范围扩展到特定实例或模块子集的方法有哪些?
如果我要安装一个已重新定义某个核心类的gem,那么只会影响该模块,或者我的任何.rb文件中是否包含受其影响的gem?
为Ruby和Groovy做出一些可能的假设提前道歉,我是两个新手,但一直试图找到两者之间的等价。
答案 0 :(得分:5)
Ruby的类永远不会“关闭”。所以当你说:
class String
def omg!
self.replace "OMG"
end
end
您正在String类上定义omg!
方法。与需要使用特殊元类概念的Groovy不同,Ruby类始终处于开放状态。
如果你想修改一组特定的字符串,你可以这样做:
module Magic
def presto
puts "OMG A HAT!"
end
end
class Array
include Magic
end
x = "Hello".extend(Magic)
puts x #=> Hello
x.presto #=> OMG A HAT!
[].presto #=> OMG A HAT!
def x.really?
true
end
x.really? #=> true
实际上,模块是可以添加到类或特定实例的方法的集合。
因此,您可以直接打开一个类,也可以使用模块向类中添加新方法。您还可以直接打开实例或使用模块向实例添加新方法。那是因为一个类只是Class的一个实例;)非常漂亮!
答案 1 :(得分:1)
除了Yehuda所说的,Ruby中的实例也有元类(技术上称为“单例类”),可以通过class <<whatever
访问。例如,用单例类重做耶胡达的魔术例子:
x = "Hello"
class <<x
include Magic
def magical?
true
end
end
x.presto #=> OMG A HAT!
x.magical? #=> true
"Something else".magical? #=> NoMethodError
答案 2 :(得分:0)
对类的修改没有范围。一旦修改了类,所有后来的require
和后面的代码都可以访问修改后的类。