core_ex 0.1.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.
- data/AUTHORS +26 -0
- data/NEWS +8 -0
- data/README +1 -0
- data/Rakefile +7 -0
- data/SPEC.dyn.yml +8 -0
- data/SPEC.yml +37 -0
- data/lib/core_ex/attr_once.rb +36 -0
- data/lib/core_ex/dtime.rb +169 -0
- data/lib/core_ex/embedded_tests.rb +33 -0
- data/lib/core_ex/enumerable.rb +173 -0
- data/lib/core_ex/exception.rb +32 -0
- data/lib/core_ex/filelist.rb +464 -0
- data/lib/core_ex/fileutils.rb +44 -0
- data/lib/core_ex/pathname.rb +196 -0
- data/lib/core_ex/require.rb +378 -0
- data/lib/core_ex/string.rb +47 -0
- data/lib/core_ex/temp_path.rb +194 -0
- data/lib/core_ex/test/unit/ui/yaml/testrunner.rb +166 -0
- data/lib/core_ex/time.rb +91 -0
- data/lib/core_ex/version.rb +119 -0
- data/lib/core_ex/yaml.rb +24 -0
- data/lib/core_ex.rb +55 -0
- data/test/check-core_ex.yml +12 -0
- data/test/check-pkg-core_ex.yml +15 -0
- data/test/resources/autoload_tree/A.rb +11 -0
- data/test/resources/autoload_tree/B.rb +10 -0
- data/test/resources/autoload_tree/foo/C.rb +18 -0
- data/test/resources/require/test_require +1 -0
- data/test/resources/require/test_require_rb.rb +1 -0
- data/test/resources/require/test_require_so.so +1 -0
- data/test/resources/use-from-gems.rb +9 -0
- data/test/resources/yaml_testrunner/unit_test.rb +43 -0
- data/test/sanity/multiple-requires.yml +20 -0
- data/test/sanity/single-requires.yml +24 -0
- data/test/sanity-suite.yml +12 -0
- data/test/test-unit-setup.rb +6 -0
- data/test/unit-suite.yml +14 -0
- metadata +113 -0
@@ -0,0 +1,464 @@
|
|
1
|
+
# Revision:: $Id: filelist.rb 249 2005-05-31 13:23:42Z ertai $
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright (c) 2003, 2004 Jim Weirich
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
# the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
#++
|
25
|
+
#
|
26
|
+
|
27
|
+
# Contributons by Nicolas Pouillard <ertai@lrde.epita.fr>.
|
28
|
+
|
29
|
+
# Some objects are dupable, some are not. So we define a version of
|
30
|
+
# dup (called rake_dup) that returns self on the handful of classes
|
31
|
+
# that are not dupable.
|
32
|
+
|
33
|
+
module Kernel
|
34
|
+
# Duplicate an object if it can be duplicated. If it can not be
|
35
|
+
# cloned or duplicated, then just return the original object.
|
36
|
+
def rake_dup()
|
37
|
+
dup
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
[NilClass, FalseClass, TrueClass, Fixnum, Symbol].each do |clazz|
|
42
|
+
clazz.class_eval {
|
43
|
+
# Duplicate an object if it can be duplicated. If it can not be
|
44
|
+
# cloned or duplicated, then just return the original object.
|
45
|
+
def rake_dup() self end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
######################################################################
|
50
|
+
# User defined methods to be added to String.
|
51
|
+
#
|
52
|
+
class String
|
53
|
+
unless instance_methods.include? "ext"
|
54
|
+
# Replace the file extension with +newext+. If there is no
|
55
|
+
# extenson on the string, append the new extension to the end. If
|
56
|
+
# the new extension is not given, or is the empty string, remove
|
57
|
+
# any existing extension.
|
58
|
+
#
|
59
|
+
# +ext+ is a user added method for the String class.
|
60
|
+
def ext(newext='')
|
61
|
+
return self.dup if ['.', '..'].include? self
|
62
|
+
if newext != ''
|
63
|
+
newext = (newext =~ /^\./) ? newext : ("." + newext)
|
64
|
+
end
|
65
|
+
dup.sub!(%r(([^/\\])\.[^./\\]*$)) { $1 + newext } || self + newext
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
####################################################################
|
72
|
+
# A FileList is essentially an array with a few helper methods
|
73
|
+
# defined to make file manipulation a bit easier.
|
74
|
+
#
|
75
|
+
# FileLists are lazy. When given a list of glob patterns for
|
76
|
+
# possible files to be included in the file list, instead of
|
77
|
+
# searching the file structures to find the files, a FileList holds
|
78
|
+
# the pattern for latter use.
|
79
|
+
#
|
80
|
+
# This allows us to define a number of FileList to match any number of
|
81
|
+
# files, but only search out the actual files when then FileList
|
82
|
+
# itself is actually used. The key is that the first time an
|
83
|
+
# element of the FileList/Array is requested, the pending patterns
|
84
|
+
# are resolved into a real list of file names.
|
85
|
+
#
|
86
|
+
class FileList
|
87
|
+
|
88
|
+
def clone
|
89
|
+
sibling = self.class.new
|
90
|
+
instance_variables.each do |ivar|
|
91
|
+
value = self.instance_variable_get(ivar)
|
92
|
+
sibling.instance_variable_set(ivar, value.rake_dup)
|
93
|
+
end
|
94
|
+
sibling
|
95
|
+
end
|
96
|
+
alias dup clone
|
97
|
+
|
98
|
+
# == Method Delegation
|
99
|
+
#
|
100
|
+
# The lazy evaluation magic of FileLists happens by implementing
|
101
|
+
# all the array specific methods to call +resolve+ before
|
102
|
+
# delegating the heavy lifting to an embedded array object
|
103
|
+
# (@items).
|
104
|
+
#
|
105
|
+
# In addition, there are two kinds of delegation calls. The
|
106
|
+
# regular kind delegates to the @items array and returns the
|
107
|
+
# result directly. Well, almost directly. It checks if the
|
108
|
+
# returned value is the @items object itself, and if so will
|
109
|
+
# return the FileList object instead.
|
110
|
+
#
|
111
|
+
# The second kind of delegation call is used in methods that
|
112
|
+
# normally return a new Array object. We want to capture the
|
113
|
+
# return value of these methods and wrap them in a new FileList
|
114
|
+
# object. We enumerate these methods in the +SPECIAL_RETURN+ list
|
115
|
+
# below.
|
116
|
+
|
117
|
+
# List of array methods (that are not in +Object+) that need to be
|
118
|
+
# delegated.
|
119
|
+
ARRAY_METHODS = Array.instance_methods - Object.instance_methods
|
120
|
+
|
121
|
+
# List of additional methods that must be delegated.
|
122
|
+
MUST_DEFINE = %w[to_a inspect]
|
123
|
+
|
124
|
+
# List of methods that should not be delegated here (we define
|
125
|
+
# special versions of them explicitly below).
|
126
|
+
MUST_NOT_DEFINE = %w[to_a to_ary partition *]
|
127
|
+
|
128
|
+
# List of delegated methods that return new array values which
|
129
|
+
# need wrapping.
|
130
|
+
SPECIAL_RETURN = %w[
|
131
|
+
map collect sort sort_by select find_all reject grep
|
132
|
+
compact flatten uniq values_at
|
133
|
+
+ - & |
|
134
|
+
]
|
135
|
+
|
136
|
+
DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).sort.uniq
|
137
|
+
|
138
|
+
# Now do the delegation.
|
139
|
+
DELEGATING_METHODS.each_with_index do |sym, i|
|
140
|
+
if SPECIAL_RETURN.include?(sym)
|
141
|
+
ln = __LINE__+1
|
142
|
+
class_eval %{
|
143
|
+
def #{sym}(*args, &block)
|
144
|
+
resolve if @pending
|
145
|
+
result = @items.send(:#{sym}, *args, &block)
|
146
|
+
FileList.new.import(result)
|
147
|
+
end
|
148
|
+
}, __FILE__, ln
|
149
|
+
else
|
150
|
+
ln = __LINE__+1
|
151
|
+
class_eval %{
|
152
|
+
def #{sym}(*args, &block)
|
153
|
+
resolve if @pending
|
154
|
+
result = @items.send(:#{sym}, *args, &block)
|
155
|
+
result.object_id == @items.object_id ? self : result
|
156
|
+
end
|
157
|
+
}, __FILE__, ln
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Create a file list from the globbable patterns given. If you
|
162
|
+
# wish to perform multiple includes or excludes at object build
|
163
|
+
# time, use the "yield self" pattern.
|
164
|
+
#
|
165
|
+
# Example:
|
166
|
+
# file_list = FileList.new['lib/**/*.rb', 'test/test*.rb']
|
167
|
+
#
|
168
|
+
# pkg_files = FileList.new['lib/**/*'] do |fl|
|
169
|
+
# fl.exclude(/\bCVS\b/)
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
def initialize(*patterns)
|
173
|
+
@pending_add = []
|
174
|
+
@pending = false
|
175
|
+
@exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
|
176
|
+
@exclude_re = nil
|
177
|
+
@items = []
|
178
|
+
patterns.each { |pattern| include(pattern) }
|
179
|
+
yield self if block_given?
|
180
|
+
end
|
181
|
+
|
182
|
+
# Add file names defined by glob patterns to the file list. If an
|
183
|
+
# array is given, add each element of the array.
|
184
|
+
#
|
185
|
+
# Example:
|
186
|
+
# file_list.include("*.java", "*.cfg")
|
187
|
+
# file_list.include %w( math.c lib.h *.o )
|
188
|
+
#
|
189
|
+
def include(*filenames)
|
190
|
+
# TODO: check for pending
|
191
|
+
filenames.each do |fn|
|
192
|
+
if fn.respond_to? :to_ary
|
193
|
+
include(*fn.to_ary)
|
194
|
+
else
|
195
|
+
@pending_add << fn
|
196
|
+
end
|
197
|
+
end
|
198
|
+
@pending = true
|
199
|
+
self
|
200
|
+
end
|
201
|
+
alias :add :include
|
202
|
+
|
203
|
+
# Register a list of file name patterns that should be excluded
|
204
|
+
# from the list. Patterns may be regular expressions, glob
|
205
|
+
# patterns or regular strings.
|
206
|
+
#
|
207
|
+
# Note that glob patterns are expanded against the file system.
|
208
|
+
# If a file is explicitly added to a file list, but does not exist
|
209
|
+
# in the file system, then an glob pattern in the exclude list
|
210
|
+
# will not exclude the file.
|
211
|
+
#
|
212
|
+
# Examples:
|
213
|
+
# FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
|
214
|
+
# FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
|
215
|
+
#
|
216
|
+
# If "a.c" is a file, then ...
|
217
|
+
# FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
|
218
|
+
#
|
219
|
+
# If "a.c" is not a file, then ...
|
220
|
+
# FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
|
221
|
+
#
|
222
|
+
def exclude(*patterns)
|
223
|
+
patterns.each do |pat| @exclude_patterns << pat end
|
224
|
+
if ! @pending
|
225
|
+
calculate_exclude_regexp
|
226
|
+
reject! { |fn| fn.to_s =~ @exclude_re }
|
227
|
+
end
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
|
233
|
+
|
234
|
+
# Clear all the exclude patterns so that we exclude nothing.
|
235
|
+
def clear_exclude
|
236
|
+
@exclude_patterns = []
|
237
|
+
calculate_exclude_regexp if ! @pending
|
238
|
+
end
|
239
|
+
|
240
|
+
# Define equality.
|
241
|
+
def ==(array)
|
242
|
+
to_ary == array
|
243
|
+
end
|
244
|
+
|
245
|
+
# Return the internal array object.
|
246
|
+
def to_a
|
247
|
+
resolve
|
248
|
+
@items
|
249
|
+
end
|
250
|
+
|
251
|
+
# Return the internal array object.
|
252
|
+
def to_ary
|
253
|
+
resolve
|
254
|
+
@items
|
255
|
+
end
|
256
|
+
|
257
|
+
# Redefine * to return either a string or a new file list.
|
258
|
+
def *(other)
|
259
|
+
result = @items * other
|
260
|
+
case result
|
261
|
+
when Array
|
262
|
+
FileList.new.import(result)
|
263
|
+
else
|
264
|
+
result
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# Resolve all the pending adds now.
|
269
|
+
def resolve
|
270
|
+
if @pending
|
271
|
+
@pending = false
|
272
|
+
@pending_add.each do |fn| resolve_add(fn) end
|
273
|
+
@pending_add = []
|
274
|
+
resolve_exclude
|
275
|
+
end
|
276
|
+
self
|
277
|
+
end
|
278
|
+
|
279
|
+
def calculate_exclude_regexp
|
280
|
+
ignores = []
|
281
|
+
@exclude_patterns.each do |pat|
|
282
|
+
case pat
|
283
|
+
when Regexp
|
284
|
+
ignores << pat
|
285
|
+
when /[*.]/
|
286
|
+
Dir[pat].each do |p| ignores << p end
|
287
|
+
else
|
288
|
+
ignores << Regexp.quote(pat)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
if ignores.empty?
|
292
|
+
@exclude_re = /^$/
|
293
|
+
else
|
294
|
+
re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
|
295
|
+
@exclude_re = Regexp.new(re_str)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def resolve_add(fn)
|
300
|
+
case fn
|
301
|
+
when Array
|
302
|
+
fn.each { |f| self.resolve_add(f) }
|
303
|
+
when %r{[*?]}
|
304
|
+
add_matching(fn)
|
305
|
+
else
|
306
|
+
# >>>>
|
307
|
+
self << fn.to_path
|
308
|
+
# <<<<
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def resolve_exclude
|
313
|
+
@exclude_patterns.each do |pat|
|
314
|
+
case pat
|
315
|
+
when Regexp
|
316
|
+
# <<<<
|
317
|
+
reject! { |fn| fn.to_s =~ pat }
|
318
|
+
# >>>>
|
319
|
+
when /[*.]/
|
320
|
+
# <<<<
|
321
|
+
reject_list = Pathname.glob(pat)
|
322
|
+
# >>>>
|
323
|
+
reject! { |fn| reject_list.include?(fn) }
|
324
|
+
else
|
325
|
+
# <<<<
|
326
|
+
reject! { |fn| fn.to_s == pat.to_s }
|
327
|
+
# >>>>
|
328
|
+
end
|
329
|
+
end
|
330
|
+
self
|
331
|
+
end
|
332
|
+
|
333
|
+
# Return a new FileList with the results of running +sub+ against
|
334
|
+
# each element of the oringal list.
|
335
|
+
#
|
336
|
+
# Example:
|
337
|
+
# FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o']
|
338
|
+
#
|
339
|
+
def sub(pat, rep)
|
340
|
+
inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
|
341
|
+
end
|
342
|
+
|
343
|
+
# Return a new FileList with the results of running +gsub+ against
|
344
|
+
# each element of the original list.
|
345
|
+
#
|
346
|
+
# Example:
|
347
|
+
# FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
|
348
|
+
# => ['lib\\test\\file', 'x\\y']
|
349
|
+
#
|
350
|
+
def gsub(pat, rep)
|
351
|
+
inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
|
352
|
+
end
|
353
|
+
|
354
|
+
# Same as +sub+ except that the oringal file list is modified.
|
355
|
+
def sub!(pat, rep)
|
356
|
+
each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
|
357
|
+
self
|
358
|
+
end
|
359
|
+
|
360
|
+
# Same as +gsub+ except that the original file list is modified.
|
361
|
+
def gsub!(pat, rep)
|
362
|
+
each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
|
363
|
+
self
|
364
|
+
end
|
365
|
+
|
366
|
+
# Return a new array with <tt>String#ext</tt> method applied to
|
367
|
+
# each member of the array.
|
368
|
+
#
|
369
|
+
# This method is a shortcut for:
|
370
|
+
#
|
371
|
+
# array.collect { |item| item.ext(newext) }
|
372
|
+
#
|
373
|
+
# +ext+ is a user added method for the Array class.
|
374
|
+
def ext(newext='')
|
375
|
+
collect { |fn| fn.ext(newext) }
|
376
|
+
end
|
377
|
+
|
378
|
+
|
379
|
+
# FileList version of partition. Needed because the nested arrays
|
380
|
+
# should be FileLists in this version.
|
381
|
+
def partition(&block) # :nodoc:
|
382
|
+
resolve
|
383
|
+
result = @items.partition(&block)
|
384
|
+
[
|
385
|
+
FileList.new.import(result[0]),
|
386
|
+
FileList.new.import(result[1]),
|
387
|
+
]
|
388
|
+
end
|
389
|
+
|
390
|
+
# Convert a FileList to a string by joining all elements with a space.
|
391
|
+
def to_s
|
392
|
+
resolve if @pending
|
393
|
+
self.join(' ')
|
394
|
+
end
|
395
|
+
|
396
|
+
# Add matching glob patterns.
|
397
|
+
def add_matching(pattern)
|
398
|
+
# <<<<
|
399
|
+
Pathname.glob(pattern) do |fn|
|
400
|
+
# >>>>
|
401
|
+
self << fn unless exclude?(fn)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
private :add_matching
|
405
|
+
|
406
|
+
# Should the given file name be excluded?
|
407
|
+
def exclude?(fn)
|
408
|
+
calculate_exclude_regexp unless @exclude_re
|
409
|
+
# <<<<
|
410
|
+
fn.to_s =~ @exclude_re
|
411
|
+
# >>>>
|
412
|
+
end
|
413
|
+
|
414
|
+
|
415
|
+
DEFAULT_IGNORE_PATTERNS = [
|
416
|
+
/(^|[\/\\])CVS([\/\\]|$)/,
|
417
|
+
/(^|[\/\\])\.svn([\/\\]|$)/,
|
418
|
+
/\.bak$/,
|
419
|
+
/~$/,
|
420
|
+
/(^|[\/\\])core$/
|
421
|
+
]
|
422
|
+
@exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
|
423
|
+
|
424
|
+
def import(array)
|
425
|
+
@items = array
|
426
|
+
self
|
427
|
+
end
|
428
|
+
|
429
|
+
class << self
|
430
|
+
# Create a new file list including the files listed. Similar to:
|
431
|
+
#
|
432
|
+
# FileList.new(*args)
|
433
|
+
def [](*args)
|
434
|
+
new(*args)
|
435
|
+
end
|
436
|
+
|
437
|
+
# Set the ignore patterns back to the default value. The
|
438
|
+
# default patterns will ignore files
|
439
|
+
# * containing "CVS" in the file path
|
440
|
+
# * containing ".svn" in the file path
|
441
|
+
# * ending with ".bak"
|
442
|
+
# * ending with "~"
|
443
|
+
# * named "core"
|
444
|
+
#
|
445
|
+
# Note that file names beginning with "." are automatically
|
446
|
+
# ignored by Ruby's glob patterns and are not specifically
|
447
|
+
# listed in the ignore patterns.
|
448
|
+
def select_default_ignore_patterns
|
449
|
+
@exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
|
450
|
+
end
|
451
|
+
|
452
|
+
# Clear the ignore patterns.
|
453
|
+
def clear_ignore_patterns
|
454
|
+
@exclude_patterns = [ /^$/ ]
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
# <<<<
|
459
|
+
def require
|
460
|
+
each { |x| x.require }
|
461
|
+
end
|
462
|
+
# >>>>
|
463
|
+
end
|
464
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Copyright: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
|
2
|
+
# Author: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: fileutils.rb 249 2005-05-31 13:23:42Z ertai $
|
7
|
+
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
module FileUtils
|
11
|
+
|
12
|
+
alias remove_dir_without_chmod remove_dir
|
13
|
+
|
14
|
+
def remove_dir (dir, force = false) #:nodoc:
|
15
|
+
dir = dir.sub(%r</\z>, '')
|
16
|
+
first_time_p = true
|
17
|
+
begin
|
18
|
+
Dir.foreach(dir) do |file|
|
19
|
+
next if /\A\.\.?\z/ =~ file
|
20
|
+
path = "#{dir}/#{file.untaint}"
|
21
|
+
if File.symlink?(path)
|
22
|
+
remove_file path, force
|
23
|
+
elsif File.directory?(path)
|
24
|
+
remove_dir path, force
|
25
|
+
else
|
26
|
+
remove_file path, force
|
27
|
+
end
|
28
|
+
end
|
29
|
+
begin
|
30
|
+
Dir.rmdir dir
|
31
|
+
rescue Errno::ENOENT
|
32
|
+
raise unless force
|
33
|
+
end
|
34
|
+
rescue
|
35
|
+
if first_time_p
|
36
|
+
first_time_p = false
|
37
|
+
File.chmod 0777, dir
|
38
|
+
retry
|
39
|
+
end
|
40
|
+
raise
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: pathname.rb 252 2005-05-31 23:41:42Z ertai $
|
7
|
+
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
require 'core_ex/embedded_tests'
|
11
|
+
require 'core_ex/string'
|
12
|
+
|
13
|
+
|
14
|
+
class Pathname
|
15
|
+
|
16
|
+
def ensure_mkdir
|
17
|
+
(mkdir) rescue Errno::EEXIST
|
18
|
+
end
|
19
|
+
|
20
|
+
def ensure_mkpath
|
21
|
+
(mkpath) rescue Errno::EEXIST
|
22
|
+
end
|
23
|
+
|
24
|
+
def extsplit ( aChar='.' )
|
25
|
+
raise ArgumentError, "#{aChar} is not just a char" if aChar.size != 1
|
26
|
+
aChar = Regexp.escape(aChar)
|
27
|
+
to_s =~ /^(.*?)(#{aChar}[^#{aChar}]*)?$/
|
28
|
+
[Pathname.new($1), $2 || '']
|
29
|
+
end
|
30
|
+
|
31
|
+
def cp ( aPath )
|
32
|
+
FileUtils.cp self.to_s, aPath.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def cp_r ( aPath )
|
36
|
+
FileUtils.cp_r self.to_s, aPath.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
def rm
|
40
|
+
FileUtils.rm self.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def rm_r
|
44
|
+
FileUtils.rm_r self.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
def rm_rf
|
48
|
+
FileUtils.rm_rf self.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def rm_f
|
52
|
+
FileUtils.rm_f self.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
# The current ruby's unlink implementation has a bug.
|
56
|
+
def unlink()
|
57
|
+
if FileTest.directory? @path and not FileTest.symlink? @path
|
58
|
+
Dir.unlink @path
|
59
|
+
else
|
60
|
+
File.unlink @path
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Allow this kind of things:
|
65
|
+
#
|
66
|
+
# root = Pathname.new('/tmp/test')
|
67
|
+
# foo, bar = 'foo', 'bar'
|
68
|
+
#
|
69
|
+
# ...
|
70
|
+
#
|
71
|
+
# (root/foo/bar).each_line do |line|
|
72
|
+
# ...
|
73
|
+
# end
|
74
|
+
alias :/ :+
|
75
|
+
|
76
|
+
def to_io
|
77
|
+
@open_mode ||= 'r'
|
78
|
+
open(@open_mode)
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_path
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
attr_accessor :open_mode
|
86
|
+
|
87
|
+
def require ( *a )
|
88
|
+
if a.empty?
|
89
|
+
RequireSystem.instance.require(self)
|
90
|
+
else
|
91
|
+
Kernel.__require__(*a)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def load ( *a )
|
96
|
+
if a.empty?
|
97
|
+
RequireSystem.instance.load(self)
|
98
|
+
else
|
99
|
+
Kernel.__load__(*a)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def expand_path_with ( directories, extensions=nil )
|
104
|
+
ext = extname
|
105
|
+
exts, dirs = [''], ['']
|
106
|
+
unless extensions.nil?
|
107
|
+
if ext.empty?
|
108
|
+
exts = extensions
|
109
|
+
else
|
110
|
+
unless extensions.include? ext
|
111
|
+
raise ArgumentError, "bad extension `#{ext}' for #{self}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
dirs = directories unless absolute?
|
117
|
+
|
118
|
+
exts.each do |ext|
|
119
|
+
dirs.each do |dir|
|
120
|
+
dir = dir.to_path
|
121
|
+
file = dir + "#{self}#{ext}"
|
122
|
+
return file.expand_path.cleanpath if file.exist?
|
123
|
+
end
|
124
|
+
end
|
125
|
+
return nil
|
126
|
+
end
|
127
|
+
|
128
|
+
module ShortCut
|
129
|
+
|
130
|
+
# Allow to use this sort of constructions:
|
131
|
+
#
|
132
|
+
# `/path/to/a/file`.open do |f|
|
133
|
+
# ...
|
134
|
+
# end
|
135
|
+
def ` ( path )
|
136
|
+
Pathname.new(path)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end # class Pathname
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
#
|
145
|
+
# Unit test suite
|
146
|
+
#
|
147
|
+
test_section __FILE__ do
|
148
|
+
|
149
|
+
|
150
|
+
require 'tempfile'
|
151
|
+
|
152
|
+
|
153
|
+
class PathnameExTest < Test::Unit::TestCase
|
154
|
+
|
155
|
+
#
|
156
|
+
# Tests
|
157
|
+
#
|
158
|
+
def test_ensure_dir
|
159
|
+
p = nil
|
160
|
+
begin
|
161
|
+
name = Tempfile.new('pathname')
|
162
|
+
p = Pathname.new(name.path)
|
163
|
+
name.delete
|
164
|
+
assert(! p.directory?, 'no directory')
|
165
|
+
assert_nothing_raised { p.ensure_mkdir }
|
166
|
+
assert(p.directory?, 'directory')
|
167
|
+
assert_nothing_raised { p.ensure_mkdir }
|
168
|
+
assert(p.directory?, 'still directory')
|
169
|
+
ensure
|
170
|
+
p.rmdir unless p.nil?
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
include Pathname::ShortCut
|
175
|
+
|
176
|
+
def test_simple
|
177
|
+
assert_equal([`path.ext1`, '.ext2'], `path.ext1.ext2`.extsplit)
|
178
|
+
assert_equal([`path`, ''], `path`.extsplit)
|
179
|
+
assert_equal([`path`, '.'], `path.`.extsplit)
|
180
|
+
assert_equal([`path`, '-ext'], `path-ext`.extsplit('-'))
|
181
|
+
assert_equal([`path-ext1`, '-ext2'], `path-ext1-ext2`.extsplit('-'))
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_slash
|
185
|
+
assert_equal(`path/to/a/file`, `path`/'to'/'a'/'file')
|
186
|
+
path, to, a, file = `/path`, 'to', 'a', 'file'
|
187
|
+
assert_equal(`/path/to/a/file`, path/to/a/file)
|
188
|
+
end
|
189
|
+
|
190
|
+
# def test_expand_path_with
|
191
|
+
# See core_ex/require RequireSystemTest#test_*_search
|
192
|
+
# end
|
193
|
+
|
194
|
+
end # class PathnameExTest
|
195
|
+
|
196
|
+
end
|