Ruby中的Open类与Groovy中的MOP的作用域

时间:2009-06-30 05:42:31

标签: ruby groovy metaprogramming

我想知道的是,我在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做出一些可能的假设提前道歉,我是两个新手,但一直试图找到两者之间的等价。

3 个答案:

答案 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和后面的代码都可以访问修改后的类。