Modules are constants in their encapsulating context, which for the top level is Kernel. That lets us get the module with const_get
. Try this:
module Has_Something
def has(*items)
items.each do |item|
mod = Kernel.const_get("Has_" + item.to_s.capitalize)
instance_eval { include mod }
end
end
end
class Baker
extend Has_Something
has :cake
end
class CandyMan
extend Has_Something
has :chocolate
end
class ChocolateCake
extend Has_Something
has :cake, :chocolate
end
If you prefer include over extend, you can do that, too:
module Has_Something
def self.included(base)
base.extend HasTemplate
end
module HasTemplate
def has(*items)
items.each do |item|
mod = Kernel.const_get("Has_" + item.to_s.capitalize)
instance_eval { include mod }
end
end
end
end
class Baker
include Has_Something
has :cake
end
class CandyMan
include Has_Something
has :chocolate
end
class ChocolateCake
include Has_Something
has :cake, :chocolate
end
In either case, this code is the same:
steve = Baker.new
bob = CandyMan.new
delicious = ChocolateCake.new
steve.has_cake? && bob.has_chocolate? # => true
delicious.has_cake? && delicious.has_chocolate? #=> true
EDIT:
Based upon your comment, what you're looking for is a way to automatically create methods of the format has_
something?
. This is even easier to do:
module Has_Something
def has (*items)
items.each do |item|
method_name = ('has_' + item.to_s + '?').to_sym
send :define_method, method_name do
true
end
end
end
end
class Baker
extend Has_Something
has :cake
end
class CandyMan
extend Has_Something
has :chocolate
end
class ChocolateCake
extend Has_Something
has :cake, :chocolate
end
steve = Baker.new
bob = CandyMan.new
delicious = ChocolateCake.new
steve.has_cake? && bob.has_chocolate? # => true
delicious.has_cake? && delicious.has_chocolate? # => true