直接和通过include定义嵌套类

时间:2018-03-13 17:30:40

标签: ruby

假设我正在为我的家庭存储系统建模。我有一堆不同类型的Container,而且我发现他们中有很多人在其中或上面都有饰品,我为这种常见情况设置了一些辅助代码。

我的容器中有MantlepieceBookcase。我只把饰品存放在前者上;而后者有所有的装饰品,精装书和软书。

这是最初的尝试:

module Properties
  def has_ornament
    include OrnamentThings
  end

  module OrnamentThings
    module Things
      class Ornament
      end
    end
  end
end

class Container
  extend Properties
end

class Mantlepiece < Container
  has_ornament
end

class Bookcase < Container
  has_ornament

  module Things
    class Hardback
    end

    class Paperback
    end
  end
end

[Mantlepiece, Bookcase].each do |place|
  puts place.name
  puts place.constants.inspect
  puts place::Things.constants.inspect
end

# Output:
# Mantlepiece
# [:Things]
# [:Ornament]
# Bookcase
# [:Things]
# [:Hardback, :Paperback]

您可以看到Mantlepiece正确嵌套Mantlepiece::Things::Ornament;但Things的{​​{1}}的课堂声明表示Bookcase仅嵌套Bookcase::ThingsHardbackPaperback遗失了。

我可以整齐地写这个,以便Bookcase::Things::Ornament可以调用Bookcase,然后声明它自己的has_ornament集合,并将它们全部嵌套在同一名称空间中吗?

1 个答案:

答案 0 :(得分:2)

即使你的壁橱和书柜都有东西,但那些东西是不同的(因为它们包含不同的类别)。因此,他们不能只包含一些常见的Things模块;他们必须通过声明Things来定义他们自己的Bookcase,就像您在module Things中所做的那样。

def has_ornament
  const_set(:Things, Module.new) unless const_defined? :Things, false
  self::Things.include OrnamentThings
end

module OrnamentThings
  class Ornament
  end
end

这是有效的,因为Ruby允许您使用与声明它们相同的语法重新打开模块。 has_ornament定义了一个全新的Things模块,然后您可以打开该模块以添加更多内容。如果您在自定义内容后调用has_ornament,则会跳过创建并添加到所做的模块中(false确保我们正在寻找{{1}仅在当前类中。)