Как мне динамически обновить массив экземпляров, чтобы он содержал список динамических методов при создании экземпляров? - PullRequest
0 голосов
/ 11 марта 2010

Я пытаюсь динамически определять методы, основанные на сопоставлениях XML. Это работает очень хорошо. Однако я хочу создать переменную экземпляра, которая является массивом динамически определенных методов.

Мой код выглядит примерно так

  def xml_attr_reader(*args)
    xml_list = ""
    args.each do |arg|
      string_val = "def #{arg}; " +
                   "   xml_mapping.#{arg}; " +
                   "end; "
      self.class_eval string_val
      xml_hash = xml_list + "'#{arg}',"
    end

    self.class_eval "@xml_attributes = [] if @xml_attributes.nil?;" +
                    "@xml_attributes = @xml_attributes + [#{xml_list}];" +
                    "puts 'xml_attrs = ' + @xml_attributes.to_s;" +
                    "def xml_attributes;" +
                    "  puts 'xml_attrs = ' + @xml_attributes.to_s;" +
                    "  @xml_attributes;" +
                    "end"
  end

Так что все работает, за исключением случаев, когда я вызываю xml_attributes для экземпляра, он возвращает ноль (и выводит 'xml_attrs =').

Хотя операторы put перед определением выводят правильный массив. (когда я создаю экземпляр экземпляра)


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

Принимая Кандадабоггу Раствор

class XmlConfig
  def xml_attr_reader(*args)
    args.each do |arg|
      class_eval(<<-RUBY, __FILE__, __LINE__)
        def #{arg}
          xml_mapping.#{arg}
        end
      RUBY
    end
    unless respond_to?(:xml_attributes)
      class_eval(<<-RUBY, __FILE__, __LINE__)
        attr_accessor :xml_attributes
      RUBY
    end
    (self.xml_attributes ||=[]).concat(args)
  end
end

и

config = XmlConfig.new
config.xml_attr_reader("age", "name")
config.age #=> age
config.name #=> name
config.xml_attributes #=> ["age", "name" ]

config.xml_attr_reader("city")
config.city #=> city
config.xml_attributes #=> ["age", "name", "city"]

Что я действительно хочу, так это (где у меня был XmlConfig как модуль, а не класс в моей версии)

class Event < ActiveWhatever
  extend XmlConfig
  xml_attr_reader :age, :name
  xml_attr_reader :email, :location
end


class PrivateEvent < Event
  xml_attr_reader :owner, :password
end

Ответы [ 2 ]

1 голос
/ 12 марта 2010

Вот решение для вашего исправленного вопроса.

   module XmlConfig
    def self.included(base)
      base.extend ClassMethods
      base.class_inheritable_array(:xml_attributes)
      base.xml_attributes = []
    end

    module ClassMethods    
      def xml_attr_reader(*args)
        args.each do |arg|
          self.class_eval(<<-RUBY, __FILE__, __LINE__)
            def #{arg}
              xml_mapping.#{arg}
            end
          RUBY
        end
        self.xml_attributes = args
      end
    end
  end

Теперь вы можете include модуль в любом классе.

  class Event < ActiveWhatever
    include XmlConfig
    xml_attr_reader :age, :name
    xml_attr_reader :email, :location
  end


  class PrivateEvent < Event
    xml_attr_reader :owner, :password
  end

Давайте проверим результат:

Event.xml_attributes        # ->[:age, :name, :email, :location]
PrivateEvent.xml_attributes # ->[:age, :name, :email, :location, 
                            #                 :owner, :password]

e= Event.new(...)
e.age     # -> 27
pe= PrivateEvent.new(...)
pe.owner  # -> Will
1 голос
/ 11 марта 2010

Попробуйте это:

class XmlConfig
  def xml_attr_reader(*args)
    args.each do |arg|
      class_eval(<<-RUBY, __FILE__, __LINE__)
        def #{arg}
          xml_mapping.#{arg}
        end
      RUBY
    end
    unless respond_to?(:xml_attributes)
      class_eval(<<-RUBY, __FILE__, __LINE__)
        attr_accessor :xml_attributes
      RUBY
    end
    (self.xml_attributes ||=[]).concat(args)
  end
end

Теперь вы можете совершать следующие звонки:

config = XmlConfig.new
config.xml_attr_reader("age", "name")
config.age #=> age
config.name #=> name
config.xml_attributes #=> ["age", "name" ]

config.xml_attr_reader("city")
config.city #=> city
config.xml_attributes #=> ["age", "name", "city"]

Примечание: Все методы являются методами экземпляра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...