More documentation for the MatchHandler class.
[kaya.git] / lib / descriptor.rb
blobd51e2ee3ecf839f3300e61a4ea0edaf4d73bde7e
1 # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 class Descriptor
9   attr_reader :name, :opts, :children
10   
11   def initialize(name, opts = { })
12     @name = name
13     @opts = opts
14     @children = []
15   end
16   
17   def add_child(desc)
18     @children << desc
19   end
20   
21   def merge_child(desc)
22     if @opts[:merge_point]
23       @children.insert(@opts[:merge_point], desc)
24       @opts[:merge_point] += 1
25     else
26       add_child(desc)
27     end
28   end
29   
30   def to_sexp
31     "(#{@name} #{@opts.inspect}#{@children.map{|c| ' ' + c.to_sexp}.join})"
32   end
33   
34   def merge!(other, prefix = "")
35     if name == other.name and
36         opts[:name] == other.opts[:name]
37       other.children.each do |child2|
38         merged = false
39         children.each do |child|
40           if child.merge!(child2, prefix + "    ")
41             merged = true
42             break
43           end
44         end
45         merge_child(child2.dup) unless merged
46       end
47       true
48     else
49       false
50     end
51   end
52   
53   class Builder
54     attr_reader :__desc__
55     private :__desc__
56     
57     def initialize(desc)
58       @__desc__ = desc
59     end
60     
61     def method_missing(name, *args, &blk)
62       opts = if args.empty?
63         { }
64       elsif args.size == 1
65         if args.first.is_a? Hash
66           args.first
67         else
68           { :name => args.first }
69         end
70       else
71         args[-1].merge(:name => args.first)
72       end
73       child = Descriptor.new(name, opts)
74       blk[self.class.new(child)] if block_given?
75       __desc__.add_child(child)
76     end
77     
78     def merge_point
79       @__desc__.opts[:merge_point] = @__desc__.children.size
80     end
81   end
82 end