file-find 0.3.1-universal-java-1.5
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/CHANGES +53 -0
- data/MANIFEST +7 -0
- data/README +111 -0
- data/lib/file/find.rb +474 -0
- data/test/test_file_find.rb +431 -0
- metadata +69 -0
data/CHANGES
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
== 0.3.1 - 9-Jan-2008
|
2
|
+
* Now defaults to using Etc instead of Sys::Admin for implementations
|
3
|
+
that don't support building C extensions, e.g. JRuby.
|
4
|
+
* Updated the test suite to work with JRuby.
|
5
|
+
* Minor optimizations for symbolic perms and atime/ctime/mtime checks.
|
6
|
+
Thanks go in part to Ryan Davis' flay library.
|
7
|
+
|
8
|
+
== 0.3.0 - 30-Dec-2008
|
9
|
+
* Added support for FileTest operations. All options passed to the constructor
|
10
|
+
that end with '?' are now validated and treated as FileTest operations.
|
11
|
+
|
12
|
+
== 0.2.5 - 29-Dec-2008
|
13
|
+
* Added maxdepth and mindepth support.
|
14
|
+
* Added a 'clean' rake task to cleanup any test-unit results files.
|
15
|
+
|
16
|
+
== 0.2.4 - 10-Dec-2008
|
17
|
+
* Added support for symbolic permissions. Thanks go to Bill Kleb for the
|
18
|
+
suggestion and to Hal Fulton for providing the solution.
|
19
|
+
|
20
|
+
== 0.2.3 - 25-Nov-2008
|
21
|
+
* Added mtime support. My previous concerns, which I believe stemmed from
|
22
|
+
the find(2) man page on Solaris 10 with regards to atime checks modifying
|
23
|
+
the mtime, appear have been unfounded.
|
24
|
+
|
25
|
+
== 0.2.2 - 19-Nov-2008
|
26
|
+
* The :user and :group options now accept a name or a numeric id. Thanks go
|
27
|
+
to Bill Kleb for the suggestion.
|
28
|
+
* Fixed yet another path bug for MS Windows.
|
29
|
+
* Updated platform check to use CONFIG instead of RUBY_PLATFORM, because the
|
30
|
+
latter does not work as I intended with other implementations, e.g. JRuby.
|
31
|
+
* Added sys-admin and test-unit as prerequisites.
|
32
|
+
* Added tests for the :user and :group options.
|
33
|
+
|
34
|
+
== 0.2.1 - 4-Oct-2007
|
35
|
+
* Added the File::Find#previous method, which lets you see the previous
|
36
|
+
match, if any.
|
37
|
+
* Path name bug fix for MS Windows.
|
38
|
+
* Test suite bug fixes for MS Windows (perm test now skipped).
|
39
|
+
* Inaccessible directories are now skipped instead of raising an error.
|
40
|
+
|
41
|
+
== 0.2.0 - 26-Apr-2007
|
42
|
+
* Fixed a bug where it was not traversing subdirectories.
|
43
|
+
* Added support for the perm and prune options.
|
44
|
+
|
45
|
+
== 0.1.1 - 25-Apr-2007
|
46
|
+
* The default for name is now '*', i.e. everything.
|
47
|
+
* Fixed a bug where directories were not matched. Thanks go to Leslie Viljoen
|
48
|
+
for the spot.
|
49
|
+
* The size option now accepts strings with comparable operators. For example,
|
50
|
+
you can now look for files greater than 400 bytes with the string "> 400".
|
51
|
+
|
52
|
+
== 0.1.0 - 24-Apr-2007
|
53
|
+
* Initial release
|
data/MANIFEST
ADDED
data/README
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
= Description
|
2
|
+
This is a drop-in replacement for the find module currently in the standard
|
3
|
+
library. It is modeled on a typical 'find' command found on most Unix systems.
|
4
|
+
|
5
|
+
= Synopsis
|
6
|
+
rule = File::Find.new(
|
7
|
+
:pattern => "*.rb",
|
8
|
+
:follow => false,
|
9
|
+
:path => ['/usr/local/lib', '/opt/local/lib']
|
10
|
+
)
|
11
|
+
|
12
|
+
rule.find{ |f|
|
13
|
+
puts f
|
14
|
+
}
|
15
|
+
|
16
|
+
= Installation
|
17
|
+
* rake test (optional)
|
18
|
+
* rake install (non-gem) -OR- rake install_gem (gem)
|
19
|
+
|
20
|
+
= Rationale
|
21
|
+
The current find module in the standard library is inadequate. It is, quite
|
22
|
+
frankly, not much more than a plain Dir.glob call. This library provides an
|
23
|
+
interface based on options typically available on your command line 'find'
|
24
|
+
command, thus allowing you much greater control over how you find your files.
|
25
|
+
|
26
|
+
I am aware of the find2 library by Motoyuki Kasahara, but it supports very
|
27
|
+
few options, hasn't been updated in over six years and isn't packaged properly.
|
28
|
+
|
29
|
+
= Options
|
30
|
+
* atime
|
31
|
+
* ctime
|
32
|
+
* follow
|
33
|
+
* ftype
|
34
|
+
* inum (except Windows)
|
35
|
+
* group (name or id)
|
36
|
+
* maxdepth
|
37
|
+
* mindepth
|
38
|
+
* mtime
|
39
|
+
* name (or 'pattern')
|
40
|
+
* path
|
41
|
+
* perm (except Windows)
|
42
|
+
* prune
|
43
|
+
* size
|
44
|
+
* user (name or id)
|
45
|
+
|
46
|
+
In addition to the above options, FileTest methods such as 'readable?' and
|
47
|
+
'writable?' may be used as keys, with true or false for their values.
|
48
|
+
|
49
|
+
See the RDoc documentation for more details about these options.
|
50
|
+
|
51
|
+
= Future Plans
|
52
|
+
More options will be added as time permits, and requests will definitely be
|
53
|
+
considered. Please log any feature requests on the project page at
|
54
|
+
http://www.rubyforge.org/projects/shards.
|
55
|
+
|
56
|
+
Some specific things I plan on adding:
|
57
|
+
|
58
|
+
* exec
|
59
|
+
* links
|
60
|
+
* support for :user and :group on MS Windows
|
61
|
+
|
62
|
+
= Options I won't support
|
63
|
+
Generally speaking, anything that would require mucking around with C code
|
64
|
+
or is just too difficult to implement in a cross platform manner will not be
|
65
|
+
supported. These include the following options:
|
66
|
+
|
67
|
+
* acl/xattr - Way too difficult to implement in a cross platform manner, and
|
68
|
+
a rarely used option in practice.
|
69
|
+
|
70
|
+
* cpio/ncpio - I will not shell out to this or any other 3rd party application.
|
71
|
+
|
72
|
+
* ls/print - Use Ruby's builtin printing methods to print as you see fit.
|
73
|
+
|
74
|
+
* ok - This is not interactive software.
|
75
|
+
|
76
|
+
= Options I may or may not support
|
77
|
+
|
78
|
+
* local/mount/xdev - This will probably not be added until I'm satisfied with
|
79
|
+
the sys-filesystem library. As of sys-filesystem 0.1.x, I'm not.
|
80
|
+
|
81
|
+
= Known Issues
|
82
|
+
The 'perm' option does not work on MS Windows, even for its limited subset of
|
83
|
+
permissions, i.e. 664 and 666. This is arguably a bug in Ruby's
|
84
|
+
File::Stat.mode method on MS Windows.
|
85
|
+
|
86
|
+
The 'user' and 'group' options are not currently supported on MS Windows.
|
87
|
+
This can be supported, but will require changes in the win32-file and
|
88
|
+
win32-file-stat libraries (which would then become dependencies).
|
89
|
+
|
90
|
+
There are 3 test failures with JRuby, all related to the 'perm' option. I
|
91
|
+
have not been able to reduce them to a simple test case and discern the
|
92
|
+
exact cause of the failures, though I suspect a bug in the JRuby
|
93
|
+
implementation of File.chmod.
|
94
|
+
|
95
|
+
= Bugs
|
96
|
+
None that I'm aware of. Please log any bug reports on the project page at
|
97
|
+
http://www.rubyforge.org/projects/shards.
|
98
|
+
|
99
|
+
= Acknowledgements
|
100
|
+
* Richard Clamp's File::Find::Rule Perl module for additional ideas and
|
101
|
+
inspiration.
|
102
|
+
* Bill Kleb for ideas regarding name, group and perm enhancements.
|
103
|
+
|
104
|
+
= License
|
105
|
+
Ruby's
|
106
|
+
|
107
|
+
= Copyright
|
108
|
+
(C) 2007-2008, Daniel J. Berger, All Rights Reserved
|
109
|
+
|
110
|
+
= Author
|
111
|
+
Daniel J. Berger
|
data/lib/file/find.rb
ADDED
@@ -0,0 +1,474 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
# For alternate implementations of Ruby, such as JRuby, that cannot
|
5
|
+
# build C extensions fall back to the Etc module.
|
6
|
+
begin
|
7
|
+
require 'sys/admin'
|
8
|
+
rescue LoadError
|
9
|
+
require 'etc'
|
10
|
+
end
|
11
|
+
|
12
|
+
class File::Find
|
13
|
+
# The version of this library
|
14
|
+
VERSION = '0.3.1'
|
15
|
+
|
16
|
+
# :stopdoc:
|
17
|
+
VALID_OPTIONS = %w/
|
18
|
+
atime
|
19
|
+
ctime
|
20
|
+
follow
|
21
|
+
ftype
|
22
|
+
inum
|
23
|
+
group
|
24
|
+
maxdepth
|
25
|
+
mindepth
|
26
|
+
mtime
|
27
|
+
name
|
28
|
+
pattern
|
29
|
+
path
|
30
|
+
perm
|
31
|
+
prune
|
32
|
+
size
|
33
|
+
user
|
34
|
+
/
|
35
|
+
# :startdoc:
|
36
|
+
|
37
|
+
# The starting path(s) for the search. The default is the current directory.
|
38
|
+
# This can be a single path or an array of paths.
|
39
|
+
#
|
40
|
+
attr_accessor :path
|
41
|
+
|
42
|
+
# The list of options passed to the constructor and/or used by the
|
43
|
+
# File::Find#find method.
|
44
|
+
#
|
45
|
+
attr_accessor :options
|
46
|
+
|
47
|
+
# Limits searches by file access time, where the value you supply is the
|
48
|
+
# number of days back from the time that the File::Find#find method was
|
49
|
+
# called.
|
50
|
+
#
|
51
|
+
attr_accessor :atime
|
52
|
+
|
53
|
+
# Limits searches by file change time, where the value you supply is the
|
54
|
+
# number of days back from the time that the File::Find#find method was
|
55
|
+
# called.
|
56
|
+
#
|
57
|
+
attr_accessor :ctime
|
58
|
+
|
59
|
+
# Limits searches to files that belong to a specific group, where the
|
60
|
+
# group can be either a group name or ID.
|
61
|
+
#
|
62
|
+
# Not currently supported on MS Windows.
|
63
|
+
#
|
64
|
+
attr_accessor :group
|
65
|
+
|
66
|
+
# An array of two element arrays for storing FileTest methods and their
|
67
|
+
# boolean value.
|
68
|
+
#
|
69
|
+
attr_accessor :filetest
|
70
|
+
|
71
|
+
# Controls the behavior of how symlinks are followed. If set to true (the
|
72
|
+
# default), then follows the file pointed to. If false, it considers the
|
73
|
+
# symlink itself.
|
74
|
+
#
|
75
|
+
attr_accessor :follow
|
76
|
+
|
77
|
+
# Limits searches to specific types of files. The possible values here are
|
78
|
+
# those returned by the File.ftype method.
|
79
|
+
#
|
80
|
+
attr_accessor :ftype
|
81
|
+
|
82
|
+
# Limits search to a file with a specific inode number. Ignored on MS
|
83
|
+
# Windows.
|
84
|
+
#
|
85
|
+
attr_accessor :inum
|
86
|
+
|
87
|
+
# Limits search to a maximum depth into the tree relative to the starting
|
88
|
+
# search directory.
|
89
|
+
#
|
90
|
+
attr_accessor :maxdepth
|
91
|
+
|
92
|
+
# Limits search to a minimum depth into the tree relative to the starting
|
93
|
+
# search directory.
|
94
|
+
#
|
95
|
+
attr_accessor :mindepth
|
96
|
+
|
97
|
+
# Limits searches by file modification time, where the value you supply is
|
98
|
+
# the number of days back from the time that the File::Find#find method was
|
99
|
+
# called.
|
100
|
+
#
|
101
|
+
attr_accessor :mtime
|
102
|
+
|
103
|
+
# The name pattern used to limit file searches. The patterns that are legal
|
104
|
+
# for Dir.glob are legal here. The default is '*', i.e. everything.
|
105
|
+
#
|
106
|
+
attr_accessor :name
|
107
|
+
|
108
|
+
# Limits searches to files which have permissions that match the octal
|
109
|
+
# value that you provide. For purposes of this comparison, only the user,
|
110
|
+
# group, and world settings are used. Do not use a leading 0 in the values
|
111
|
+
# that you supply, e.g. use 755 not 0755.
|
112
|
+
#
|
113
|
+
# You may optionally use symbolic permissions, e.g. "g+rw", "u=rwx", etc.
|
114
|
+
#
|
115
|
+
# Not currently supported on MS Windows.
|
116
|
+
#
|
117
|
+
attr_accessor :perm
|
118
|
+
|
119
|
+
# Skips files or directories that match the string provided as an argument.
|
120
|
+
#
|
121
|
+
attr_accessor :prune
|
122
|
+
|
123
|
+
# If the value passed is an integer, this option limits searches to files
|
124
|
+
# that match the size, in bytes, exactly. If a string is passed, you can
|
125
|
+
# use the standard comparable operators to match files, e.g. ">= 200" would
|
126
|
+
# limit searches to files greater than or equal to 200 bytes.
|
127
|
+
#
|
128
|
+
attr_accessor :size
|
129
|
+
|
130
|
+
# Limits searches to files that belong to a specific user, where the user
|
131
|
+
# can be either a user name or an ID.
|
132
|
+
#
|
133
|
+
# Not currently supported on MS Windows.
|
134
|
+
#
|
135
|
+
attr_accessor :user
|
136
|
+
|
137
|
+
# The file that matched previously in the current search.
|
138
|
+
#
|
139
|
+
attr_reader :previous
|
140
|
+
|
141
|
+
alias pattern name
|
142
|
+
alias pattern= name=
|
143
|
+
|
144
|
+
# Creates and returns a new File::Find object. The options set for this
|
145
|
+
# object serve as the rules for determining what files the File::Find#find
|
146
|
+
# method will search for.
|
147
|
+
#
|
148
|
+
# In addition to the standard list of valid options, you may also use
|
149
|
+
# FileTest methods as options, setting their value to true or false.
|
150
|
+
#
|
151
|
+
# Example:
|
152
|
+
#
|
153
|
+
# rule = File::Find.new(
|
154
|
+
# :name => "*.rb",
|
155
|
+
# :follow => false,
|
156
|
+
# :path => ['/usr/local/lib', '/opt/local/lib'],
|
157
|
+
# :readable? => true
|
158
|
+
# )
|
159
|
+
#
|
160
|
+
def initialize(options = {})
|
161
|
+
@options = options
|
162
|
+
|
163
|
+
@atime = nil
|
164
|
+
@ctime = nil
|
165
|
+
@ftype = nil
|
166
|
+
@group = nil
|
167
|
+
@follow = true
|
168
|
+
@inum = nil
|
169
|
+
@mtime = nil
|
170
|
+
@perm = nil
|
171
|
+
@prune = nil
|
172
|
+
@size = nil
|
173
|
+
@user = nil
|
174
|
+
|
175
|
+
@previous = nil
|
176
|
+
@maxdepth = nil
|
177
|
+
@mindepth = nil
|
178
|
+
@filetest = []
|
179
|
+
|
180
|
+
validate_and_set_options(options) unless options.empty?
|
181
|
+
|
182
|
+
@path ||= Dir.pwd
|
183
|
+
@name ||= '*'
|
184
|
+
end
|
185
|
+
|
186
|
+
# Executes the find based on the rules you set for the File::Find object.
|
187
|
+
# In block form, yields each file in turn that matches the specified rules.
|
188
|
+
# In non-block form it will return an array of matches instead.
|
189
|
+
#
|
190
|
+
# Example:
|
191
|
+
#
|
192
|
+
# rule = File::Find.new(
|
193
|
+
# :name => "*.rb",
|
194
|
+
# :follow => false,
|
195
|
+
# :path => ['/usr/local/lib', '/opt/local/lib']
|
196
|
+
# )
|
197
|
+
#
|
198
|
+
# rule.find{ |f|
|
199
|
+
# puts f
|
200
|
+
# }
|
201
|
+
#
|
202
|
+
def find
|
203
|
+
results = [] unless block_given?
|
204
|
+
paths = @path.to_a
|
205
|
+
|
206
|
+
if @prune
|
207
|
+
prune_regex = Regexp.new(@prune)
|
208
|
+
else
|
209
|
+
prune_regex = nil
|
210
|
+
end
|
211
|
+
|
212
|
+
paths.each{ |path|
|
213
|
+
begin
|
214
|
+
Dir.foreach(path){ |file|
|
215
|
+
next if file == '.'
|
216
|
+
next if file == '..'
|
217
|
+
|
218
|
+
if prune_regex
|
219
|
+
next if prune_regex.match(file)
|
220
|
+
end
|
221
|
+
|
222
|
+
orig = file.dup
|
223
|
+
file = File.join(path, file)
|
224
|
+
|
225
|
+
stat_method = @follow ? :lstat : :stat
|
226
|
+
|
227
|
+
# Skip files we cannot access, stale links, etc.
|
228
|
+
begin
|
229
|
+
stat_info = File.send(stat_method, file)
|
230
|
+
rescue Errno::ENOENT, Errno::EACCES
|
231
|
+
next
|
232
|
+
rescue Errno::ELOOP
|
233
|
+
stat_method = :lstat # Handle recursive symlinks
|
234
|
+
retry if stat_method.to_s != 'lstat'
|
235
|
+
end
|
236
|
+
|
237
|
+
glob = File.join(File.dirname(file), @name)
|
238
|
+
|
239
|
+
# Dir[] doesn't like backslashes
|
240
|
+
if File::ALT_SEPARATOR
|
241
|
+
file.tr!(File::ALT_SEPARATOR, File::SEPARATOR)
|
242
|
+
glob.tr!(File::ALT_SEPARATOR, File::SEPARATOR)
|
243
|
+
end
|
244
|
+
|
245
|
+
if @maxdepth || @mindepth
|
246
|
+
file_depth = file.split(File::SEPARATOR).length
|
247
|
+
path_depth = @path.split(File::SEPARATOR).length
|
248
|
+
depth = file_depth - path_depth
|
249
|
+
|
250
|
+
if @maxdepth && (depth > @maxdepth)
|
251
|
+
if File.directory?(file)
|
252
|
+
unless paths.include?(file) && depth > @maxdepth
|
253
|
+
paths << file
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
next
|
258
|
+
end
|
259
|
+
|
260
|
+
if @mindepth && (depth < @mindepth)
|
261
|
+
if File.directory?(file)
|
262
|
+
unless paths.include?(file) && depth < @mindepth
|
263
|
+
paths << file
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
next
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# Add directories back onto the list of paths to search unless
|
272
|
+
# they've already been added
|
273
|
+
#
|
274
|
+
if stat_info.directory?
|
275
|
+
paths << file unless paths.include?(file)
|
276
|
+
end
|
277
|
+
|
278
|
+
next unless Dir[glob].include?(file)
|
279
|
+
|
280
|
+
unless @filetest.empty?
|
281
|
+
file_test = true
|
282
|
+
|
283
|
+
@filetest.each{ |array|
|
284
|
+
meth = array[0]
|
285
|
+
bool = array[1]
|
286
|
+
|
287
|
+
unless File.send(meth, file) == bool
|
288
|
+
file_test = false
|
289
|
+
break
|
290
|
+
end
|
291
|
+
}
|
292
|
+
|
293
|
+
next unless file_test
|
294
|
+
end
|
295
|
+
|
296
|
+
if @atime || @ctime || @mtime
|
297
|
+
date1 = Date.parse(Time.now.to_s)
|
298
|
+
|
299
|
+
if @atime
|
300
|
+
date2 = Date.parse(stat_info.atime.to_s)
|
301
|
+
next unless (date1 - date2).numerator == @atime
|
302
|
+
end
|
303
|
+
|
304
|
+
if @ctime
|
305
|
+
date2 = Date.parse(stat_info.ctime.to_s)
|
306
|
+
next unless (date1 - date2).numerator == @ctime
|
307
|
+
end
|
308
|
+
|
309
|
+
if @mtime
|
310
|
+
date2 = Date.parse(stat_info.mtime.to_s)
|
311
|
+
next unless (date1 - date2).numerator == @mtime
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
if @ftype
|
316
|
+
next unless File.ftype(file) == @ftype
|
317
|
+
end
|
318
|
+
|
319
|
+
if @group
|
320
|
+
if @group.is_a?(String)
|
321
|
+
next unless get_group(stat_info.gid).name == @group
|
322
|
+
else
|
323
|
+
next unless stat_info.gid == @group
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
unless Config::CONFIG['host_os'] =~ /windows|mswin/i
|
328
|
+
if @inum
|
329
|
+
next unless stat_info.ino == @inum
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# This currently doesn't work on MS Windows, even in limited
|
334
|
+
# fashion for 0666 and 0664, because File.stat.mode doesn't
|
335
|
+
# return the proper value.
|
336
|
+
#
|
337
|
+
if @perm
|
338
|
+
if @perm.is_a?(String)
|
339
|
+
octal_perm = sym2oct(@perm)
|
340
|
+
next unless stat_info.mode & octal_perm == octal_perm
|
341
|
+
else
|
342
|
+
next unless sprintf("%o", stat_info.mode & 07777) == @perm.to_s
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# Allow plain numbers, or strings for comparison operators.
|
347
|
+
if @size
|
348
|
+
if @size.is_a?(String)
|
349
|
+
regex = /^([><=]+)\s*?(\d+)$/
|
350
|
+
match = regex.match(@size)
|
351
|
+
|
352
|
+
if match.nil? || match.captures.include?(nil)
|
353
|
+
raise ArgumentError, "invalid size string: '#{@size}'"
|
354
|
+
end
|
355
|
+
|
356
|
+
operator = match.captures.first.strip
|
357
|
+
number = match.captures.last.strip.to_i
|
358
|
+
|
359
|
+
next unless stat_info.size.send(operator, number)
|
360
|
+
else
|
361
|
+
next unless stat_info.size == @size
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
if @user
|
366
|
+
if @user.is_a?(String)
|
367
|
+
next unless get_user(stat_info.uid).name == @user
|
368
|
+
else
|
369
|
+
next unless stat_info.uid == @user
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
if block_given?
|
374
|
+
yield file
|
375
|
+
else
|
376
|
+
results << file
|
377
|
+
end
|
378
|
+
|
379
|
+
@previous = file unless @previous == file
|
380
|
+
}
|
381
|
+
rescue Errno::EACCES
|
382
|
+
next # Skip inaccessible directories
|
383
|
+
end
|
384
|
+
}
|
385
|
+
|
386
|
+
block_given? ? nil : results
|
387
|
+
end
|
388
|
+
|
389
|
+
private
|
390
|
+
|
391
|
+
# This validates that the keys are valid. If they are, it sets the value
|
392
|
+
# of that key's corresponding method to the given value. If a key ends
|
393
|
+
# with a '?', it's validated as a File method.
|
394
|
+
#
|
395
|
+
def validate_and_set_options(options)
|
396
|
+
options.each do |key, value|
|
397
|
+
key = key.to_s.downcase
|
398
|
+
|
399
|
+
if key[-1].chr == '?'
|
400
|
+
sym = key.to_sym
|
401
|
+
|
402
|
+
unless File.respond_to?(sym)
|
403
|
+
raise ArgumentError, "invalid option '#{key}'"
|
404
|
+
end
|
405
|
+
|
406
|
+
@filetest << [sym, value]
|
407
|
+
else
|
408
|
+
unless VALID_OPTIONS.include?(key)
|
409
|
+
raise ArgumentError, "invalid option '#{key}'"
|
410
|
+
end
|
411
|
+
|
412
|
+
send("#{key}=", value)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Converts a symoblic permissions mode into its octal equivalent.
|
418
|
+
#--
|
419
|
+
# Taken almost entirely from ruby-talk: 96956 (Hal Fulton).
|
420
|
+
#
|
421
|
+
def sym2oct(str)
|
422
|
+
left = {'u' => 0700, 'g' => 0070, 'o' => 0007, 'a' => 0777}
|
423
|
+
right = {'r' => 0444, 'w' => 0222, 'x' => 0111}
|
424
|
+
regex = /([ugoa]+)([+-=])([rwx]+)/
|
425
|
+
|
426
|
+
cmds = str.split(',')
|
427
|
+
|
428
|
+
perm = 0
|
429
|
+
|
430
|
+
cmds.each do |cmd|
|
431
|
+
match = cmd.match(regex)
|
432
|
+
raise "Invalid symbolic permissions: '#{str}'" if match.nil?
|
433
|
+
|
434
|
+
junk, who, what, how = match.to_a
|
435
|
+
|
436
|
+
who = who.split(//).inject(num=0) { |num,b| num |= left[b]; num }
|
437
|
+
how = how.split(//).inject(num=0) { |num,b| num |= right[b]; num }
|
438
|
+
mask = who & how
|
439
|
+
|
440
|
+
case what
|
441
|
+
when '+'
|
442
|
+
perm = perm | mask
|
443
|
+
when '-'
|
444
|
+
perm = perm & ~mask
|
445
|
+
when '='
|
446
|
+
perm = mask
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
perm
|
451
|
+
end
|
452
|
+
|
453
|
+
# Returns the group object based on the group id. Implemented for the
|
454
|
+
# sake of platforms that cannot build extensions, such as JRuby.
|
455
|
+
#
|
456
|
+
def get_group(gid)
|
457
|
+
if defined? Sys::Admin
|
458
|
+
Sys::Admin.get_group(gid)
|
459
|
+
else
|
460
|
+
Etc.getgrgid(gid)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
# Returns the user object based on the group id. Implemented for the
|
465
|
+
# sake of platforms that cannot build extensions, such as JRuby.
|
466
|
+
#
|
467
|
+
def get_user(uid)
|
468
|
+
if defined? Sys::Admin
|
469
|
+
Sys::Admin.get_user(uid)
|
470
|
+
else
|
471
|
+
Etc.getpwuid(uid)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
@@ -0,0 +1,431 @@
|
|
1
|
+
######################################################################
|
2
|
+
# test_file_find.rb
|
3
|
+
#
|
4
|
+
# Test case for the File::Find package. You should run this via the
|
5
|
+
# 'rake test' task.
|
6
|
+
######################################################################
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'test-unit'
|
9
|
+
|
10
|
+
require 'test/unit'
|
11
|
+
require 'fileutils'
|
12
|
+
require 'file/find'
|
13
|
+
require 'rbconfig'
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'sys/admin'
|
17
|
+
rescue LoadError
|
18
|
+
require 'etc'
|
19
|
+
end
|
20
|
+
|
21
|
+
include Config
|
22
|
+
include FileUtils
|
23
|
+
|
24
|
+
class TC_File_Find < Test::Unit::TestCase
|
25
|
+
def self.startup
|
26
|
+
Dir.chdir('test') unless File.basename(Dir.pwd) == 'test'
|
27
|
+
|
28
|
+
@@windows = CONFIG['host_os'] =~ /windows|mswin/i
|
29
|
+
@@jruby = RUBY_PLATFORM.match('java')
|
30
|
+
|
31
|
+
unless @@windows
|
32
|
+
if @@jruby
|
33
|
+
@@loguser = Etc.getpwnam(Etc.getlogin)
|
34
|
+
@@logroup = Etc.getgrgid(@@loguser.gid)
|
35
|
+
else
|
36
|
+
@@loguser = Sys::Admin.get_user(Sys::Admin.get_login)
|
37
|
+
@@logroup = Sys::Admin.get_group(@@loguser.gid)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup
|
43
|
+
@file1 = 'test1.rb'
|
44
|
+
@file2 = 'test1.txt'
|
45
|
+
@file3 = 'foo.txt'
|
46
|
+
@file4 = 'foo.doc'
|
47
|
+
@dir1 = 'dir1'
|
48
|
+
@dir2 = 'dir2'
|
49
|
+
|
50
|
+
File.open(@file1, 'w'){}
|
51
|
+
File.open(@file2, 'w'){}
|
52
|
+
File.open(@file3, 'w'){}
|
53
|
+
File.open(@file4, 'w'){}
|
54
|
+
|
55
|
+
unless @@windows
|
56
|
+
@link1 = 'link1'
|
57
|
+
File.symlink(@file1, @link1)
|
58
|
+
end
|
59
|
+
|
60
|
+
Dir.mkdir(@dir1) unless File.exists?(@dir1)
|
61
|
+
Dir.mkdir(@dir2) unless File.exists?(@dir2)
|
62
|
+
|
63
|
+
File.open(File.join(@dir1, 'bar.txt'), 'w'){}
|
64
|
+
File.open(File.join(@dir2, 'baz.txt'), 'w'){}
|
65
|
+
|
66
|
+
@rule1 = File::Find.new(:name => '*.txt')
|
67
|
+
@rule2 = File::Find.new
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_version
|
71
|
+
assert_equal('0.3.1', File::Find::VERSION)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_path
|
75
|
+
assert_respond_to(@rule1, :path)
|
76
|
+
assert_respond_to(@rule1, :path=)
|
77
|
+
assert_equal(Dir.pwd, @rule1.path)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_options
|
81
|
+
assert_respond_to(@rule1, :options)
|
82
|
+
assert_respond_to(@rule1, :options=)
|
83
|
+
assert_equal({:name => '*.txt'}, @rule1.options)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_atime_basic
|
87
|
+
assert_respond_to(@rule1, :atime)
|
88
|
+
assert_respond_to(@rule1, :atime=)
|
89
|
+
assert_nil(@rule1.atime)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_atime
|
93
|
+
rule1 = File::Find.new(:name => "*.rb", :atime => 0)
|
94
|
+
rule2 = File::Find.new(:name => "*.rb", :atime => 1)
|
95
|
+
|
96
|
+
assert_false(rule1.find.empty?)
|
97
|
+
assert_true(rule2.find.empty?)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_ctime_basic
|
101
|
+
assert_respond_to(@rule1, :ctime)
|
102
|
+
assert_respond_to(@rule1, :ctime=)
|
103
|
+
assert_nil(@rule1.ctime)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_ctime
|
107
|
+
rule1 = File::Find.new(:name => "*.rb", :ctime => 0)
|
108
|
+
rule2 = File::Find.new(:name => "*.rb", :ctime => 1)
|
109
|
+
|
110
|
+
assert_false(rule1.find.empty?)
|
111
|
+
assert_true(rule2.find.empty?)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_find_basic
|
115
|
+
assert_respond_to(@rule1, :find)
|
116
|
+
assert_nothing_raised{ @rule1.find }
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_find
|
120
|
+
assert_kind_of(Array, @rule1.find)
|
121
|
+
assert_nil(@rule1.find{})
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_filetest_basic
|
125
|
+
assert_respond_to(@rule1, :filetest)
|
126
|
+
assert_respond_to(@rule1, :filetest=)
|
127
|
+
assert_nothing_raised{ @rule1.filetest }
|
128
|
+
assert_kind_of(Array, @rule1.filetest)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_filetest_valid_options
|
132
|
+
assert_nothing_raised{ File::Find.new(:readable? => true) }
|
133
|
+
assert_nothing_raised{ File::Find.new(:writable? => true) }
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_filetest
|
137
|
+
omit_if(@@windows && @@jruby, "Skipping file test on JRuby/Windows")
|
138
|
+
|
139
|
+
rule = File::Find.new(:name => "*.doc", :writable? => true)
|
140
|
+
File.chmod(0644, @file4)
|
141
|
+
|
142
|
+
assert_equal([@file4], rule.find.map{ |f| File.basename(f) })
|
143
|
+
|
144
|
+
File.chmod(0444, @file4)
|
145
|
+
|
146
|
+
assert_equal([], rule.find)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_mtime
|
150
|
+
rule1 = File::Find.new(:name => "*.rb", :mtime => 0)
|
151
|
+
rule2 = File::Find.new(:name => "*.rb", :mtime => 1)
|
152
|
+
|
153
|
+
assert_false(rule1.find.empty?)
|
154
|
+
assert_true(rule2.find.empty?)
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_mtime_basic
|
158
|
+
assert_respond_to(@rule1, :mtime)
|
159
|
+
assert_respond_to(@rule1, :mtime=)
|
160
|
+
assert_nil(@rule1.mtime)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_ftype_basic
|
164
|
+
assert_respond_to(@rule1, :ftype)
|
165
|
+
assert_respond_to(@rule1, :ftype=)
|
166
|
+
assert_nil(@rule1.ftype)
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_ftype
|
170
|
+
rule1 = File::Find.new(:name => "*.rb", :ftype => "file")
|
171
|
+
rule2 = File::Find.new(:name => "*.rb", :ftype => "characterSpecial")
|
172
|
+
|
173
|
+
assert_false(rule1.find.empty?)
|
174
|
+
assert_true(rule2.find.empty?)
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_group_basic
|
178
|
+
assert_respond_to(@rule1, :group)
|
179
|
+
assert_respond_to(@rule1, :group=)
|
180
|
+
assert_nil(@rule1.group)
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_group_with_numeric_id
|
184
|
+
omit_if(@@windows, 'group test skipped on MS Windows')
|
185
|
+
@rule1 = File::Find.new(:name => '*.doc', :group => @@loguser.gid)
|
186
|
+
assert_equal([File.expand_path(@file4)], @rule1.find)
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_group_with_string
|
190
|
+
omit_if(@@windows, 'group test skipped on MS Windows')
|
191
|
+
@rule1 = File::Find.new(:name => '*.doc', :group => @@logroup.name)
|
192
|
+
assert_equal([File.expand_path(@file4)], @rule1.find)
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_group_with_bad_id
|
196
|
+
omit_if(@@windows, 'group test skipped on MS Windows')
|
197
|
+
@rule1 = File::Find.new(:name => '*.doc', :group => 'totallybogus')
|
198
|
+
@rule2 = File::Find.new(:name => '*.doc', :group => 99999999)
|
199
|
+
assert_equal([], @rule1.find)
|
200
|
+
assert_equal([], @rule2.find)
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_inum_basic
|
204
|
+
assert_respond_to(@rule1, :inum)
|
205
|
+
assert_respond_to(@rule1, :inum=)
|
206
|
+
assert_nil(@rule1.inum)
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_follow_basic
|
210
|
+
assert_respond_to(@rule1, :follow)
|
211
|
+
assert_respond_to(@rule1, :follow=)
|
212
|
+
assert_true(@rule1.follow)
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_maxdepth_basic
|
216
|
+
assert_respond_to(@rule1, :maxdepth)
|
217
|
+
assert_respond_to(@rule1, :maxdepth=)
|
218
|
+
assert_nil(@rule1.maxdepth)
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_maxdepth_file
|
222
|
+
mkpath('a1/a2/a3')
|
223
|
+
touch('a1/a.foo')
|
224
|
+
touch('a1/a2/b.foo')
|
225
|
+
touch('a1/a2/c.foo')
|
226
|
+
touch('a1/a2/a3/d.foo')
|
227
|
+
touch('a1/a2/a3/e.foo')
|
228
|
+
touch('a1/a2/a3/f.foo')
|
229
|
+
|
230
|
+
@rule2.pattern = "*.foo"
|
231
|
+
@rule2.maxdepth = 1
|
232
|
+
assert_equal([], @rule2.find)
|
233
|
+
|
234
|
+
@rule2.maxdepth = 2
|
235
|
+
assert_equal(['a.foo'], @rule2.find.map{ |e| File.basename(e) })
|
236
|
+
|
237
|
+
@rule2.maxdepth = 3
|
238
|
+
assert_equal(['a.foo', 'b.foo', 'c.foo'], @rule2.find.map{ |e| File.basename(e) })
|
239
|
+
|
240
|
+
@rule2.maxdepth = nil
|
241
|
+
assert_equal(['a.foo', 'b.foo', 'c.foo', 'd.foo', 'e.foo', 'f.foo'], @rule2.find.map{ |e| File.basename(e) })
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_maxdepth_directory
|
245
|
+
mkpath('a/b/c')
|
246
|
+
@rule2.pattern = "c"
|
247
|
+
|
248
|
+
@rule2.maxdepth = 1
|
249
|
+
assert_equal([], @rule2.find)
|
250
|
+
|
251
|
+
@rule2.maxdepth = 2
|
252
|
+
assert_equal([], @rule2.find)
|
253
|
+
|
254
|
+
@rule2.maxdepth = 3
|
255
|
+
assert_equal(['c'], @rule2.find.map{ |e| File.basename(e) })
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_mindepth_basic
|
259
|
+
assert_respond_to(@rule1, :mindepth)
|
260
|
+
assert_respond_to(@rule1, :mindepth=)
|
261
|
+
assert_nil(@rule1.mindepth)
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_mindepth_file
|
265
|
+
mkpath('a1/a2/a3')
|
266
|
+
touch('z.min')
|
267
|
+
touch('a1/a.min')
|
268
|
+
touch('a1/a2/b.min')
|
269
|
+
touch('a1/a2/c.min')
|
270
|
+
touch('a1/a2/a3/d.min')
|
271
|
+
touch('a1/a2/a3/e.min')
|
272
|
+
touch('a1/a2/a3/f.min')
|
273
|
+
|
274
|
+
@rule2.pattern = "*.min"
|
275
|
+
|
276
|
+
@rule2.mindepth = 0
|
277
|
+
assert_equal(['z.min', 'a.min', 'b.min', 'c.min', 'd.min', 'e.min', 'f.min'], @rule2.find.map{ |e| File.basename(e) })
|
278
|
+
|
279
|
+
@rule2.mindepth = 1
|
280
|
+
assert_equal(['z.min', 'a.min', 'b.min', 'c.min', 'd.min', 'e.min', 'f.min'], @rule2.find.map{ |e| File.basename(e) })
|
281
|
+
|
282
|
+
@rule2.mindepth = 2
|
283
|
+
assert_equal(['a.min', 'b.min', 'c.min', 'd.min', 'e.min', 'f.min'], @rule2.find.map{ |e| File.basename(e) })
|
284
|
+
|
285
|
+
@rule2.mindepth = 3
|
286
|
+
assert_equal(['b.min', 'c.min', 'd.min', 'e.min', 'f.min'], @rule2.find.map{ |e| File.basename(e) })
|
287
|
+
|
288
|
+
@rule2.mindepth = 4
|
289
|
+
assert_equal(['d.min', 'e.min', 'f.min'], @rule2.find.map{ |e| File.basename(e) })
|
290
|
+
|
291
|
+
@rule2.mindepth = 5
|
292
|
+
assert_equal([], @rule2.find.map{ |e| File.basename(e) })
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_mindepth_directory
|
296
|
+
mkpath('a/b/c')
|
297
|
+
@rule2.pattern = "a"
|
298
|
+
|
299
|
+
@rule2.mindepth = 1
|
300
|
+
assert_equal(['a'], @rule2.find.map{ |e| File.basename(e) })
|
301
|
+
|
302
|
+
@rule2.mindepth = 2
|
303
|
+
assert_equal([], @rule2.find)
|
304
|
+
|
305
|
+
@rule2.mindepth = 3
|
306
|
+
assert_equal([], @rule2.find)
|
307
|
+
end
|
308
|
+
|
309
|
+
def test_name_basic
|
310
|
+
assert_respond_to(@rule1, :name)
|
311
|
+
assert_respond_to(@rule1, :name=)
|
312
|
+
assert_equal('*.txt', @rule1.name)
|
313
|
+
end
|
314
|
+
|
315
|
+
def test_pattern_alias
|
316
|
+
assert_respond_to(@rule1, :pattern)
|
317
|
+
assert_respond_to(@rule1, :pattern=)
|
318
|
+
assert_true(@rule1.method(:name) == @rule1.method(:pattern))
|
319
|
+
assert_true(@rule1.method(:name=) == @rule1.method(:pattern=))
|
320
|
+
end
|
321
|
+
|
322
|
+
def test_perm_basic
|
323
|
+
assert_respond_to(@rule1, :perm)
|
324
|
+
assert_respond_to(@rule1, :perm=)
|
325
|
+
assert_nil(@rule1.perm)
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_perm
|
329
|
+
omit_if(@@windows, 'perm test skipped on MS Windows')
|
330
|
+
File.chmod(0664, @file1)
|
331
|
+
File.chmod(0644, @file2)
|
332
|
+
results = File::Find.new(:name => "test1*", :perm => 664).find
|
333
|
+
|
334
|
+
assert_equal(1, results.length)
|
335
|
+
assert_equal('test1.rb', File.basename(results.first))
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_perm_with_symbolic_permissions
|
339
|
+
omit_if(@@windows, 'symbolic perm test skipped on MS Windows')
|
340
|
+
|
341
|
+
File.chmod(0664, @file1) # test1.rb
|
342
|
+
File.chmod(0644, @file2) # test1.txt
|
343
|
+
results1 = File::Find.new(:name => "test1*", :perm => "g=rw").find
|
344
|
+
results2 = File::Find.new(:name => "test1*", :perm => "u=rw").find
|
345
|
+
|
346
|
+
assert_equal(1, results1.length)
|
347
|
+
assert_equal(2, results2.length)
|
348
|
+
assert_equal('test1.rb', File.basename(results1.first))
|
349
|
+
assert_equal(['test1.rb', 'test1.txt'], results2.map{ |e| File.basename(e) })
|
350
|
+
end
|
351
|
+
|
352
|
+
def test_prune_basic
|
353
|
+
assert_respond_to(@rule1, :prune)
|
354
|
+
assert_respond_to(@rule1, :prune=)
|
355
|
+
assert_nil(@rule1.prune)
|
356
|
+
end
|
357
|
+
|
358
|
+
def test_prune
|
359
|
+
rule = File::Find.new(:name => "*.txt", :prune => 'foo')
|
360
|
+
assert_equal('test1.txt', File.basename(rule.find.first))
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_size_basic
|
364
|
+
assert_respond_to(@rule1, :size)
|
365
|
+
assert_respond_to(@rule1, :size=)
|
366
|
+
assert_nil(@rule1.size)
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_user_basic
|
370
|
+
assert_respond_to(@rule1, :user)
|
371
|
+
assert_respond_to(@rule1, :user=)
|
372
|
+
assert_nil(@rule1.user)
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_user_with_numeric_id
|
376
|
+
omit_if(@@windows, 'user test skipped on MS Windows')
|
377
|
+
@rule1 = File::Find.new(:name => '*.doc', :user => @@loguser.uid)
|
378
|
+
assert_equal([File.expand_path(@file4)], @rule1.find)
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_user_with_string
|
382
|
+
omit_if(@@windows, 'user test skipped on MS Windows')
|
383
|
+
@rule1 = File::Find.new(:name => '*.doc', :user => @@loguser.name)
|
384
|
+
assert_equal([File.expand_path(@file4)], @rule1.find)
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_user_with_bad_id
|
388
|
+
omit_if(@@windows, 'user test skipped on MS Windows')
|
389
|
+
@rule1 = File::Find.new(:name => '*.doc', :user => 'totallybogus')
|
390
|
+
@rule2 = File::Find.new(:name => '*.doc', :user => 99999999)
|
391
|
+
assert_equal([], @rule1.find)
|
392
|
+
assert_equal([], @rule2.find)
|
393
|
+
end
|
394
|
+
|
395
|
+
def test_previous_basic
|
396
|
+
assert_respond_to(@rule1, :previous)
|
397
|
+
end
|
398
|
+
|
399
|
+
def test_expected_errors
|
400
|
+
assert_raise(Errno::ENOENT){ File::Find.new(:path => '/bogus/dir').find }
|
401
|
+
assert_raise(ArgumentError){ File::Find.new(:bogus => 1) }
|
402
|
+
assert_raise(ArgumentError){ File::Find.new(:bogus? => true) }
|
403
|
+
end
|
404
|
+
|
405
|
+
def teardown
|
406
|
+
rm_rf(@file1)
|
407
|
+
rm_rf(@file2)
|
408
|
+
rm_rf(@file3)
|
409
|
+
rm_rf(@file4)
|
410
|
+
rm_rf(@dir1)
|
411
|
+
rm_rf(@dir2)
|
412
|
+
rm_rf(@link1) unless @@windows
|
413
|
+
rm_rf('a')
|
414
|
+
rm_rf('a1')
|
415
|
+
rm_rf('z.min') if File.exists?('z.min')
|
416
|
+
|
417
|
+
@rule1 = nil
|
418
|
+
@rule2 = nil
|
419
|
+
@file1 = nil
|
420
|
+
@file2 = nil
|
421
|
+
@file3 = nil
|
422
|
+
@file4 = nil
|
423
|
+
end
|
424
|
+
|
425
|
+
def self.shutdown
|
426
|
+
@@windows = nil
|
427
|
+
@@jruby = nil
|
428
|
+
@@loguser = nil unless @@windows
|
429
|
+
@@logroup = nil unless @@windows
|
430
|
+
end
|
431
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
extensions: []
|
3
|
+
|
4
|
+
homepage: http://www.rubyforge.org/projects/shards
|
5
|
+
executables: []
|
6
|
+
|
7
|
+
version: !ruby/object:Gem::Version
|
8
|
+
version: 0.3.1
|
9
|
+
post_install_message:
|
10
|
+
date: 2009-01-09 07:00:00 +00:00
|
11
|
+
files:
|
12
|
+
- lib/file
|
13
|
+
- lib/file/find.rb
|
14
|
+
- test/test_file_find.rb
|
15
|
+
- README
|
16
|
+
- CHANGES
|
17
|
+
- MANIFEST
|
18
|
+
rubygems_version: 1.3.1
|
19
|
+
rdoc_options: []
|
20
|
+
|
21
|
+
signing_key:
|
22
|
+
cert_chain: []
|
23
|
+
|
24
|
+
name: file-find
|
25
|
+
has_rdoc: true
|
26
|
+
platform: universal-java-1.5
|
27
|
+
summary: A better way to find files
|
28
|
+
default_executable:
|
29
|
+
bindir: bin
|
30
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
31
|
+
version:
|
32
|
+
requirements:
|
33
|
+
- - '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
version:
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
specification_version: 2
|
45
|
+
test_files:
|
46
|
+
- test/test_file_find.rb
|
47
|
+
dependencies:
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
type: :runtime
|
50
|
+
name: test-unit
|
51
|
+
version_requirement:
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
version:
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 2.0.2
|
58
|
+
description: A better way to find files
|
59
|
+
email: djberg96@gmail.com
|
60
|
+
authors:
|
61
|
+
- Daniel Berger
|
62
|
+
extra_rdoc_files:
|
63
|
+
- README
|
64
|
+
- CHANGES
|
65
|
+
- MANIFEST
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project: shards
|
69
|
+
autorequire:
|