Обзор открытых классов в Ruby против MOP в Groovy - PullRequest
1 голос
/ 30 июня 2009

Я пытаюсь выяснить, есть ли какая-то эквивалентность тому, что я вижу в Groovy как ExpandoMetaClasses . Я читал о открытых классах , но не могу понять, какой уровень видимости Ruby допускает модификации класса.

Заимствуя пример из блога выше, в Groovy я мог бы изменить класс String Java и добавить к нему метод следующим образом:

String.metaClass.shout = {->
  return delegate.toUpperCase()
}

println "Hello MetaProgramming".shout()

// output
// HELLO METAPROGRAMMING

И я думаю , что Руби заставит вас переопределить класс и, возможно, присвоить ему псевдоним (пожалуйста, помогите прояснить мои недоразумения на этом этапе):

class String
  def foo
    "foo"
  end
end 

puts "".foo # prints "foo"

В Groovy есть способы распространения переопределения основных методов библиотеки Java на отдельные экземпляры или группу экземпляров с использованием категорий, что похоже на то, что я определил бы как миксины в Ruby.

Как можно использовать открытые классы для конкретных экземпляров или подмножеств модулей?

Если бы я должен был установить гем, в котором был переопределен какой-то базовый класс, затронул бы только этот модуль или на него повлиял бы любой файл .rb, в который я включил этот драгоценный камень?

Заранее извиняюсь за то, что сделал некоторые возможные предположения как для Ruby, так и для Groovy, я новичок в обоих, но пытаюсь найти эквивалентность между ними.

Ответы [ 3 ]

5 голосов
/ 30 июня 2009

Классы Руби никогда не "закрыты". Поэтому, когда вы говорите:

class String
  def omg!
    self.replace "OMG"
  end
end

Вы определяете метод omg! в классе String. В отличие от 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

По сути, модуль - это набор методов, которые можно добавить в класс или конкретные экземпляры.

Таким образом, вы можете либо открыть класс напрямую, либо добавить новые методы в класс с помощью модуля. Вы также можете открыть экземпляр напрямую или добавить новые методы в экземпляр, используя модуль. Это потому, что класс - это просто экземпляр класса;) Довольно изящно!

1 голос
/ 30 июня 2009

В дополнение к тому, что сказал Иегуда, экземпляры в 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
0 голосов
/ 30 июня 2009

Нет ограничений по модификациям классов.Как только класс изменяется, измененный класс становится доступным для всех последующих require s и следующего кода.

...