file-find 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/CHANGES +4 -0
  2. data/README +75 -73
  3. data/Rakefile +23 -35
  4. data/file-find.gemspec +20 -21
  5. data/lib/file/find.rb +481 -481
  6. data/test/test_file_find.rb +60 -45
  7. metadata +39 -17
data/CHANGES CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.3.5 - 15-Jul-2011
2
+ * Fixed a bug with the :follow option.
3
+ * Gemspec, Rakefile and test cleanup.
4
+
1
5
  == 0.3.4 - 19-Sep-2009
2
6
  * Fixed a packaging bug. Thanks go to Gabriel Horner for the spot.
3
7
  * Added the 'gem' task to the Rakefile for building the gem. Removed the
data/README CHANGED
@@ -1,108 +1,110 @@
1
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.
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
4
 
5
5
  = Synopsis
6
- rule = File::Find.new(
7
- :pattern => "*.rb",
8
- :follow => false,
9
- :path => ['/usr/local/lib', '/opt/local/lib']
10
- )
6
+ require 'file/find'
11
7
 
12
- rule.find{ |f|
13
- puts f
14
- }
8
+ rule = File::Find.new(
9
+ :pattern => "*.rb",
10
+ :follow => false,
11
+ :path => ['/usr/local/lib', '/opt/local/lib']
12
+ )
13
+
14
+ rule.find{ |f|
15
+ puts f
16
+ }
15
17
 
16
18
  = Installation
17
- * rake test (optional)
18
- * rake install (non-gem) -OR- rake install_gem (gem)
19
+
20
+ gem install file-find
19
21
 
20
22
  = 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
23
 
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.
24
+ The current find module in the standard library is inadequate. It is, quite
25
+ frankly, not much more than a plain Dir.glob call. This library provides an
26
+ interface based on options typically available on your command line 'find'
27
+ command, thus allowing you much greater control over how you find your files.
28
28
 
29
29
  = Options
30
- * atime
31
- * ctime
32
- * follow
33
- * ftype
34
- * inum (except Windows)
35
- * group (name or id)
36
- * maxdepth
37
- * mindepth
38
- * mount
39
- * mtime
40
- * name (or 'pattern')
41
- * path
42
- * perm (except Windows)
43
- * prune
44
- * size
45
- * user (name or id)
46
-
47
- In addition to the above options, FileTest methods such as 'readable?' and
48
- 'writable?' may be used as keys, with true or false for their values.
49
-
50
- See the RDoc documentation for more details about these options.
30
+ * atime
31
+ * ctime
32
+ * follow
33
+ * ftype
34
+ * inum (except Windows)
35
+ * group (name or id)
36
+ * maxdepth
37
+ * mindepth
38
+ * mount
39
+ * mtime
40
+ * name (or 'pattern')
41
+ * path
42
+ * perm (except Windows)
43
+ * prune
44
+ * size
45
+ * user (name or id)
46
+
47
+ In addition to the above options, FileTest methods such as 'readable?' and
48
+ 'writable?' may be used as keys, with true or false for their values.
49
+
50
+ See the RDoc documentation for more details about these options.
51
51
 
52
52
  = Future Plans
53
- More options will be added as time permits, and requests will definitely be
54
- considered. Please log any feature requests on the project page at
55
- http://www.rubyforge.org/projects/shards.
53
+ More options will be added as time permits, and requests will definitely be
54
+ considered. Please log any feature requests on the project page at
55
+ http://www.rubyforge.org/projects/shards.
56
56
 
57
- Some specific things I plan on adding:
57
+ Some specific things I plan on adding:
58
58
 
59
- * exec
60
- * links
61
- * support for :user and :group on MS Windows
59
+ * exec
60
+ * links
61
+ * support for :user and :group on MS Windows
62
62
 
63
63
  = Options I won't support
64
- Generally speaking, anything that would require mucking around with C code
65
- or is just too difficult to implement in a cross platform manner will not be
66
- supported. These include the following options:
64
+ Generally speaking, anything that would require mucking around with C code
65
+ or is just too difficult to implement in a cross platform manner will not be
66
+ supported. These include the following options:
67
67
 
68
- * acl/xattr - Way too difficult to implement in a cross platform manner, and
69
- a rarely used option in practice.
68
+ * acl/xattr - Way too difficult to implement in a cross platform manner, and
69
+ a rarely used option in practice.
70
70
 
71
- * cpio/ncpio - I will not shell out to this or any other 3rd party application.
71
+ * cpio/ncpio - I will not shell out to this or any other 3rd party
72
+ application.
72
73
 
73
- * ls/print - Use Ruby's builtin printing methods to print as you see fit.
74
+ * ls/print - Use Ruby's builtin printing methods to print as you see fit.
74
75
 
75
- * ok - This is not interactive software.
76
+ * ok - This is not interactive software.
76
77
 
77
78
  = Known Issues
78
- The 'perm' option does not work on MS Windows, even for its limited subset of
79
- permissions, i.e. 664 and 666. This is arguably a bug in Ruby's
80
- File::Stat.mode method on MS Windows.
79
+ The 'perm' option does not work on MS Windows, even for its limited subset of
80
+ permissions, i.e. 664 and 666. This is arguably a bug in Ruby's
81
+ File::Stat.mode method on MS Windows.
81
82
 
