Reputation: 23
Using Ruby, I want to dynamically create class-level instance variables inside corresponding getters. For two of them, I use attr_reader. But for those which need to be initialized to an empty array, I do the following:
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
from my understanding this code is equivalent to:
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
Firstly I would like to know if I am correct in my understanding. Secondly, I would like to know if there is a way to memoize the variables, as in the following:
def type1_matches
@type1_matches ||= []
end
Upvotes: 2
Views: 1161
Reputation: 1228
Here is a sample pattern that I wrote for such use-cases: https://gist.github.com/ritikesh/09384fec25c4b05cfdec8674ce3a9076
here's the code from it:
# 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
}
Upvotes: 3
Reputation: 121000
First of all, you define type1_matches
, not type1
. Secondly, define_method
accepts strings, #to_sym
is superfluous. The last, but not least, you define getter being in fact a setter. So, to define type1
as you wanted:
define_method "#{elem}=", value do
instance_variable_set("@#{elem}", value)
end
Now, for getter, lazily instantiated to empty array:
define_method "#{elem}" do
instance_variable_set("@#{elem}", []) \
unless instance_variable_defined?("@#{elem}")
instance_variable_get("@#{elem}")
end
Upvotes: 2