#!/usr/bin/ruby -w # implementation of Composite, Visitor and Value patterns # TODO apply Value pattern to Component class Module def abstract(*ids) for id in ids name = id.id2name # 1.4.x specific class_eval %Q{ def #{name}(*a) raise NotImplementError, "#{name} not implemented" end } end end alias implements include end # interface definitions module Component abstract :components end module Visitor abstract :visit, :visitComposite, :visitLeaf end module Visitee abstract :accept end module Value abstract :value, :value= end # concrete implementations class Composite; implements Component, Visitee attr :name def initialize name @name = name @components = [] end def add item @components << item end # Component interface def components @components end # Visitee interface def accept visitor visitor.visitComposite(self) end def inspect s = @name @components.each{ |c| if c.type == Leaf s += " " + c.name else items = c.components if items items.each{ |i| s += " " + i.inspect } end end } s end end class Leaf; implements Component, Visitee attr :name def initialize name @name = name end # Component interface def components nil end # Visitee interface def accept visitor visitor.visitLeaf(self) end def inspect @name end end class StringVisitor; implements Visitor attr :result def initialize item=nil @result = "" if item item.accept(self) end end def visit item item.accept(self) end def visitComposite item @result += "( #{item.name} " sep = "" item.components.each{ |c| @result += sep c.accept(self) sep = " " } @result += " )" end def visitLeaf item @result += item.name end end root = Composite.new("root") root.add(Leaf.new("l1")) root.add(Leaf.new("l2")) c = Composite.new("c1") c.add(Leaf.new("l3")) c.add(Leaf.new("l4")) root.add(c) #p root v = StringVisitor.new v.visit(root) puts v.result v = StringVisitor.new root puts v.result