In the following code, the module is extended which means the method hash_initialized is treated as a class method, or an instance method of the eigen class. This is what we need since hash_initialized is called in the context of the eigen class.
What i don't understand is if the context for the module is the eigen class, then define_method should create a instance method called "initialize" of the eigen class, or in other words, a class method of class Cheese. Don't we need an instance method "initialize" here?
module HashInitialized
def hash_initialized(*fields)
define_method(:initialize) do |h|
missing = fields - h.keys
raise Exception, "Not all fields set: #{missing}" if missing.any?
h.each do |k,v|
instance_variable_set("@#{k}", v) if fields.include?(k)
end
end
end
end
class Cheese
extend HashInitialized
attr_accessor :color, :odor, :taste
hash_initialized :color, :odor, :taste
end
When you encounter seeming conundrums such as this one, try salting your code with
puts self
statements:As you see,
self
is the classCheese
, notCheese
's singleton_class. Hence, the receiver for Module#define_method isCheese
, so the method obligingly creates the instance methodinitialize
onCheese
.initialize
is not among the instance methods created onCheese
because I modified the code slightly to make it a private method:I also slightly altered the code that assigns values to the instance variables, and made the type of exception more specific.
If appropriate, you could change your argument test to:
You may wish to have
initialize
create the assessors: