1 # $Id: treeable.rb,v 1.4 2012/04/17 02:49:40 machan Exp $
2
3 require 'enumerator'
4
5 require 'tmdoc/tmstd/assertion'
6
7
8 module TmStd
9
10 module Treeable
11 def each_descendant(selector = nil, &block)
12 Assertion.opt_kind_of selector, Proc
13 Assertion.kind_of block, Proc
14
15 if selector
16 for child in self.children
17 if selector.call(child)
18 yield child
19 __each_descendant__(child, selector, &block)
20 end
21 end
22 else
23 for child in self.children
24 yield child
25 __each_descendant__(child, selector, &block)
26 end
27 end
28
29 nil
30 end
31
32
33 def __each_descendant__(child, selector = nil, &block)
34 Assertion.opt_kind_of selector, Proc
35 Assertion.kind_of block, Proc
36
37 if selector
38 child.each_descendant do |grand_child|
39 if selector.call(grand_child)
40 yield grand_child
41 end
42 end
43 else
44 child.each_descendant do |grand_child|
45 yield grand_child
46 end
47 end
48
49 nil
50 end
51 private :__each_descendant__
52
53
54 def descendants(&selector)
55 Assertion.opt_kind_of selector, Proc
56
57 ds = self.to_enum(:each_descendant, selector).to_a
58
59 Assertion.kind_of ds, Array
60 end
61
62
63 def descendant_any?(&selector)
64 Assertion.kind_of selector, Proc
65
66 result = self.to_enum(:each_descendant).any?(&selector)
67
68 Assertion.boolean result
69 end
70
71
72 def descendant_all?(&selector)
73 Assertion.kind_of selector, Proc
74
75 result = self.to_enum(:each_descendant).all?(&selector)
76
77 Assertion.boolean result
78 end
79
80
81 def print_tree(io, opts = {})
82 Assertion.kind_of opts, Hash
83
84 in_verbatim = false
85 rejector = nil
86 selector = nil
87 do_sort = false
88 comparator = nil
89
90 for key, val in opts
91 Assertion.kind_of key, Symbol
92
93 case key
94 when :in_verbatim
95 ASSERT.boolean val
96
97 in_verbatim = val
98 when :rejector
99 Assertion.kind_of val, Proc
100
101 rejector = val
102 when :selector
103 Assertion.kind_of val, Proc
104
105 selector = val
106 when :do_sort
107 ASSERT.boolean val
108
109 do_sort = val
110 when :comparator
111 Assertion.kind_of val, Proc
112
113 comparator = val
114 else
115 Assertion.abort "Unknown option: %s", key
116 end
117 end
118
119 __print_tree__(
120 io, 0, in_verbatim, rejector, selector, do_sort, comparator
121 )
122
123 nil
124 end
125
126
127 def __print_tree__(
128 io, depth, in_verbatim, rejector, selector, do_sort, comparator
129 )
130 Assertion.kind_of depth, Integer
131 Assertion.boolean in_verbatim
132 Assertion.opt_kind_of rejector, Proc
133 Assertion.opt_kind_of selector, Proc
134 Assertion.boolean do_sort
135 Assertion.opt_kind_of comparator, Proc
136
137 selected =
138 if rejector || selector
139 self.children.select { |child|
140 rejector_result =
141 if rejector
142 ! rejector.call(child)
143 else
144 true
145 end
146
147 if rejector_result
148 if selector
149 selector.call(child)
150 else
151 true
152 end
153 else
154 false
155 end
156 }
157 else
158 self.children
159 end
160 sorted =
161 if do_sort
162 if comparator
163 selected.sort_by(&comparator)
164 else
165 selected.sort_by { |elem| elem.to_s }
166 end
167 else
168 selected
169 end
170
171 (0 .. depth).each do
172 __print_tree_indent__(io)
173 end
174
175 __print_tree_enter__(io)
176
177 for child in sorted
178 child.__print_tree__(
179 io,
180 depth + 1,
181 in_verbatim,
182 rejector,
183 selector,
184 do_sort,
185 comparator
186 )
187 end
188
189 nil
190 end
191
192
193 def __print_tree_indent__(io)
194 io << '| '
195
196 nil
197 end
198 private :__print_tree_indent__
199
200
201 def __print_tree_enter__(io)
202 io << self.to_s << "\n"
203
204 nil
205 end
206 private :__print_tree_enter__
207 end
208
209 end # TmStd