Модули являются константами в их инкапсулирующем контексте, который для верхнего уровня - ядро. Это позволяет нам получить модуль с const_get
. Попробуйте это:
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
Если вы предпочитаете включить over extension, вы можете сделать это тоже:
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
В любом случае этот код одинаков:
steve = Baker.new
bob = CandyMan.new
delicious = ChocolateCake.new
steve.has_cake? && bob.has_chocolate? # => true
delicious.has_cake? && delicious.has_chocolate? #=> true
EDIT:
Исходя из вашего комментария, вы ищете способ автоматического создания методов в формате has_
что-то ?
. Это еще проще сделать:
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