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.
@@ -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