rubypath 0.3.2 → 1.0.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
- metadata +5 -55
- data/CHANGELOG.md +0 -24
- data/LICENSE.txt +0 -165
- data/README.md +0 -102
- data/doc/file.README.html +0 -175
- data/lib/rubypath.rb +0 -29
- data/lib/rubypath/backend.rb +0 -92
- data/lib/rubypath/backend/mock.rb +0 -356
- data/lib/rubypath/backend/sys.rb +0 -161
- data/lib/rubypath/comparison.rb +0 -19
- data/lib/rubypath/construction.rb +0 -109
- data/lib/rubypath/dir_operations.rb +0 -160
- data/lib/rubypath/extensions.rb +0 -157
- data/lib/rubypath/file_operations.rb +0 -192
- data/lib/rubypath/file_predicates.rb +0 -32
- data/lib/rubypath/identity.rb +0 -59
- data/lib/rubypath/io_operations.rb +0 -82
- data/lib/rubypath/mock.rb +0 -42
- data/lib/rubypath/path_operations.rb +0 -311
- data/lib/rubypath/path_predicates.rb +0 -61
- data/lib/rubypath/version.rb +0 -11
- data/rubypath.gemspec +0 -22
- data/spec/README_spec.rb +0 -27
- data/spec/rubypath/comparison_spec.rb +0 -77
- data/spec/rubypath/construction_spec.rb +0 -101
- data/spec/rubypath/dir_operations_spec.rb +0 -225
- data/spec/rubypath/extensions_spec.rb +0 -270
- data/spec/rubypath/file_operations_spec.rb +0 -428
- data/spec/rubypath/file_predicates_spec.rb +0 -66
- data/spec/rubypath/identity_spec.rb +0 -21
- data/spec/rubypath/io_operations_spec.rb +0 -128
- data/spec/rubypath/path_operations_spec.rb +0 -483
- data/spec/rubypath/path_predicates_spec.rb +0 -75
- data/spec/spec_helper.rb +0 -42
- data/spec/support/describe_method.rb +0 -18
- data/spec/support/with_backend.rb +0 -37
data/lib/rubypath.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'rubypath/version'
|
2
|
-
require 'tmpdir'
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
class Path
|
8
|
-
require 'rubypath/identity'
|
9
|
-
require 'rubypath/construction'
|
10
|
-
require 'rubypath/comparison'
|
11
|
-
require 'rubypath/extensions'
|
12
|
-
|
13
|
-
require 'rubypath/path_operations'
|
14
|
-
require 'rubypath/path_predicates'
|
15
|
-
require 'rubypath/file_operations'
|
16
|
-
require 'rubypath/file_predicates'
|
17
|
-
require 'rubypath/dir_operations'
|
18
|
-
require 'rubypath/io_operations'
|
19
|
-
|
20
|
-
require 'rubypath/mock'
|
21
|
-
require 'rubypath/backend'
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
module Kernel
|
26
|
-
def Path(*args)
|
27
|
-
Path.new *args
|
28
|
-
end
|
29
|
-
end
|
data/lib/rubypath/backend.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
class Path
|
2
|
-
class Backend
|
3
|
-
class << self
|
4
|
-
def instance
|
5
|
-
@instance ||= new
|
6
|
-
end
|
7
|
-
|
8
|
-
def delegate(mth)
|
9
|
-
define_method mth do |*args|
|
10
|
-
backend.send mth, *args
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def mock(*args, &block)
|
15
|
-
self.instance.mock(*args, &block)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_accessor :backend
|
20
|
-
def initialize
|
21
|
-
self.backend = Backend::Sys.new
|
22
|
-
end
|
23
|
-
|
24
|
-
def mock(opts = {}, &block)
|
25
|
-
if opts[:root]
|
26
|
-
# Use real file system scoped to given directory (chroot like)
|
27
|
-
if opts[:root] == :tmp
|
28
|
-
::Dir.mktmpdir('rubypath') do |path|
|
29
|
-
use_backend Backend::Sys.new(path), &block
|
30
|
-
end
|
31
|
-
else
|
32
|
-
use_backend Backend::Sys.new(opts[:root]), &block
|
33
|
-
end
|
34
|
-
else
|
35
|
-
# Use mock FS
|
36
|
-
use_backend Backend::Mock.new, &block
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def use_backend(be)
|
41
|
-
old_backend, self.backend = backend, be
|
42
|
-
yield
|
43
|
-
backend.quit if backend.respond_to? :quit
|
44
|
-
self.backend = old_backend
|
45
|
-
end
|
46
|
-
|
47
|
-
delegate :expand_path
|
48
|
-
delegate :getwd
|
49
|
-
delegate :exists?
|
50
|
-
delegate :mkdir
|
51
|
-
delegate :mkpath
|
52
|
-
delegate :directory?
|
53
|
-
delegate :file?
|
54
|
-
delegate :touch
|
55
|
-
delegate :write
|
56
|
-
delegate :read
|
57
|
-
delegate :mtime
|
58
|
-
delegate :mtime=
|
59
|
-
delegate :entries
|
60
|
-
delegate :glob
|
61
|
-
delegate :atime
|
62
|
-
delegate :atime=
|
63
|
-
delegate :get_umask
|
64
|
-
delegate :set_umask
|
65
|
-
delegate :mode
|
66
|
-
delegate :chmod
|
67
|
-
delegate :unlink
|
68
|
-
delegate :rmtree
|
69
|
-
delegate :rmtree!
|
70
|
-
delegate :safe_rmtree
|
71
|
-
delegate :safe_rmtree!
|
72
|
-
end
|
73
|
-
|
74
|
-
private
|
75
|
-
|
76
|
-
def invoke_backend(mth, *args)
|
77
|
-
args << self if args.empty?
|
78
|
-
self.class.send :invoke_backend, mth, *args
|
79
|
-
end
|
80
|
-
|
81
|
-
class << self
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def invoke_backend(mth, *args)
|
86
|
-
Backend.instance.send mth, *args
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
require 'rubypath/backend/mock'
|
91
|
-
require 'rubypath/backend/sys'
|
92
|
-
end
|
@@ -1,356 +0,0 @@
|
|
1
|
-
class Path::Backend
|
2
|
-
|
3
|
-
class Mock
|
4
|
-
attr_reader :user, :homes
|
5
|
-
|
6
|
-
# @!group Virtual File System Configuration
|
7
|
-
|
8
|
-
# Set user that owns the current process.
|
9
|
-
def current_user=(user)
|
10
|
-
@user = user.to_s
|
11
|
-
end
|
12
|
-
|
13
|
-
# Define new home directories. Must be given as has a hash that is
|
14
|
-
# interpreted as a user name to home directory mapping.
|
15
|
-
attr_writer :homes
|
16
|
-
|
17
|
-
# Set current working directory.
|
18
|
-
attr_writer :cwd
|
19
|
-
|
20
|
-
# @!group Internal Methods
|
21
|
-
|
22
|
-
def initialize
|
23
|
-
@user = 'root'
|
24
|
-
@homes = {'root' => '/root'}
|
25
|
-
@cwd = '/root'
|
26
|
-
@umask = 0022
|
27
|
-
end
|
28
|
-
|
29
|
-
def home(user)
|
30
|
-
homes.fetch(user){ raise ArgumentError.new "user #{user} doesn't exist" }
|
31
|
-
end
|
32
|
-
|
33
|
-
# @!group Backend Operations
|
34
|
-
|
35
|
-
def expand_path(path, base = getwd)
|
36
|
-
if %r{^~(?<name>[^/]*)(/(?<rest>.*))?$} =~ path
|
37
|
-
::File.expand_path rest.to_s, home(name.empty? ? user : name)
|
38
|
-
else
|
39
|
-
::File.expand_path(path, base)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
alias_method :expand, :expand_path
|
43
|
-
|
44
|
-
def getwd
|
45
|
-
@cwd ||= '/'
|
46
|
-
end
|
47
|
-
|
48
|
-
def file?(path)
|
49
|
-
lookup(path).is_a?(File)
|
50
|
-
end
|
51
|
-
|
52
|
-
def directory?(path)
|
53
|
-
lookup(path).is_a?(Dir)
|
54
|
-
end
|
55
|
-
|
56
|
-
def exists?(path)
|
57
|
-
lookup(path) ? true : false
|
58
|
-
end
|
59
|
-
|
60
|
-
def mkdir(path)
|
61
|
-
return if path.to_s == '/'
|
62
|
-
|
63
|
-
node = lookup_parent! path
|
64
|
-
dir = node.lookup ::File.basename path
|
65
|
-
unless dir.is_a?(Dir)
|
66
|
-
if dir.nil?
|
67
|
-
node.add Dir.new(self, ::File.basename(path))
|
68
|
-
else
|
69
|
-
raise ArgumentError.new \
|
70
|
-
"Node #{dir.path} exists and is no directory."
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def mkpath(path)
|
76
|
-
path = expand_path(path)
|
77
|
-
::Pathname.new(path).descend do |p|
|
78
|
-
mkdir(p.to_s)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def touch(path)
|
83
|
-
node = lookup_parent! path
|
84
|
-
file = node.lookup ::File.basename path
|
85
|
-
if file
|
86
|
-
file.mtime = Time.now
|
87
|
-
else
|
88
|
-
node.add File.new(self, ::File.basename(path))
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def write(path, content, *args)
|
93
|
-
node = lookup_parent! path
|
94
|
-
file = node.lookup ::File.basename(path)
|
95
|
-
unless file
|
96
|
-
file = File.new self, ::File.basename(path)
|
97
|
-
node.add file
|
98
|
-
end
|
99
|
-
|
100
|
-
case file
|
101
|
-
when File
|
102
|
-
if args.empty?
|
103
|
-
file.content = content
|
104
|
-
else
|
105
|
-
offset = args[0].to_i
|
106
|
-
file.content[offset, content.length] = content
|
107
|
-
end
|
108
|
-
file.mtime = Time.now
|
109
|
-
when Dir
|
110
|
-
raise Errno::EISDIR.new path
|
111
|
-
else
|
112
|
-
raise ArgumentError.new
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def mtime(path)
|
117
|
-
lookup!(path).mtime
|
118
|
-
end
|
119
|
-
|
120
|
-
def mtime=(path, time)
|
121
|
-
lookup!(path).mtime = time
|
122
|
-
end
|
123
|
-
|
124
|
-
def atime(path)
|
125
|
-
lookup!(path).atime
|
126
|
-
end
|
127
|
-
|
128
|
-
def atime=(path, time)
|
129
|
-
lookup!(path).atime = time
|
130
|
-
end
|
131
|
-
|
132
|
-
def read(path, *args)
|
133
|
-
file = lookup_file!(path)
|
134
|
-
file.atime = Time.now
|
135
|
-
content = file.content
|
136
|
-
if args[0]
|
137
|
-
length = args[0].to_i
|
138
|
-
offset = args[1] ? args[1].to_i : 0
|
139
|
-
content = content.slice(offset, length)
|
140
|
-
end
|
141
|
-
content
|
142
|
-
end
|
143
|
-
|
144
|
-
def entries(path)
|
145
|
-
node = lookup_dir! path
|
146
|
-
node.children.map(&:name) + %w(. ..)
|
147
|
-
end
|
148
|
-
|
149
|
-
def glob(pattern, flags = 0, &block)
|
150
|
-
root.all.select do |node|
|
151
|
-
::File.fnmatch pattern, node.path, (flags | ::File::FNM_PATHNAME)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def get_umask
|
156
|
-
@umask
|
157
|
-
end
|
158
|
-
|
159
|
-
def set_umask(mask)
|
160
|
-
@umask = Integer(mask)
|
161
|
-
end
|
162
|
-
|
163
|
-
def mode(path)
|
164
|
-
lookup!(path).mode
|
165
|
-
end
|
166
|
-
|
167
|
-
def unlink(path)
|
168
|
-
node = lookup_parent!(path)
|
169
|
-
file = node.lookup ::File.basename path
|
170
|
-
case file
|
171
|
-
when Dir
|
172
|
-
raise Errno::EISDIR.new path
|
173
|
-
when File
|
174
|
-
node.children.delete(file)
|
175
|
-
when nil
|
176
|
-
raise Errno::ENOENT.new path
|
177
|
-
else
|
178
|
-
raise ArgumentError.new "Unknown node #{node.inspect} for #unlink."
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def rmtree(path)
|
183
|
-
node = lookup path
|
184
|
-
case node
|
185
|
-
when Dir, File
|
186
|
-
lookup_parent!(path).children.delete(node)
|
187
|
-
when nil
|
188
|
-
nil
|
189
|
-
else
|
190
|
-
raise ArgumentError.new "Unknown node #{node.inspect} for #rmtree."
|
191
|
-
end
|
192
|
-
end
|
193
|
-
alias_method :safe_rmtree, :rmtree
|
194
|
-
|
195
|
-
def rmtree!(path)
|
196
|
-
node = lookup path
|
197
|
-
case node
|
198
|
-
when Dir, File
|
199
|
-
lookup_parent!(path).children.delete(node)
|
200
|
-
when nil
|
201
|
-
raise Errno::ENOENT.new path
|
202
|
-
else
|
203
|
-
raise ArgumentError.new "Unknown node #{node.inspect} for #rmtree."
|
204
|
-
end
|
205
|
-
end
|
206
|
-
alias_method :safe_rmtree!, :rmtree!
|
207
|
-
|
208
|
-
# @!group Internal Virtual File System
|
209
|
-
|
210
|
-
# Return root node.
|
211
|
-
def root
|
212
|
-
@root ||= Dir.new(self, '')
|
213
|
-
end
|
214
|
-
|
215
|
-
def to_lookup(path)
|
216
|
-
path = expand path
|
217
|
-
path.sub(/^\/+/, '')
|
218
|
-
end
|
219
|
-
|
220
|
-
def lookup(path)
|
221
|
-
root.lookup to_lookup path
|
222
|
-
end
|
223
|
-
|
224
|
-
def lookup!(path)
|
225
|
-
if (node = lookup(path))
|
226
|
-
node
|
227
|
-
else
|
228
|
-
raise Errno::ENOENT.new path
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
def lookup_file!(path)
|
233
|
-
node = lookup! path
|
234
|
-
case node
|
235
|
-
when File
|
236
|
-
node
|
237
|
-
when Dir
|
238
|
-
raise Errno::EISDIR.new path
|
239
|
-
else
|
240
|
-
raise ArgumentError.new "NOT A FILE: #{path}"
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def lookup_dir!(path)
|
245
|
-
if (node = lookup!(path)).is_a?(Dir)
|
246
|
-
node
|
247
|
-
else
|
248
|
-
raise Errno::ENOENT.new path
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
def lookup_parent!(path)
|
253
|
-
node = lookup ::File.dirname expand path
|
254
|
-
if node
|
255
|
-
node.is_a?(Dir) ? node : raise(Errno::ENOTDIR.new path)
|
256
|
-
else
|
257
|
-
raise Errno::ENOENT.new path
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
#
|
262
|
-
class Node
|
263
|
-
attr_reader :sys, :name, :parent
|
264
|
-
attr_accessor :mtime, :atime, :mode
|
265
|
-
|
266
|
-
def initialize(backend, name, ops = {})
|
267
|
-
@sys = backend
|
268
|
-
@name = name
|
269
|
-
@mtime = Time.now
|
270
|
-
@atime = Time.now
|
271
|
-
end
|
272
|
-
|
273
|
-
def mtime=(time)
|
274
|
-
if time.is_a?(Time)
|
275
|
-
@mtime = time
|
276
|
-
else
|
277
|
-
raise "Not Time but `#{time.inspect}` of `#{time.class.name}` given."
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
def lookup(path)
|
282
|
-
raise NotImplementError.new 'Subclass responsibility.'
|
283
|
-
end
|
284
|
-
|
285
|
-
def added(parent)
|
286
|
-
@parent = parent
|
287
|
-
end
|
288
|
-
|
289
|
-
def path
|
290
|
-
parent ? "#{parent.path}/#{name}" : name
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
#
|
295
|
-
class Dir < Node
|
296
|
-
def initialize(backend, name, opts = {})
|
297
|
-
super
|
298
|
-
self.mode = 0777 - backend.get_umask
|
299
|
-
end
|
300
|
-
|
301
|
-
def lookup(path)
|
302
|
-
name, rest = path.to_s.split('/', 2).map(&:to_s)
|
303
|
-
|
304
|
-
if name.nil?
|
305
|
-
if rest.nil?
|
306
|
-
self
|
307
|
-
else
|
308
|
-
lookup rest
|
309
|
-
end
|
310
|
-
else
|
311
|
-
child = children.find{|c| c.name == name }
|
312
|
-
if child
|
313
|
-
rest.nil? ? child : child.lookup(rest)
|
314
|
-
else
|
315
|
-
nil
|
316
|
-
end
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
def add(node)
|
321
|
-
if children.any?{|c| c.name == node.name }
|
322
|
-
raise ArgumentError.new "Node #{path}/#{node.name} already exists."
|
323
|
-
else
|
324
|
-
children << node
|
325
|
-
node.added self
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
def all
|
330
|
-
children.reduce([]) do |memo, child|
|
331
|
-
memo << child
|
332
|
-
memo += child.all if child.is_a?(Dir)
|
333
|
-
memo
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
def children
|
338
|
-
@children ||= []
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
#
|
343
|
-
class File < Node
|
344
|
-
attr_accessor :content
|
345
|
-
|
346
|
-
def initialize(backend, name, opts = {})
|
347
|
-
super
|
348
|
-
self.mode = 0666 - backend.get_umask
|
349
|
-
end
|
350
|
-
|
351
|
-
def lookup(path)
|
352
|
-
nil
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
356
|
-
end
|