tree.rb 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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