82
- The 'user' and 'group' options are not currently supported on MS Windows.
83
- This can be supported, but will require changes in the win32-file and
84
- win32-file-stat libraries (which would then become dependencies).
83
+ The 'user' and 'group' options are not currently supported on MS Windows.
84
+ This can be supported, but will require changes in the win32-file and
85
+ win32-file-stat libraries (which would then become dependencies).
85
86
 
86
- There are 3 test failures with JRuby, all related to the 'perm' option. I
87
- have not been able to reduce them to a simple test case and discern the
88
- exact cause of the failures, though I suspect a bug in the JRuby
89
- implementation of File.chmod.
87
+ There are 3 test failures with JRuby, all related to the 'perm' option. I
88
+ have not been able to reduce them to a simple test case and discern the
89
+ exact cause of the failures, though I suspect a bug in the JRuby
90
+ implementation of File.chmod.
90
91
 
91
92
  = Bugs
92
- None that I'm aware of. Please log any bug reports on the project page at
93
- http://www.rubyforge.org/projects/shards.
93
+ None that I'm aware of beyond the ones mentioned in the Known Issues. Please
94
+ log any bug reports on the project page at
95
+ http://www.rubyforge.org/projects/shards.
94
96
 
95
97
  = Acknowledgements
96
- * Richard Clamp's File::Find::Rule Perl module for additional ideas and
97
- inspiration.
98
- * Bill Kleb for ideas regarding name, group and perm enhancements.
99
- * Hal Fulton for his implementation of symbolic permissions.
98
+ * Richard Clamp's File::Find::Rule Perl module for additional ideas and
99
+ inspiration.
100
+ * Bill Kleb for ideas regarding name, group and perm enhancements.
101
+ * Hal Fulton for his implementation of symbolic permissions.
100
102
 
101
103
  = License
102
- Artistic 2.0
104
+ Artistic 2.0
103
105
 
104
106
  = Copyright
105
- (C) 2007-2009, Daniel J. Berger, All Rights Reserved
107
+ (C) 2007-2011, Daniel J. Berger, All Rights Reserved
106
108
 
107
109
  = Author
108
- Daniel J. Berger
110
+ Daniel J. Berger
data/Rakefile CHANGED
@@ -1,46 +1,34 @@
1
1
  require 'rake'
2
+ require 'rake/clean'
2
3
  require 'rake/testtask'
3
4
 
4
- desc "Cleanup .test-result files if present"
5
- task :clean do
6
- rm_rf '.test-result' if File.exists?('.test-result')
5
+ CLEAN.include("**/*.gem", "**/*.rbc", "**/link*")
7
6
 
8
- Dir.foreach(Dir.pwd){ |file|
9
- if File.directory?(file)
10
- Dir.chdir(file){
11
- rm_rf '.test-result' if File.exists?('.test-result')
12
- }
13
- end
14
- }
15
- end
16
-
17
- desc "Install the file-find library (non-gem)"
18
- task :install do
19
- dest = File.join(Config::CONFIG['sitelibdir'], 'file')
20
- Dir.mkdir(dest) unless File.exists? dest
21
- cp 'lib/file/find.rb', dest, :verbose => true
22
- end
23
-
24
- desc "Install the file-find library as a gem"
25
- task :install_gem do
26
- ruby 'file-find.gemspec'
27
- file = Dir["*.gem"].first
28
- sh "gem install #{file}"
29
- end
30
-
31
- desc 'Create a gem'
32
- task :gem do
33
- spec = eval(IO.read('file-find.gemspec'))
34
- if RUBY_PLATFORM.match('java')
7
+ namespace :gem do
8
+ desc 'Create the file-find gem'
9
+ task :create => [:clean] do
10
+ spec = eval(IO.read('file-find.gemspec'))
11
+ if RUBY_PLATFORM.match('java')
35
12
  spec.platform = Gem::Platform::CURRENT
36
- else
13
+ else
37
14
  spec.add_dependency('sys-admin', '>= 1.5.2')
38
- end
15
+ end
39
16
 
40
- Gem::Builder.new(spec).build
17
+ Gem::Builder.new(spec).build
18
+ end
19
+
20
+ desc "Install the file-find gem"
21
+ task :install => [:create] do
22
+ ruby 'file-find.gemspec'
23
+ file = Dir["*.gem"].first
24
+ sh "gem install #{file}"
25
+ end
41
26
  end
42
27
 
43
28
  Rake::TestTask.new do |t|
44
- t.warning = true
45
- t.verbose = true
29
+ task :test => 'clean'
30
+ t.warning = true
31
+ t.verbose = true
46
32
  end
33
+
34
+ task :default => :test
@@ -1,27 +1,26 @@
1
1
  require 'rubygems'
2
2
 
3
- Gem::Specification.new do |gem|
4
- gem.name = 'file-find'
5
- gem.version = '0.3.4'
6
- gem.author = 'Daniel Berger'
7
- gem.license = 'Artistic 2.0'
8
- gem.summary = 'A better way to find files'
9
- gem.email = 'djberg96@gmail.com'
10
- gem.homepage = 'http://www.rubyforge.org/projects/shards'
11
- gem.platform = Gem::Platform::RUBY
12
- gem.files = Dir['**/*'].reject{ |f| f.include?('CVS') }
13
- gem.test_file = 'test/test_file_find.rb'
14
- gem.has_rdoc = true
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'file-find'
5
+ spec.version = '0.3.5'
6
+ spec.author = 'Daniel Berger'
7
+ spec.license = 'Artistic 2.0'
8
+ spec.summary = 'A better way to find files'
9
+ spec.email = 'djberg96@gmail.com'
10
+ spec.homepage = 'http://www.rubyforge.org/projects/shards'
11
+ spec.platform = Gem::Platform::RUBY
12
+ spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
13
+ spec.test_file = 'test/test_file_find.rb'
15
14
 
