在ruby中动态定义memoized getter

时间:2015-07-03 17:43:27

标签: ruby metaprogramming

使用Ruby,我想在相应的getter中动态创建类级实例变量。对于其中两个,我使用attr_reader。但对于需要初始化为空数组的那些,我会执行以下操作:

class MatchMake
  class << self
    attr_reader :local_data, :remote_data
    ["type1", "type2"].each do |elem|
      define_method "#{elem}_matches".to_sym do
        instance_variable_set("@#{elem}_matches", [])
      end
    end
  end
  ...
end

根据我的理解,此代码相当于:

class MatchMake
  class << self
    def local_data
      @local_data
    end
    def remote_data
      @remote_data
    end
    def type1_matches
      @type1_matches = []
    end
    def type2_matches
      @type2_matches = []
    end
  end
  ...
end

首先,我想知道我的理解是否正确。其次,我想知道是否有办法记忆变量,如下所示:

def type1_matches
  @type1_matches ||= []
end

2 个答案:

答案 0 :(得分:2)

首先,您定义type1_matches,而不是type1。其次,define_method接受字符串,#to_sym是多余的。最后,但并非最不重要的是,你定义getter实际上是一个setter。因此,要根据需要定义type1

define_method "#{elem}=", value do
  instance_variable_set("@#{elem}", value)
end

现在,对于getter,懒惰地实例化为空数组:

define_method "#{elem}" do
  instance_variable_set("@#{elem}", []) \
      unless instance_variable_defined?("@#{elem}")
  instance_variable_get("@#{elem}")
end

答案 1 :(得分:2)

以下是我为此类用例编写的示例模式: https://gist.github.com/ritikesh/09384fec25c4b05cfdec8674ce3a9076

这里是代码:

# memoize db/cache results in instance variable dynamically
def memoize_results(key)
  return instance_variable_get(key) if instance_variable_defined?(key)
  instance_variable_set key, yield  
end

# usage
MY_CONSTANT = [:active, :inactive]
MY_CONSTANT.each { |key|
  define_method("#{key}_users") do
    memoize_results("@#{key}_users") do
      User.send(key).all # assumes that user responds to active, inactive(via scope/filter etc..)
    end
  end
}
相关问题