fast_find 0.1.1 → 0.2.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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +17 -0
- data/README.md +55 -45
- data/bin/benchmark +37 -16
- data/fast_find.gemspec +10 -8
- data/lib/fast_find.rb +106 -152
- data/lib/fast_find/version.rb +3 -1
- metadata +30 -17
- data/.travis.yml +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 84526cadc7a5aaedce296eafbef1df65c837fba29f0eca88a8510eb89d92a105
|
4
|
+
data.tar.gz: 74d015c6eea35d56091f2ad5a0c34bf68d59cb893e0eee2272228d83bcd2ce6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0985c016e8df0f5cd0d1c1a4a7f8e0601c8f573345bbf5c10b1cf649affdc24b20a2b8ea045e4417f5e94b42c45245847b35b93e77b4d85bc15711d626c51931'
|
7
|
+
data.tar.gz: 5c866bc2cd95b4ad053a1c17069d67fe48e1895a8141724f56e1787e9ea632075150e43db26e4ed5c74ec56e172e596bb6cbcaa569e29816a8a4c2bf04b408a4
|
@@ -0,0 +1,17 @@
|
|
1
|
+
name: CI
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
strategy:
|
6
|
+
fail-fast: false
|
7
|
+
matrix:
|
8
|
+
os: [ubuntu-latest]
|
9
|
+
ruby: ['2.5', '2.6', '3.0', head, jruby, jruby-head, truffleruby]
|
10
|
+
runs-on: ${{ matrix.os }}
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
- uses: ruby/setup-ruby@v1
|
14
|
+
with:
|
15
|
+
ruby-version: ${{ matrix.ruby }}
|
16
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
17
|
+
- run: bundle exec rake test
|
data/README.md
CHANGED
@@ -1,80 +1,90 @@
|
|
1
1
|
# FastFind
|
2
2
|
|
3
|
-
FastFind is a
|
4
|
-
|
5
|
-
|
3
|
+
`FastFind` is a multi-threaded alternative to the standard `Find` module,
|
4
|
+
offering increased performance on Rubies which can run `Dir#entries` and
|
5
|
+
`File#lstat` calls concurrently (i.e. JRuby).
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
still prove a win.
|
11
|
-
|
12
|
-
This code is considered experimental. Beware of dog.
|
7
|
+
While it can operate as a drop-in replacement for `Find`, it's best used with
|
8
|
+
a two-argument block which also yields the `File::Stat` object associated with
|
9
|
+
each yielded path.
|
13
10
|
|
14
11
|
## Installation
|
15
12
|
|
16
13
|
Add this line to your application's Gemfile:
|
17
14
|
|
18
|
-
|
15
|
+
```shell
|
16
|
+
gem 'fast_find'
|
17
|
+
```
|
19
18
|
|
20
19
|
And then execute:
|
21
20
|
|
22
|
-
|
21
|
+
```shell
|
22
|
+
$ bundle
|
23
|
+
```
|
23
24
|
|
24
25
|
## Usage
|
25
26
|
|
26
|
-
Traditional Find-style:
|
27
|
+
Traditional Find-style (not recommended):
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
```ruby
|
30
|
+
FastFind.find(dir) { |entry| frob(entry) }
|
31
|
+
FastFind.find(dir, ignore_errors: false) { .. } # => explodes in your face
|
32
|
+
FastFind.find(dir) # => Enumerator
|
33
|
+
```
|
31
34
|
|
32
35
|
Extended style using the second argument to get a `File::Stat`, or `Exception`
|
33
|
-
object (if `ignore_errors` is false, this will be raised
|
34
|
-
|
35
|
-
FastFind.find(dir) {|entry, stat| frob(entry, stat) }
|
36
|
+
object (if `ignore_errors` is false, this will be raised after the block).
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
```ruby
|
39
|
+
FastFind.find(dir) { |entry, stat| frob(entry, stat) }
|
40
|
+
```
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
`FastFind` uses a concurrent-ruby executor to run, which can be customised
|
43
|
+
by passing it as a named argument:
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
```ruby
|
46
|
+
executor = Concurrent::FixedThreadPool.new(16, idletime: 90)
|
47
|
+
FastFind.find(dir, executor: executor)
|
48
|
+
```
|
47
49
|
|
48
|
-
|
50
|
+
Or while no concurrent `find` operations are in progress, to the module itself:
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
+
```ruby
|
53
|
+
FastFind.default_executor = Concurrent::FixedThreadPool.new(16, idletime: 90)
|
54
|
+
```
|
52
55
|
|
53
|
-
|
56
|
+
Due to the use of a bounded result queue it is *not* recommended to use an
|
57
|
+
executor with a bounded queue or which runs in the same thread as this may
|
58
|
+
result in deadlocks or dropped results.
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
`FastFind#prune` works. So does `Find#prune`.
|
60
|
+
As with `Find`, `FastFind#prune` will avoid recursing into a directory.
|
58
61
|
|
59
62
|
## Performance
|
60
63
|
|
61
|
-
Scanning a cached copy of the NetBSD CVS repository:
|
64
|
+
Scanning a cached copy of the NetBSD CVS repository wtih default settings:
|
65
|
+
|
66
|
+
jruby 9.2.14.0 (2.5.7) 2020-12-08 ebe64bafb9 OpenJDK 64-Bit Server VM 15.0.2+7-1 on 15.0.2+7-1 +jit:
|
62
67
|
|
63
|
-
|
64
|
-
|
68
|
+
```
|
69
|
+
user system total real
|
70
|
+
FastFind 22.296875 40.851562 63.148438 ( 8.014612)
|
71
|
+
Find 15.179688 28.031250 43.210938 ( 43.036654)
|
72
|
+
FastFind as Find 37.679688 44.375000 82.054688 ( 29.502235)
|
73
|
+
```
|
65
74
|
|
66
|
-
|
67
|
-
Find 32.890625 27.742188 60.632813 ( 47.518944)
|
68
|
-
FastFind 35.273438 41.742188 77.015625 ( 8.140893)
|
75
|
+
These results highlight the importance of the two-argument version.
|
69
76
|
|
70
|
-
ruby
|
77
|
+
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) \[x86_64-freebsd12.2]:
|
71
78
|
|
72
|
-
|
73
|
-
|
74
|
-
|
79
|
+
```
|
80
|
+
user system total real
|
81
|
+
FastFind 30.436830 29.265892 59.702722 ( 41.432262)
|
82
|
+
Find 10.346662 20.317705 30.664367 ( 30.666812)
|
83
|
+
FastFind as Find 28.300448 35.654871 63.955319 ( 39.212032)
|
84
|
+
```
|
75
85
|
|
76
|
-
|
77
|
-
|
86
|
+
Sadly the current implementation is a significant pessimisation on MRI, likely
|
87
|
+
due to thread overhead.
|
78
88
|
|
79
89
|
## Development
|
80
90
|
|
data/bin/benchmark
CHANGED
@@ -1,28 +1,49 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'find'
|
4
5
|
require 'benchmark'
|
5
6
|
|
6
|
-
require
|
7
|
+
require 'bundler/setup'
|
7
8
|
require 'fast_find'
|
8
9
|
|
9
|
-
FastFinder = FastFind::Finder.new
|
10
|
-
|
11
10
|
test_dirs = ARGV
|
12
|
-
abort("Usage: #{$
|
11
|
+
abort("Usage: #{$PROGRAM_NAME} [dir1 [dir2[ ..]]]") if test_dirs.empty?
|
13
12
|
|
14
13
|
Benchmark.bmbm do |b|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
b.report('FastFind') do
|
15
|
+
files = directories = 0
|
16
|
+
FastFind.find(*test_dirs) do |f, stat|
|
17
|
+
if stat.directory?
|
18
|
+
directories += 1
|
19
|
+
else
|
20
|
+
files += 1
|
21
|
+
end
|
22
|
+
# files << [f, stat]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
b.report('Find') do
|
27
|
+
files = directories = 0
|
28
|
+
Find.find(*test_dirs) do |f|
|
29
|
+
if File.directory?(f)
|
30
|
+
directories += 1
|
31
|
+
else
|
32
|
+
files += 1
|
33
|
+
end
|
34
|
+
# files << [f, File.lstat(f)]
|
35
|
+
end
|
36
|
+
end
|
21
37
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
38
|
+
b.report('FastFind as Find') do
|
39
|
+
files = directories = 0
|
40
|
+
FastFind.find(*test_dirs) do |f|
|
41
|
+
if File.directory?(f)
|
42
|
+
directories += 1
|
43
|
+
else
|
44
|
+
files += 1
|
45
|
+
end
|
46
|
+
# files << [f, File.lstat(f)]
|
47
|
+
end
|
48
|
+
end
|
28
49
|
end
|
data/fast_find.gemspec
CHANGED
@@ -9,10 +9,10 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Thomas Hurst"]
|
10
10
|
spec.email = ["tom@hur.st"]
|
11
11
|
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.description = %q{FastFind is a
|
14
|
-
|
15
|
-
|
12
|
+
spec.summary = %q{Multi-threaded Find alternative.}
|
13
|
+
spec.description = %q{FastFind is a high-performance Find alternative for
|
14
|
+
Ruby implementations with effective thread
|
15
|
+
concurrency, particularly JRuby.}
|
16
16
|
spec.homepage = "https://github.com/Freaky/fast_find"
|
17
17
|
spec.license = "MIT"
|
18
18
|
|
@@ -24,14 +24,16 @@ Gem::Specification.new do |spec|
|
|
24
24
|
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
25
25
|
end
|
26
26
|
|
27
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
27
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|\.git)/}) }
|
28
28
|
spec.bindir = "exe"
|
29
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
30
|
spec.require_paths = ["lib"]
|
31
31
|
|
32
|
-
spec.required_ruby_version = ">= 2.
|
32
|
+
spec.required_ruby_version = ">= 2.5"
|
33
33
|
|
34
|
-
spec.
|
35
|
-
|
34
|
+
spec.add_dependency "concurrent-ruby", "~> 1.1"
|
35
|
+
|
36
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
37
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
36
38
|
spec.add_development_dependency "minitest"
|
37
39
|
end
|
data/lib/fast_find.rb
CHANGED
@@ -1,158 +1,112 @@
|
|
1
|
-
#
|
2
|
-
# fast_find.rb: A Find workalike optimized for performance.
|
3
|
-
#
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
require 'set'
|
6
|
-
|
4
|
+
|
5
|
+
require 'concurrent'
|
6
|
+
|
7
7
|
require 'fast_find/version'
|
8
8
|
|
9
|
+
# A Find workalike optimized for multithreaded operation on supporting Rubies
|
9
10
|
module FastFind
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
class Walker
|
113
|
-
def spawn(queue)
|
114
|
-
Thread.new do
|
115
|
-
@encoding = Encoding.find("filesystem")
|
116
|
-
while job = queue.deq
|
117
|
-
walk(job[0], job[1])
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def walk(path, results)
|
123
|
-
enc = path.encoding == Encoding::US_ASCII ? @encoding : path.encoding
|
124
|
-
|
125
|
-
Dir.entries(path, encoding: enc).each do |entry|
|
126
|
-
next if entry == '.' or entry == '..'
|
127
|
-
|
128
|
-
stat(File.join(path, entry), results)
|
129
|
-
end
|
130
|
-
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP,
|
131
|
-
Errno::ENAMETOOLONG => e
|
132
|
-
error(e, results)
|
133
|
-
ensure
|
134
|
-
finish(path, results)
|
135
|
-
end
|
136
|
-
|
137
|
-
def stat(entry, results)
|
138
|
-
results << [entry, Util.safe_stat(entry)]
|
139
|
-
end
|
140
|
-
|
141
|
-
def finish(path, results)
|
142
|
-
results << [path, :finished]
|
143
|
-
end
|
144
|
-
|
145
|
-
def error(e, results)
|
146
|
-
results << [:exception, e]
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
module Util
|
151
|
-
def self.safe_stat(path)
|
152
|
-
File.lstat(path)
|
153
|
-
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP,
|
154
|
-
Errno::ENAMETOOLONG => e
|
155
|
-
e
|
156
|
-
end
|
157
|
-
end
|
11
|
+
class << self
|
12
|
+
attr_accessor :default_executor
|
13
|
+
|
14
|
+
def prune
|
15
|
+
throw :prune
|
16
|
+
end
|
17
|
+
|
18
|
+
def find(*paths, ignore_error: true, executor: default_executor, &block)
|
19
|
+
block or return enum_for(__method__, *paths, ignore_error: ignore_error, executor: executor)
|
20
|
+
|
21
|
+
results = SizedQueue.new(1024)
|
22
|
+
pending = Set.new
|
23
|
+
|
24
|
+
paths.map!(&:dup).each do |path|
|
25
|
+
path = path.to_path if path.respond_to? :to_path
|
26
|
+
results << [path, safe_stat(path)]
|
27
|
+
end
|
28
|
+
results << %i[initial finished]
|
29
|
+
pending << path_signature(:initial)
|
30
|
+
|
31
|
+
while (result = results.deq)
|
32
|
+
path, stat = result
|
33
|
+
|
34
|
+
if stat == :finished
|
35
|
+
break if pending.delete(path_signature(path)).empty?
|
36
|
+
|
37
|
+
next
|
38
|
+
end
|
39
|
+
|
40
|
+
catch(:prune) do
|
41
|
+
yield_entry(result, block) if path.is_a? String
|
42
|
+
|
43
|
+
if stat.is_a?(File::Stat) && stat.directory? && pending.add?(path_signature(path))
|
44
|
+
executor.post(path, results) do |path_, results_|
|
45
|
+
walk(path_, results_)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
raise stat if stat.is_a?(Exception) && !ignore_error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
FS_ENCODING = Encoding.find('filesystem')
|
57
|
+
|
58
|
+
def walk(path, results)
|
59
|
+
enc = path.encoding == Encoding::US_ASCII ? FS_ENCODING : path.encoding
|
60
|
+
|
61
|
+
# This benchmarks as about 10% faster than Dirs.foreach
|
62
|
+
Dir.entries(path, encoding: enc).each do |entry|
|
63
|
+
next if (entry == '.') || (entry == '..')
|
64
|
+
|
65
|
+
results << stat(File.join(path, entry))
|
66
|
+
end
|
67
|
+
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP,
|
68
|
+
Errno::ENAMETOOLONG => e
|
69
|
+
results << error(e)
|
70
|
+
ensure
|
71
|
+
results << finish(path)
|
72
|
+
end
|
73
|
+
|
74
|
+
def stat(entry)
|
75
|
+
[entry, safe_stat(entry)]
|
76
|
+
end
|
77
|
+
|
78
|
+
def finish(path)
|
79
|
+
[path, :finished]
|
80
|
+
end
|
81
|
+
|
82
|
+
def error(e)
|
83
|
+
[:exception, e]
|
84
|
+
end
|
85
|
+
|
86
|
+
def path_signature(path)
|
87
|
+
[path, path.encoding]
|
88
|
+
end
|
89
|
+
|
90
|
+
def yield_entry(entry, block)
|
91
|
+
if block.arity == 2
|
92
|
+
block.call(entry[0].dup, entry[1])
|
93
|
+
else
|
94
|
+
block.call entry[0].dup
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def safe_stat(path)
|
99
|
+
File.lstat(path)
|
100
|
+
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP,
|
101
|
+
Errno::ENAMETOOLONG => e
|
102
|
+
e
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
self.default_executor = case RUBY_ENGINE
|
107
|
+
when 'jruby', 'rbx'
|
108
|
+
Concurrent::FixedThreadPool.new(8, idletime: 60)
|
109
|
+
else
|
110
|
+
Concurrent::FixedThreadPool.new(1, idletime: 60)
|
111
|
+
end
|
158
112
|
end
|
data/lib/fast_find/version.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_find
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Hurst
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
16
|
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '1.
|
19
|
-
name:
|
18
|
+
version: '1.1'
|
19
|
+
name: concurrent-ruby
|
20
|
+
type: :runtime
|
20
21
|
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
33
|
+
name: bundler
|
21
34
|
type: :development
|
35
|
+
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
40
|
+
version: '2.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
29
43
|
requirements:
|
30
44
|
- - "~>"
|
31
45
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
46
|
+
version: '13.0'
|
33
47
|
name: rake
|
34
|
-
prerelease: false
|
35
48
|
type: :development
|
49
|
+
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
54
|
+
version: '13.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
43
57
|
requirements:
|
@@ -45,25 +59,25 @@ dependencies:
|
|
45
59
|
- !ruby/object:Gem::Version
|
46
60
|
version: '0'
|
47
61
|
name: minitest
|
48
|
-
prerelease: false
|
49
62
|
type: :development
|
63
|
+
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
55
69
|
description: |-
|
56
|
-
FastFind is a
|
57
|
-
|
58
|
-
|
70
|
+
FastFind is a high-performance Find alternative for
|
71
|
+
Ruby implementations with effective thread
|
72
|
+
concurrency, particularly JRuby.
|
59
73
|
email:
|
60
74
|
- tom@hur.st
|
61
75
|
executables: []
|
62
76
|
extensions: []
|
63
77
|
extra_rdoc_files: []
|
64
78
|
files:
|
79
|
+
- ".github/workflows/ci.yml"
|
65
80
|
- ".gitignore"
|
66
|
-
- ".travis.yml"
|
67
81
|
- Gemfile
|
68
82
|
- LICENSE.txt
|
69
83
|
- README.md
|
@@ -87,16 +101,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
101
|
requirements:
|
88
102
|
- - ">="
|
89
103
|
- !ruby/object:Gem::Version
|
90
|
-
version: '2.
|
104
|
+
version: '2.5'
|
91
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
107
|
- - ">="
|
94
108
|
- !ruby/object:Gem::Version
|
95
109
|
version: '0'
|
96
110
|
requirements: []
|
97
|
-
|
98
|
-
rubygems_version: 2.4.8
|
111
|
+
rubygems_version: 3.0.6
|
99
112
|
signing_key:
|
100
113
|
specification_version: 4
|
101
|
-
summary:
|
114
|
+
summary: Multi-threaded Find alternative.
|
102
115
|
test_files: []
|
data/.travis.yml
DELETED