Добавить существующие классы в модуль - PullRequest
5 голосов
/ 27 августа 2010

У меня есть несколько существующих классов ruby ​​в папке app / classes:

class A
   ...
end

class B
   ...
end

Я бы хотел сгруппировать эти классы в модуле MyModule

Я знаю, что могу сделать как:

module MyModule
  class A
      ...
   end
   class B
      ...
   end
end

но есть ли ярлык метапрограммирования, который мог бы сделать то же самое, чтобы я мог "импортировать" все существующие классы?

Спасибо, Люк

Ответы [ 5 ]

9 голосов
/ 27 августа 2010
module Foo
  A = ::A
  B = ::B
end

Foo::A.new.bar

Обратите внимание, что префикс :: для константы начинает сначала поиск глобального пространства имен.Как ведущий / по пути.Это позволяет дифференцировать глобальный класс A от модульной константы Foo::A.

5 голосов
/ 27 августа 2010

Используйте крючок const_missing. Если константа не может быть найдена в текущем модуле, попробуйте разрешить в глобальном пространстве имен:

class A; end
class B; end

module M
    def self.const_missing(c)
        Object.const_get(c)
    end
end

M::A.new
M::B.new
3 голосов
/ 27 августа 2010

@ Ответ Squeegy уже говорит вам, что делать, но я думаю, что не менее важно понять, почему работает. И это на самом деле довольно просто: классы в Ruby не представляют собой ничего особенного. Это просто объекты, как и любой другой объект, который присваивается переменным, как и любая другая переменная. Точнее, они являются экземплярами класса Class и обычно присваиваются константам (то есть переменным, имя которых начинается с заглавной буквы).

Итак, вы можете использовать псевдоним любого другого объекта для нескольких переменных:

a = ''
b = a
a << 'Hello'
c = b
b << ', World!'
puts c # => Hello, World!

Вы также можете использовать псевдонимы для нескольких переменных:

class Foo; end
bar = Foo
p bar.new # => #<Foo:0x1d9f220>

Если вы хотите переместить классы в пространство имен вместо простого наложения их на псевдонимы, вам также необходимо установить исходные переменные для другого объекта, например nil, в дополнение к ответу @ Squeegy:

::A = nil
::B = nil
1 голос
/ 09 сентября 2010

Если вы хотите поместить их в модуль, я не вижу смысла сначала включать их в глобальное пространство имен, а затем накладывать их на псевдонимы внутри модуля.Я думаю, что вы хотите сделать (хотя я сомневаюсь, что это хорошая вещь) примерно так:

file classes/g1.rb

class A1
  def self.a
    "a1"
  end
end

class B1
  def self.b
    "b1"
  end
end

file classes/g2.rb

class A2
  def self.a
    "a2"
  end
end

class B2
  def self.b
    "b2"
  end
end

file imp.rb

module MyModule
  ["g1.rb", "g2.rb"].each do |file|
    self.class_eval open("classes/#{file}"){ |f| f.read }
  end
end

puts defined? MyModule
puts defined? A1
puts defined? MyModule::A1

puts MyModule::A1.a
puts MyModule::B2.b

output

constant
nil
constant
a1
b2

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

1 голос
/ 27 августа 2010

Да, в вашем модуле создайте класс и наследуйте его от ваших внешних классов.Например,

class A
...
end

module MyModule
 class NewA < A
 end
end

Класс MyModule :: NewA будет иметь все атрибуты и методы класса A.
С другой стороны, модули в ruby ​​никогда не блокируются, поэтому ничего не останавливаетсявы просто пишете определение класса прямо в модуль.

...