我有一个关于如何在运行时包含模块和执行那些方法的问题。我读到了Metaprogramming,我想我得到了基本观点,但我不明白如何在我的具体案例中使用它。
例如: 我想以两种不同的方式生成基于块的文本
class TextGenerator
def create_text
if condition
create_full_text
else
create_short_text
end
end
private
def create_full_text
intro
middle
ending
end
def create_short_text
middle
end
def intro
"intro"
end
def middle
"middle"
end
def ending
"ending"
end
end
我想要实现的是,我想将方法 create_full_text 和 create_short_text 的功能提取到专用模块,并在条件匹配时包含模块。文本创建将通过包含模块中的 create_text 调用。
我的问题是否可以理解,也让这个想法有意义? 也许有人可以把我推向正确的方向。
根据Sergios的回答,还有一种以动态方式扩展的方法。
而不是:
if condition
generator.extend(WithFullText)
else
generator.extend(WithShortText)
end
拥有像(非常基本的广泛例子)那样的东西会很棒:
@MODULES = {
full: "WithFullText",
short: "WithShortText"
}
def create_text_by_type(type)
module_name = @MODULES[type]
#no idea how this can work
module_class = getModuleByName(module_name)
generator.extend(module_class)
generator.create_text
end
最佳亚历克斯
答案 0 :(得分:0)
也许有人可以把我推向正确的方向
不确定。例如,您可以使用extend
从模块中动态添加方法。
module WithFullText
def create_full_text
"full text"
end
end
class TextGenerator
end
generator = TextGenerator.new
generator.create_full_text # ~> -:5:in `<main>': undefined method `create_full_text' for #<TextGenerator:0x007ffb818b1990> (NoMethodError)
generator.extend(WithFullText)
generator.create_full_text # => "full text"
虽然通常情况下,人们只需要包含两种方法,然后再调用其中一种方法。
class TextGenerator
include MyTextMethods
end
你需要一个非常好的理由不来做到这一点(因为这意味着更复杂的代码/流程)。
答案 1 :(得分:0)
我相信你需要的是战略设计模式。有比使用include
更好的方法来实现它。元编程也是一种强大的工具,但很多时候,使用简单的case
而不是使用send
方法生成一些神奇的方法,代码更易读,更容易理解。
这样的事情怎么样:
module TextGenerator
class FullText
def self.generate
"full text"
end
end
class ShortText
def self.generate
"short text"
end
end
end
module ChooseTextGeneratorStrategy
def self.included klass
klass.singleton_class.send(:attr_reader, :create_text_type)
end
def create_text
case self.class.create_text_type
when :short
TextGenerator::ShortText.generate
when :full
TextGenerator::FullText.generate
end
end
end
class ClassNeedsFullText
include ChooseTextGeneratorStrategy
@create_text_type = :full
end
class ClassNeedsShortText
include ChooseTextGeneratorStrategy
@create_text_type = :short
end
p ClassNeedsFullText.new.create_text # "full text"
p ClassNeedsShortText.new.create_text # "short text"
命名可能不是最好的,但你可以明白这一点。如果您需要ClassNeedsFullText
的上下文,则可以通过参数TextGenerator::FullText.generate self
简单地传递它。
@create_text_type
只是一个例子。您可以使用辅助方法进一步简化它:
def act_like_create_text type
include ChooseTextGeneratorStrategy
@create_text_type = type
end
class ClassNeedsShortText
act_like_create_text :short
end
p ClassNeedsShortText.new.create_text # "short text"