build-files 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/Rakefile +3 -6
- data/build-files.gemspec +1 -1
- data/lib/build/files.rb +3 -1
- data/lib/build/files/directory.rb +1 -1
- data/lib/build/files/filesystem.rb +38 -0
- data/lib/build/files/glob.rb +1 -1
- data/lib/build/files/{paths.rb → list.rb} +3 -121
- data/lib/build/files/path.rb +171 -0
- data/lib/build/files/state.rb +36 -22
- data/lib/build/files/version.rb +1 -1
- data/spec/build/files/list_spec.rb +118 -0
- data/spec/build/files/path_spec.rb +100 -0
- data/{test/test_state.rb → spec/build/files/state_spec.rb} +33 -34
- metadata +14 -12
- data/test/test_files.rb +0 -75
- data/test/test_paths.rb +0 -111
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dea84d68b0394c651e2593a20dc08b7f7631e4b3
|
4
|
+
data.tar.gz: 40cf1afa1b7bbfb740b73383529137d8810456c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7a42fa79f16d31f4376b9dd86ca98ed794e14955b100cb844caead310f2f84c5d0b99e5d0060df9f0d1d7361f8e5d61e46a428adcbda4af4fe96e90c4c05d9c
|
7
|
+
data.tar.gz: 87603e85d029f54e8613348034c6846f3ef9a6ef19699fd3680de8b44ff7410d926abe8ef1a45b52de6ff258b329ebcc745c2ef7abc3de1b098fc8edb643f5b7
|
data/Rakefile
CHANGED
data/build-files.gemspec
CHANGED
@@ -19,6 +19,6 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
-
spec.add_development_dependency "
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0.0.rc1"
|
23
23
|
spec.add_development_dependency "rake"
|
24
24
|
end
|
data/lib/build/files.rb
CHANGED
@@ -18,9 +18,11 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require_relative 'files/
|
21
|
+
require_relative 'files/list'
|
22
22
|
require_relative 'files/glob'
|
23
23
|
require_relative 'files/directory'
|
24
24
|
|
25
25
|
require_relative 'files/state'
|
26
26
|
require_relative 'files/monitor'
|
27
|
+
|
28
|
+
require_relative 'files/filesystem'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
module Build
|
22
|
+
module Files
|
23
|
+
# Represents a file path with an absolute root and a relative offset:
|
24
|
+
class Path
|
25
|
+
def exist?
|
26
|
+
File.exist? self
|
27
|
+
end
|
28
|
+
|
29
|
+
def directory?
|
30
|
+
File.directory? self
|
31
|
+
end
|
32
|
+
|
33
|
+
def mtime
|
34
|
+
File.mtime self
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/build/files/glob.rb
CHANGED
@@ -18,128 +18,10 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
|
21
|
+
require_relative 'path'
|
22
22
|
|
23
23
|
module Build
|
24
24
|
module Files
|
25
|
-
# Represents a file path with an absolute root and a relative offset:
|
26
|
-
class Path
|
27
|
-
def self.relative_path(root, full_path)
|
28
|
-
relative_offset = root.length
|
29
|
-
|
30
|
-
# Deal with the case where the root may or may not end with the path separator:
|
31
|
-
relative_offset += 1 unless root.end_with?(File::SEPARATOR)
|
32
|
-
|
33
|
-
return full_path.slice(relative_offset..-1)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Both paths must be full absolute paths, and path must have root as an prefix.
|
37
|
-
def initialize(full_path, root = nil)
|
38
|
-
# This is the object identity:
|
39
|
-
@full_path = full_path
|
40
|
-
|
41
|
-
if root
|
42
|
-
@root = root
|
43
|
-
@relative_path = nil
|
44
|
-
else
|
45
|
-
# Effectively dirname and basename:
|
46
|
-
@root, @relative_path = File.split(full_path)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
attr :root
|
51
|
-
|
52
|
-
def to_str
|
53
|
-
@full_path
|
54
|
-
end
|
55
|
-
|
56
|
-
def to_path
|
57
|
-
@full_path
|
58
|
-
end
|
59
|
-
|
60
|
-
def length
|
61
|
-
@full_path.length
|
62
|
-
end
|
63
|
-
|
64
|
-
def parts
|
65
|
-
@parts ||= @full_path.split(File::SEPARATOR)
|
66
|
-
end
|
67
|
-
|
68
|
-
def relative_path
|
69
|
-
@relative_path ||= Path.relative_path(@root, @full_path)
|
70
|
-
end
|
71
|
-
|
72
|
-
def relative_parts
|
73
|
-
basename, _, filename = self.relative_path.rpartition(File::SEPARATOR)
|
74
|
-
|
75
|
-
return basename, filename
|
76
|
-
end
|
77
|
-
|
78
|
-
def +(extension)
|
79
|
-
self.class.new(@full_path + extension, @root)
|
80
|
-
end
|
81
|
-
|
82
|
-
def rebase(root)
|
83
|
-
self.class.new(File.join(root, relative_path), root)
|
84
|
-
end
|
85
|
-
|
86
|
-
def with(root: @root, extension: nil)
|
87
|
-
self.class.new(File.join(root, extension ? relative_path + extension : relative_path), root)
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.join(root, relative_path)
|
91
|
-
self.new(File.join(root, relative_path), root)
|
92
|
-
end
|
93
|
-
|
94
|
-
def shortest_path(working_directory = Dir.pwd)
|
95
|
-
if start_with? working_directory
|
96
|
-
Path.new(working_directory, @full_path)
|
97
|
-
else
|
98
|
-
self
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def to_s
|
103
|
-
@full_path
|
104
|
-
end
|
105
|
-
|
106
|
-
def inspect
|
107
|
-
"#{@root.inspect}/#{relative_path.inspect}"
|
108
|
-
end
|
109
|
-
|
110
|
-
def hash
|
111
|
-
@full_path.hash
|
112
|
-
end
|
113
|
-
|
114
|
-
def eql?(other)
|
115
|
-
@full_path.eql?(other.to_s)
|
116
|
-
end
|
117
|
-
|
118
|
-
def ==(other)
|
119
|
-
self.to_s == other.to_s
|
120
|
-
end
|
121
|
-
|
122
|
-
def for_reading
|
123
|
-
[@full_path, File::RDONLY]
|
124
|
-
end
|
125
|
-
|
126
|
-
def for_writing
|
127
|
-
[@full_path, File::CREAT|File::TRUNC|File::WRONLY]
|
128
|
-
end
|
129
|
-
|
130
|
-
def for_appending
|
131
|
-
[@full_path, File::CREAT|File::APPEND|File::WRONLY]
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def self.Path(*args)
|
136
|
-
if Path === args[0]
|
137
|
-
args[0]
|
138
|
-
else
|
139
|
-
Path.new(*args)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
25
|
# A list of paths, where #each yields instances of Path.
|
144
26
|
class List
|
145
27
|
include Enumerable
|
@@ -308,7 +190,7 @@ module Build
|
|
308
190
|
"<Composite #{@files.inspect}>"
|
309
191
|
end
|
310
192
|
end
|
311
|
-
|
312
|
-
NONE = Composite.new([]).freeze
|
193
|
+
|
194
|
+
List::NONE = Composite.new([]).freeze
|
313
195
|
end
|
314
196
|
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
module Build
|
22
|
+
module Files
|
23
|
+
# Represents a file path with an absolute root and a relative offset:
|
24
|
+
class Path
|
25
|
+
# Returns the length of the prefix which is shared by two strings.
|
26
|
+
def self.prefix_length(a, b)
|
27
|
+
[a.size, b.size].min.times{|i| return i if a[i] != b[i]}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns a list of components for a path, either represented as a Path instance or a String.
|
31
|
+
def self.components(path)
|
32
|
+
if Path === path
|
33
|
+
path.components
|
34
|
+
else
|
35
|
+
path.split(File::SEPARATOR)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return the shortest relative path to get to path from root:
|
40
|
+
def self.shortest_path(path, root)
|
41
|
+
path_components = Path.components(path)
|
42
|
+
root_components = Path.components(root)
|
43
|
+
|
44
|
+
# Find the common prefix:
|
45
|
+
i = prefix_length(path_components, root_components)
|
46
|
+
|
47
|
+
# The difference between the root path and the required path, taking into account the common prefix:
|
48
|
+
up = root_components.size - i
|
49
|
+
|
50
|
+
return File.join([".."] * up + path_components[i..-1])
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.relative_path(root, full_path)
|
54
|
+
relative_offset = root.length
|
55
|
+
|
56
|
+
# Deal with the case where the root may or may not end with the path separator:
|
57
|
+
relative_offset += 1 unless root.end_with?(File::SEPARATOR)
|
58
|
+
|
59
|
+
return full_path.slice(relative_offset..-1)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Both paths must be full absolute paths, and path must have root as an prefix.
|
63
|
+
def initialize(full_path, root = nil, relative_path = nil)
|
64
|
+
# This is the object identity:
|
65
|
+
@full_path = full_path
|
66
|
+
|
67
|
+
if root
|
68
|
+
@root = root
|
69
|
+
@relative_path = relative_path
|
70
|
+
else
|
71
|
+
# Effectively dirname and basename:
|
72
|
+
@root, _, @relative_path = full_path.rpartition(File::SEPARATOR)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def components
|
78
|
+
@components ||= @full_path.split(File::SEPARATOR)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Ensure the path has an absolute root if it doesn't already:
|
82
|
+
def to_absolute(root)
|
83
|
+
if @root == "."
|
84
|
+
self.rebase(root)
|
85
|
+
else
|
86
|
+
self
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
attr :root
|
91
|
+
|
92
|
+
def to_str
|
93
|
+
@full_path
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_path
|
97
|
+
@full_path
|
98
|
+
end
|
99
|
+
|
100
|
+
def length
|
101
|
+
@full_path.length
|
102
|
+
end
|
103
|
+
|
104
|
+
def parts
|
105
|
+
@parts ||= @full_path.split(File::SEPARATOR)
|
106
|
+
end
|
107
|
+
|
108
|
+
def relative_path
|
109
|
+
@relative_path ||= Path.relative_path(@root.to_s, @full_path)
|
110
|
+
end
|
111
|
+
|
112
|
+
def relative_parts
|
113
|
+
basename, _, filename = self.relative_path.rpartition(File::SEPARATOR)
|
114
|
+
|
115
|
+
return basename, filename
|
116
|
+
end
|
117
|
+
|
118
|
+
def +(extension)
|
119
|
+
self.class.new(@full_path + extension, @root)
|
120
|
+
end
|
121
|
+
|
122
|
+
def rebase(root)
|
123
|
+
self.class.new(File.join(root, relative_path), root)
|
124
|
+
end
|
125
|
+
|
126
|
+
def with(root: @root, extension: nil)
|
127
|
+
self.class.new(File.join(root, extension ? relative_path + extension : relative_path), root)
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.join(root, relative_path)
|
131
|
+
self.new(File.join(root, relative_path), root)
|
132
|
+
end
|
133
|
+
|
134
|
+
def shortest_path(root)
|
135
|
+
self.class.shortest_path(self, root)
|
136
|
+
end
|
137
|
+
|
138
|
+
def to_s
|
139
|
+
@full_path
|
140
|
+
end
|
141
|
+
|
142
|
+
def inspect
|
143
|
+
"#{@root.inspect}/#{relative_path.inspect}"
|
144
|
+
end
|
145
|
+
|
146
|
+
def hash
|
147
|
+
@full_path.hash
|
148
|
+
end
|
149
|
+
|
150
|
+
def eql?(other)
|
151
|
+
@full_path.eql?(other.to_s)
|
152
|
+
end
|
153
|
+
|
154
|
+
def ==(other)
|
155
|
+
self.to_s == other.to_s
|
156
|
+
end
|
157
|
+
|
158
|
+
def for_reading
|
159
|
+
[@full_path, File::RDONLY]
|
160
|
+
end
|
161
|
+
|
162
|
+
def for_writing
|
163
|
+
[@full_path, File::CREAT|File::TRUNC|File::WRONLY]
|
164
|
+
end
|
165
|
+
|
166
|
+
def for_appending
|
167
|
+
[@full_path, File::CREAT|File::APPEND|File::WRONLY]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
data/lib/build/files/state.rb
CHANGED
@@ -35,6 +35,10 @@ module Build
|
|
35
35
|
def <=> other
|
36
36
|
@time <=> other.time
|
37
37
|
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
"<FileTime #{@path.inspect} #{@time.inspect}>"
|
41
|
+
end
|
38
42
|
end
|
39
43
|
|
40
44
|
class State
|
@@ -97,7 +101,7 @@ module Build
|
|
97
101
|
# puts "Missing: #{path}"
|
98
102
|
end
|
99
103
|
end
|
100
|
-
|
104
|
+
|
101
105
|
@removed = last_times.keys
|
102
106
|
|
103
107
|
@oldest_time = file_times.min
|
@@ -105,24 +109,28 @@ module Build
|
|
105
109
|
|
106
110
|
return @added.size > 0 || @changed.size > 0 || @removed.size > 0 || @missing.size > 0
|
107
111
|
end
|
108
|
-
|
112
|
+
|
109
113
|
attr :oldest_time
|
110
114
|
attr :newest_time
|
111
|
-
|
115
|
+
|
112
116
|
attr :missing
|
113
|
-
|
117
|
+
|
114
118
|
def missing?
|
115
119
|
!@missing.empty?
|
116
120
|
end
|
117
|
-
|
121
|
+
|
118
122
|
# Outputs is a list of full paths and must not include any patterns/globs.
|
119
123
|
def intersects?(outputs)
|
120
124
|
@files.intersects?(outputs)
|
121
125
|
end
|
122
|
-
|
126
|
+
|
123
127
|
def empty?
|
124
128
|
@files.to_a.empty?
|
125
129
|
end
|
130
|
+
|
131
|
+
def inspect
|
132
|
+
"<State Added:#{@added} Removed:#{@removed} Changed:#{@changed} Missing:#{@missing}>"
|
133
|
+
end
|
126
134
|
end
|
127
135
|
|
128
136
|
class IOState
|
@@ -130,69 +138,75 @@ module Build
|
|
130
138
|
@input_state = State.new(inputs)
|
131
139
|
@output_state = State.new(outputs)
|
132
140
|
end
|
133
|
-
|
141
|
+
|
134
142
|
attr :input_state
|
135
143
|
attr :output_state
|
136
|
-
|
144
|
+
|
137
145
|
# Output is dirty if files are missing or if latest input is older than any output.
|
138
146
|
def dirty?
|
147
|
+
@dirty = []
|
148
|
+
|
139
149
|
if @output_state.missing?
|
140
150
|
# puts "Output file missing: #{output_state.missing.inspect}"
|
141
|
-
|
151
|
+
|
142
152
|
return true
|
143
153
|
end
|
144
|
-
|
154
|
+
|
145
155
|
# If there are no inputs, we are always clean as long as outputs exist:
|
146
156
|
# if @input_state.empty?
|
147
157
|
# return false
|
148
158
|
# end
|
149
|
-
|
159
|
+
|
150
160
|
oldest_output_time = @output_state.oldest_time
|
151
161
|
newest_input_time = @input_state.newest_time
|
152
|
-
|
162
|
+
|
153
163
|
if newest_input_time and oldest_output_time
|
154
164
|
# if newest_input_time > oldest_output_time
|
155
165
|
# puts "Out of date file: #{newest_input_time.inspect} > #{oldest_output_time.inspect}"
|
156
166
|
# end
|
157
|
-
|
167
|
+
|
158
168
|
return newest_input_time > oldest_output_time
|
159
169
|
end
|
160
|
-
|
170
|
+
|
161
171
|
# puts "Missing file dates: #{newest_input_time.inspect} < #{oldest_output_time.inspect}"
|
162
|
-
|
172
|
+
|
163
173
|
return true
|
164
174
|
end
|
165
|
-
|
175
|
+
|
166
176
|
def fresh?
|
167
177
|
not dirty?
|
168
178
|
end
|
169
|
-
|
179
|
+
|
170
180
|
def files
|
171
181
|
@input_state.files + @output_state.files
|
172
182
|
end
|
173
|
-
|
183
|
+
|
174
184
|
def added
|
175
185
|
@input_state.added + @output_state.added
|
176
186
|
end
|
177
|
-
|
187
|
+
|
178
188
|
def removed
|
179
189
|
@input_state.removed + @output_state.removed
|
180
190
|
end
|
181
|
-
|
191
|
+
|
182
192
|
def changed
|
183
193
|
@input_state.changed + @output_state.changed
|
184
194
|
end
|
185
|
-
|
195
|
+
|
186
196
|
def update!
|
187
197
|
input_changed = @input_state.update!
|
188
198
|
output_changed = @output_state.update!
|
189
199
|
|
190
200
|
input_changed or output_changed
|
191
201
|
end
|
192
|
-
|
202
|
+
|
193
203
|
def intersects?(outputs)
|
194
204
|
@input_state.intersects?(outputs) or @output_state.intersects?(outputs)
|
195
205
|
end
|
206
|
+
|
207
|
+
def inspect
|
208
|
+
"<IOState Input:#{@input_state.inspect} Output:#{@output_state.inspect}>"
|
209
|
+
end
|
196
210
|
end
|
197
211
|
|
198
212
|
class Handle
|
data/lib/build/files/version.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'build/files'
|
22
|
+
require 'build/files/list'
|
23
|
+
require 'build/files/glob'
|
24
|
+
|
25
|
+
module Build::Files::ListSpec
|
26
|
+
include Build::Files
|
27
|
+
|
28
|
+
describe Build::Files::Paths do
|
29
|
+
let(:path) {Path.new("/foo/bar/baz", "/foo")}
|
30
|
+
|
31
|
+
it "maps paths with a new extension" do
|
32
|
+
paths = Paths.new([
|
33
|
+
Path.join('/foo/bar', 'alice'),
|
34
|
+
Path.join('/foo/bar', 'bob'),
|
35
|
+
Path.join('/foo/bar', 'charles'),
|
36
|
+
path
|
37
|
+
])
|
38
|
+
|
39
|
+
expect(paths).to include(path)
|
40
|
+
|
41
|
+
expect(paths).to be_intersects(paths)
|
42
|
+
expect(paths).to_not be_intersects(Paths::NONE)
|
43
|
+
|
44
|
+
mapped_paths = paths.map {|path| path + ".o"}
|
45
|
+
|
46
|
+
expect(mapped_paths).to be_kind_of(Paths)
|
47
|
+
expect(mapped_paths.roots).to be == paths.roots
|
48
|
+
end
|
49
|
+
|
50
|
+
it "globs multiple files" do
|
51
|
+
glob = Glob.new(__dir__, '*.rb')
|
52
|
+
|
53
|
+
expect(glob.count).to be > 1
|
54
|
+
|
55
|
+
mapped_paths = glob.map {|path| path + ".txt"}
|
56
|
+
|
57
|
+
expect(glob.roots).to be == mapped_paths.roots
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should intersect one file in the glob" do
|
61
|
+
# Glob all test files:
|
62
|
+
glob = Glob.new(__dir__, "*.rb")
|
63
|
+
|
64
|
+
expect(glob.count).to be > 0
|
65
|
+
|
66
|
+
# Should include this file:
|
67
|
+
expect(glob).to include(__FILE__)
|
68
|
+
|
69
|
+
# Glob should intersect self:
|
70
|
+
expect(glob).to be_intersects(glob)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should include composites" do
|
74
|
+
lib = File.join(__dir__, "../lib")
|
75
|
+
|
76
|
+
test_glob = Glob.new(__dir__, "*.rb")
|
77
|
+
lib_glob = Glob.new(lib, "*.rb")
|
78
|
+
|
79
|
+
both = test_glob + lib_glob
|
80
|
+
|
81
|
+
# List#roots is the generic accessor for Lists
|
82
|
+
expect(both.roots).to include test_glob.root
|
83
|
+
|
84
|
+
# The composite should include both:
|
85
|
+
expect(both).to include(__FILE__)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should have path with correct root" do
|
89
|
+
test_glob = Glob.new(__dir__, "*.rb")
|
90
|
+
|
91
|
+
expect(test_glob.first).to be_kind_of Path
|
92
|
+
|
93
|
+
expect(test_glob.first.root).to be == __dir__
|
94
|
+
end
|
95
|
+
|
96
|
+
it "maps paths with new extension" do
|
97
|
+
glob = Glob.new(__dir__, "*.rb")
|
98
|
+
|
99
|
+
paths = glob.map {|path| path + ".txt"}
|
100
|
+
|
101
|
+
expect(paths.first).to be == (glob.first + ".txt")
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should define an empty set of files" do
|
105
|
+
expect(Paths::NONE).to be_kind_of List
|
106
|
+
|
107
|
+
expect(Paths::NONE.count).to be 0
|
108
|
+
end
|
109
|
+
|
110
|
+
it "can be used as key in hash" do
|
111
|
+
cache = {}
|
112
|
+
|
113
|
+
cache[Paths.new(path)] = true
|
114
|
+
|
115
|
+
expect(cache).to include(Paths.new(path))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'build/files'
|
22
|
+
require 'build/files/path'
|
23
|
+
|
24
|
+
module Build::Files::PathSpec
|
25
|
+
include Build::Files
|
26
|
+
|
27
|
+
describe Build::Files::Path do
|
28
|
+
let(:path) {Path.new("/foo/bar/baz", "/foo")}
|
29
|
+
|
30
|
+
it "should convert to string" do
|
31
|
+
# The to_str method should return the full path (i.e. the same as to_s):
|
32
|
+
expect(path.to_s).to be == path.to_str
|
33
|
+
|
34
|
+
# Check the equality operator:
|
35
|
+
expect(path).to be == path.dup
|
36
|
+
|
37
|
+
# The length should be reported correctly:
|
38
|
+
expect(path.length).to be == path.to_s.length
|
39
|
+
|
40
|
+
# Check the return types:
|
41
|
+
expect(path).to be_kind_of Path
|
42
|
+
expect(path.root).to be_kind_of String
|
43
|
+
expect(path.relative_path).to be_kind_of String
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should consist of parts" do
|
47
|
+
expect(path.parts).to be == ["", "foo", "bar", "baz"]
|
48
|
+
|
49
|
+
expect(path.root).to be == "/foo"
|
50
|
+
|
51
|
+
expect(path.relative_path).to be == "bar/baz"
|
52
|
+
|
53
|
+
expect(path.relative_parts).to be == ["bar", "baz"]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should have a new extension" do
|
57
|
+
renamed_path = path.with(root: '/tmp', extension: '.txt')
|
58
|
+
|
59
|
+
expect(renamed_path.root).to be == '/tmp'
|
60
|
+
|
61
|
+
expect(renamed_path.relative_path).to be == 'bar/baz.txt'
|
62
|
+
|
63
|
+
object_path = path + ".o"
|
64
|
+
|
65
|
+
expect(object_path.root).to be == "/foo"
|
66
|
+
expect(object_path.relative_path).to be == "bar/baz.o"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should give the shortest path for outer paths" do
|
70
|
+
spec_path = Path.new(__FILE__)
|
71
|
+
source_path = Path.new(File.expand_path("../../../lib/build/files/list.rb"))
|
72
|
+
|
73
|
+
input = Path.new("/a/b/c/file.cpp")
|
74
|
+
output = Path.new("/a/b/c/d/e/")
|
75
|
+
|
76
|
+
expect(input.root).to be == "/a/b/c"
|
77
|
+
expect(output.root).to be == "/a/b/c/d/e"
|
78
|
+
|
79
|
+
short = input.shortest_path(output)
|
80
|
+
|
81
|
+
expect(short).to be == "../../file.cpp"
|
82
|
+
|
83
|
+
expect(File.expand_path(short, output)).to be == input
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should give the shortest path for inner paths" do
|
87
|
+
input = Path.new("/a/b/c/file.cpp")
|
88
|
+
output = Path.new("/a/")
|
89
|
+
|
90
|
+
expect(input.root).to be == "/a/b/c"
|
91
|
+
expect(output.root).to be == "/a"
|
92
|
+
|
93
|
+
short = input.shortest_path(output)
|
94
|
+
|
95
|
+
expect(short).to be == "b/c/file.cpp"
|
96
|
+
|
97
|
+
expect(File.expand_path(short, output)).to be == input
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -18,44 +18,43 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require 'minitest/autorun'
|
22
|
-
|
23
21
|
require 'build/files'
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
def setup
|
29
|
-
@files = Glob.new(__dir__, "*.rb")
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_basic_update
|
33
|
-
state = State.new(@files)
|
34
|
-
|
35
|
-
refute state.update!, "Files not changed"
|
23
|
+
module Build::Files::StateSpec
|
24
|
+
describe Build::Files::State do
|
25
|
+
let(:files) {Build::Files::Glob.new(__dir__, "*.rb")}
|
36
26
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
assert state.update!, "Files missing"
|
48
|
-
refute_empty state.missing
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_duplicates
|
52
|
-
state = State.new(@files + @files)
|
27
|
+
it "should have no changes initially" do
|
28
|
+
state = Build::Files::State.new(files)
|
29
|
+
|
30
|
+
expect(state.update!).to be false
|
31
|
+
|
32
|
+
expect(state.changed).to be == []
|
33
|
+
expect(state.added).to be == []
|
34
|
+
expect(state.removed).to be == []
|
35
|
+
expect(state.missing).to be == []
|
36
|
+
end
|
53
37
|
|
54
|
-
|
38
|
+
it "should report missing files" do
|
39
|
+
rebased_files = files.to_paths.rebase(File.join(__dir__, 'foo'))
|
40
|
+
state = Build::Files::State.new(rebased_files)
|
41
|
+
|
42
|
+
# Some changes were detected:
|
43
|
+
expect(state.update!).to be true
|
44
|
+
|
45
|
+
# Some files are missing:
|
46
|
+
expect(state.missing).to_not be_empty
|
47
|
+
end
|
55
48
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
49
|
+
it "should not be confused by duplicates" do
|
50
|
+
state = Build::Files::State.new(files + files)
|
51
|
+
|
52
|
+
expect(state.update!).to be false
|
53
|
+
|
54
|
+
expect(state.changed).to be == []
|
55
|
+
expect(state.added).to be == []
|
56
|
+
expect(state.removed).to be == []
|
57
|
+
expect(state.missing).to be == []
|
58
|
+
end
|
60
59
|
end
|
61
60
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: build-files
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,19 +25,19 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 3.0.0.rc1
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 3.0.0.rc1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,14 +66,16 @@ files:
|
|
66
66
|
- build-files.gemspec
|
67
67
|
- lib/build/files.rb
|
68
68
|
- lib/build/files/directory.rb
|
69
|
+
- lib/build/files/filesystem.rb
|
69
70
|
- lib/build/files/glob.rb
|
71
|
+
- lib/build/files/list.rb
|
70
72
|
- lib/build/files/monitor.rb
|
71
|
-
- lib/build/files/
|
73
|
+
- lib/build/files/path.rb
|
72
74
|
- lib/build/files/state.rb
|
73
75
|
- lib/build/files/version.rb
|
74
|
-
-
|
75
|
-
-
|
76
|
-
-
|
76
|
+
- spec/build/files/list_spec.rb
|
77
|
+
- spec/build/files/path_spec.rb
|
78
|
+
- spec/build/files/state_spec.rb
|
77
79
|
homepage: ''
|
78
80
|
licenses:
|
79
81
|
- MIT
|
@@ -100,6 +102,6 @@ specification_version: 4
|
|
100
102
|
summary: Build::Files is a set of idiomatic classes for dealing with paths and monitoring
|
101
103
|
directories.
|
102
104
|
test_files:
|
103
|
-
-
|
104
|
-
-
|
105
|
-
-
|
105
|
+
- spec/build/files/list_spec.rb
|
106
|
+
- spec/build/files/path_spec.rb
|
107
|
+
- spec/build/files/state_spec.rb
|
data/test/test_files.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'minitest/autorun'
|
22
|
-
|
23
|
-
require 'build/files'
|
24
|
-
|
25
|
-
class TestFiles < MiniTest::Test
|
26
|
-
include Build::Files
|
27
|
-
|
28
|
-
def test_inclusion
|
29
|
-
# Glob all test files:
|
30
|
-
glob = Glob.new(__dir__, "*.rb")
|
31
|
-
|
32
|
-
assert glob.count > 0
|
33
|
-
|
34
|
-
# Should include this file:
|
35
|
-
assert_includes glob, __FILE__
|
36
|
-
|
37
|
-
# Glob should intersect self:
|
38
|
-
assert glob.intersects?(glob)
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_composites
|
42
|
-
lib = File.join(__dir__, "../lib")
|
43
|
-
|
44
|
-
test_glob = Glob.new(__dir__, "*.rb")
|
45
|
-
lib_glob = Glob.new(lib, "*.rb")
|
46
|
-
|
47
|
-
both = test_glob + lib_glob
|
48
|
-
|
49
|
-
# List#roots is the generic accessor for Lists
|
50
|
-
assert both.roots.include? test_glob.root
|
51
|
-
|
52
|
-
# The composite should include both:
|
53
|
-
assert both.include?(__FILE__)
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_roots
|
57
|
-
test_glob = Glob.new(__dir__, "*.rb")
|
58
|
-
|
59
|
-
assert_kind_of Path, test_glob.first
|
60
|
-
|
61
|
-
assert_equal __dir__, test_glob.first.root
|
62
|
-
end
|
63
|
-
|
64
|
-
def test_renaming
|
65
|
-
glob = Glob.new(__dir__, "*.rb")
|
66
|
-
|
67
|
-
paths = glob.map {|path| path + ".txt"}
|
68
|
-
|
69
|
-
assert_equal(paths.first, glob.first + ".txt")
|
70
|
-
end
|
71
|
-
|
72
|
-
def test_none
|
73
|
-
assert_equal 0, NONE.count
|
74
|
-
end
|
75
|
-
end
|
data/test/test_paths.rb
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'minitest/autorun'
|
22
|
-
|
23
|
-
require 'build/files/paths'
|
24
|
-
require 'build/files/glob'
|
25
|
-
|
26
|
-
class TestPaths < MiniTest::Test
|
27
|
-
include Build::Files
|
28
|
-
|
29
|
-
def setup
|
30
|
-
@path = Path.new("/foo/bar/baz", "/foo")
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_path_conversions
|
34
|
-
# The to_str method should return the full path (i.e. the same as to_s):
|
35
|
-
assert_equal @path.to_s, @path.to_str
|
36
|
-
|
37
|
-
# Checkt the equality operator:
|
38
|
-
assert_equal @path, @path.dup
|
39
|
-
|
40
|
-
# The length should be reported correctly:
|
41
|
-
assert_equal @path.length, @path.to_s.length
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_path_parts
|
45
|
-
assert_equal ["", "foo", "bar", "baz"], @path.parts
|
46
|
-
|
47
|
-
assert_equal "/foo", @path.root
|
48
|
-
|
49
|
-
assert_equal "bar/baz", @path.relative_path
|
50
|
-
|
51
|
-
assert_equal ["bar", "baz"], @path.relative_parts
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_path_with
|
55
|
-
path = @path.with(root: '/tmp', extension: '.txt')
|
56
|
-
|
57
|
-
assert_equal '/tmp', path.root
|
58
|
-
|
59
|
-
assert_equal 'bar/baz.txt', path.relative_path
|
60
|
-
end
|
61
|
-
|
62
|
-
def test_path_class
|
63
|
-
assert_instance_of Path, @path
|
64
|
-
assert_instance_of String, @path.root
|
65
|
-
assert_instance_of String, @path.relative_path
|
66
|
-
end
|
67
|
-
|
68
|
-
def test_path_manipulation
|
69
|
-
object_path = @path + ".o"
|
70
|
-
|
71
|
-
assert_equal "/foo", object_path.root
|
72
|
-
assert_equal "bar/baz.o", object_path.relative_path
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_paths
|
76
|
-
paths = Paths.new([
|
77
|
-
Path.join('/foo/bar', 'alice'),
|
78
|
-
Path.join('/foo/bar', 'bob'),
|
79
|
-
Path.join('/foo/bar', 'charles'),
|
80
|
-
@path
|
81
|
-
])
|
82
|
-
|
83
|
-
assert_includes paths, @path
|
84
|
-
|
85
|
-
assert paths.intersects?(paths)
|
86
|
-
refute paths.intersects?(NONE)
|
87
|
-
|
88
|
-
mapped_paths = paths.map {|path| path + ".o"}
|
89
|
-
|
90
|
-
assert_instance_of Paths, mapped_paths
|
91
|
-
assert_equal paths.roots, mapped_paths.roots
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_glob
|
95
|
-
glob = Glob.new(__dir__, '*.rb')
|
96
|
-
|
97
|
-
assert glob.count > 0, "Found some files"
|
98
|
-
|
99
|
-
mapped_paths = glob.map {|path| path + ".txt"}
|
100
|
-
|
101
|
-
assert_equal glob.roots, mapped_paths.roots
|
102
|
-
end
|
103
|
-
|
104
|
-
def test_hashing
|
105
|
-
cache = {}
|
106
|
-
|
107
|
-
cache[Paths.new(@path)] = true
|
108
|
-
|
109
|
-
assert cache[Paths.new(@path)]
|
110
|
-
end
|
111
|
-
end
|