Ruby 模块包含钩子而不是常规扩展?

推荐

有一种通用方法可以通过模块包含的钩子从模块中添加类方法,然后使用 ClassMethods 子模块扩展基类。这种方式在“Metaprogramming Ruby 2: Program Like the Ruby Pros”一书中有描述。这是那里的一个例子:

module CheckedAttributes

  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods

    def attr_checked(attribute, &validation)

      define_method "#{attribute}=" do |value|
        raise 'Invalid attribute' unless validation.call(value)
        instance_variable_set("@#{attribute}", value)
      end

      define_method attribute do
        instance_variable_get "@#{attribute}"
      end
    end
  end
end

class Person
  include CheckedAttributes
  attr_checked :age do |v|
    v >= 18
  end
end

但是首先包含几乎空的模块,然后再用一个模块扩展它的包含器的原因是什么?为什么不以目标模块本身的方式扩展类呢?

module CheckedAttributes

  def attr_checked(attribute, &validation)

    define_method "#{attribute}=" do |value|
      raise 'Invalid attribute' unless validation.call(value)
      instance_variable_set("@#{attribute}", value)
    end

    define_method attribute do
      instance_variable_get "@#{attribute}"
    end
  end
end

class Person
  extend CheckedAttributes

  attr_checked :age do |v|
    v >= 18
  end
end

上面的代码完全等同于本书的初始示例吗?或者有什么陷阱?

阿列克谢·马蒂乌什金

我不知道,你把这个代码,但这种模式涉及ClassMethods的情况下正常使用,当你想改变这两个类eigenclass避免需要同时调用include Fooextend Bar

module Named
  def self.included(base)
    base.extend ClassMethods
  end

  def describe
    "Person is: #{name}"
  end

  module ClassMethods
    def name!
      define_method "name=" do |value|
        raise 'Invalid attribute' unless validation.call(value)
        instance_variable_set("@name", value)
      end

      define_method "name" do
        instance_variable_get "@name"
      end
    end
  end
end

class Person
  include Named
  name!
end

p = Person.new
p.name = "Trump"
p.describe #⇒ "Person is: Trump"

在您的示例中,它的意义为零。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章