fast_find 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9c5cd7c541e439cb4bd46acd6c28838e7867a369
4
- data.tar.gz: 827db02601353683fd17828a779f71d5a282f80c
2
+ SHA256:
3
+ metadata.gz: 84526cadc7a5aaedce296eafbef1df65c837fba29f0eca88a8510eb89d92a105
4
+ data.tar.gz: 74d015c6eea35d56091f2ad5a0c34bf68d59cb893e0eee2272228d83bcd2ce6b
5
5
  SHA512:
6
- metadata.gz: dd2cde72e12d19e762e9a6830f73c12024bab29cecdb7f439501627f0a4c306aafc7130bd2e3ac6344ea7e0b20b4c57c22510f2859cdfd5a2c37dc7935d93913
7
- data.tar.gz: af278abe2c42f33cb905e227c389a4a8c0d73aa5c4b30eb7f08b479159a21049e59ba1353776888c72ac1a7dbef1135931b7439060adc07b804f4fd5c8fbadec
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 performance-oriented multi-threaded alternative to the standard
4
- `Find` module that ships with Ruby. It should generally be a drop-in
5
- replacement.
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
- FastFind is expected to be marginally slower on MRI/YARV, since multithreaded
8
- `File#lstat` calls there appear to serialize. However, using the FastFind-
9
- specific second argument to pass in the `File::Stat` object for each file may
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
- gem 'fast_find', git: 'https://github.com/Freaky/fast_find.git'
15
+ ```shell
16
+ gem 'fast_find'
17
+ ```
19
18
 
20
19
  And then execute:
21
20
 
22
- $ bundle
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
- FastFind.find(dir) {|entry| frob(entry) }
29
- FastFind.find(dir, ignore_errors: false) { .. } # => explodes in your face
30
- FastFind.find(dir) # => Enumerator
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 instead).
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
- For increased performance and better scaling behaviour, it is recommended to use
38
- a single shared FastFind object. Multiple concurrent calls to
39
- `FastFind::Finder#find` are safe and will share a persistant work pool.
38
+ ```ruby
39
+ FastFind.find(dir) { |entry, stat| frob(entry, stat) }
40
+ ```
40
41
 
41
- Finder = FastFind::Finder.new
42
- Finder.find(dir) { .. }
42
+ `FastFind` uses a concurrent-ruby executor to run, which can be customised
43
+ by passing it as a named argument:
43
44
 
44
- You can call `Finder#shutdown` to close the work pool if you're done with the
45
- instance for the time being. Ensure no other calls to its `#find` are in flight
46
- beforehand. The pool is restarted the next time `#find` is called.
45
+ ```ruby
46
+ executor = Concurrent::FixedThreadPool.new(16, idletime: 90)
47
+ FastFind.find(dir, executor: executor)
48
+ ```
47
49
 
48
- Use the `concurrency` named argument to change the number of worker threads:
50
+ Or while no concurrent `find` operations are in progress, to the module itself:
49
51
 
50
- FastFind.find(dir, concurrency: 4)
51
- FastFind::Finder.new(concurrency: 4)
52
+ ```ruby
53
+ FastFind.default_executor = Concurrent::FixedThreadPool.new(16, idletime: 90)
54
+ ```
52
55
 
53
- Defaults are `8` for Rubinius and JRuby, `1` for anything else.
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
- Note the yielded blocks are all executed in the parent thread, *not* in workers.
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
- jruby 9.0.1.0-SNAPSHOT (2.2.2) 2015-07-23 e88911e OpenJDK 64-Bit Server VM
64
- 25.51-b03 on 1.8.0_51-b16 +jit [FreeBSD-amd64]:
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
- user system total real
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 2.2.2p95 (2015-04-13 revision 50295) [x86_64-freebsd10.1]:
77
+ ruby 3.0.0p0 (2020-12-25 revision 95aff21468) \[x86_64-freebsd12.2]:
71
78
 
72
- user system total real
73
- Find 10.187500 22.351562 32.539062 ( 32.545201)
74
- FastFind 9.039062 14.226562 23.265625 ( 23.277589)
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
- On MRI `Find` here is penalised because both `Find` and the benchmark code is
77
- performing a `File#lstat`.
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 "bundler/setup"
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: #{$0} [dir1 [dir2[ ..]]]") if test_dirs.empty?
11
+ abort("Usage: #{$PROGRAM_NAME} [dir1 [dir2[ ..]]]") if test_dirs.empty?
13
12
 
