fynd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.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: