Рубиновое метапрограммирование для достижения динамических методов? - PullRequest
0 голосов
/ 05 ноября 2019

Хотите получить следующий код, используя метапрограммирование.

@resource = {}
@voters = {}
@is_upvoted = {}

def resource(comment)
  @resource[comment.id]
end

def voters(comment)
  @voters[comment.id]
end

def is_upvoted(comment)
  @is_upvoted[comment.id]
end

Как я могу создать эти методы, используя метапрограммирование ruby, и получить доступ к хешу?

Можете ли вы сказать мне, что не так в моемкод?

['resource', 'voters', 'is_upvoted'].each do |attribute|
  define_method("#{attribute}") do |comment|
    instance_variable_set("@#{attribute}", comment.id)
  end
end

Ответы [ 3 ]

1 голос
/ 05 ноября 2019

Этот бит кажется избыточным:

@resource = {}
@voters = {}
@is_upvoted = {}

Поскольку вы уже зацикливаете массив для выполнения метапрограммирования.

Вы можете попробовать что-то вроде:

class Foo 

  %w(
    resource
    voters
    is_upvoted
  ).each do |attr_sym|
    define_method attr_sym do |comment|
      instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
      instance_variable_get("@#{attr_sym}")[comment.id]
    end
  end

end

Что, я считаю, даст вам методы, примерно такие:

class Foo 

  def resource(comment)
    @resource ||= {}
    @resource[comment.id]
  end

end

Лично мне кажется, что не очень хорошо иметьcomment.id в вашем методе. Потому что, если когда-нибудь вы захотите использовать другой атрибут (или что-то совсем другое) в качестве key?

Итак, я думаю, я бы сделал:

class Foo 

  %w(
    resource
    voters
    is_upvoted
  ).each do |attr_sym|
    define_method attr_sym do |key|
      instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
      instance_variable_get("@#{attr_sym}")[key]
    end
  end

end

Теперь, кажется,как будто вам нужен простой способ установить пары ключ-значение в вашей переменной экземпляра, так что, я думаю, я бы попробовал что-то вроде:

class Foo 

  %w(
    resource
    voters
    is_upvoted
  ).each do |attr_sym|
    define_method attr_sym do |key=nil|
      instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
      hsh = instance_variable_get("@#{attr_sym}")
      return hsh[key] if key
      hsh
    end
  end

end

В этом случае вы должны быть в состоянии сделать это (при условииу вас есть переменная @comment, которая отвечает на id):

@comment.id 
 => 1 
foo = Foo.new
 => #<Foo:0x000056536d7504b0>
foo.resource 
 => {}
foo.resource[@comment.id] = :bar
 => :bar 
foo.resource 
 => {1=>:bar}
foo.resource[@comment.id]
 => :bar
1 голос
/ 05 ноября 2019

Можете ли вы сказать мне, что не так в моем коде?

Это эквивалентно этому:

def resource(comment)
  @resource = comment.id
end

instance_variable_get будет лучшим выбором.

0 голосов
/ 05 ноября 2019

Вот как я его использовал и он работает

['resource', 'voters', 'is_upvoted'].each do |attribute|
  define_method("#{attribute}") do |comment|
    instance_variable_get("@#{attribute}")[comment.id]
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...