16
- gem.rubyforge_project = 'shards'
17
- gem.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
15
+ spec.rubyforge_project = 'shards'
16
+ spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
18
17
 
19
- gem.add_development_dependency('test-unit', '>= 2.0.3')
18
+ spec.add_development_dependency('test-unit', '>= 2.1.1')
20
19
 
21
- gem.description = <<-EOF
22
- The file-find library provides a better, more object oriented approach
23
- to finding files. It allows you to find files based on a variety of
24
- properties, such as access time, size, owner, etc. You can also limit
25
- directory depth.
26
- EOF
20
+ spec.description = <<-EOF
21
+ The file-find library provides a better, more object oriented approach
22
+ to finding files. It allows you to find files based on a variety of
23
+ properties, such as access time, size, owner, etc. You can also limit
24
+ directory depth.
25
+ EOF
27
26
  end
@@ -4,501 +4,501 @@ require 'rbconfig'
4
4
  # For alternate implementations of Ruby, such as JRuby, that cannot
5
5
  # build C extensions fall back to the Etc module.
6
6
  begin
7
- require 'sys/admin'
7
+ require 'sys/admin'
8
8
  rescue LoadError
9
- require 'etc'
9
+ require 'etc'
10
10
  end
11
11
 
12
12
  class File::Find
