build-files 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4b40717a33b523317133659681b1ce50c021ac00
4
- data.tar.gz: 61a65ca8c6d12d04a8a72bde0aac31557249e687
3
+ metadata.gz: dea84d68b0394c651e2593a20dc08b7f7631e4b3
4
+ data.tar.gz: 40cf1afa1b7bbfb740b73383529137d8810456c6
5
5
  SHA512:
6
- metadata.gz: e692d35c69a5f5896d8902ad3c4960cf8c3aefa4d9f4c06329c36ada616dd4f4d2a2f3f77cbcdec47ce67a0fc0312746451739d7426b5dc50006233a62af0714
7
- data.tar.gz: ad4623c1d5a3ca483d0f06630b96e715c4da232c9d376918d7a4b1b52cf54ddffd8184eb73c995fa334b84e317e1640e4a842137386873427df1e8be6b0f87b2
6
+ metadata.gz: c7a42fa79f16d31f4376b9dd86ca98ed794e14955b100cb844caead310f2f84c5d0b99e5d0060df9f0d1d7361f8e5d61e46a428adcbda4af4fe96e90c4c05d9c
7
+ data.tar.gz: 87603e85d029f54e8613348034c6846f3ef9a6ef19699fd3680de8b44ff7410d926abe8ef1a45b52de6ff258b329ebcc745c2ef7abc3de1b098fc8edb643f5b7
data/Rakefile CHANGED
@@ -1,9 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
2
+ require "rspec/core/rake_task"
3
3
 
4
- Rake::TestTask.new do |t|
5
- t.libs << 'test'
6
- end
4
+ RSpec::Core::RakeTask.new(:spec)
7
5
 
8
- desc "Run tests"
9
- task :default => :test
6
+ task :default => :spec
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 "minitest", "~> 5.3.2"
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/paths'
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'
@@ -18,7 +18,7 @@
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 'paths'
21
+ require_relative 'list'
22
22
 
23
23
  module Build
24
24
  module Files
@@ -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
@@ -18,7 +18,7 @@
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 'paths'
21
+ require_relative 'list'
22
22
 
23
23
  module Build
24
24
  module Files
@@ -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
- require 'set'
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
@@ -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
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Build
22
22
  module Files
23
- VERSION = "0.1.0"
23
+ VERSION = "0.2.0"
24
24
  end
25
25
  end
@@ -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
- class TestState < MiniTest::Test
26
- include Build::Files
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
- assert_equal [], state.changed
38
- assert_equal [], state.added
39
- assert_equal [], state.removed
40
- assert_equal [], state.missing
41
- end
42
-
43
- def test_missing
44
- files = @files.to_paths.rebase(File.join(__dir__, 'program'))
45
- state = State.new(files)
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
- refute state.update!, "Files not changed"
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
- assert_equal [], state.changed
57
- assert_equal [], state.added
58
- assert_equal [], state.removed
59
- assert_equal [], state.missing
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.1.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-05-18 00:00:00.000000000 Z
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: minitest
28
+ name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 5.3.2
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: 5.3.2
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/paths.rb
73
+ - lib/build/files/path.rb
72
74
  - lib/build/files/state.rb
73
75
  - lib/build/files/version.rb
74
- - test/test_files.rb
75
- - test/test_paths.rb
76
- - test/test_state.rb
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
- - test/test_files.rb
104
- - test/test_paths.rb
105
- - test/test_state.rb
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