Reputation: 1415
I am confused by the following code from Poignant Guide:
# The guts of life force within Dwemthy's Array
class Creature
# Get a metaclass for this class
def self.metaclass; class << self; self; end; end
# Advanced metaprogramming code for nice, clean traits
def self.traits( *arr )
return @traits if arr.empty?
# 1. Set up accessors for each variable
attr_accessor( *arr )
# 2. Add a new class method to for each trait.
arr.each do |a|
metaclass.instance_eval do
define_method( a ) do |val|
@traits ||= {}
@traits[a] = val
end
end
end
# 3. For each monster, the `initialize' method
# should use the default number for each trait.
class_eval do
define_method( :initialize ) do
self.class.traits.each do |k,v|
instance_variable_set("@#{k}", v)
end
end
end
end
# Creature attributes are read-only
traits :life, :strength, :charisma, :weapon
end
The above code is used to create a new class, as in the following:
class Dragon < Creature
life( 1340 ) # tough scales
strength( 451 ) # bristling veins
charisma( 1020 ) # toothy smile
weapon( 939 ) # fire breath
end
I need to study the basics of meta-programming more on my own, but for now I just want to know, where does the val
block argument come from in define_method( a ) do |val|
? It represents the point values assigned to each trait, but I don't understand how each of those numbers become a block argument.
Also, why is a
passed in the parentheses to define_method
, while val
is passed in as a block argument?
I've read over this question on the subject of define_method arguments, but it doesn't address the reasons for passing arguments to define_method
rather than to the block.
Upvotes: 0
Views: 179
Reputation: 168101
In the form
define_method(:foo){|x| ...}
:foo
is the method name and x
is the argument. They have different roles. It is the same as:
def foo(x)
...
end
Upvotes: 1