13
- # The version of the file-find library
14
- VERSION = '0.3.4'
15
-
16
- # :stopdoc:
17
- VALID_OPTIONS = %w/
18
- atime
19
- ctime
20
- follow
21
- ftype
22
- inum
23
- group
24
- links
25
- maxdepth
26
- mindepth
27
- mount
28
- mtime
29
- name
30
- pattern
31
- path
32
- perm
33
- prune
34
- size
35
- user
36
- /
37
- # :startdoc:
38
-
39
- # The starting path(s) for the search. The default is the current directory.
40
- # This can be a single path or an array of paths.
41
- #
42
- attr_accessor :path
43
-
44
- # The list of options passed to the constructor and/or used by the
45
- # File::Find#find method.
46
- #
47
- attr_accessor :options
48
-
49
- # Limits searches by file access time, where the value you supply is the
50
- # number of days back from the time that the File::Find#find method was
51
- # called.
52
- #
53
- attr_accessor :atime
54
-
55
- # Limits searches by file change time, where the value you supply is the
56
- # number of days back from the time that the File::Find#find method was
57
- # called.
58
- #
59
- attr_accessor :ctime
60
-
61
- # Limits searches to files that belong to a specific group, where the
62
- # group can be either a group name or ID.
63
- #
64
- # Not currently supported on MS Windows.
65
- #
66
- attr_accessor :group
67
-
68
- # An array of two element arrays for storing FileTest methods and their
69
- # boolean value.
70
- #
71
- attr_accessor :filetest
72
-
73
- # Controls the behavior of how symlinks are followed. If set to true (the
74
- # default), then follows the file pointed to. If false, it considers the
75
- # symlink itself.
76
- #
77
- attr_accessor :follow
78
-
79
- # Limits searches to specific types of files. The possible values here are
80
- # those returned by the File.ftype method.
81
- #
82
- attr_accessor :ftype
83
-
84
- # Limits search to a file with a specific inode number. Ignored on MS
85
- # Windows.
86
- #
87
- attr_accessor :inum
88
-
89
- # Limits search to files with the specified number of links.
90
- #
91
- attr_accessor :links
92
-
93
- # Limits search to a maximum depth into the tree relative to the starting
94
- # search directory.
95
- #
96
- attr_accessor :maxdepth
97
-
98
- # Limits searches to a minimum depth into the tree relative to the starting
99
- # search directory.
100
- #
101
- attr_accessor :mindepth
102
-
103
- # Limits searches to the same filesystem as the specified directory. For
104
- # Windows users, this refers to the volume.
105
- #
106
- attr_reader :mount
107
-
108
- # Limits searches by file modification time, where the value you supply is
109
- # the number of days back from the time that the File::Find#find method was
110
- # called.
111
- #
112
- attr_accessor :mtime
113
-
114
- # The name pattern used to limit file searches. The patterns that are legal
115
- # for Dir.glob are legal here. The default is '*', i.e. everything.
116
- #
117
- attr_accessor :name
118
-
119
- # Limits searches to files which have permissions that match the octal
120
- # value that you provide. For purposes of this comparison, only the user,
121
- # group, and world settings are used. Do not use a leading 0 in the values
122
- # that you supply, e.g. use 755 not 0755.
123
- #
124
- # You may optionally use symbolic permissions, e.g. "g+rw", "u=rwx", etc.
125
- #
126
- # Not currently supported on MS Windows.
127
- #
128
- attr_accessor :perm
129
-
130
- # Skips files or directories that match the string provided as an argument.
131
- #
132
- attr_accessor :prune
133
-
134
- # If the value passed is an integer, this option limits searches to files
135
- # that match the size, in bytes, exactly. If a string is passed, you can
136
- # use the standard comparable operators to match files, e.g. ">= 200" would
137
- # limit searches to files greater than or equal to 200 bytes.
138
- #
139
- attr_accessor :size
140
-
141
- # Limits searches to files that belong to a specific user, where the user
142
- # can be either a user name or an ID.
143
- #
144
- # Not currently supported on MS Windows.
145
- #
146
- attr_accessor :user
147
-
148
- # The file that matched previously in the current search.
149
- #
150
- attr_reader :previous
151
-
152
- alias pattern name
153
- alias pattern= name=
154
-
155
- # Creates and returns a new File::Find object. The options set for this
156
- # object serve as the rules for determining what files the File::Find#find
157
- # method will search for.
158
- #
159
- # In addition to the standard list of valid options, you may also use
160
- # FileTest methods as options, setting their value to true or false.
161
- #
162
- # Example:
163
- #
164
- # rule = File::Find.new(
165
- # :name => "*.rb",
166
- # :follow => false,
167
- # :path => ['/usr/local/lib', '/opt/local/lib'],
168
- # :readable? => true
169
- # )
170
- #
171
- def initialize(options = {})
172
- @options = options
173
-
174
- @atime = nil
175
- @ctime = nil
176
- @ftype = nil
177
- @group = nil
178
- @follow = true
179
- @inum = nil
180
- @links = nil
181
- @mount = nil
182
- @mtime = nil
183
- @perm = nil
184
- @prune = nil
185
- @size = nil
186
- @user = nil
187
-
188
- @previous = nil
189
- @maxdepth = nil
190
- @mindepth = nil
191
- @filetest = []
192
-
193
- validate_and_set_options(options) unless options.empty?
194
-
195
- @filesystem = File.stat(@mount).dev if @mount
196
-
197
- @path ||= Dir.pwd
198
- @name ||= '*'
199
- end
200
-
201
- # Executes the find based on the rules you set for the File::Find object.
202
- # In block form, yields each file in turn that matches the specified rules.
203
- # In non-block form it will return an array of matches instead.
204
- #
205
- # Example:
206
- #
207
- # rule = File::Find.new(
208
- # :name => "*.rb",
209
- # :follow => false,
210
- # :path => ['/usr/local/lib', '/opt/local/lib']
211
- # )
212
- #
213
- # rule.find{ |f|
214
- # puts f
215
- # }
216
- #
217
- def find
218
- results = [] unless block_given?
219
- paths = @path.is_a?(String) ? [@path] : @path # Ruby 1.9.x compatibility
220
-
221
- if @prune
222
- prune_regex = Regexp.new(@prune)
223
- else
224
- prune_regex = nil
225
- end
13
+ # The version of the file-find library
14
+ VERSION = '0.3.5'
15
+
16
+ # :stopdoc:
17
+ VALID_OPTIONS = %w/
18
+ atime
19
+ ctime
20
+ follow
21
+ ftype
22
+ inum
23
+ group
24
+ links
25
+ maxdepth
26
+ mindepth
27
+ mount
28
+ mtime
29
+ name
30
+ pattern
31
+ path
32
+ perm
33
+ prune
34
+ size
35
+ user
36
+ /
37
+ # :startdoc:
38
+
39
+ # The starting path(s) for the search. The default is the current directory.
40
+ # This can be a single path or an array of paths.
41
+ #
42
+ attr_accessor :path
43
+
44
+ # The list of options passed to the constructor and/or used by the
45
+ # File::Find#find method.
46
+ #
47
+ attr_accessor :options
48
+
49
+ # Limits searches by file access time, where the value you supply is the
50
+ # number of days back from the time that the File::Find#find method was
51
+ # called.
52
+ #
53
+ attr_accessor :atime
54
+
55
+ # Limits searches by file change time, where the value you supply is the
56
+ # number of days back from the time that the File::Find#find method was
57
+ # called.
58
+ #
59
+ attr_accessor :ctime
60
+
61
+ # Limits searches to files that belong to a specific group, where the
62
+ # group can be either a group name or ID.
63
+ #
64
+ # Not currently supported on MS Windows.
65
+ #
66
+ attr_accessor :group
67
+
68
+ # An array of two element arrays for storing FileTest methods and their
69
+ # boolean value.
70
+ #
71
+ attr_accessor :filetest
72
+
73
+ # Controls the behavior of how symlinks are followed. If set to true (the
74
+ # default), then follows the file pointed to. If false, it considers the
75
+ # symlink itself.
76
+ #
77
+ attr_accessor :follow
78
+
79
+ # Limits searches to specific types of files. The possible values here are
80
+ # those returned by the File.ftype method.
81
+ #
82
+ attr_accessor :ftype
83
+
84
+ # Limits search to a file with a specific inode number. Ignored on MS
85
+ # Windows.
86
+ #
87
+ attr_accessor :inum
88
+
89
+ # Limits search to files with the specified number of links.
90
+ #
91
+ attr_accessor :links
92
+
93
+ # Limits search to a maximum depth into the tree relative to the starting
94
+ # search directory.
95
+ #
96
+ attr_accessor :maxdepth
97
+
98
+ # Limits searches to a minimum depth into the tree relative to the starting
99
+ # search directory.
100
+ #
101
+ attr_accessor :mindepth
102
+
103
+ # Limits searches to the same filesystem as the specified directory. For
104
+ # Windows users, this refers to the volume.
105
+ #
106
+ attr_reader :mount
107
+
108
+ # Limits searches by file modification time, where the value you supply is
109
+ # the number of days back from the time that the File::Find#find method was
110
+ # called.
111
+ #
112
+ attr_accessor :mtime
113
+
114
+ # The name pattern used to limit file searches. The patterns that are legal
115
+ # for Dir.glob are legal here. The default is '*', i.e. everything.
116
+ #
117
+ attr_accessor :name
118
+
119
+ # Limits searches to files which have permissions that match the octal
120
+ # value that you provide. For purposes of this comparison, only the user,
121
+ # group, and world settings are used. Do not use a leading 0 in the values
122
+ # that you supply, e.g. use 755 not 0755.
123
+ #
124
+ # You may optionally use symbolic permissions, e.g. "g+rw", "u=rwx", etc.
125
+ #
126
+ # Not currently supported on MS Windows.
127
+ #
128
+ attr_accessor :perm
129
+
130
+ # Skips files or directories that match the string provided as an argument.
131
+ #
132
+ attr_accessor :prune
133
+
134
+ # If the value passed is an integer, this option limits searches to files
135
+ # that match the size, in bytes, exactly. If a string is passed, you can
136
+ # use the standard comparable operators to match files, e.g. ">= 200" would
137
+ # limit searches to files greater than or equal to 200 bytes.
138
+ #
139
+ attr_accessor :size
140
+
141
+ # Limits searches to files that belong to a specific user, where the user
142
+ # can be either a user name or an ID.
143
+ #
144
+ # Not currently supported on MS Windows.
145
+ #
146
+ attr_accessor :user
147
+
148
+ # The file that matched previously in the current search.
149
+ #
150
+ attr_reader :previous
151
+
152
+ alias pattern name
153
+ alias pattern= name=
154
+
155
+ # Creates and returns a new File::Find object. The options set for this
156
+ # object serve as the rules for determining what files the File::Find#find
157
+ # method will search for.
158
+ #
159
+ # In addition to the standard list of valid options, you may also use
160
+ # FileTest methods as options, setting their value to true or false.
161
+ #
162
+ # Example:
163
+ #
164
+ # rule = File::Find.new(
165
+ # :name => "*.rb",
166
+ # :follow => false,
167
+ # :path => ['/usr/local/lib', '/opt/local/lib'],
168
+ # :readable? => true
169
+ # )
170
+ #
171
+ def initialize(options = {})
172
+ @options = options
173
+
174
+ @atime = nil
175
+ @ctime = nil
176
+ @ftype = nil
177
+ @group = nil
178
+ @follow = true
179
+ @inum = nil
180
+ @links = nil
181
+ @mount = nil
182
+ @mtime = nil
183
+ @perm = nil
184
+ @prune = nil
185
+ @size = nil
186
+ @user = nil
187
+
188
+ @previous = nil
189
+ @maxdepth = nil
190
+ @mindepth = nil
191
+ @filetest = []
192
+
193
+ validate_and_set_options(options) unless options.empty?
194
+
195
+ @filesystem = File.stat(@mount).dev if @mount
196
+
197
+ @path ||= Dir.pwd
198
+ @name ||= '*'
199
+ end
200
+
201
+ # Executes the find based on the rules you set for the File::Find object.
202
+ # In block form, yields each file in turn that matches the specified rules.
203
+ # In non-block form it will return an array of matches instead.
204
+ #
205
+ # Example:
206
+ #
207
+ # rule = File::Find.new(
208
+ # :name => "*.rb",
209
+ # :follow => false,
210
+ # :path => ['/usr/local/lib', '/opt/local/lib']
211
+ # )
212
+ #
213
+ # rule.find{ |f|
214
+ # puts f
215
+ # }
216
+ #
217
+ def find
218
+ results = [] unless block_given?
219
+ paths = @path.is_a?(String) ? [@path] : @path # Ruby 1.9.x compatibility
220
+
221
+ if @prune
222
+ prune_regex = Regexp.new(@prune)
223
+ else
224
+ prune_regex = nil
225
+ end
226
+
227
+ paths.each{ |path|
228
+ begin
229
+ Dir.foreach(path){ |file|
230
+ next if file == '.'
231
+ next if file == '..'
232
+
233
+ if prune_regex
234
+ next if prune_regex.match(file)
235
+ end
236
+
237
+ orig = file.dup
238
+ file = File.join(path, file)
239
+
240
+ stat_method = @follow ? :stat : :lstat
241
+
242
+ # Skip files we cannot access, stale links, etc.
243
+ begin
244
+ stat_info = File.send(stat_method, file)
245
+ rescue Errno::ENOENT, Errno::EACCES
246
+ next
247
+ rescue Errno::ELOOP
248
+ stat_method = :lstat # Handle recursive symlinks
249
+ retry if stat_method.to_s != 'lstat'
250
+ end
251
+
252
+ glob = File.join(File.dirname(file), @name)
253
+
254
+ # Dir[] doesn't like backslashes
255
+ if File::ALT_SEPARATOR
256
+ file.tr!(File::ALT_SEPARATOR, File::SEPARATOR)
257
+ glob.tr!(File::ALT_SEPARATOR, File::SEPARATOR)
258
+ end
259
+
260
+ if @mount
261
+ next unless stat_info.dev == @filesystem
262
+ end
263
+
264
+ if @links
265
+ next unless stat_info.nlink == @links
266
+ end
267
+
268
+ if @maxdepth || @mindepth
269
+ file_depth = file.split(File::SEPARATOR).length
270
+ path_depth = @path.split(File::SEPARATOR).length
271
+ depth = file_depth - path_depth
272
+
273
+ if @maxdepth && (depth > @maxdepth)
274
+ if File.directory?(file)
275
+ unless paths.include?(file) && depth > @maxdepth
276
+ paths << file
277
+ end
278
+ end
279
+
280
+ next
281
+ end
282
+
283
+ if @mindepth && (depth < @mindepth)
284
+ if File.directory?(file)
285
+ unless paths.include?(file) && depth < @mindepth
286
+ paths << file
287
+ end
288
+ end
289
+
290
+ next
291
+ end
292
+ end
293
+
294
+ # Add directories back onto the list of paths to search unless
295
+ # they've already been added
296
+ #
297
+ if stat_info.directory?
298
+ paths << file unless paths.include?(file)
299
+ end
300
+
301
+ next unless Dir[glob].include?(file)
302
+
303
+ unless @filetest.empty?
304
+ file_test = true
226
305
 
227
- paths.each{ |path|
228
- begin
229
- Dir.foreach(path){ |file|
230
- next if file == '.'
231
- next if file == '..'
232
-
233
- if prune_regex
234
- next if prune_regex.match(file)
235
- end
236
-
237
- orig = file.dup
238
- file = File.join(path, file)
239
-
240
- stat_method = @follow ? :lstat : :stat
241
-
242
- # Skip files we cannot access, stale links, etc.
243
- begin
244
- stat_info = File.send(stat_method, file)
245
- rescue Errno::ENOENT, Errno::EACCES
246
- next
247
- rescue Errno::ELOOP
248
- stat_method = :lstat # Handle recursive symlinks
249
- retry if stat_method.to_s != 'lstat'
250
- end
251
-
252
- glob = File.join(File.dirname(file), @name)
253
-
254
- # Dir[] doesn't like backslashes
255
- if File::ALT_SEPARATOR
256
- file.tr!(File::ALT_SEPARATOR, File::SEPARATOR)
257
- glob.tr!(File::ALT_SEPARATOR, File::SEPARATOR)
258
- end
259
-
260
- if @mount
261
- next unless stat_info.dev == @filesystem
262
- end
263
-
264
- if @links
265
- next unless stat_info.nlink == @links
266
- end
267
-
268
- if @maxdepth || @mindepth
269
- file_depth = file.split(File::SEPARATOR).length
270
- path_depth = @path.split(File::SEPARATOR).length
271
- depth = file_depth - path_depth
272
-
273
- if @maxdepth && (depth > @maxdepth)
274
- if File.directory?(file)
275
- unless paths.include?(file) && depth > @maxdepth
276
- paths << file
277
- end
278
- end
279
-
280
- next
281
- end
282
-
283
- if @mindepth && (depth < @mindepth)
284
- if File.directory?(file)
285
- unless paths.include?(file) && depth < @mindepth
286
- paths << file
287
- end
288
- end
289
-
290
- next
291
- end
292
- end
293
-
294
- # Add directories back onto the list of paths to search unless
295
- # they've already been added
296
- #
297
- if stat_info.directory?
298
- paths << file unless paths.include?(file)
299
- end
300
-
301
- next unless Dir[glob].include?(file)
302
-
303
- unless @filetest.empty?
304
- file_test = true
305
-
306
- @filetest.each{ |array|
307
- meth = array[0]
308
- bool = array[1]
309
-
310
- unless File.send(meth, file) == bool
311
- file_test = false
312
- break
313
- end
314
- }
315
-
316
- next unless file_test
317
- end
318
-
319
- if @atime || @ctime || @mtime
320
- date1 = Date.parse(Time.now.to_s)
321
-
322
- if @atime
323
- date2 = Date.parse(stat_info.atime.to_s)
324
- next unless (date1 - date2).numerator == @atime
325
- end
326
-
327
- if @ctime
328
- date2 = Date.parse(stat_info.ctime.to_s)
329
- next unless (date1 - date2).numerator == @ctime
330
- end
331
-
332
- if @mtime
333
- date2 = Date.parse(stat_info.mtime.to_s)
334
- next unless (date1 - date2).numerator == @mtime
335
- end
336
- end
337
-
338
- if @ftype
339
- next unless File.ftype(file) == @ftype
340
- end
341
-
342
- if @group
343
- if @group.is_a?(String)
344
- next unless get_group(stat_info.gid).name == @group
345
- else
346
- next unless stat_info.gid == @group
347
- end
348
- end
349
-
350
- unless Config::CONFIG['host_os'] =~ /windows|mswin/i
351
- if @inum
352
- next unless stat_info.ino == @inum
353
- end
354
- end
355
-
356
- # This currently doesn't work on MS Windows, even in limited
357
- # fashion for 0666 and 0664, because File.stat.mode doesn't
358
- # return the proper value.
359
- #
360
- if @perm
361
- if @perm.is_a?(String)
362
- octal_perm = sym2oct(@perm)
363
- next unless stat_info.mode & octal_perm == octal_perm
364
- else
365
- next unless sprintf("%o", stat_info.mode & 07777) == @perm.to_s
366
- end
367
- end
368
-
369
- # Allow plain numbers, or strings for comparison operators.
370
- if @size
371
- if @size.is_a?(String)
372
- regex = /^([><=]+)\s*?(\d+)$/
373
- match = regex.match(@size)
374
-
375
- if match.nil? || match.captures.include?(nil)
376
- raise ArgumentError, "invalid size string: '#{@size}'"
377
- end
378
-
379
- operator = match.captures.first.strip
380
- number = match.captures.last.strip.to_i
381
-
382
- next unless stat_info.size.send(operator, number)
383
- else
384
- next unless stat_info.size == @size
385
- end
386
- end
387
-
388
- if @user
389
- if @user.is_a?(String)
390
- next unless get_user(stat_info.uid).name == @user
391
- else
392
- next unless stat_info.uid == @user
393
- end
394
- end
395
-
396
- if block_given?
397
- yield file
398
- else
399
- results << file
400
- end
401
-
402
- @previous = file unless @previous == file
306
+ @filetest.each{ |array|
307
+ meth = array[0]
308
+ bool = array[1]
309
+
310
+ unless File.send(meth, file) == bool
311
+ file_test = false
312
+ break
313
+ end
403
314
  }
404
- rescue Errno::EACCES
405
- next # Skip inaccessible directories
406
- end
407
- }
408
-
409
- block_given? ? nil : results
410
- end
411
-
412
- # Limits searches to the same file system as the specified +mount_point+.
413
- #
414
- def mount=(mount_point)
415
- @mount = mount_point
416
- @filesystem = File.stat(mount_point).dev
417
- end
418
-
419
- private
420
-
421
- # This validates that the keys are valid. If they are, it sets the value
422
- # of that key's corresponding method to the given value. If a key ends
423
- # with a '?', it's validated as a File method.
424
- #
425
- def validate_and_set_options(options)
426
- options.each do |key, value|
427
- key = key.to_s.downcase
428
-
429
- if key[-1].chr == '?'
430
- sym = key.to_sym
431
-
432
- unless File.respond_to?(sym)
433
- raise ArgumentError, "invalid option '#{key}'"
315
+
316
+ next unless file_test
317
+ end
318
+
319
+ if @atime || @ctime || @mtime
320
+ date1 = Date.parse(Time.now.to_s)
321
+
322
+ if @atime
323
+ date2 = Date.parse(stat_info.atime.to_s)
324
+ next unless (date1 - date2).numerator == @atime
434
325
  end
435
326
 
436
- @filetest << [sym, value]
437
- else
438
- unless VALID_OPTIONS.include?(key)
439
- raise ArgumentError, "invalid option '#{key}'"
327
+ if @ctime
328
+ date2 = Date.parse(stat_info.ctime.to_s)
329
+ next unless (date1 - date2).numerator == @ctime
440
330
  end
441
331
 
442
- send("#{key}=", value)
443
- end
444
- end
445
- end
446
-
447
- # Converts a symoblic permissions mode into its octal equivalent.
448
- #--
449
- # Taken almost entirely from ruby-talk: 96956 (Hal Fulton).
450
- #
451
- def sym2oct(str)
452
- left = {'u' => 0700, 'g' => 0070, 'o' => 0007, 'a' => 0777}
453
- right = {'r' => 0444, 'w' => 0222, 'x' => 0111}
454
- regex = /([ugoa]+)([+-=])([rwx]+)/
455
-
456
- cmds = str.split(',')
457
-
458
- perm = 0
459
-
460
- cmds.each do |cmd|
461
- match = cmd.match(regex)
462
- raise "Invalid symbolic permissions: '#{str}'" if match.nil?
463
-
464
- junk, who, what, how = match.to_a
465
-
466
- who = who.split(//).inject(who_num=0){ |num,b| num |= left[b]; num }
467
- how = how.split(//).inject(how_num=0){ |num,b| num |= right[b]; num }
468
- mask = who & how
469
-
470
- case what
471
- when '+'
472
- perm = perm | mask
473
- when '-'
474
- perm = perm & ~mask
475
- when '='
476
- perm = mask
477
- end
332
+ if @mtime
333
+ date2 = Date.parse(stat_info.mtime.to_s)
334
+ next unless (date1 - date2).numerator == @mtime
335
+ end
336
+ end
337
+
338
+ if @ftype
339
+ next unless File.ftype(file) == @ftype
340
+ end
341
+
342
+ if @group
343
+ if @group.is_a?(String)
344
+ next unless get_group(stat_info.gid).name == @group
345
+ else
346
+ next unless stat_info.gid == @group
347
+ end
348
+ end
349
+
350
+ unless Config::CONFIG['host_os'] =~ /windows|mswin/i
351
+ if @inum
352
+ next unless stat_info.ino == @inum
353
+ end
354
+ end
355
+
356
+ # This currently doesn't work on MS Windows, even in limited
357
+ # fashion for 0666 and 0664, because File.stat.mode doesn't
358
+ # return the proper value.
359
+ #
360
+ if @perm
361
+ if @perm.is_a?(String)
362
+ octal_perm = sym2oct(@perm)
363
+ next unless stat_info.mode & octal_perm == octal_perm
364
+ else
365
+ next unless sprintf("%o", stat_info.mode & 07777) == @perm.to_s
366
+ end
367
+ end
368
+
369
+ # Allow plain numbers, or strings for comparison operators.
370
+ if @size
371
+ if @size.is_a?(String)
372
+ regex = /^([><=]+)\s*?(\d+)$/
373
+ match = regex.match(@size)
374
+
375
+ if match.nil? || match.captures.include?(nil)
376
+ raise ArgumentError, "invalid size string: '#{@size}'"
377
+ end
378
+
379
+ operator = match.captures.first.strip
380
+ number = match.captures.last.strip.to_i
381
+
382
+ next unless stat_info.size.send(operator, number)
383
+ else
384
+ next unless stat_info.size == @size
385
+ end
386
+ end
387
+
388
+ if @user
389
+ if @user.is_a?(String)
390
+ next unless get_user(stat_info.uid).name == @user
391
+ else
392
+ next unless stat_info.uid == @user
393
+ end
394
+ end
395
+
396
+ if block_given?
397
+ yield file
398
+ else
399
+ results << file
400
+ end
401
+
402
+ @previous = file unless @previous == file
403
+ }
404
+ rescue Errno::EACCES
405
+ next # Skip inaccessible directories
478
406
  end
407
+ }
408
+
409
+ block_given? ? nil : results
410
+ end
411
+
412
+ # Limits searches to the same file system as the specified +mount_point+.
413
+ #
414
+ def mount=(mount_point)
415
+ @mount = mount_point
416
+ @filesystem = File.stat(mount_point).dev
417
+ end
418
+
419
+ private
479
420
 
480
- perm
481
- end
421
+ # This validates that the keys are valid. If they are, it sets the value
422
+ # of that key's corresponding method to the given value. If a key ends
423
+ # with a '?', it's validated as a File method.
424
+ #
425
+ def validate_and_set_options(options)
426
+ options.each do |key, value|
427
+ key = key.to_s.downcase
482
428
 
483
- # Returns the group object based on the group id. Implemented for the
484
- # sake of platforms that cannot build extensions, such as JRuby.
485
- #
486
- def get_group(gid)
487
- if defined? Sys::Admin
488
- Sys::Admin.get_group(gid)
429
+ if key[-1].chr == '?'
430
+ sym = key.to_sym
431
+
432
+ unless File.respond_to?(sym)
433
+ raise ArgumentError, "invalid option '#{key}'"
434
+ end
435
+
436
+ @filetest << [sym, value]
489
437
  else
490
- Etc.getgrgid(gid)
438
+ unless VALID_OPTIONS.include?(key)
439
+ raise ArgumentError, "invalid option '#{key}'"
440
+ end
441
+
442
+ send("#{key}=", value)
491
443
  end
492
- end
493
-
494
- # Returns the user object based on the group id. Implemented for the
495
- # sake of platforms that cannot build extensions, such as JRuby.
496
- #
497
- def get_user(uid)
498
- if defined? Sys::Admin
499
- Sys::Admin.get_user(uid)
500
- else
501
- Etc.getpwuid(uid)
444
+ end
445
+ end
446
+
447
+ # Converts a symoblic permissions mode into its octal equivalent.
448
+ #--
449
+ # Taken almost entirely from ruby-talk: 96956 (Hal Fulton).
450
+ #
451
+ def sym2oct(str)
452
+ left = {'u' => 0700, 'g' => 0070, 'o' => 0007, 'a' => 0777}
453
+ right = {'r' => 0444, 'w' => 0222, 'x' => 0111}
454
+ regex = /([ugoa]+)([+-=])([rwx]+)/
455
+
456
+ cmds = str.split(',')
457
+
458
+ perm = 0
459
+
460
+ cmds.each do |cmd|
461
+ match = cmd.match(regex)
462
+ raise "Invalid symbolic permissions: '#{str}'" if match.nil?
463
+
464
+ junk, who, what, how = match.to_a
465
+
466
+ who = who.split(//).inject(who_num=0){ |num,b| num |= left[b]; num }
467
+ how = how.split(//).inject(how_num=0){ |num,b| num |= right[b]; num }
468
+ mask = who & how
469
+
470
+ case what
471
+ when '+'
472
+ perm = perm | mask
473
+ when '-'
474
+ perm = perm & ~mask
475
+ when '='
476
+ perm = mask
502
477
  end
503
- end
478
+ end
479
+
480
+ perm
481
+ end
482
+
483
+ # Returns the group object based on the group id. Implemented for the
484
+ # sake of platforms that cannot build extensions, such as JRuby.
485
+ #
486
+ def get_group(gid)
487
+ if defined? Sys::Admin
488
+ Sys::Admin.get_group(gid)
489
+ else
490
+ Etc.getgrgid(gid)
491
+ end
492
+ end
493
+
494
+ # Returns the user object based on the group id. Implemented for the
495
+ # sake of platforms that cannot build extensions, such as JRuby.
496
+ #
497
+ def get_user(uid)
498
+ if defined? Sys::Admin
499
+ Sys::Admin.get_user(uid)
500
+ else
501
+ Etc.getpwuid(uid)
502
+ end
503
+ end
504
504
  end