Ruby和元编程和模块

时间:2017-09-15 10:46:25

标签: ruby module metaprogramming

我有一个关于如何在运行时包含模块和执行那些方法的问题。我读到了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

最佳亚历克斯

2 个答案:

答案 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"