Как загрузить неизвестный класс в модуль? - PullRequest
3 голосов
/ 26 марта 2011

У меня есть несколько rb-файлов, все с одинаковой структурой:

class RandomName < FooBar
end

Случайное имя - это случайное имя класса, которое изменяется в каждом rb-файле, но все наследуется от Foobar.

howя могу загрузить все randomclass оттуда файлы RB?

Ответы [ 3 ]

4 голосов
/ 26 марта 2011

Я думаю, что решение состоит из двух частей:

  1. Как динамически создать экземпляр класса

    a.Использование String#constantize из ActiveSupport

    klass = "SomeNamespace::SomeClassName".constantize
    klass.new
    

    b.Используйте Module#const_get (который не обрабатывает пространства имен)

    klass = const_get(:SomeClassName)
    klass.new
    
  2. Как определить имя класса

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

    Dir["/path/to/directory/*.rb"].each do |file| 
      require file 
      file_name = File.basename(file.path, '.rb')
       # using ActiveSupport for camelcase and constantize
      file_name.camelcase.constantize.new 
    end
    

Я думаю, вы должны объяснить, что вы пытаетесь достичь.Подход, который вы выбираете, кажется нетрадиционным, и может быть гораздо более эффективный способ достижения вашей цели без всей этой загрузки файлов и динамического создания классов со случайными именами.

Помните, только потому, что ruby ​​позволяетчто-то, это не значит, что на самом деле это хорошая идея!

4 голосов
/ 26 марта 2011

вы можете определить метод с именем inherited в классе FooBar. смотрите здесь

class FooBar
  def self.inherited(subclass)
    puts "New subclass: #{subclass}"
  end
end

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

0 голосов
/ 06 марта 2014

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

Я использовал eval, потому что у него нет зависимостей Rails (янаписание чистого кода Ruby здесь).

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

klass = "classname"

begin

    # Load the file containing the class from same directory I'm executing in
    require_relative klass # Or pass a local directory like "lib/#{klass}"

    # Use eval to convert that string to a Constant (also capitalize it first)
    k = eval(klass.capitalize).new

rescue
    # Do something if the convention fails and class cannot be instantiated.

end

k.foo # Go ahead and start doing things with your new class.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...