fynd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,30 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fynd.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ end
9
+
10
+ group :doc do
11
+ gem 'yard', '~> 0.8.2.1'
12
+ gem 'redcarpet', '~> 2.1.1'
13
+ end
14
+
15
+ group :test do
16
+ gem 'guard', '~> 1.3.2'
17
+ gem 'guard-rspec', '~> 1.2.1'
18
+ gem 'guard-spork', '~> 1.1.0'
19
+ gem 'rb-fsevent', '~> 0.9.1'
20
+ gem 'growl', '~> 1.0.3'
21
+ gem 'simplecov', '~> 0.6.4'
22
+ gem 'timecop', '~> 0.4.6'
23
+ end
24
+
25
+ # JSON
26
+ # gem 'json', :platform => :jruby
27
+ gem 'yajl-ruby', :platform => [ :ruby_18, :ruby_19 ]
28
+
29
+ # OpenSSL
30
+ gem 'jruby-openssl', :platform => :jruby
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ ignore %r{^spec/fixtures/}
2
+
3
+ guard 'rspec', :version => 2, :cli => "--color --format doc" do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ watch(%r{^spec/support/.+.rb$}) { "spec" }
8
+ end
9
+
10
+ guard 'spork' do
11
+ watch('spec/spec_helper.rb')
12
+ watch(%r{^spec/support/.+.rb$}) { "spec" }
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Dan Ryan
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # Fynd
2
+
3
+ I found GNU find to be slow, so I made it slower.
4
+
5
+ ## Is it any good?
6
+
7
+ [No.](http://news.ycombinator.com/item?id=3067434)
8
+
9
+ ## Installation
10
+
11
+ gem install fynd
12
+
13
+ ## Usage
14
+
15
+ ```ruby
16
+ require 'fynd'
17
+ include Fynd
18
+
19
+ # `find /var/log -iname '*system*' -type f`
20
+
21
+ find("/var/log").iname("system").type(:file).files
22
+
23
+ => ["/var/log/system.log", "/var/log/system.log.0.bz2", "/var/log/system.log.1.bz2", "/var/log/system.log.2.bz2", "/var/log/system.log.3.bz2", "/var/log/system.log.4.bz2", "/var/log/system.log.5.bz2", "/var/log/system.log.6.bz2", "/var/log/system.log.7.bz2"]
24
+ ```
25
+
26
+ You can keep pass the files to a block [if you're a bad enough dude](http://i.imgur.com/x37pI.jpg).
27
+
28
+ ```ruby
29
+ require 'fynd'
30
+ include Fynd
31
+
32
+ # `find /var/log -iname '*system` -type f -print
33
+
34
+ find("/var/log").iname("system").type(:file).files do |file|
35
+ puts file
36
+ end
37
+
38
+ # Prints out:
39
+ # /var/log/system.log
40
+ # /var/log/system.log.0.bz2
41
+ # /var/log/system.log.1.bz2
42
+ # /var/log/system.log.2.bz2
43
+ # /var/log/system.log.3.bz2
44
+ # /var/log/system.log.4.bz2
45
+ # /var/log/system.log.5.bz2
46
+ # /var/log/system.log.6.bz2
47
+ # /var/log/system.log.7.bz2
48
+ ```
49
+ ## Contributing
50
+
51
+ 1. Fork it
52
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
53
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
54
+ 4. Push to the branch (`git push origin my-new-feature`)
55
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/fynd.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fynd/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "fynd"
8
+ gem.version = Fynd::VERSION
9
+ gem.authors = ["Dan Ryan"]
10
+ gem.email = ["scriptfu@gmail.com"]
11
+ gem.description = %q{I found GNU find to be slow, so I made it slower.}
12
+ gem.summary = %q{A pure Ruby re-implementation of GNU find.}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "activesupport", '~> 3.2.8'
21
+ end
@@ -0,0 +1,336 @@
1
+ module Fynd::Actions
2
+ # Delete files; true if removal succeeded. If the removal failed,
3
+ # an error message is issued. Use of this action automatically
4
+ # turns on the '-depth' option.
5
+ def delete
6
+ end
7
+
8
+ # Execute command; true if 0 status is returned. All following
9
+ # arguments to find are taken to be arguments to the command until
10
+ # an argument consisting of ';' is encountered. The string '{}'
11
+ # is replaced by the current file name being processed everywhere
12
+ # it occurs in the arguments to the command, not just in arguments
13
+ # where it is alone, as in some versions of find. Both of these
14
+ # constructions might need to be escaped (with a '\') or quoted to
15
+ # protect them from expansion by the shell. See the EXAMPLES sec-
16
+ # tion for examples of the use of the '-exec' option. The speci-
17
+ # fied command is run once for each matched file. The command is
18
+ # executed in the starting directory. There are unavoidable
19
+ # security problems surrounding use of the -exec option; you
20
+ # should use the -execdir option instead.
21
+ #
22
+ # -exec command {} +
23
+ #
24
+ # This variant of the -exec option runs the specified command on
25
+ # the selected files, but the command line is built by appending
26
+ # each selected file name at the end; the total number of invoca-
27
+ # tions of the command will be much less than the number of
28
+ # matched files. The command line is built in much the same way
29
+ # that xargs builds its command lines. Only one instance of '{}'
30
+ # is allowed within the command. The command is executed in the
31
+ # starting directory.
32
+ def exec(command)
33
+ end
34
+
35
+ # Like -exec, but the specified command is run from the subdirec-
36
+ # tory containing the matched file, which is not normally the
37
+ # directory in which you started find. This a much more secure
38
+ # method for invoking commands, as it avoids race conditions dur-
39
+ # ing resolution of the paths to the matched files. As with the
40
+ # -exec option, the '+' form of -execdir will build a command line
41
+ # to process more than one matched file, but any given invocation
42
+ # of command will only list files that exist in the same subdirec-
43
+ # tory. If you use this option, you must ensure that your $PATH
44
+ # environment variable does not reference the current directory;
45
+ # otherwise, an attacker can run any commands they like by leaving
46
+ # an appropriately-named file in a directory in which you will run
47
+ # -execdir.
48
+ def execdir(command)
49
+ end
50
+
51
+ # True; like -ls but write to file like -fprint. The output file
52
+ # is always created, even if the predicate is never matched. See
53
+ # the UNUSUAL FILENAMES section for information about how unusual
54
+ # characters in filenames are handled.
55
+ def fls(file)
56
+ end
57
+
58
+ # True; print the full file name into file file. If file does not
59
+ # exist when find is run, it is created; if it does exist, it is
60
+ # truncated. The file names ''/dev/stdout'' and ''/dev/stderr''
61
+ # are handled specially; they refer to the standard output and
62
+ # standard error output, respectively. The output file is always
63
+ # created, even if the predicate is never matched. See the
64
+ # UNUSUAL FILENAMES section for information about how unusual
65
+ # characters in filenames are handled.
66
+ def fprint(file)
67
+ end
68
+
69
+ # True; like -print0 but write to file like -fprint. The output
70
+ # file is always created, even if the predicate is never matched.
71
+ # See the UNUSUAL FILENAMES section for information about how
72
+ # unusual characters in filenames are handled.
73
+ def fprint0(file)
74
+ end
75
+
76
+ # True; like -printf but write to file like -fprint. The output
77
+ # file is always created, even if the predicate is never matched.
78
+ # See the UNUSUAL FILENAMES section for information about how
79
+ # unusual characters in filenames are handled.
80
+ def fprintf(file, format)
81
+ end
82
+
83
+ # Like -exec but ask the user first (on the standard input); if
84
+ # the response does not start with 'y' or 'Y', do not run the com-
85
+ # mand, and return false. If the command is run, its standard
86
+ # input is redirected from /dev/null.
87
+ def ok(command)
88
+ end
89
+
90
+ # Like -execdir but ask the user first (on the standard input); if
91
+ # the response does not start with 'y' or 'Y', do not run the com-
92
+ # mand, and return false. If the command is run, its standard
93
+ # input is redirected from /dev/null.
94
+ def okdir(command)
95
+ end
96
+
97
+ # Print the full file name on the standard output, followed
98
+ # by a newline. If you are piping the output of find into
99
+ # another program and there is the faintest possibility that the
100
+ # files which you are searching for might contain a newline, then
101
+ # you should seriously consider using the '-print0' option instead
102
+ # of '-print'. See the UNUSUAL FILENAMES section for information
103
+ # about how unusual characters in filenames are handled.
104
+ def print
105
+
106
+ end
107
+
108
+ # Print the full file name on the standard output, followed
109
+ # by a null character (instead of the newline character that
110
+ # '-print' uses). This allows file names that contain newlines or
111
+ # other types of white space to be correctly interpreted by pro-
112
+ # grams that process the find output. This option corresponds to
113
+ # the '-0' option of xargs.
114
+ def print0
115
+ end
116
+
117
+ # Print format on the standard output, interpreting '\'
118
+ # escapes and '%' directives. Field widths and precisions can be
119
+ # specified as with the 'printf' C function. Please note that
120
+ # many of the fields are printed as %s rather than %d, and this
121
+ # may mean that flags don't work as you might expect. This also
122
+ # means that the '-' flag does work (it forces fields to be left-
123
+ # aligned). Unlike -print, -printf does not add a newline at the
124
+ # end of the string. The escapes and directives are:
125
+ #
126
+ # \a Alarm bell.
127
+ #
128
+ # \b Backspace.
129
+ #
130
+ # \c Stop printing from this format immediately and flush the
131
+ # output.
132
+ #
133
+ # \f Form feed.
134
+ #
135
+ # \n Newline.
136
+ #
137
+ # \r Carriage return.
138
+ #
139
+ # \t Horizontal tab.
140
+ #
141
+ # \v Vertical tab.
142
+ #
143
+ # \ ASCII NUL.
144
+ #
145
+ # \\ A literal backslash ('\').
146
+ #
147
+ # \NNN The character whose ASCII code is NNN (octal).
148
+ #
149
+ # A '\' character followed by any other character is treated as an
150
+ # ordinary character, so they both are printed.
151
+ #
152
+ # %% A literal percent sign.
153
+ #
154
+ # %a File's last access time in the format returned by the C
155
+ # 'ctime' function.
156
+ #
157
+ # %Ak File's last access time in the format specified by k,
158
+ # which is either '@' or a directive for the C 'strftime'
159
+ # function. The possible values for k are listed below;
160
+ # some of them might not be available on all systems, due
161
+ # to differences in 'strftime' between systems.
162
+ #
163
+ # @ seconds since Jan. 1, 1970, 00:00 GMT.
164
+ #
165
+ # Time fields:
166
+ #
167
+ # H hour (00..23)
168
+ #
169
+ # I hour (01..12)
170
+ #
171
+ # k hour ( 0..23)
172
+ #
173
+ # l hour ( 1..12)
174
+ #
175
+ # M minute (00..59)
176
+ #
177
+ # p locale's AM or PM
178
+ #
179
+ # r time, 12-hour (hh:mm:ss [AP]M)
180
+ #
181
+ # S second (00..61)
182
+ #
183
+ # T time, 24-hour (hh:mm:ss)
184
+ #
185
+ # + Date and time, separated by '+', for example
186
+ # '2004-04-28+22:22:05'. The time is given in the
187
+ # current timezone (which may be affected by set-
188
+ # ting the TZ environment variable). This is a GNU
189
+ # extension.
190
+ #
191
+ # X locale's time representation (H:M:S)
192
+ #
193
+ # Z time zone (e.g., EDT), or nothing if no time zone
194
+ # is determinable
195
+ #
196
+ # Date fields:
197
+ #
198
+ # a locale's abbreviated weekday name (Sun..Sat)
199
+ #
200
+ # A locale's full weekday name, variable length (Sun-
201
+ # day..Saturday)
202
+ #
203
+ # b locale's abbreviated month name (Jan..Dec)
204
+ #
205
+ # B locale's full month name, variable length (Jan-
206
+ # uary..December)
207
+ #
208
+ # c locale's date and time (Sat Nov 04 12:02:33 EST
209
+ # 1989)
210
+ #
211
+ # d day of month (01..31)
212
+ #
213
+ # D date (mm/dd/yy)
214
+ #
215
+ # h same as b
216
+ #
217
+ # j day of year (001..366)
218
+ #
219
+ # m month (01..12)
220
+ #
221
+ # U week number of year with Sunday as first day of
222
+ # week (00..53)
223
+ #
224
+ # w day of week (0..6)
225
+ #
226
+ # W week number of year with Monday as first day of
227
+ # week (00..53)
228
+ #
229
+ # x locale's date representation (mm/dd/yy)
230
+ #
231
+ # y last two digits of year (00..99)
232
+ #
233
+ # Y year (1970...)
234
+ #
235
+ # %b The amount of disk space used for this file in 512-byte
236
+ # blocks. Since disk space is allocated in multiples of the
237
+ # filesystem block size this is usually greater than
238
+ # %s/1024, but it can also be smaller if the file is a
239
+ # sparse file.
240
+ #
241
+ # %c File's last status change time in the format returned by
242
+ # the C 'ctime' function.
243
+ #
244
+ # %Ck File's last status change time in the format specified by
245
+ # k, which is the same as for %A.
246
+ #
247
+ # %d File's depth in the directory tree; 0 means the file is a
248
+ # command line argument.
249
+ #
250
+ # %D The device number on which the file exists (the st_dev
251
+ # field of struct stat), in decimal.
252
+ #
253
+ # %f File's name with any leading directories removed (only
254
+ # the last element).
255
+ #
256
+ # %F Type of the filesystem the file is on; this value can be
257
+ # used for -fstype.
258
+ #
259
+ # %g File's group name, or numeric group ID if the group has
260
+ # no name.
261
+ #
262
+ # %G File's numeric group ID.
263
+ #
264
+ # %h Leading directories of file's name (all but the last ele-
265
+ # ment). If the file name contains no slashes (since it is
266
+ # in the current directory) the %h specifier expands to
267
+ # ".".
268
+ #
269
+ # %H Command line argument under which file was found.
270
+ #
271
+ # %i File's inode number (in decimal).
272
+ #
273
+ # %k The amount of disk space used for this file in 1K blocks.
274
+ # Since disk space is allocated in multiples of the
275
+ # filesystem block size this is usually greater than
276
+ # %s/1024, but it can also be smaller if the file is a
277
+ # sparse file.
278
+ #
279
+ # %l Object of symbolic link (empty string if file is not a
280
+ # symbolic link).
281
+ #
282
+ # %m File's permission bits (in octal). This option uses the
283
+ # 'traditional' numbers which most Unix implementations
284
+ # use, but if your particular implementation uses an
285
+ # unusual ordering of octal permissions bits, you will see
286
+ # a difference between the actual value of the file's mode
287
+ # and the output of %m. Normally you will want to have a
288
+ # leading zero on this number, and to do this, you should
289
+ # use the # flag (as in, for example, '%#m').
290
+ #
291
+ # %M File's permissions (in symbolic form, as for ls). This
292
+ # directive is supported in findutils 4.2.5 and later.
293
+ #
294
+ # %n Number of hard links to file.
295
+ #
296
+ # %p File's name.
297
+ #
298
+ # %P File's name with the name of the command line argument
299
+ # under which it was found removed.
300
+ #
301
+ # %s File's size in bytes.
302
+ #
303
+ # %t File's last modification time in the format returned by
304
+ # the C 'ctime' function.
305
+ #
306
+ # %Tk File's last modification time in the format specified by
307
+ # k, which is the same as for %A.
308
+ #
309
+ # %u File's user name, or numeric user ID if the user has no
310
+ # name.
311
+ #
312
+ # %U File's numeric user ID.
313
+ #
314
+ # %y File's type (like in ls -l), U=unknown type (shouldn't
315
+ # happen)
316
+ #
317
+ # %Y File's type (like %y), plus follow symlinks: L=loop,
318
+ # N=nonexistent
319
+ #
320
+ # %Z (SELinux only) file's security context.
321
+ #
322
+ # A '%' character followed by any other character is discarded
323
+ # (but the other character is printed).
324
+ #
325
+ # The %m and %d directives support the # , 0 and + flags, but the
326
+ # other directives do not, even if they print numbers. Numeric
327
+ # directives that do not support these flags include G, U, b, D, k
328
+ # and n. The '-' format flag is supported and changes the align-
329
+ # ment of a field from right-justified (which is the default) to
330
+ # left-justified.
331
+ #
332
+ # See the UNUSUAL FILENAMES section for information about how
333
+ # unusual characters in filenames are handled.
334
+ def printf(format)
335
+ end
336
+ end
@@ -0,0 +1,75 @@
1
+ require 'forwardable'
2
+ require 'find' # <- lol
3
+
4
+ require 'fynd/sieve'
5
+
6
+ module Fynd
7
+ class Criteria
8
+ extend Forwardable
9
+
10
+ attr_accessor :sieve
11
+
12
+ def_delegators :@sieve, :collection, :conditions
13
+
14
+ def initialize(*paths)
15
+ @sieve = Sieve.new
16
+ @sieve.collection = []
17
+ @sieve.conditions = {}
18
+ @sieve.conditions['actions'] = {}
19
+ @sieve.conditions['operators'] = {}
20
+ @sieve.conditions['tests'] = {}
21
+
22
+ # For every path...
23
+ paths.each do |path|
24
+ # Pull out all directories
25
+ # dirs = Dir.glob(File.expand_path(path)).select { |f| File.stat(f).directory? }
26
+ # Shove all found files into the collection
27
+ # @sieve.collection << Dir.glob(File.expand_path(path))
28
+ @sieve.collection << Find.find(path).to_a
29
+ end
30
+
31
+ # Flatten it and strip out non-unique files
32
+ @sieve.collection.flatten!.uniq!
33
+ end
34
+
35
+ # def find(*paths)
36
+ # where(:paths => paths)
37
+ # self
38
+ # end
39
+
40
+ def run
41
+ sieve.run
42
+ return sieve.files
43
+ end
44
+
45
+ def files
46
+ files = sieve.run
47
+
48
+ if block_given?
49
+ yield files
50
+ else
51
+ return files
52
+ end
53
+ end
54
+
55
+ def method_missing(symbol, *args, &block)
56
+ if sieve.respond_to?(symbol)
57
+ if ACTIONS.include?(symbol)
58
+ # Only one action per expression
59
+ sieve.conditions['action'] = { symbol.to_s => args[0] }
60
+ elsif OPERATORS.include?(symbol)
61
+ sieve.conditions['operations'].deep_merge!({ symbol.to_s => args[0] })
62
+ elsif TESTS.include?(symbol)
63
+ sieve.conditions['tests'].deep_merge!({ symbol.to_s => args[0] })
64
+ else
65
+ super(symbol, *args, &blocks)
66
+ end
67
+ self
68
+ else
69
+ super(symbol, *args, &blocks)
70
+ end
71
+ end
72
+
73
+ # TODO: implement enumerables; all, first, each, etc.
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ module Fynd::Helpers
2
+
3
+ end
@@ -0,0 +1,10 @@
1
+ module Fynd::Operators
2
+ def not(expr)
3
+ end
4
+
5
+ def and(expr)
6
+ end
7
+
8
+ def or(expr)
9
+ end
10
+ end
data/lib/fynd/sieve.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'forwardable'
2
+
3
+ require 'fynd/actions'
4
+ require 'fynd/operators'
5
+ require 'fynd/tests'
6
+ require 'fynd/helpers'
7
+
8
+ module Fynd
9
+ class Sieve
10
+ include Helpers
11
+ include Actions
12
+ include Operators
13
+ include Tests
14
+
15
+ attr_accessor :collection, :conditions, :files
16
+
17
+ def initialize
18
+ @collection = []
19
+ @conditions = {}
20
+ @files = nil
21
+ end
22
+
23
+ def run
24
+ @files = collection.dup
25
+ # first we match files with our tests
26
+ conditions['tests'].each do |symbol, value|
27
+ value.nil? ? self.__send__(symbol) : self.__send__(symbol, value)
28
+ end
29
+
30
+ @files
31
+ end
32
+
33
+ end
34
+ end
data/lib/fynd/tests.rb ADDED
@@ -0,0 +1,357 @@
1
+ require 'etc'
2
+
3
+ module Fynd::Tests
4
+ # Numeric arguments can be specified as
5
+ #
6
+ # +n for greater than n,
7
+ #
8
+ # -n for less than n,
9
+ #
10
+ # n for exactly n.
11
+
12
+ # File was last accessed n minutes ago.
13
+ def amin(n)
14
+ end
15
+
16
+ # File was last accessed more recently than file was modified. If
17
+ # file is a symbolic link and the -H option or the -L option is in
18
+ # effect, the access time of the file it points to is always used.
19
+ def anewer(other)
20
+ files.select! do |file|
21
+ File.stat(file).atime > File.stat(other).atime
22
+ end
23
+ end
24
+
25
+ # File was last accessed n*24 hours ago. When find figures out
26
+ # how many 24-hour periods ago the file was last accessed, any
27
+ # fractional part is ignored, so to match -atime +1, a file has to
28
+ # have been accessed at least two days ago.
29
+ def atime(n)
30
+ match = n.match(/([-+]?)(\d+)/)
31
+ comparer, interval = match[1], match[2].to_i
32
+ time = Time.now
33
+
34
+ files.select! do |file|
35
+ atime = File.stat(file).atime
36
+
37
+ case comparer
38
+ when '+'
39
+ # more than n days ago
40
+ atime < time - interval.days
41
+ when '-'
42
+ # less than n days ago
43
+ atime > time - interval.days
44
+ when ''
45
+ # exactly n days ago
46
+ atime <= time - (interval - 1).days && atime >= time - interval.days
47
+ else
48
+ raise ArgumentError, "argument must be n, +n, or -n"
49
+ end
50
+ end
51
+ end
52
+
53
+ # File's status was last changed n minutes ago.
54
+ def cmin(n)
55
+ end
56
+
57
+ # File's status was last changed more recently than file was modi-
58
+ # fied. If file is a symbolic link and the -H option or the -L
59
+ # option is in effect, the status-change time of the file it
60
+ # points to is always used.
61
+ def cnewer(other)
62
+ files.select! do |file|
63
+ File.stat(file).ctime > File.stat(other).ctime
64
+ end
65
+ end
66
+
67
+ # File's status was last changed n*24 hours ago. See the comments
68
+ # for -atime to understand how rounding affects the interpretation
69
+ # of file status change times.
70
+ def ctime(n)
71
+ end
72
+
73
+ # File is empty and is either a regular file or a directory.
74
+ def empty
75
+ files.select! do |file|
76
+ File.stat(file).zero?
77
+ end
78
+ end
79
+
80
+ alias :empty? :empty
81
+
82
+ # Always false.
83
+ def false
84
+ # false
85
+ end
86
+
87
+ alias :false? :false
88
+
89
+ # File's numeric group ID is n.
90
+ def gid(n)
91
+ files.select! do |file|
92
+ File.stat(file).gid == n.to_i
93
+ end
94
+ end
95
+
96
+ # File belongs to group gname (numeric group ID allowed).
97
+ def group(name)
98
+ files.select! do |file|
99
+ gid = File.stat(file).gid
100
+ Etc.getgrgid(gid).name == name
101
+ end
102
+ end
103
+
104
+ # Like -lname, but the match is case insensitive. If the -L
105
+ # option or the -follow option is in effect, this test returns
106
+ # false unless the symbolic link is broken.
107
+ def ilname(pattern)
108
+ end
109
+
110
+ # Like -name, but the match is case insensitive. For example, the
111
+ # patterns 'fo*' and 'F??' match the file names 'Foo', 'FOO',
112
+ # 'foo', 'fOo', etc. In these patterns, unlike filename expan-
113
+ # sion by the shell, an initial '.' can be matched by '*'. That
114
+ # is, find -name *bar will match the file '.foobar'. Please note
115
+ # that you should quote patterns as a matter of course, otherwise
116
+ # the shell will expand any wildcard characters in them.
117
+ def iname(pattern)
118
+ files.select! do |file|
119
+ file =~ /#{pattern}/i
120
+ end
121
+ end
122
+
123
+ # File has inode number n. It is normally easier to use the
124
+ # -samefile test instead.
125
+ def inum(n)
126
+ files.select! do |file|
127
+ File.stat(file).ino == n.to_i
128
+ end
129
+ end
130
+
131
+ # Like -regex, but the match is case insensitive.
132
+ def iregex(pattern)
133
+ end
134
+
135
+ # Like -wholename, but the match is case insensitive.
136
+ def iwholename(pattern)
137
+ end
138
+
139
+ # File has n links.
140
+ def links(n)
141
+ end
142
+
143
+ # File is a symbolic link whose contents match shell pattern pat-
144
+ # tern. The metacharacters do not treat '/' or '.' specially. If
145
+ # the -L option or the -follow option is in effect, this test
146
+ # returns false unless the symbolic link is broken.
147
+ def lname(pattern)
148
+ end
149
+
150
+ # File's data was last modified n minutes ago.
151
+ def mmin(n)
152
+ end
153
+
154
+ # File's data was last modified n*24 hours ago. See the comments
155
+ # for -atime to understand how rounding affects the interpretation
156
+ # of file modification times.
157
+ def mtime(n)
158
+ end
159
+
160
+ # Base of file name (the path with the leading directories
161
+ # removed) matches shell pattern pattern. The metacharacters
162
+ # ('*', '?', and '[]') match a '.' at the start of the base name
163
+ # (this is a change in findutils-4.2.2; see section STANDARDS CON-
164
+ # FORMANCE below). To ignore a directory and the files under it,
165
+ # use -prune; see an example in the description of -wholename.
166
+ # Braces are not recognised as being special, despite the fact
167
+ # that some shells including Bash imbue braces with a special
168
+ # meaning in shell patterns. The filename matching is performed
169
+ # with the use of the fnmatch(3) library function. Don't forget
170
+ # to enclose the pattern in quotes in order to protect it from
171
+ # expansion by the shell.
172
+ def name(pattern)
173
+ files.select! do |file|
174
+ file =~ /#{pattern}/
175
+ end
176
+ end
177
+
178
+ # File was modified more recently than file. If file is a sym-
179
+ # bolic link and the -H option or the -L option is in effect, the
180
+ # modification time of the file it points to is always used.
181
+ def newer(other)
182
+ end
183
+
184
+ # No user corresponds to file's numeric user ID.
185
+ def nouser
186
+ files.select! do |file|
187
+ uid = File.stat(file).uid
188
+ begin
189
+ Etc.getpwuid(uid)
190
+ false
191
+ rescue ArgumentError => e
192
+ true
193
+ end
194
+ end
195
+ end
196
+
197
+ # No group corresponds to file's numeric group ID.
198
+ def nogroup
199
+ files.select! do |file|
200
+ gid = File.stat(file).gid
201
+ begin
202
+ Etc.getgrgid(gid)
203
+ false
204
+ rescue ArgumentError => e
205
+ true
206
+ end
207
+ end
208
+ end
209
+
210
+ # See -wholename. The predicate -path is also supported by HP-UX find.
211
+ def path(pattern)
212
+ end
213
+
214
+ # -perm mode
215
+ #
216
+ # File's permission bits are exactly mode (octal or symbolic).
217
+ # Since an exact match is required, if you want to use this form
218
+ # for symbolic modes, you may have to specify a rather complex
219
+ # mode string. For example '-perm g=w' will only match files
220
+ # which have mode 0020 (that is, ones for which group write per-
221
+ # mission is the only permission set). It is more likely that you
222
+ # will want to use the '/' or '-' forms, for example '-perm -g=w',
223
+ # which matches any file with group write permission. See the
224
+ # EXAMPLES section for some illustrative examples.
225
+ #
226
+ # -perm -mode
227
+ #
228
+ # All of the permission bits mode are set for the file. Symbolic
229
+ # modes are accepted in this form, and this is usually the way in
230
+ # which would want to use them. You must specify 'u', 'g' or 'o'
231
+ # if you use a symbolic mode. See the EXAMPLES section for some
232
+ # illustrative examples.
233
+ #
234
+ # -perm /mode
235
+ #
236
+ # Any of the permission bits mode are set for the file. Symbolic
237
+ # modes are accepted in this form. You must specify 'u', 'g' or
238
+ # 'o' if you use a symbolic mode. See the EXAMPLES section for
239
+ # some illustrative examples. If no permission bits in mode are
240
+ # set, this test currently matches no files. However, it will
241
+ # soon be changed to match any file (the idea is to be more con-
242
+ # sistent with the behaviour of perm -000).
243
+ def perm(mode)
244
+ end
245
+
246
+ # File name matches regular expression pattern. This is a match
247
+ # on the whole path, not a search. For example, to match a file
248
+ # named './fubar3', you can use the regular expression '.*bar.' or
249
+ # '.*b.*3', but not 'f.*r3'. The regular expressions understood
250
+ # by find are by default Emacs Regular Expressions, but this can
251
+ # be changed with the -regextype option.
252
+ def regex(pattern)
253
+ end
254
+
255
+ # File refers to the same inode as name. When -L is in effect,
256
+ # this can include symbolic links.
257
+ def samefile(other)
258
+ end
259
+
260
+ # File uses n units of space. The following suffixes can be used:
261
+ #
262
+ # 'b' for 512-byte blocks (this is the default if no suffix is
263
+ # used)
264
+ #
265
+ # 'c' for bytes
266
+ #
267
+ # 'w' for two-byte words
268
+ #
269
+ # 'k' for Kilobytes (units of 1024 bytes)
270
+ #
271
+ # 'M' for Megabytes (units of 1048576 bytes)
272
+ #
273
+ # 'G' for Gigabytes (units of 1073741824 bytes)
274
+ #
275
+ # The size does not count indirect blocks, but it does count
276
+ # blocks in sparse files that are not actually allocated. Bear in
277
+ # mind that the '%k' and '%b' format specifiers of -printf handle
278
+ # sparse files differently. The 'b' suffix always denotes
279
+ # 512-byte blocks and never 1 Kilobyte blocks, which is different
280
+ # to the behaviour of -ls.
281
+ def size(n)
282
+ end
283
+
284
+ # Always true.
285
+ def true
286
+ end
287
+
288
+ # File is of type c:
289
+ #
290
+ # b block (buffered) special
291
+ # c character (unbuffered) special
292
+ # d directory
293
+ # p named pipe (FIFO)
294
+ # f regular file
295
+ # l symbolic link; this is never true if the -L option or the
296
+ # -follow option is in effect, unless the symbolic link is
297
+ # broken. If you want to search for symbolic links when -L
298
+ # is in effect, use -xtype.
299
+ # s socket
300
+ # D door (Solaris)
301
+ def type(c)
302
+ files.select! do |file|
303
+ case c.to_s
304
+ when 'f', 'file'
305
+ File.stat(file).file?
306
+ when 'd', 'dir', 'directory'
307
+ File.stat(file).directory?
308
+ else
309
+ false
310
+ end
311
+ end
312
+ end
313
+
314
+ # File's numeric user ID is n.
315
+ def uid(n)
316
+ files.select! do |file|
317
+ File.stat(file).uid == n.to_i
318
+ end
319
+ end
320
+
321
+ # File was last accessed n days after its status was last changed.
322
+ def used(n)
323
+ end
324
+
325
+ # File is owned by user uname (numeric user ID allowed).
326
+ def user(name)
327
+ files.select! do |file|
328
+ uid = File.stat(file).uid.to_i
329
+ Etc.getpwuid(uid).name == name
330
+ end
331
+ end
332
+
333
+ # File name matches shell pattern pattern. The metacharacters do
334
+ # not treat '/' or '.' specially; so, for example,
335
+ #
336
+ # find . -wholename './sr*sc'
337
+ #
338
+ # will print an entry for a directory called './src/misc' (if one
339
+ # exists). To ignore a whole directory tree, use -prune rather
340
+ # than checking every file in the tree. For example, to skip the
341
+ # directory 'src/emacs' and all files and directories under it,
342
+ # and print the names of the other files found, do something like
343
+ # this:
344
+ #
345
+ # find . -wholename './src/emacs' -prune -o -print
346
+ #
347
+ def wholename(pattern)
348
+ end
349
+
350
+ # The same as -type unless the file is a symbolic link. For sym-
351
+ # bolic links: if the -H or -P option was specified, true if the
352
+ # file is a link to a file of type c; if the -L option has been
353
+ # given, true if c is 'l'. In other words, for symbolic links,
354
+ # -xtype checks the type of the file that -type does not check.
355
+ def xtype(c)
356
+ end
357
+ end
@@ -0,0 +1,3 @@
1
+ module Fynd
2
+ VERSION = "0.1.0"
3
+ end
data/lib/fynd.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'active_support/all'
2
+
3
+ require 'fynd/version'
4
+
5
+ require 'fynd/actions'
6
+ require 'fynd/operators'
7
+ require 'fynd/tests'
8
+
9
+ require 'fynd/criteria'
10
+
11
+ module Fynd
12
+ ACTIONS = Fynd::Actions.instance_methods
13
+ OPERATORS = Fynd::Operators.instance_methods
14
+ TESTS = Fynd::Tests.instance_methods
15
+
16
+ extend self
17
+
18
+ def find(*paths)
19
+ Criteria.new(*paths)
20
+ end
21
+
22
+ end
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'spork'
3
+
4
+ Spork.prefork do
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'bundler'
8
+ Bundler.require
9
+
10
+ require 'rspec'
11
+ require 'timecop'
12
+ # require 'fakefs'
13
+ require 'fileutils'
14
+
15
+ require 'fynd'
16
+
17
+ RSpec.configure do |config|
18
+ config.before do
19
+ Timecop.freeze
20
+ # FakeFS.activate!
21
+ end
22
+ config.after do
23
+ Timecop.return
24
+ # FakeFS.deactivate!
25
+ end
26
+ end
27
+ end
28
+
29
+ Spork.each_run do
30
+ # This code will be run each time you run your specs.
31
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
32
+ end
33
+
34
+ # Crash loud in tests!
35
+ Thread.abort_on_exception = true
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fynd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Ryan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.8
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.8
30
+ description: I found GNU find to be slow, so I made it slower.
31
+ email:
32
+ - scriptfu@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - Guardfile
40
+ - LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - fynd.gemspec
44
+ - lib/fynd.rb
45
+ - lib/fynd/actions.rb
46
+ - lib/fynd/criteria.rb
47
+ - lib/fynd/helpers.rb
48
+ - lib/fynd/operators.rb
49
+ - lib/fynd/sieve.rb
50
+ - lib/fynd/tests.rb
51
+ - lib/fynd/version.rb
52
+ - spec/spec_helper.rb
53
+ homepage: ''
54
+ licenses: []
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ segments:
66
+ - 0
67
+ hash: -1732080129686787563
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ segments:
75
+ - 0
76
+ hash: -1732080129686787563
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.24
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: A pure Ruby re-implementation of GNU find.
83
+ test_files:
84
+ - spec/spec_helper.rb
85
+ has_rdoc: