tree.rb 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/.gemtest +0 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +160 -0
  4. data/Rakefile +12 -0
  5. data/bin/tree.rb +9 -0
  6. data/examples/directory_walker/directory_without_subdirectory.rb +37 -0
  7. data/examples/directory_walker/find_files.rb +18 -0
  8. data/examples/directory_walker/print_files.rb +12 -0
  9. data/examples/protovis/directory_to_json_visitor.rb +15 -0
  10. data/examples/protovis/index.html +87 -0
  11. data/examples/protovis/protovis-r3.2.js +277 -0
  12. data/examples/protovis/treevisitor.js +33 -0
  13. data/examples/protovis/treevisitor.png +0 -0
  14. data/lib/tree_visitor.rb +2 -0
  15. data/lib/treevisitor/abs_node.rb +144 -0
  16. data/lib/treevisitor/basic_tree_node_visitor.rb +44 -0
  17. data/lib/treevisitor/cli/cli_tree.rb +121 -0
  18. data/lib/treevisitor/directory_walker.rb +300 -0
  19. data/lib/treevisitor/leaf_node.rb +33 -0
  20. data/lib/treevisitor/tree_node.rb +296 -0
  21. data/lib/treevisitor/tree_node_visitor.rb +120 -0
  22. data/lib/treevisitor/util/dir_processor.rb +46 -0
  23. data/lib/treevisitor/version.rb +4 -0
  24. data/lib/treevisitor/visitors/block_tree_node_visitor.rb +21 -0
  25. data/lib/treevisitor/visitors/build_dir_tree_visitor.rb +57 -0
  26. data/lib/treevisitor/visitors/callback_tree_node_visitor2.rb +48 -0
  27. data/lib/treevisitor/visitors/clone_tree_node_visitor.rb +39 -0
  28. data/lib/treevisitor/visitors/depth_tree_node_visitor.rb +27 -0
  29. data/lib/treevisitor/visitors/directory_to_hash_visitor.rb +33 -0
  30. data/lib/treevisitor/visitors/flat_print_tree_node_visitors.rb +20 -0
  31. data/lib/treevisitor/visitors/print_dir_tree_visitor.rb +21 -0
  32. data/lib/treevisitor/visitors/print_tree_node_visitor.rb +40 -0
  33. data/lib/treevisitor.rb +40 -0
  34. data/lib/treevisitor_cli.rb +7 -0
  35. data/spec/fixtures/test_dir_1/.dir_with_dot/dummy.txt +0 -0
  36. data/spec/fixtures/test_dir_1/dir.1/dir.1.2/file.1.2.1 +0 -0
  37. data/spec/fixtures/test_dir_1/dir.1/file.1.1 +0 -0
  38. data/spec/fixtures/test_dir_1/dir.2/file.2.1 +0 -0
  39. data/spec/fixtures/test_dir_2/[Dsube]/sub/.gitkeep +0 -0
  40. data/spec/spec_helper.rb +27 -0
  41. data/spec/treevisitor/cli/cli_tree_spec.rb +69 -0
  42. data/spec/treevisitor/directory_walker_spec.rb +99 -0
  43. data/spec/treevisitor/tree_dsl_spec.rb +57 -0
  44. data/spec/treevisitor/tree_dsl_with_derived_class1_spec.rb +53 -0
  45. data/spec/treevisitor/tree_dsl_with_derived_class_spec.rb +51 -0
  46. data/spec/treevisitor/tree_node_paths_spec.rb +70 -0
  47. data/spec/treevisitor/tree_node_spec.rb +135 -0
  48. data/spec/treevisitor/tree_node_visitor_delegate_spec.rb +35 -0
  49. data/spec/treevisitor/tree_node_visitor_dsl_spec.rb +66 -0
  50. data/spec/treevisitor/util/dir_processor_spec.rb +13 -0
  51. data/spec/treevisitor/visitors/block_tree_node_visitor_spec.rb +25 -0
  52. data/spec/treevisitor/visitors/callback_tree_node_visitor2_spec.rb +38 -0
  53. data/spec/treevisitor/visitors/depth_tree_node_visitor_spec.rb +28 -0
  54. data/spec/treevisitor/visitors/tree_node_visitors_spec.rb +27 -0
  55. data/tasks/rspec.rake +34 -0
  56. data/tasks/yard.rake +36 -0
  57. data/tree.rb.gemspec +70 -0
  58. metadata +231 -0
@@ -0,0 +1,296 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ #
4
+ # TreeNode can contains other TreeNode (children)
5
+ # and can contains LeafNode (leaves)
6
+ #
7
+ # TreeNode @children -1---n-> TreeNode
8
+ # @leaves -1---n-> LeafNode
9
+ #
10
+ # define dsl to create Tree
11
+ #
12
+ # @example
13
+ # tree = TreeNode.create do
14
+ # node "root" do
15
+ # leaf "l1"
16
+ # node "sub" do
17
+ # leaf "l3"
18
+ # end
19
+ # node "wo leaves"
20
+ # end
21
+ class TreeNode < AbsNode
22
+
23
+ class << self
24
+
25
+ # DSL create a root node
26
+ #
27
+ # tree = TreeNode.create do ... end
28
+ #
29
+ # @param [Class] class1 Subclass of TreeNode default TreeNode
30
+ # @param [Class] class2 Subclass of LeafNode default LeafNode
31
+ # @param [Object] block
32
+ def create(class1 = TreeNode, class2 = LeafNode, &block)
33
+ if class1.ancestors.include?(TreeNode) and class2.ancestors.include?(LeafNode)
34
+ @tree_node_class = class1
35
+ @leaf_node_class = class2
36
+ elsif class1.ancestors.include?(LeafNode) and class2 == LeafNode
37
+ @tree_node_class = self
38
+ @leaf_node_class = class1
39
+ end
40
+
41
+ if @tree_node_class.nil? || @leaf_node_class.nil?
42
+ raise "Must be specified class derived from TreeNode and LeafNode"
43
+ end
44
+
45
+ @scope_stack = []
46
+ class_eval(&block)
47
+ end
48
+
49
+ private
50
+
51
+ # DSL node add a child to the surrounding node
52
+ # TreeNode.create do
53
+ # node "..."
54
+ # end
55
+ def node(*args, &block)
56
+ parent_node = @scope_stack.length > 0 ? @scope_stack[-1] : nil
57
+ args << parent_node
58
+ tree_node = @tree_node_class.new(*args)
59
+ @scope_stack.push tree_node
60
+ if block
61
+ if block.arity == 0 || block.arity == -1
62
+ class_eval(&block)
63
+ elsif block.arity == 1
64
+ new_block = Proc.new { block.call(tree_node) }
65
+ class_eval(&new_block)
66
+ else
67
+ raise "block take too much arguments #{block.arity}"
68
+ end
69
+ end
70
+ @scope_stack.pop
71
+ end
72
+
73
+ # DSL node add a leaf to the surround node
74
+ # TreeNode.create do
75
+ # leaf "..."
76
+ # end
77
+ def leaf(*args, &block)
78
+ tree_node = @scope_stack[-1]
79
+ args << tree_node
80
+ leaf_node = @leaf_node_class.new(*args)
81
+ if block
82
+ if block.arity == 0 || block.arity == -1
83
+ class_eval(&block)
84
+ elsif block.arity == 1
85
+ new_block = Proc.new { block.call(leaf_node) }
86
+ class_eval(&new_block)
87
+ else
88
+ raise "block take too much arguments #{block.arity}"
89
+ end
90
+ end
91
+ leaf_node
92
+ end
93
+ end # end class << self
94
+
95
+ # leaves of this node
96
+ attr_reader :leaves
97
+
98
+ # children i.e. other tree node
99
+ attr_reader :children
100
+
101
+ #
102
+ # @param [Object] content of this node
103
+ # @param [Object] parent of this node. If parent is nil, it is a root
104
+ def initialize(content, parent = nil)
105
+ @leaves = []
106
+ @children = []
107
+ super(content)
108
+ parent.add_child(self) if parent
109
+ end
110
+
111
+ #
112
+ # Test if is a root
113
+ #
114
+ # @return [Boolean] true if this node is a root
115
+ def root?
116
+ @parent.nil?
117
+ end
118
+
119
+ #
120
+ # invalidate cached info
121
+ # invalidate propagates form parent to children and leaves
122
+ #
123
+ def invalidate
124
+ super
125
+ @children.each { |c| c.invalidate }
126
+ @leaves.each { |l| l.invalidate }
127
+ end
128
+
129
+ #
130
+ # @return [FixNum] total number of nodes
131
+ #
132
+ def nr_nodes
133
+ nr = @leaves.length + @children.length
134
+ @children.inject(nr) { |sum, c| sum + c.nr_nodes }
135
+ end
136
+
137
+ #
138
+ # @return [FixNum] total number of leaves
139
+ #
140
+ def nr_leaves
141
+ @leaves.length + @children.inject(0) { |sum, child| sum + child.nr_leaves }
142
+ end
143
+
144
+ #
145
+ # @return [FixNum] total number of children
146
+ #
147
+ def nr_children
148
+ @children.length + @children.inject(0) { |sum, child| sum + child.nr_children }
149
+ end
150
+
151
+ #
152
+ # Add a Leaf
153
+ # @param [LeafNode]
154
+ #
155
+ # @return self
156
+ #
157
+ def add_leaf(leaf)
158
+ return if leaf.parent == self
159
+ if not leaf.parent.nil?
160
+ leaf.remove_from_parent
161
+ end
162
+ leaf.parent = self
163
+ if @leaves.length > 0
164
+ @leaves.last.next = leaf
165
+ leaf.prev = @leaves.last
166
+ else
167
+ leaf.prev = nil
168
+ end
169
+ leaf.next = nil
170
+ leaf.invalidate
171
+ @leaves << leaf
172
+ self
173
+ end
174
+
175
+ #
176
+ # Add a Tree
177
+ # @param [LeafNode]
178
+ #
179
+ # @return self
180
+ #
181
+ def add_child(tree_node)
182
+ return if tree_node.parent == self
183
+ if not tree_node.parent.nil?
184
+ tree_node.remove_from_parent
185
+ else
186
+ tree_node.prefix_path = nil
187
+ end
188
+ tree_node.invalidate
189
+ tree_node.parent = self
190
+ if @children.length > 0
191
+ @children.last.next = tree_node
192
+ tree_node.prev = @children.last
193
+ else
194
+ tree_node.prev = nil
195
+ end
196
+ tree_node.next = nil
197
+ @children << tree_node
198
+ self
199
+ end
200
+
201
+ #
202
+ # Find a node down the hierarchy with content
203
+ # @param [Object,Regexp] content of searched node
204
+ # @return [Object, nil] nil if not found
205
+ #
206
+ def find(content = nil, &block)
207
+ if content and block_given?
208
+ raise "TreeNode::find - passed content AND block"
209
+ end
210
+
211
+ if content
212
+ if content.class == Regexp
213
+ block = proc { |l| l.content =~ content }
214
+ else
215
+ block = proc { |l| l.content == content }
216
+ end
217
+ end
218
+ return self if block.call(self)
219
+
220
+ leaf = @leaves.find { |l| block.call(l) }
221
+ return leaf if leaf
222
+
223
+ @children.each do |child|
224
+ node = child.find &block
225
+ return node if node
226
+ end
227
+ nil
228
+ end
229
+
230
+ #
231
+ # return the visitor
232
+ #
233
+ def accept(visitor)
234
+ visitor.enter_node(self)
235
+ @leaves.each do |leaf|
236
+ leaf.accept(visitor)
237
+ end
238
+ @children.each do |child|
239
+ child.accept(visitor)
240
+ end
241
+ visitor.exit_node(self)
242
+ visitor
243
+ end
244
+
245
+ #
246
+ # Format the content of tree
247
+ #
248
+ def to_str(prefix= "", tty_color = false)
249
+ str = ""
250
+
251
+ # print node itself
252
+ if root?
253
+ if tty_color
254
+ str << ANSI.red{ to_s } << "\n"
255
+ else
256
+ str << to_s << "\n"
257
+ end
258
+ else
259
+ str << prefix
260
+ if self.next
261
+ str << '|-- '
262
+ else
263
+ str << '`-- '
264
+ end
265
+ if tty_color
266
+ str << ANSI.red{ to_s } << "\n"
267
+ else
268
+ str << to_s << "\n"
269
+ end
270
+ prefix += self.next ? "| " : " "
271
+ end
272
+
273
+ # print leaves
274
+ @leaves.each do |leaf|
275
+ str << prefix
276
+ if !leaf.next.nil? or !@children.empty?
277
+ str << '|-- '
278
+ else
279
+ str << '`-- '
280
+ end
281
+ if tty_color
282
+ str << ANSI.green{ leaf.to_s } << "\n"
283
+ else
284
+ str << leaf.to_s << "\n"
285
+ end
286
+ end
287
+
288
+ # print children
289
+ @children.each do |child|
290
+ str << child.to_str(prefix, tty_color)
291
+ end
292
+ str
293
+ end
294
+
295
+ end
296
+ end
@@ -0,0 +1,120 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+
4
+ #
5
+ # More complex TreeNodeVisitor, define a simple dsl
6
+ # @example
7
+ # TreeNodeVisitor.new do
8
+ # on_enter_node do |node|
9
+ # puts "hello #{node}"
10
+ # end
11
+ # on_exit_node do |node|
12
+ # puts "bye #{node}"
13
+ # end
14
+ # on_leaf do |leaf|
15
+ # puts "how you do #{leaf}"
16
+ # end
17
+ # end
18
+ #
19
+ class TreeNodeVisitor
20
+
21
+ # @param [Object] delegate
22
+ def initialize(delegate = nil, &block)
23
+ @on_enter_tree_node_blocks = []
24
+ @on_exit_tree_node_blocks = []
25
+ @on_visit_leaf_node_blocks = []
26
+ @stack = []
27
+ @root = nil
28
+ @delegate = delegate
29
+ if block
30
+ instance_eval(&block)
31
+ end
32
+ end
33
+
34
+ #
35
+ # called on tree node at start of the visit i.e. we start to visit the subtree
36
+ #
37
+ def enter_node(tree_node)
38
+ parent = @stack.last
39
+ if @delegate
40
+ @delegate.enter_node(tree_node) if @delegate.respond_to? :enter_node
41
+ else
42
+ @on_enter_tree_node_blocks.each do |b|
43
+ if b.arity == 1
44
+ b.call(tree_node)
45
+ elsif b.arity == 2
46
+ b.call(tree_node, parent)
47
+ end
48
+ end
49
+ end
50
+ @root = tree_node if @stack.empty?
51
+ @stack.push(tree_node)
52
+ end
53
+
54
+ #
55
+ # called on tree node at end of the visit i.e. oll subtree are visited
56
+ #
57
+ def exit_node(tree_node)
58
+ parent = @stack.last
59
+ if @delegate
60
+ @delegate.exit_node(tree_node) if @delegate.respond_to? :exit_node
61
+ else
62
+ @on_exit_tree_node_blocks.each do |b|
63
+ if b.arity == 1
64
+ b.call(tree_node)
65
+ elsif b.arity == 2
66
+ b.call(tree_node, parent)
67
+ end
68
+ end
69
+ end
70
+ @stack.pop
71
+ end
72
+
73
+ #
74
+ # called when visit leaf node
75
+ #
76
+ def visit_leaf(leaf_node)
77
+ parent = @stack.last
78
+ if @delegate
79
+ @delegate.visit_leaf(leaf_node) if @delegate.respond_to? :visit_leaf
80
+ else
81
+ @on_visit_leaf_node_blocks.each do |b|
82
+ if b.arity == 1
83
+ b.call(leaf_node)
84
+ elsif b.arity == 2
85
+ b.call(leaf_node, parent)
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ #
92
+ # add a block to be called when entering into a tree_node
93
+ #
94
+ def on_enter_node(&block)
95
+ raise "already defined a delegate" if @delegate
96
+ raise "block missing" unless block
97
+ @on_enter_tree_node_blocks << block
98
+ end
99
+
100
+ #
101
+ # add a block to be called when exiting from a TreeNode
102
+ #
103
+ def on_exit_node(&block)
104
+ raise "already defined a delegate" if @delegate
105
+ raise "block missing" unless block
106
+ @on_exit_tree_node_blocks << block
107
+ end
108
+
109
+ #
110
+ # add a block to be called when visiting a leaf node
111
+ #
112
+ def on_leaf(&block)
113
+ raise "already defined a delegate" if @delegate
114
+ raise "block missing" unless block
115
+ @on_visit_leaf_node_blocks << block
116
+ end
117
+
118
+ end
119
+
120
+ end
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+
4
+ #
5
+ # Visit a directory tree
6
+ # not TreeNode related
7
+ #
8
+ class DirProcessor
9
+
10
+ def initialize( &action )
11
+ @processors = {}
12
+ @default_processor = action
13
+ end
14
+
15
+ def add_processor( re, &action )
16
+ @processors[ re ] = action
17
+ end
18
+
19
+ def process( dirname )
20
+ @dirname = dirname
21
+ old_dirname = Dir.pwd
22
+ Dir.chdir( @dirname )
23
+ Dir["**/*"].each { |f|
24
+ pn = Pathname.new( f ).expand_path
25
+ # puts "#{self.class.name}#loadfromdir #{f}"
26
+ next if pn.directory?
27
+ process_file( pn )
28
+ }
29
+ Dir.chdir( old_dirname )
30
+ self
31
+ end
32
+
33
+ private
34
+
35
+ def process_file( pn )
36
+ # puts "file: #{f}"
37
+ pair = @processors.find { |re,action| re =~ pn.to_s }
38
+ unless pair.nil?
39
+ pair[1].call( pn )
40
+ else
41
+ @default_processor.call( pn ) if @default_processor
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ VERSION="0.3.0"
4
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ #
4
+ # It calls a block when visit a tree_node or leaf_node
5
+ #
6
+ class BlockTreeNodeVisitor < BasicTreeNodeVisitor
7
+
8
+ def initialize( &action )
9
+ @block = action
10
+ end
11
+
12
+ def enter_node( tree_node )
13
+ @block.call( tree_node )
14
+ end
15
+
16
+ def visit_leaf( leaf_node )
17
+ @block.call( leaf_node )
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ #
4
+ # Builds a TreeNode from a filesystem directory
5
+ # It similar to CloneTreeNodeVisitor
6
+ #
7
+ class BuildDirTreeVisitor # < BasicTreeNodeVisitor
8
+
9
+ attr_reader :root
10
+
11
+ #
12
+ # Number of visited directory (aka nr_nodes - nr_leaf)
13
+ #
14
+ attr_reader :nr_directories
15
+
16
+
17
+ #
18
+ # Number of visited directory (nr_leaves)
19
+ # @see AbsNode#nr_leaves
20
+ #
21
+ attr_reader :nr_files
22
+
23
+ def initialize
24
+ super
25
+ @root = nil
26
+ @stack = []
27
+ @nr_directories = 0
28
+ @nr_files = 0
29
+ end
30
+
31
+ def enter_node( pathname )
32
+ if @stack.empty?
33
+ tree_node = TreeNode.new( File.basename( pathname ) )
34
+ @root = tree_node
35
+ else
36
+ tree_node = TreeNode.new( File.basename( pathname ), @stack.last )
37
+ end
38
+ @nr_directories += 1
39
+ @stack.push( tree_node )
40
+ end
41
+
42
+ def cannot_enter_node(pathname, error)
43
+
44
+ end
45
+
46
+ def exit_node( pathname )
47
+ @stack.pop
48
+ end
49
+
50
+ def visit_leaf( pathname )
51
+ @nr_files += 1
52
+ # connect the leaf_node created to the last tree_node on the stack
53
+ LeafNode.new( File.basename(pathname), @stack.last )
54
+ end
55
+
56
+ end
57
+ end # end module TreeVisitor
@@ -0,0 +1,48 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ #
4
+ # Executes a block when enter in a node
5
+ # The block are defined from on_enter_X methods
6
+ # The blocks take as argument the node and the parent_node
7
+ #
8
+ class CallbackTreeNodeVisitor2
9
+
10
+ attr_reader :root
11
+
12
+ def initialize(delegate = nil)
13
+ super()
14
+ @stack = []
15
+ @root = nil
16
+ @delegate = delegate
17
+ end
18
+
19
+ def on_enter_node(&block)
20
+ raise "already defined a delegate" if @delegate
21
+ @action_enter_tree_node = block
22
+ end
23
+
24
+ def on_visit_leaf(&block)
25
+ raise "already defined a delegate" if @delegate
26
+ @action_visit_leaf_node = block
27
+ end
28
+
29
+ def enter_node(src_tree_node)
30
+ dst_parent_node = @stack.empty? ? nil : @stack.last
31
+ dst_tree_node = @action_enter_tree_node.call(src_tree_node, dst_parent_node) if @action_enter_tree_node
32
+ dst_tree_node = @delegate.enter_node(src_tree_node, dst_parent_node) if @delegate and @delegate.respond_to? :enter_node
33
+ @root = dst_tree_node if @stack.empty?
34
+ @stack.push(dst_tree_node)
35
+ end
36
+
37
+ def exit_node(src_tree_node)
38
+ @stack.pop
39
+ end
40
+
41
+ def visit_leaf(src_leaf_node)
42
+ parent_node = @stack.last
43
+ @action_visit_leaf_node.call(src_leaf_node, parent_node) if @action_visit_leaf_node
44
+ @delegate.visit_leaf(src_leaf_node, parent_node) if @delegate and @delegate.respond_to? :visit_leaf
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ #
4
+ # Clone a tree_node, nodes are duplicated.
5
+ # Node content are not duplicated!
6
+ #
7
+ class CloneTreeNodeVisitor # < BasicTreeNodeVisitor
8
+
9
+ #
10
+ # Contains the cloned tree node after the visit
11
+ #
12
+ attr_reader :cloned_root
13
+
14
+ def initialize
15
+ super
16
+ @cloned_root = nil
17
+ @stack = []
18
+ end
19
+
20
+ def enter_node( tree_node )
21
+ if @stack.empty?
22
+ cloned_tree_node = TreeNode.new( tree_node.content )
23
+ @cloned_root = cloned_tree_node
24
+ else
25
+ cloned_tree_node = TreeNode.new( tree_node.content, @stack.last )
26
+ end
27
+ @stack.push( cloned_tree_node )
28
+ end
29
+
30
+ def exit_node( tree_node )
31
+ @stack.pop
32
+ end
33
+
34
+ def visit_leaf( leaf_node )
35
+ LeafNode.new( leaf_node.content, @stack.last )
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ #
4
+ # Simple visitor: show how calculate the depth of a tree
5
+ #
6
+ class DepthTreeNodeVisitor # < BasicTreeNodeVisitor
7
+
8
+ attr_reader :depth
9
+
10
+ def initialize
11
+ super
12
+ @depth = 0
13
+ end
14
+
15
+ def enter_node( tree_node )
16
+ @depth += 1
17
+ end
18
+
19
+ def exit_node( tree_node )
20
+ @depth -= 1
21
+ end
22
+
23
+ def visit_leaf( leaf_node )
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module TreeVisitor
4
+ #
5
+ # Build hash with directory structure
6
+ #
7
+ class DirectoryToHashVisitor # < TreeVisitor::BasicTreeNodeVisitor
8
+
9
+ attr_reader :root
10
+
11
+ def initialize(pathname)
12
+ @stack = []
13
+ @node = {}
14
+ @root = @node
15
+ end
16
+
17
+ def enter_node(pathname)
18
+ subnode = {}
19
+ @node[File.basename(pathname)] = subnode
20
+ @stack.push(@node)
21
+ @node = subnode
22
+ end
23
+
24
+ def exit_node(pathname)
25
+ @node = @stack.pop
26
+ end
27
+
28
+ def visit_leaf(pathname)
29
+ @node[File.basename(pathname)] = File.stat(pathname).size
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TreeVisitor
3
+ #
4
+ # Print for every node the name
5
+ #
6
+ class FlatPrintTreeNodeVisitor # < BasicTreeNodeVisitor
7
+
8
+ def enter_node( tree_node )
9
+ puts tree_node.name
10
+ end
11
+
12
+ def exit_node( tree_node )
13
+ end
14
+
15
+ def visit_leaf( leaf_node )
16
+ puts leaf_node.name
17
+ end
18
+
19
+ end
20
+ end