gf-treevisitor 0.0.6
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.
- data/LICENSE +20 -0
- data/README.rdoc +22 -0
- data/bin/dirtree.rb +13 -0
- data/lib/gf_utility/file_utilities.rb +70 -0
- data/lib/gf_utility/kwartzhelper.rb +82 -0
- data/lib/gf_utility/md5.rb +17 -0
- data/lib/gf_utility/numeric.rb +17 -0
- data/lib/treevisitor.rb +3 -0
- data/lib/treevisitor/abs_node.rb +116 -0
- data/lib/treevisitor/build_dir_tree_visitor.rb +58 -0
- data/lib/treevisitor/cli/cli_dir_tree.rb +84 -0
- data/lib/treevisitor/dir_processor.rb +40 -0
- data/lib/treevisitor/dir_tree_walker.rb +99 -0
- data/lib/treevisitor/leaf_node.rb +27 -0
- data/lib/treevisitor/tree_node.rb +134 -0
- data/lib/treevisitor/tree_node_visitor.rb +251 -0
- data/lib/treevisitor/visitor/print_node_visitor2.rb +35 -0
- data/test/gf_utility/tc_kwartz.rb +20 -0
- data/test/gf_utility/tc_md5.rb +14 -0
- data/test/gf_utility/tc_numeric.rb +13 -0
- data/test/gf_utility/test_helper.rb +5 -0
- data/test/treevisitor/tc_dir_processor.rb +10 -0
- data/test/treevisitor/tc_dir_tree_walker.rb +30 -0
- data/test/treevisitor/tc_tree_node.rb +129 -0
- data/test/treevisitor/tc_tree_node_visitor.rb +66 -0
- data/test/treevisitor/test_helper.rb +10 -0
- data/test/ts_treevisitor.rb +16 -0
- data/test_data/gf_utility/kwartz_test_data/source/test1.html +5 -0
- data/test_data/tree_visitor/test_data/dir.1/dir.1.2/file.1.2.1 +0 -0
- data/test_data/tree_visitor/test_data/dir.1/file.1.1 +0 -0
- data/test_data/tree_visitor/test_data/dir.2/file.2.1 +0 -0
- metadata +91 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
class DirProcessor
|
4
|
+
|
5
|
+
def initialize( dirname, &action )
|
6
|
+
@dirname = dirname
|
7
|
+
@processors = {}
|
8
|
+
@default_processor = action
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_processor( re, &action )
|
12
|
+
@processors[ re ] = action
|
13
|
+
end
|
14
|
+
|
15
|
+
def run()
|
16
|
+
old_dirname = Dir.pwd
|
17
|
+
Dir.chdir( @dirname )
|
18
|
+
Dir["**/*"].each { |f|
|
19
|
+
pn = Pathname.new( f ).expand_path
|
20
|
+
# puts "#{self.class.name}#loadfromdir #{f}"
|
21
|
+
next if pn.directory?
|
22
|
+
process_file( pn )
|
23
|
+
}
|
24
|
+
Dir.chdir( old_dirname )
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def process_file( pn )
|
31
|
+
# puts "file: #{f}"
|
32
|
+
pair = @processors.find { |re,action| re =~ pn.to_s }
|
33
|
+
unless pair.nil?
|
34
|
+
pair[1].call( pn )
|
35
|
+
else
|
36
|
+
@default_processor.call( pn ) if @default_processor
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class DirTreeWalker
|
2
|
+
|
3
|
+
def initialize( dirname )
|
4
|
+
@dirname = dirname
|
5
|
+
unless File.directory?( dirname )
|
6
|
+
raise "#{dirname} is not a directory!"
|
7
|
+
end
|
8
|
+
|
9
|
+
@visitor = nil
|
10
|
+
@ignore_dir_patterns = []
|
11
|
+
@inspect_file_patterns = []
|
12
|
+
@ignore_file_patterns = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_ignore_dir( pattern )
|
16
|
+
@ignore_dir_patterns << pattern
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_ignore_file( pattern )
|
20
|
+
@ignore_file_patterns << pattern
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# quali file bisogna prendere in considerazione
|
25
|
+
# inspect opposto di ignore :-)
|
26
|
+
#
|
27
|
+
def add_inspect_file( pattern )
|
28
|
+
@inspect_file_patterns << pattern
|
29
|
+
end
|
30
|
+
|
31
|
+
def ignore_dir?( dirname )
|
32
|
+
basename = File.basename( dirname )
|
33
|
+
@ignore_dir_patterns.find{ |pattern|
|
34
|
+
basename == pattern
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def ignore_file?( filename )
|
39
|
+
basename = File.basename( filename )
|
40
|
+
@ignore_file_patterns.find{ |pattern|
|
41
|
+
if pattern.kind_of? Regexp
|
42
|
+
pattern =~ basename
|
43
|
+
else
|
44
|
+
pattern == basename
|
45
|
+
end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect_file?( filename )
|
50
|
+
return true if @inspect_file_patterns.empty?
|
51
|
+
basename = File.basename( filename )
|
52
|
+
@inspect_file_patterns.find{ |pattern|
|
53
|
+
if pattern.kind_of? Regexp
|
54
|
+
pattern =~ basename
|
55
|
+
else
|
56
|
+
pattern == basename
|
57
|
+
end
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def run( treeNodeVisitor )
|
62
|
+
@visitor = treeNodeVisitor
|
63
|
+
process_directory( File.expand_path( @dirname ) )
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
#
|
69
|
+
# recurse on other directories
|
70
|
+
#
|
71
|
+
# def process_directory( parentNode, dirname )
|
72
|
+
def process_directory( dirname )
|
73
|
+
return if ignore_dir?( dirname )
|
74
|
+
|
75
|
+
@visitor.enter_treeNode( dirname )
|
76
|
+
|
77
|
+
Dir.entries( dirname ).each { |basename|
|
78
|
+
next if basename == "." or basename == ".."
|
79
|
+
pathname = File.join( dirname, basename )
|
80
|
+
|
81
|
+
if File.directory?( pathname )
|
82
|
+
|
83
|
+
# directory
|
84
|
+
if ! ignore_dir?( basename )
|
85
|
+
process_directory( pathname )
|
86
|
+
end
|
87
|
+
|
88
|
+
else
|
89
|
+
|
90
|
+
# file
|
91
|
+
if inspect_file?( basename ) && ! ignore_file?( basename )
|
92
|
+
@visitor.visit_leafNode( pathname )
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
}
|
97
|
+
@visitor.exit_treeNode( dirname )
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# common
|
2
|
+
require "treevisitor/abs_node"
|
3
|
+
|
4
|
+
#
|
5
|
+
# Deriva da AbsNode
|
6
|
+
#
|
7
|
+
# definisce un metodo to_str
|
8
|
+
#
|
9
|
+
#
|
10
|
+
class LeafNode < AbsNode
|
11
|
+
|
12
|
+
def initialize( name, parent = nil )
|
13
|
+
super( name )
|
14
|
+
if parent
|
15
|
+
parent.add_leaf( self )
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def accept( visitor )
|
20
|
+
visitor.visit_leafNode( self )
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_str
|
24
|
+
name.to_str
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# common
|
2
|
+
require 'treevisitor/leaf_node'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Un treeNode e' come un AbsNode
|
6
|
+
# in piu' ha la possibilita' di contenere
|
7
|
+
# altri treeNode e LeafNode
|
8
|
+
#
|
9
|
+
# TreeNode @childs -1---n-> TreeNode
|
10
|
+
# @leaves -1---n-> LeafNode
|
11
|
+
#
|
12
|
+
class TreeNode < AbsNode
|
13
|
+
|
14
|
+
attr_reader :leaves
|
15
|
+
attr_reader :childs
|
16
|
+
|
17
|
+
def initialize( name, parent = nil )
|
18
|
+
@leaves = []
|
19
|
+
@childs = []
|
20
|
+
super( name )
|
21
|
+
if parent
|
22
|
+
parent.add_child( self )
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def root?
|
27
|
+
@parent.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# invalidate cached info
|
32
|
+
#
|
33
|
+
def invalidate
|
34
|
+
super
|
35
|
+
@childs.each{ |c| c.invalidate }
|
36
|
+
@leaves.each{ |l| l.invalidate }
|
37
|
+
end
|
38
|
+
|
39
|
+
def nr_nodes
|
40
|
+
nr = @leaves.length + @childs.length
|
41
|
+
@childs.inject( nr ) { |nr,c| nr + c.nr_nodes }
|
42
|
+
end
|
43
|
+
|
44
|
+
def nr_leaves
|
45
|
+
@leaves.length + @childs.inject(0) { |sum, child| sum + child.nr_leaves }
|
46
|
+
end
|
47
|
+
|
48
|
+
def nr_childs
|
49
|
+
@childs.length + @childs.inject(0) { |sum, child| sum + child.nr_childs }
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_leaf( leaf )
|
53
|
+
return if leaf.parent == self
|
54
|
+
if not leaf.parent.nil?
|
55
|
+
leaf.remove_from_parent()
|
56
|
+
end
|
57
|
+
leaf.parent = self
|
58
|
+
if @leaves.length > 0
|
59
|
+
@leaves.last.next = leaf
|
60
|
+
leaf.prev = @leaves.last
|
61
|
+
leaf.next = nil
|
62
|
+
end
|
63
|
+
leaf.invalidate
|
64
|
+
@leaves << leaf
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_child( treeNode )
|
68
|
+
return if treeNode.parent == self
|
69
|
+
if not treeNode.parent.nil?
|
70
|
+
treeNode.remove_from_parent()
|
71
|
+
end
|
72
|
+
treeNode.invalidate
|
73
|
+
treeNode.parent = self
|
74
|
+
@childs << treeNode
|
75
|
+
end
|
76
|
+
|
77
|
+
def find( name )
|
78
|
+
if self.name == name
|
79
|
+
return self
|
80
|
+
end
|
81
|
+
|
82
|
+
leaf = @leaves.find { |l| l.name == name }
|
83
|
+
if leaf
|
84
|
+
return leaf
|
85
|
+
end
|
86
|
+
|
87
|
+
@childs.each {|c|
|
88
|
+
node = c.find(name)
|
89
|
+
return node if node
|
90
|
+
}
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def accept( visitor )
|
95
|
+
visitor.enter_treeNode( self )
|
96
|
+
@leaves.each{ |l|
|
97
|
+
l.accept( visitor )
|
98
|
+
}
|
99
|
+
@childs.each { |tn|
|
100
|
+
tn.accept( visitor )
|
101
|
+
}
|
102
|
+
visitor.exit_treeNode( self )
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_str( depth = 0 )
|
106
|
+
str = ""
|
107
|
+
(0...depth).step {
|
108
|
+
str << " |-"
|
109
|
+
}
|
110
|
+
|
111
|
+
str << @name
|
112
|
+
str << "\n"
|
113
|
+
|
114
|
+
if ! @leaves.empty?
|
115
|
+
@leaves.each{ |l|
|
116
|
+
(0...depth-1).step {
|
117
|
+
str << " |-"
|
118
|
+
}
|
119
|
+
if @childs.empty?
|
120
|
+
str << " | "
|
121
|
+
else
|
122
|
+
str << " | | "
|
123
|
+
end
|
124
|
+
str << l.to_str
|
125
|
+
str << "\n"
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
@childs.each { |tn|
|
130
|
+
str << tn.to_str( depth + 1 )
|
131
|
+
}
|
132
|
+
str
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
# rubygems
|
2
|
+
require 'rubygems'
|
3
|
+
require 'abstract'
|
4
|
+
|
5
|
+
#
|
6
|
+
# Classe astratta per visitare un TreeNode
|
7
|
+
#
|
8
|
+
class TreeNodeVisitor
|
9
|
+
|
10
|
+
def enter_treeNode( treeNode )
|
11
|
+
not_implemented
|
12
|
+
end
|
13
|
+
|
14
|
+
def exit_treeNode( treeNode )
|
15
|
+
not_implemented
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_leafNode( leafNode )
|
19
|
+
not_implemented
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Utilizzo della classa astratta DirTreeProcessor
|
26
|
+
# per chimare un blocco su tutti i TreeNode
|
27
|
+
#
|
28
|
+
class BlockTreeNodeVisitor
|
29
|
+
|
30
|
+
def initialize( &action )
|
31
|
+
@block = action
|
32
|
+
end
|
33
|
+
|
34
|
+
def enter_treeNode( treeNode )
|
35
|
+
@block.call( treeNode )
|
36
|
+
end
|
37
|
+
|
38
|
+
def exit_treeNode( treeNode )
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit_leafNode( leafNode )
|
42
|
+
@block.call( leafNode )
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Utilizzo della classa astratta DirTreeProcessor
|
49
|
+
# per stampare i nodi di un TreeNode
|
50
|
+
#
|
51
|
+
class FlatPrintTreeNodeVisitor < TreeNodeVisitor
|
52
|
+
|
53
|
+
def enter_treeNode( treeNode )
|
54
|
+
puts treeNode.name
|
55
|
+
end
|
56
|
+
|
57
|
+
def exit_treeNode( treeNode )
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit_leafNode( leafNode )
|
61
|
+
puts leafNode.name
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
class PrintTreeNodeVisitor < TreeNodeVisitor
|
68
|
+
|
69
|
+
def initialize( *args )
|
70
|
+
super( *args )
|
71
|
+
@depth = 0
|
72
|
+
end
|
73
|
+
|
74
|
+
def visit_leafNode( leafNode )
|
75
|
+
str = ""
|
76
|
+
(0...@depth-1).step {
|
77
|
+
str << " |-"
|
78
|
+
}
|
79
|
+
str << " | "
|
80
|
+
puts str + leafNode.name.to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
def enter_treeNode( treeNode )
|
84
|
+
|
85
|
+
str = ""
|
86
|
+
(0...@depth).step {
|
87
|
+
str << " |-"
|
88
|
+
}
|
89
|
+
|
90
|
+
if @depth == 0
|
91
|
+
puts str + treeNode.name.to_s
|
92
|
+
else
|
93
|
+
puts str + treeNode.name.to_s
|
94
|
+
end
|
95
|
+
@depth += 1
|
96
|
+
end
|
97
|
+
|
98
|
+
def exit_treeNode( treeNode )
|
99
|
+
@depth -= 1
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
#
|
105
|
+
#
|
106
|
+
#
|
107
|
+
class DepthTreeNodeVisitor < TreeNodeVisitor
|
108
|
+
|
109
|
+
attr_reader :depth
|
110
|
+
|
111
|
+
def initialize
|
112
|
+
super
|
113
|
+
@depth = 0
|
114
|
+
end
|
115
|
+
|
116
|
+
def enter_treeNode( treeNode )
|
117
|
+
@depth += 1
|
118
|
+
end
|
119
|
+
|
120
|
+
def exit_treeNode( treeNode )
|
121
|
+
@depth -= 1
|
122
|
+
end
|
123
|
+
|
124
|
+
def visit_leafNode( leafNode )
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
#
|
130
|
+
# Esempio
|
131
|
+
# Clona un TreeNode
|
132
|
+
#
|
133
|
+
class CloneTreeNodeVisitor < TreeNodeVisitor
|
134
|
+
|
135
|
+
attr_reader :clonedRoot
|
136
|
+
|
137
|
+
def initialize
|
138
|
+
super
|
139
|
+
@clonedRoot = nil
|
140
|
+
@stack = []
|
141
|
+
end
|
142
|
+
|
143
|
+
def enter_treeNode( treeNode )
|
144
|
+
if @stack.empty?
|
145
|
+
clonedTreeNode = TreeNode.new( treeNode.name )
|
146
|
+
@clonedRoot = clonedTreeNode
|
147
|
+
else
|
148
|
+
clonedTreeNode = TreeNode.new( treeNode.name, @stack.last )
|
149
|
+
end
|
150
|
+
@stack.push( clonedTreeNode )
|
151
|
+
end
|
152
|
+
|
153
|
+
def exit_treeNode( treeNode )
|
154
|
+
@stack.pop
|
155
|
+
end
|
156
|
+
|
157
|
+
def visit_leafNode( leafNode )
|
158
|
+
clonedLeafNode = LeafNode.new( leafNode.name, @stack.last )
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# CallbackTreeNodeVisitor
|
165
|
+
#
|
166
|
+
class CallbackTreeNodeVisitor < TreeNodeVisitor
|
167
|
+
|
168
|
+
def initialize( root = nil )
|
169
|
+
super()
|
170
|
+
@stack = []
|
171
|
+
@root = root
|
172
|
+
@stack.push( root ) if root
|
173
|
+
@action_enterTreeNode = nil
|
174
|
+
@action_visitLeafNode = nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def onEnterTreeNode( &action )
|
178
|
+
@action_enterTreeNode = action
|
179
|
+
end
|
180
|
+
|
181
|
+
def onVisitLeafNode( &action )
|
182
|
+
@action_visitLeafNode = action
|
183
|
+
end
|
184
|
+
|
185
|
+
def enter_treeNode( treeNode )
|
186
|
+
parentNode = if @stack.empty?
|
187
|
+
nil
|
188
|
+
else
|
189
|
+
@stack.last
|
190
|
+
end
|
191
|
+
@root = treeNode if @stack.empty?
|
192
|
+
@stack.push( treeNode )
|
193
|
+
@action_enterTreeNode.call( treeNode ) if @action_enterTreeNode
|
194
|
+
end
|
195
|
+
|
196
|
+
def exit_treeNode( treeNode )
|
197
|
+
@stack.pop
|
198
|
+
end
|
199
|
+
|
200
|
+
def visit_leafNode( leafNode )
|
201
|
+
parentNode = @stack.last
|
202
|
+
@action_visitLeafNode.call( leafNode ) if @action_visitLeafNode
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
#
|
209
|
+
# CallbackTreeNodeVisitor
|
210
|
+
#
|
211
|
+
class CallbackTreeNodeVisitor2 < TreeNodeVisitor
|
212
|
+
|
213
|
+
attr_reader :root
|
214
|
+
|
215
|
+
def initialize( root = nil )
|
216
|
+
super()
|
217
|
+
@stack = []
|
218
|
+
@root = root
|
219
|
+
@stack.push( root ) if root
|
220
|
+
end
|
221
|
+
|
222
|
+
def onEnterTreeNode( &action )
|
223
|
+
@action_enterTreeNode = action
|
224
|
+
end
|
225
|
+
|
226
|
+
def onVisitLeafNode( &action )
|
227
|
+
@action_visitLeafNode = action
|
228
|
+
end
|
229
|
+
|
230
|
+
def enter_treeNode( treeNode )
|
231
|
+
newParentNode = if @stack.empty?
|
232
|
+
nil
|
233
|
+
else
|
234
|
+
@stack.last
|
235
|
+
end
|
236
|
+
newTreeNode = @action_enterTreeNode.call( treeNode, newParentNode )
|
237
|
+
@root = newTreeNode if @stack.empty?
|
238
|
+
@stack.push( newTreeNode )
|
239
|
+
end
|
240
|
+
|
241
|
+
def exit_treeNode( treeNode )
|
242
|
+
@stack.pop
|
243
|
+
end
|
244
|
+
|
245
|
+
def visit_leafNode( leafNode )
|
246
|
+
newParentNode = @stack.last
|
247
|
+
@action_visitLeafNode.call( leafNode, newParentNode )
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|