build-files 1.3.0 → 1.4.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 +5 -5
- data/.rspec +1 -1
- data/.travis.yml +12 -13
- data/Gemfile +0 -3
- data/Rakefile +1 -3
- data/build-files.gemspec +4 -5
- data/lib/build/files.rb +1 -0
- data/lib/build/files/composite.rb +99 -0
- data/lib/build/files/difference.rb +65 -0
- data/lib/build/files/handle.rb +59 -0
- data/lib/build/files/list.rb +4 -74
- data/lib/build/files/monitor.rb +18 -206
- data/lib/build/files/monitor/fsevent.rb +55 -0
- data/lib/build/files/monitor/inotify.rb +53 -0
- data/lib/build/files/monitor/polling.rb +145 -0
- data/lib/build/files/path.rb +14 -3
- data/lib/build/files/version.rb +1 -1
- data/spec/build/files/monitor_spec.rb +53 -63
- data/spec/build/files/path_spec.rb +172 -168
- data/spec/build/files/state_spec.rb +1 -1
- data/spec/spec_helper.rb +11 -0
- metadata +29 -9
- data/.simplecov +0 -9
@@ -0,0 +1,55 @@
|
|
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
|
+
require_relative 'polling'
|
22
|
+
|
23
|
+
require 'rb-fsevent'
|
24
|
+
|
25
|
+
module Build
|
26
|
+
module Files
|
27
|
+
module Monitor
|
28
|
+
class FSEvent < Polling
|
29
|
+
def run(**options, &block)
|
30
|
+
notifier = ::FSEvent.new
|
31
|
+
|
32
|
+
catch(:interrupt) do
|
33
|
+
while true
|
34
|
+
notifier.watch self.roots do |directories|
|
35
|
+
directories.collect! do |directory|
|
36
|
+
File.expand_path(directory)
|
37
|
+
end
|
38
|
+
|
39
|
+
self.update(directories)
|
40
|
+
|
41
|
+
yield
|
42
|
+
|
43
|
+
if self.updated
|
44
|
+
notifier.stop
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
notifier.run
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,53 @@
|
|
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
|
+
require_relative 'polling'
|
22
|
+
|
23
|
+
require 'rb-inotify'
|
24
|
+
|
25
|
+
module Build
|
26
|
+
module Files
|
27
|
+
module Monitor
|
28
|
+
class INotify < Polling
|
29
|
+
def run(**options, &block)
|
30
|
+
notifier = ::INotify::Notifier.new
|
31
|
+
|
32
|
+
catch(:interrupt) do
|
33
|
+
while true
|
34
|
+
self.roots.each do |root|
|
35
|
+
notifier.watch root, :create, :modify, :attrib, :delete do |event|
|
36
|
+
self.update([root])
|
37
|
+
|
38
|
+
yield
|
39
|
+
|
40
|
+
if self.updated
|
41
|
+
notifier.stop
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
notifier.run
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,145 @@
|
|
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
|
+
require 'set'
|
22
|
+
require 'logger'
|
23
|
+
|
24
|
+
require_relative '../handle'
|
25
|
+
|
26
|
+
module Build
|
27
|
+
module Files
|
28
|
+
module Monitor
|
29
|
+
class Polling
|
30
|
+
def initialize(logger: nil)
|
31
|
+
@directories = Hash.new do |hash, key|
|
32
|
+
hash[key] = Set.new
|
33
|
+
end
|
34
|
+
|
35
|
+
@updated = false
|
36
|
+
|
37
|
+
@deletions = nil
|
38
|
+
|
39
|
+
@logger = logger || Logger.new(nil)
|
40
|
+
end
|
41
|
+
|
42
|
+
attr :updated
|
43
|
+
|
44
|
+
# Notify the monitor that files in these directories have changed.
|
45
|
+
def update(directories, *args)
|
46
|
+
@logger.debug{"Update: #{directories} #{args.inspect}"}
|
47
|
+
|
48
|
+
delay_deletions do
|
49
|
+
directories.each do |directory|
|
50
|
+
@logger.debug{"Directory: #{directory}"}
|
51
|
+
|
52
|
+
@directories[directory].each do |handle|
|
53
|
+
@logger.debug{"Handle changed: #{handle.inspect}"}
|
54
|
+
|
55
|
+
# Changes here may not actually require an update to the handle:
|
56
|
+
handle.changed!(*args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def roots
|
63
|
+
@directories.keys
|
64
|
+
end
|
65
|
+
|
66
|
+
def delete(handle)
|
67
|
+
if @deletions
|
68
|
+
@logger.debug{"Delayed delete handle: #{handle}"}
|
69
|
+
@deletions << handle
|
70
|
+
else
|
71
|
+
purge(handle)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def track_changes(files, &block)
|
76
|
+
handle = Handle.new(self, files, &block)
|
77
|
+
|
78
|
+
add(handle)
|
79
|
+
end
|
80
|
+
|
81
|
+
def add(handle)
|
82
|
+
@logger.debug{"Adding handle: #{handle}"}
|
83
|
+
|
84
|
+
handle.directories.each do |directory|
|
85
|
+
# We want the full path as a plain string:
|
86
|
+
directory = directory.to_s
|
87
|
+
|
88
|
+
@directories[directory] << handle
|
89
|
+
|
90
|
+
# We just added the first handle:
|
91
|
+
if @directories[directory].size == 1
|
92
|
+
# If the handle already existed, this might trigger unnecessarily.
|
93
|
+
@updated = true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
handle
|
98
|
+
end
|
99
|
+
|
100
|
+
def run(**options, &block)
|
101
|
+
catch(:interrupt) do
|
102
|
+
while true
|
103
|
+
monitor.update(monitor.roots)
|
104
|
+
|
105
|
+
yield
|
106
|
+
|
107
|
+
sleep(options[:latency] || 1.0)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
def delay_deletions
|
115
|
+
@deletions = []
|
116
|
+
|
117
|
+
yield
|
118
|
+
|
119
|
+
@deletions.each do |handle|
|
120
|
+
purge(handle)
|
121
|
+
end
|
122
|
+
|
123
|
+
@deletions = nil
|
124
|
+
end
|
125
|
+
|
126
|
+
def purge(handle)
|
127
|
+
@logger.debug{"Purge handle: #{handle}"}
|
128
|
+
|
129
|
+
handle.directories.each do |directory|
|
130
|
+
directory = directory.to_s
|
131
|
+
|
132
|
+
@directories[directory].delete(handle)
|
133
|
+
|
134
|
+
# Remove the entire record if there are no handles:
|
135
|
+
if @directories[directory].size == 0
|
136
|
+
@directories.delete(directory)
|
137
|
+
|
138
|
+
@updated = true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/build/files/path.rb
CHANGED
@@ -123,13 +123,24 @@ module Build
|
|
123
123
|
self.class.new(@full_path + extension, @root)
|
124
124
|
end
|
125
125
|
|
126
|
+
# Add a path component to the current path.
|
127
|
+
# @param path [String, nil] (Optionally) the path to append.
|
126
128
|
def +(path)
|
127
|
-
|
129
|
+
if path
|
130
|
+
self.class.new(File.join(@full_path, path), @root)
|
131
|
+
else
|
132
|
+
self
|
133
|
+
end
|
128
134
|
end
|
129
135
|
|
130
|
-
#
|
136
|
+
# Use the current path to define a new root, with an optional sub-path.
|
137
|
+
# @param path [String, nil] (Optionally) the path to append.
|
131
138
|
def /(path)
|
132
|
-
|
139
|
+
if path
|
140
|
+
self.class.new(File.join(self, path), self)
|
141
|
+
else
|
142
|
+
self.class.new(self, self)
|
143
|
+
end
|
133
144
|
end
|
134
145
|
|
135
146
|
def rebase(root)
|
data/lib/build/files/version.rb
CHANGED
@@ -25,76 +25,66 @@ require 'build/files/path'
|
|
25
25
|
require 'build/files/system'
|
26
26
|
require 'build/files/directory'
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
RSpec.shared_examples_for Monitor do |driver|
|
29
|
+
let(:root) {Build::Files::Path.expand('tmp', __dir__)}
|
30
|
+
let(:path) {root + "test.txt"}
|
30
31
|
|
31
|
-
|
32
|
+
before do
|
33
|
+
root.delete
|
34
|
+
root.create
|
35
|
+
end
|
32
36
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
let(:directory) {Build::Files::Directory.new(root)}
|
38
|
+
let(:monitor) {Build::Files::Monitor.new}
|
39
|
+
|
40
|
+
it "should include touched path" do
|
41
|
+
path.touch
|
42
|
+
|
43
|
+
expect(directory.to_a).to include(path)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should detect additions' do
|
47
|
+
changed = false
|
48
|
+
|
49
|
+
monitor.track_changes(directory) do |state|
|
50
|
+
changed = true
|
44
51
|
|
45
|
-
|
46
|
-
directory = Build::Files::Directory.new(ROOT)
|
47
|
-
monitor = Build::Files::Monitor.new
|
48
|
-
|
49
|
-
changed = false
|
50
|
-
|
51
|
-
monitor.track_changes(directory) do |state|
|
52
|
-
changed = state.added.include? path
|
53
|
-
end
|
54
|
-
|
55
|
-
touched = false
|
56
|
-
triggered = 0
|
57
|
-
|
58
|
-
thread = Thread.new do
|
59
|
-
while triggered == 0 or touched == false
|
60
|
-
sleep 0.1 if touched
|
61
|
-
|
62
|
-
path.touch
|
63
|
-
touched = true
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
monitor.run(driver: driver) do
|
68
|
-
triggered += 1
|
69
|
-
|
70
|
-
throw :interrupt if touched
|
71
|
-
end
|
72
|
-
|
73
|
-
thread.join
|
74
|
-
|
75
|
-
expect(changed).to be true
|
76
|
-
expect(triggered).to be >= 1
|
77
|
-
end
|
52
|
+
expect(state.added).to include(path)
|
78
53
|
end
|
79
54
|
|
80
|
-
|
81
|
-
|
55
|
+
thread = Thread.new do
|
56
|
+
sleep 1
|
57
|
+
path.touch
|
58
|
+
end
|
82
59
|
|
83
|
-
|
84
|
-
|
60
|
+
monitor.run do
|
61
|
+
throw :interrupt if changed
|
62
|
+
end
|
85
63
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
handler.remove!
|
96
|
-
|
97
|
-
expect(monitor.roots).to be_empty
|
64
|
+
thread.join
|
65
|
+
|
66
|
+
expect(changed).to be true
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should add and remove monitored paths" do
|
70
|
+
handler = monitor.track_changes(directory) do |state|
|
71
|
+
# Do nothing.
|
98
72
|
end
|
73
|
+
|
74
|
+
expect(monitor.roots).to be_include root
|
75
|
+
|
76
|
+
handler.remove!
|
77
|
+
|
78
|
+
expect(monitor.roots).to be_empty
|
99
79
|
end
|
100
80
|
end
|
81
|
+
|
82
|
+
RSpec.describe Build::Files::Monitor::Polling do
|
83
|
+
it_behaves_like Monitor
|
84
|
+
end
|
85
|
+
|
86
|
+
if defined? Build::Files::Monitor::Native
|
87
|
+
RSpec.describe Build::Files::Monitor::Native do
|
88
|
+
it_behaves_like Monitor
|
89
|
+
end
|
90
|
+
end
|
@@ -23,173 +23,177 @@ require 'build/files/path'
|
|
23
23
|
|
24
24
|
require 'pathname'
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
26
|
+
RSpec.describe Build::Files::Path do
|
27
|
+
it "should expand the path" do
|
28
|
+
expect(Build::Files::Path.expand("foo", "/bar")).to be == "/bar/foo"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should give the shortest path for outer paths" do
|
32
|
+
input = Build::Files::Path.new("/a/b/c/file.cpp")
|
33
|
+
output = Build::Files::Path.new("/a/b/c/d/e/")
|
34
|
+
|
35
|
+
expect(input.root).to be == "/a/b/c"
|
36
|
+
expect(output.root).to be == "/a/b/c/d/e"
|
37
|
+
|
38
|
+
short = input.shortest_path(output)
|
39
|
+
|
40
|
+
expect(short).to be == "../../file.cpp"
|
41
|
+
|
42
|
+
expect(File.expand_path(short, output)).to be == input
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should give the shortest path for inner paths" do
|
46
|
+
input = Build::Files::Path.new("/a/b/c/file.cpp")
|
47
|
+
output = Build::Files::Path.new("/a/")
|
48
|
+
|
49
|
+
expect(input.root).to be == "/a/b/c"
|
50
|
+
expect(output.root).to be == "/a"
|
51
|
+
|
52
|
+
short = input.shortest_path(output)
|
53
|
+
|
54
|
+
expect(short).to be == "b/c/file.cpp"
|
55
|
+
|
56
|
+
expect(File.expand_path(short, output)).to be == input
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
RSpec.describe Build::Files::Path.new("/test") do
|
61
|
+
it "should start_with? full path" do
|
62
|
+
expect(subject).to be_start_with '/test'
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should start_with? partial pattern" do
|
66
|
+
expect(subject).to be_start_with '/te'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
RSpec.describe Build::Files::Path.new("/foo/bar.txt") do
|
71
|
+
it "should replace existing file extension" do
|
72
|
+
expect(subject.with(extension: '.jpeg', basename: true)).to be == "/foo/bar.jpeg"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should append file extension" do
|
76
|
+
expect(subject.with(extension: '.jpeg')).to be == "/foo/bar.txt.jpeg"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should change basename" do
|
80
|
+
expect(subject.with(basename: 'baz', extension: '.txt')).to be == "/foo/baz.txt"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
RSpec.describe Build::Files::Path.new("/foo/bar/baz", "/foo") do
|
85
|
+
it "can add nil path" do
|
86
|
+
expect(subject + nil).to be == subject
|
87
|
+
end
|
88
|
+
|
89
|
+
it "can add nil root" do
|
90
|
+
expect(subject / nil).to be == subject
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should be inspectable" do
|
94
|
+
expect(subject.inspect).to be_include subject.root.to_s
|
95
|
+
expect(subject.inspect).to be_include subject.relative_path.to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should convert to path" do
|
99
|
+
pathname = Pathname("/foo/bar/baz")
|
100
|
+
|
101
|
+
expect(Build::Files::Path[pathname]).to be == subject
|
102
|
+
expect(Build::Files::Path["/foo/bar/baz"]).to be == subject
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should be equal" do
|
106
|
+
expect(subject).to be_eql subject
|
107
|
+
expect(subject).to be == subject
|
108
|
+
|
109
|
+
different_root_path = Build::Files::Path.join("/foo/bar", "baz")
|
110
|
+
expect(subject).to_not be_eql different_root_path
|
111
|
+
expect(subject).to be == different_root_path
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should convert to string" do
|
115
|
+
expect(subject.to_s).to be == "/foo/bar/baz"
|
116
|
+
|
117
|
+
# The to_str method should return the full path (i.e. the same as to_s):
|
118
|
+
expect(subject.to_s).to be == subject.to_str
|
119
|
+
|
120
|
+
# Check the equality operator:
|
121
|
+
expect(subject).to be == subject.dup
|
122
|
+
|
123
|
+
# The length should be reported correctly:
|
124
|
+
expect(subject.length).to be == subject.to_s.length
|
125
|
+
|
126
|
+
# Check the return types:
|
127
|
+
expect(subject).to be_kind_of Build::Files::Path
|
128
|
+
expect(subject.root).to be_kind_of String
|
129
|
+
expect(subject.relative_path).to be_kind_of String
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should consist of parts" do
|
133
|
+
expect(subject.parts).to be == ["", "foo", "bar", "baz"]
|
134
|
+
|
135
|
+
expect(subject.root).to be == "/foo"
|
136
|
+
|
137
|
+
expect(subject.relative_path).to be == "bar/baz"
|
138
|
+
|
139
|
+
expect(subject.relative_parts).to be == ["bar", "baz"]
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should have a new extension" do
|
143
|
+
renamed_path = subject.with(root: '/tmp', extension: '.txt')
|
144
|
+
|
145
|
+
expect(renamed_path.root).to be == '/tmp'
|
146
|
+
|
147
|
+
expect(renamed_path.relative_path).to be == 'bar/baz.txt'
|
148
|
+
|
149
|
+
object_path = subject.append(".o")
|
150
|
+
|
151
|
+
expect(object_path.root).to be == "/foo"
|
152
|
+
expect(object_path.relative_path).to be == "bar/baz.o"
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should append a path" do
|
156
|
+
subject = Build::Files::Path.new("/a/b/c")
|
157
|
+
|
158
|
+
expect(subject + "d/e/f").to be == "/a/b/c/d/e/f"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should give a list of components" do
|
162
|
+
expect(Build::Files::Path.components(subject)).to be == ["", "foo", "bar", "baz"]
|
163
|
+
expect(Build::Files::Path.components(subject.to_s)).to be == ["", "foo", "bar", "baz"]
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should give a basename" do
|
167
|
+
expect(subject.basename).to be == "baz"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should have a new root" do
|
171
|
+
rerooted_path = subject / "cat"
|
172
|
+
|
173
|
+
expect(rerooted_path.root).to be == "/foo/bar/baz"
|
174
|
+
expect(rerooted_path.relative_path).to be == "cat"
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should give correct modes for reading" do
|
178
|
+
expect(subject.for_reading).to be == [subject.to_s, File::RDONLY]
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should give correct modes for writing" do
|
182
|
+
expect(subject.for_writing).to be == [subject.to_s, File::CREAT|File::TRUNC|File::WRONLY]
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should give correct modes for appending" do
|
186
|
+
expect(subject.for_appending).to be == [subject.to_s, File::CREAT|File::APPEND|File::WRONLY]
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should match against relative path" do
|
190
|
+
expect(subject.match(subject.relative_path)).to be_truthy
|
191
|
+
expect(subject.match("*/baz")).to be_truthy
|
192
|
+
expect(subject.match("/baz")).to be_falsey
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should match against absolute path" do
|
196
|
+
expect(subject.match(subject.to_s)).to be_truthy
|
197
|
+
expect(subject.match("/foo/**")).to be_truthy
|
194
198
|
end
|
195
199
|
end
|