14
13
  Benchmark.bmbm do |b|
15
- b.report("Find") do
16
- files = Set.new
17
- Find.find(*test_dirs) do |f|
18
- files << [f, File.lstat(f)]
19
- end
20
- end
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
- b.report("FastFind") do
23
- files = Set.new
24
- FastFinder.find(*test_dirs) do |f, stat|
25
- files << [f, stat]
26
- end
27
- end
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{High performance 'find' alternative.}
13
- spec.description = %q{FastFind is a find workalike which optionally passes
14
- in the File::Stat to the block, and can use multile
15
- threads to walk directories concurrently.}
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.0"
32
+ spec.required_ruby_version = ">= 2.5"
33
33
 
34
- spec.add_development_dependency "bundler", "~> 1.9"
35
- spec.add_development_dependency "rake", "~> 10.0"
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
- require 'thread'
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
- DEFAULT_CONCURRENCY = %w(jruby rbx).include?(RUBY_ENGINE) ? 8 : 1
11
-
12
- def self.find(*paths, concurrency: DEFAULT_CONCURRENCY, ignore_error: true,
13
- &block)
14
- Finder.new(concurrency: concurrency, one_shot: true)
15
- .find(*paths, ignore_error: ignore_error, &block)
16
- end
17
-
18
- def self.prune
19
- throw :prune
20
- end
21
-
22
- class Finder
23
- def initialize(concurrency: DEFAULT_CONCURRENCY, one_shot: false)
24
- @mutex = Mutex.new
25
- @queue = Queue.new
26
- @one_shot = one_shot
27
- @concurrency = concurrency
28
- @walkers = nil
29
- end
30
-
31
- def startup
32
- @mutex.synchronize do
33
- return if @walkers
34
-
35
- @walkers = @concurrency.times.map { Walker.new.spawn(@queue) }
36
- end
37
- end
38
-
39
- def shutdown
40
- @mutex.synchronize do
41
- return unless @walkers
42
-
43
- @queue.clear
44
- @walkers.each { @queue << nil }
45
- @walkers.each(&:join)
46
-
47
- @walkers = nil
48
- end
49
- end
50
-
51
- def find(*paths, ignore_error: true, &block)
52
- block or return enum_for(__method__, *paths, ignore_error: ignore_error)
53
-
54
- results = Queue.new
55
- pending = Set.new
56
-
57
- startup
58
-
59
- paths.map!(&:dup).each do |path|
60
- path = path.to_path if path.respond_to? :to_path
61
- results << [path, Util.safe_stat(path)]
62
- end
63
- results << [:initial, :finished]
64
- pending << [:initial, :initial.encoding]
65
-
66
- while result = results.deq
67
- path, stat = result
68
-
69
- if stat == :finished
70
- pending.delete([path, path.encoding])
71
-
72
- if pending.empty?
73
- break
74
- else
75
- next
76
- end
77
- end
78
-
79
- catch(:prune) do
80
- yield_entry(result, block) if path.is_a? String
81
-
82
- case stat
83
- when Exception then raise stat unless ignore_error
84
- when File::Stat
85
- if stat.directory? and !pending.include?(pe = [path, path.encoding])
86
- pending << pe
87
- @queue << [path, results]
88
- end
89
- end
90
- end
91
- end
92
- ensure
93
- if one_shot?
94
- @queue.clear
95
- shutdown
96
- end
97
- end
98
-
99
- private
100
-
101
- def one_shot?() !!@one_shot end
102
-
103
- def yield_entry(entry, block)
104
- if block.arity == 2
105
- block.call(entry[0].dup.taint, entry[1])
106
- else
107
- block.call entry[0].dup.taint
108
- end
109
- end
110
- end
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FastFind
2
- VERSION = "0.1.1"
4
+ VERSION = '0.2.0'
3
5
  end
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.1.1
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: 2015-08-01 00:00:00.000000000 Z
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.9'
19
- name: bundler
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: '1.9'
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: '10.0'
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: '10.0'
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 find workalike which optionally passes
57
- in the File::Stat to the block, and can use multile
58
- threads to walk directories concurrently.
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.0'
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
- rubyforge_project:
98
- rubygems_version: 2.4.8
111
+ rubygems_version: 3.0.6
99
112
  signing_key:
100
113
  specification_version: 4
101
- summary: High performance 'find' alternative.
114
+ summary: Multi-threaded Find alternative.
102
115
  test_files: []
data/.travis.yml DELETED
@@ -1,3 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.2.2