假设我正在为我的家庭存储系统建模。我有一堆不同类型的Container
,而且我发现他们中有很多人在其中或上面都有饰品,我为这种常见情况设置了一些辅助代码。
我的容器中有Mantlepiece
和Bookcase
。我只把饰品存放在前者上;而后者有所有的装饰品,精装书和软书。
这是最初的尝试:
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::Things
和Hardback
。 Paperback
遗失了。
我可以整齐地写这个,以便Bookcase::Things::Ornament
可以调用Bookcase
,然后声明它自己的has_ornament
集合,并将它们全部嵌套在同一名称空间中吗?
答案 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}仅在当前类中。)