timers 4.3.0 → 4.3.2

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
2
  SHA256:
3
- metadata.gz: ccf7aa14dc18086e3a47fb44eb3a12569ba6752e6f7d22aecf7486684a594331
4
- data.tar.gz: 0c37cdab96fc3ae8a1fbd0deb07b69800260b32118c7d1b37d2a4114258c32e8
3
+ metadata.gz: 52ef1e26aab6a7bbbf5c9d687028bdc36f52810dd7ebc0c76873b6bef9f30ca2
4
+ data.tar.gz: 26105fe04a6d2bfcdf9efb46ebd83d9562a08af3c2f113892a8be57713be6112
5
5
  SHA512:
6
- metadata.gz: dcb1826464d594d78d0a67bf18f89bb3137ffdbdcb36306176bbaa961aab387b93442c4827f5a8e331b90de056dbc9f9f63dbdeb22671dcdd35203741f415967
7
- data.tar.gz: 43dcaccab4fab882ca498ec196f08d47beb2636044b62103640406e5a0411d1eb6d837363eae50266c11642a59880179eca6a9f4053aefab1b4daf11a28319bd
6
+ metadata.gz: 2a3ae0e0d9644627fef3aeffdfde86456d74c28ab89194486743fee2a25e8832c5aafb05f88174f6ee27d4f9402e05b4f80776c49cc34d70da527e63f9097685
7
+ data.tar.gz: 1f30b97aa11f6f42b3ce1786ae42f06334a86064306601635774b8d84cc88df765e8312a455798984520d44e3db35f8094fb23ec35cb736eb2191bfa27dece0c
@@ -1,11 +1,26 @@
1
1
  # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
2
 
8
- require "timers/version"
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
9
22
 
10
- require "timers/group"
11
- require "timers/wait"
23
+ require_relative "timers/version"
24
+
25
+ require_relative "timers/group"
26
+ require_relative "timers/wait"
@@ -1,9 +1,24 @@
1
1
  # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
7
22
 
8
23
  require_relative "timer"
9
24
 
@@ -1,9 +1,24 @@
1
1
  # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
7
22
 
8
23
  require "set"
9
24
  require "forwardable"
@@ -1,9 +1,24 @@
1
1
  # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
7
22
 
8
23
  module Timers
9
24
  # A collection of timers which may fire at different times
@@ -1,9 +1,24 @@
1
1
  # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
7
22
 
8
23
  module Timers
9
24
  # An individual timer set to fire a given proc at a given time. A timer is
@@ -1,10 +1,25 @@
1
1
  # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
7
22
 
8
23
  module Timers
9
- VERSION = "4.3.0"
24
+ VERSION = "4.3.2"
10
25
  end
@@ -1,9 +1,24 @@
1
1
  # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
7
22
 
8
23
  require_relative "interval"
9
24
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timers
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 4.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  - Tony Arcieri
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-21 00:00:00.000000000 Z
12
+ date: 2020-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -26,49 +26,39 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
- name: rspec
29
+ name: covered
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '3.6'
34
+ version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '3.6'
41
+ version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
- name: rake
43
+ name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ">="
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '0'
48
+ version: '3.0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ">="
53
+ - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: '0'
56
- description: Schedule procs to run after a certain time, or at periodic intervals,
57
- using any API that accepts a timeout.
55
+ version: '3.0'
56
+ description:
58
57
  email:
59
- - samuel@codeotaku.com
60
- - bascule@gmail.com
61
58
  executables: []
62
59
  extensions: []
63
60
  extra_rdoc_files: []
64
61
  files:
65
- - ".editorconfig"
66
- - ".gitignore"
67
- - ".rspec"
68
- - ".travis.yml"
69
- - Gemfile
70
- - README.md
71
- - Rakefile
72
62
  - lib/timers.rb
73
63
  - lib/timers/events.rb
74
64
  - lib/timers/group.rb
@@ -76,20 +66,11 @@ files:
76
66
  - lib/timers/timer.rb
77
67
  - lib/timers/version.rb
78
68
  - lib/timers/wait.rb
79
- - spec/spec_helper.rb
80
- - spec/timers/cancel_spec.rb
81
- - spec/timers/events_spec.rb
82
- - spec/timers/every_spec.rb
83
- - spec/timers/group_spec.rb
84
- - spec/timers/performance_spec.rb
85
- - spec/timers/strict_spec.rb
86
- - spec/timers/wait_spec.rb
87
- - timers.gemspec
88
69
  homepage: https://github.com/socketry/timers
89
70
  licenses:
90
71
  - MIT
91
72
  metadata: {}
92
- post_install_message:
73
+ post_install_message:
93
74
  rdoc_options: []
94
75
  require_paths:
95
76
  - lib
@@ -97,23 +78,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
78
  requirements:
98
79
  - - ">="
99
80
  - !ruby/object:Gem::Version
100
- version: 2.2.1
81
+ version: '0'
101
82
  required_rubygems_version: !ruby/object:Gem::Requirement
102
83
  requirements:
103
84
  - - ">="
104
85
  - !ruby/object:Gem::Version
105
86
  version: '0'
106
87
  requirements: []
107
- rubygems_version: 3.0.1
108
- signing_key:
88
+ rubygems_version: 3.1.2
89
+ signing_key:
109
90
  specification_version: 4
110
- summary: Pure Ruby one-shot and periodic timers
111
- test_files:
112
- - spec/spec_helper.rb
113
- - spec/timers/cancel_spec.rb
114
- - spec/timers/events_spec.rb
115
- - spec/timers/every_spec.rb
116
- - spec/timers/group_spec.rb
117
- - spec/timers/performance_spec.rb
118
- - spec/timers/strict_spec.rb
119
- - spec/timers/wait_spec.rb
91
+ summary: Pure Ruby one-shot and periodic timers.
92
+ test_files: []
@@ -1,6 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = tab
5
- indent_size = 2
6
-
data/.gitignore DELETED
@@ -1,17 +0,0 @@
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/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --warnings
3
- --require spec_helper
@@ -1,20 +0,0 @@
1
- language: ruby
2
- dist: xenial
3
- cache: bundler
4
-
5
- matrix:
6
- include:
7
- - rvm: 2.3
8
- - rvm: 2.4
9
- - rvm: 2.5
10
- - rvm: 2.6
11
- - rvm: jruby-head
12
- env: JRUBY_OPTS="--debug -X+O"
13
- - rvm: truffleruby
14
- - rvm: ruby-head
15
- - rvm: rbx-3
16
- allow_failures:
17
- - rvm: ruby-head
18
- - rvm: jruby-head
19
- - rvm: rbx-3
20
- - rvm: truffleruby
data/Gemfile DELETED
@@ -1,15 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :development do
6
- gem 'pry'
7
- end
8
-
9
- group :test do
10
- gem 'benchmark-ips'
11
-
12
- gem "ruby-prof", platform: :mri
13
- gem 'simplecov', platform: :mri
14
- gem 'coveralls', platform: :mri
15
- end
data/README.md DELETED
@@ -1,149 +0,0 @@
1
- # Timers
2
-
3
- Collections of one-shot and periodic timers, intended for use with event loops such as [async].
4
-
5
- [![Build Status](https://secure.travis-ci.org/socketry/timers.svg)](https://travis-ci.org/socketry/timers)
6
- [![Code Climate](https://codeclimate.com/github/socketry/timers.svg)](https://codeclimate.com/github/socketry/timers)
7
- [![Coverage Status](https://coveralls.io/repos/socketry/timers/badge.svg)](https://coveralls.io/r/socketry/timers)
8
-
9
- [async]: https://github.com/socketry/async
10
-
11
- ## Installation
12
-
13
- Add this line to your application's Gemfile:
14
-
15
- ```ruby
16
- gem 'timers'
17
- ```
18
-
19
- And then execute:
20
-
21
- $ bundle
22
-
23
- Or install it yourself as:
24
-
25
- $ gem install timers
26
-
27
- ## Usage
28
-
29
- Create a new timer group with `Timers::Group.new`:
30
-
31
- ```ruby
32
- require 'timers'
33
-
34
- timers = Timers::Group.new
35
- ```
36
-
37
- Schedule a proc to run after 5 seconds with `Timers::Group#after`:
38
-
39
- ```ruby
40
- five_second_timer = timers.after(5) { puts "Take five" }
41
- ```
42
-
43
- The `five_second_timer` variable is now bound to a Timers::Timer object. To
44
- cancel a timer, use `Timers::Timer#cancel`
45
-
46
- Once you've scheduled a timer, you can wait until the next timer fires with `Timers::Group#wait`:
47
-
48
- ```ruby
49
- # Waits 5 seconds
50
- timers.wait
51
-
52
- # The script will now print "Take five"
53
- ```
54
-
55
- You can schedule a block to run periodically with `Timers::Group#every`:
56
-
57
- ```ruby
58
- every_five_seconds = timers.every(5) { puts "Another 5 seconds" }
59
-
60
- loop { timers.wait }
61
- ```
62
-
63
- You can also schedule a block to run immediately and periodically with `Timers::Group#now_and_every`:
64
- ```ruby
65
- now_and_every_five_seconds = timers.now_and_every(5) { puts "Now and in another 5 seconds" }
66
-
67
- loop { timers.wait }
68
- ```
69
-
70
- If you'd like another method to do the waiting for you, e.g. `Kernel.select`,
71
- you can use `Timers::Group#wait_interval` to obtain the amount of time to wait. When
72
- a timeout is encountered, you can fire all pending timers with `Timers::Group#fire`:
73
-
74
- ```ruby
75
- loop do
76
- interval = timers.wait_interval
77
- ready_readers, ready_writers = select readers, writers, nil, interval
78
-
79
- if ready_readers || ready_writers
80
- # Handle IO
81
- ...
82
- else
83
- # Timeout!
84
- timers.fire
85
- end
86
- end
87
- ```
88
-
89
- You can also pause and continue individual timers, or all timers:
90
-
91
- ```ruby
92
- paused_timer = timers.every(5) { puts "I was paused" }
93
-
94
- paused_timer.pause
95
- 10.times { timers.wait } # will not fire paused timer
96
-
97
- paused_timer.resume
98
- 10.times { timers.wait } # will fire timer
99
-
100
- timers.pause
101
- 10.times { timers.wait } # will not fire any timers
102
-
103
- timers.resume
104
- 10.times { timers.wait } # will fire all timers
105
- ```
106
-
107
- ## Contributing
108
-
109
- 1. Fork it
110
- 2. Create your feature branch (`git checkout -b my-new-feature`)
111
- 3. Commit your changes (`git commit -am 'Add some feature'`)
112
- 4. Push to the branch (`git push origin my-new-feature`)
113
- 5. Create new Pull Request
114
-
115
- ## License
116
-
117
- Released under the MIT license.
118
-
119
- Copyright, 2018, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
120
- Copyright, 2016, by [Tony Arcieri](bascule@gmail.com).
121
- Copyright, 2016, by Jeremy Hinegardner.
122
- Copyright, 2016, by Sean Gregory.
123
- Copyright, 2016, by Chuck Remes.
124
- Copyright, 2016, by Utenmiki.
125
- Copyright, 2016, by Ron Evans.
126
- Copyright, 2016, by Larry Lv.
127
- Copyright, 2016, by Bruno Enten.
128
- Copyright, 2016, by Jesse Cooke.
129
- Copyright, 2016, by Nicholas Evans.
130
- Copyright, 2016, by Dimitrij Denissenko.
131
- Copyright, 2016, by Ryan LeCompte.
132
-
133
- Permission is hereby granted, free of charge, to any person obtaining a copy
134
- of this software and associated documentation files (the "Software"), to deal
135
- in the Software without restriction, including without limitation the rights
136
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
137
- copies of the Software, and to permit persons to whom the Software is
138
- furnished to do so, subject to the following conditions:
139
-
140
- The above copyright notice and this permission notice shall be included in
141
- all copies or substantial portions of the Software.
142
-
143
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
144
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
145
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
146
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
147
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
148
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
149
- THE SOFTWARE.
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:test)
5
-
6
- task :default => :test
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- # Level of accuracy enforced by tests (50ms)
9
- TIMER_QUANTUM = 0.05
10
-
11
- if ENV['COVERAGE'] || ENV['TRAVIS']
12
- begin
13
- require 'simplecov'
14
-
15
- SimpleCov.start do
16
- add_filter "/spec/"
17
- end
18
-
19
- if ENV['TRAVIS']
20
- require 'coveralls'
21
- Coveralls.wear!
22
- end
23
- rescue LoadError
24
- warn "Could not load simplecov: #{$!}"
25
- end
26
- end
27
-
28
- require 'bundler/setup'
29
- Bundler.require(:test)
30
-
31
- require 'timers'
32
-
33
- RSpec.configure do |config|
34
- # Enable flags like --only-failures and --next-failure
35
- config.example_status_persistence_file_path = ".rspec_status"
36
-
37
- config.expect_with :rspec do |c|
38
- c.syntax = :expect
39
- end
40
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- RSpec.describe Timers::Group do
9
- it "should be able to cancel twice" do
10
- fired = false
11
-
12
- timer = subject.after(0.1) { fired = true }
13
-
14
- 2.times do
15
- timer.cancel
16
- subject.wait
17
- end
18
-
19
- expect(fired).to be false
20
- end
21
-
22
- it "should be possble to reset after cancel" do
23
- fired = false
24
-
25
- timer = subject.after(0.1) { fired = true }
26
- timer.cancel
27
-
28
- subject.wait
29
-
30
- timer.reset
31
-
32
- subject.wait
33
-
34
- expect(fired).to be true
35
- end
36
-
37
- it "should cancel and remove one shot timers after they fire" do
38
- x = 0
39
-
40
- Timers::Wait.for(2) do |_remaining|
41
- timer = subject.every(0.2) { x += 1 }
42
- subject.after(0.1) { timer.cancel }
43
-
44
- subject.wait
45
- end
46
-
47
- expect(subject.timers).to be_empty
48
- expect(x).to be == 0
49
- end
50
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- RSpec.describe Timers::Events do
9
- it "should register an event" do
10
- fired = false
11
-
12
- callback = proc do |_time|
13
- fired = true
14
- end
15
-
16
- subject.schedule(0.1, callback)
17
-
18
- expect(subject.size).to be == 1
19
-
20
- subject.fire(0.15)
21
-
22
- expect(subject.size).to be == 0
23
-
24
- expect(fired).to be true
25
- end
26
-
27
- it "should register events in order" do
28
- fired = []
29
-
30
- times = [0.95, 0.1, 0.3, 0.5, 0.4, 0.2, 0.01, 0.9]
31
-
32
- times.each do |requested_time|
33
- callback = proc do |_time|
34
- fired << requested_time
35
- end
36
-
37
- subject.schedule(requested_time, callback)
38
- end
39
-
40
- subject.fire(0.5)
41
- expect(fired).to be == times.sort.first(6)
42
-
43
- subject.fire(1.0)
44
- expect(fired).to be == times.sort
45
- end
46
-
47
- it "should fire events with the time they were fired at" do
48
- fired_at = :not_fired
49
-
50
- callback = proc do |time|
51
- # The time we actually were fired at:
52
- fired_at = time
53
- end
54
-
55
- subject.schedule(0.5, callback)
56
-
57
- subject.fire(1.0)
58
-
59
- expect(fired_at).to be == 1.0
60
- end
61
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- RSpec.describe Timers::Group do
9
- it "should fire several times" do
10
- result = []
11
-
12
- subject.every(0.7) { result << :a }
13
- subject.every(2.3) { result << :b }
14
- subject.every(1.3) { result << :c }
15
- subject.every(2.4) { result << :d }
16
-
17
- Timers::Wait.for(2.5) do |remaining|
18
- subject.wait if subject.wait_interval < remaining
19
- end
20
-
21
- expect(result).to be == [:a, :c, :a, :a, :b, :d]
22
- end
23
-
24
- it "should fire immediately and then several times later" do
25
- result = []
26
-
27
- subject.every(0.7) { result << :a }
28
- subject.every(2.3) { result << :b }
29
- subject.now_and_every(1.3) { result << :c }
30
- subject.now_and_every(2.4) { result << :d }
31
-
32
- Timers::Wait.for(2.5) do |remaining|
33
- subject.wait if subject.wait_interval < remaining
34
- end
35
-
36
- expect(result).to be == [:c, :d, :a, :c, :a, :a, :b, :d]
37
- end
38
- end
@@ -1,260 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- RSpec.describe Timers::Group do
9
- describe "#wait" do
10
- it "calls the wait block with nil" do
11
- called = false
12
-
13
- subject.wait do |interval|
14
- expect(interval).to be_nil
15
- called = true
16
- end
17
-
18
- expect(called).to be true
19
- end
20
-
21
- it "calls the wait block with an interval" do
22
- called = false
23
- fired = false
24
-
25
- subject.after(0.1) { fired = true }
26
-
27
- subject.wait do |interval|
28
- expect(interval).to be_within(TIMER_QUANTUM).of(0.1)
29
- called = true
30
- sleep 0.2
31
- end
32
-
33
- expect(called).to be true
34
- expect(fired).to be true
35
- end
36
- end
37
-
38
- it "sleeps until the next timer" do
39
- interval = TIMER_QUANTUM * 2
40
- started_at = Time.now
41
-
42
- fired = false
43
- subject.after(interval) { fired = true }
44
- subject.wait
45
-
46
- expect(fired).to be true
47
- expect(Time.now - started_at).to be_within(TIMER_QUANTUM).of interval
48
- end
49
-
50
- it "fires instantly when next timer is in the past" do
51
- fired = false
52
- subject.after(TIMER_QUANTUM) { fired = true }
53
- sleep(TIMER_QUANTUM * 2)
54
- subject.wait
55
-
56
- expect(fired).to be true
57
- end
58
-
59
- it "calculates the interval until the next timer should fire" do
60
- interval = 0.1
61
-
62
- subject.after(interval)
63
- expect(subject.wait_interval).to be_within(TIMER_QUANTUM).of interval
64
-
65
- sleep(interval)
66
- expect(subject.wait_interval).to be <= 0
67
- end
68
-
69
- it "fires timers in the correct order" do
70
- result = []
71
-
72
- subject.after(TIMER_QUANTUM * 2) { result << :two }
73
- subject.after(TIMER_QUANTUM * 3) { result << :three }
74
- subject.after(TIMER_QUANTUM * 1) { result << :one }
75
-
76
- sleep TIMER_QUANTUM * 4
77
- subject.fire
78
-
79
- expect(result).to eq [:one, :two, :three]
80
- end
81
-
82
- it "raises TypeError if given an invalid time" do
83
- expect do
84
- subject.after(nil) { nil }
85
- end.to raise_exception(TypeError)
86
- end
87
-
88
- describe "recurring timers" do
89
- it "continues to fire the timers at each interval" do
90
- result = []
91
-
92
- subject.every(TIMER_QUANTUM * 2) { result << :foo }
93
-
94
- sleep TIMER_QUANTUM * 3
95
- subject.fire
96
- expect(result).to eq [:foo]
97
-
98
- sleep TIMER_QUANTUM * 5
99
- subject.fire
100
- expect(result).to eq [:foo, :foo]
101
- end
102
- end
103
-
104
- it "calculates the proper interval to wait until firing" do
105
- interval_ms = 25
106
-
107
- subject.after(interval_ms / 1000.0)
108
-
109
- expect(subject.wait_interval).to be_within(TIMER_QUANTUM).of(interval_ms / 1000.0)
110
- end
111
-
112
- describe "pause and continue timers" do
113
- before(:each) do
114
- @interval = TIMER_QUANTUM * 2
115
-
116
- @fired = false
117
- @timer = subject.after(@interval) { @fired = true }
118
- @fired2 = false
119
- @timer2 = subject.after(@interval) { @fired2 = true }
120
- end
121
-
122
- it "does not fire when paused" do
123
- @timer.pause
124
- subject.wait
125
- expect(@fired).to be false
126
- end
127
-
128
- it "fires when continued after pause" do
129
- @timer.pause
130
- subject.wait
131
- @timer.resume
132
-
133
- sleep @timer.interval
134
- subject.wait
135
-
136
- expect(@fired).to be true
137
- end
138
-
139
- it "can pause all timers at once" do
140
- subject.pause
141
- subject.wait
142
- expect(@fired).to be false
143
- expect(@fired2).to be false
144
- end
145
-
146
- it "can continue all timers at once" do
147
- subject.pause
148
- subject.wait
149
- subject.resume
150
-
151
- # We need to wait until we are sure both timers will fire, otherwise highly accurate clocks
152
- # (e.g. JVM)may only fire the first timer, but not the second, because they are actually
153
- # schedueled at different times.
154
- sleep TIMER_QUANTUM * 2
155
- subject.wait
156
-
157
- expect(@fired).to be true
158
- expect(@fired2).to be true
159
- end
160
-
161
- it "can fire the timer directly" do
162
- fired = false
163
- timer = subject.after(TIMER_QUANTUM * 1) { fired = true }
164
- timer.pause
165
- subject.wait
166
- expect(fired).not_to be true
167
- timer.resume
168
- expect(fired).not_to be true
169
- timer.fire
170
- expect(fired).to be true
171
- end
172
- end
173
-
174
- describe "delay timer" do
175
- it "adds appropriate amount of time to timer" do
176
- timer = subject.after(10)
177
- timer.delay(5)
178
- expect(timer.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(15)
179
- end
180
- end
181
-
182
- describe "delay timer collection" do
183
- it "delay on set adds appropriate amount of time to all timers" do
184
- timer = subject.after(10)
185
- timer2 = subject.after(20)
186
- subject.delay(5)
187
- expect(timer.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(15)
188
- expect(timer2.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(25)
189
- end
190
- end
191
-
192
- describe "on delaying a timer" do
193
- it "fires timers in the correct order" do
194
- result = []
195
-
196
- subject.after(TIMER_QUANTUM * 2) { result << :two }
197
- subject.after(TIMER_QUANTUM * 3) { result << :three }
198
- first = subject.after(TIMER_QUANTUM * 1) { result << :one }
199
- first.delay(TIMER_QUANTUM * 3)
200
-
201
- sleep TIMER_QUANTUM * 5
202
- subject.fire
203
-
204
- expect(result).to eq [:two, :three, :one]
205
- end
206
- end
207
-
208
- describe "#inspect" do
209
- it "before firing" do
210
- fired = false
211
- timer = subject.after(TIMER_QUANTUM * 5) { fired = true }
212
- timer.pause
213
- expect(fired).not_to be true
214
- expect(timer.inspect).to match(/\A#<Timers::Timer:0x[\da-f]+ fires in [-\.\de]+ seconds>\Z/)
215
- end
216
-
217
- it "after firing" do
218
- fired = false
219
- timer = subject.after(TIMER_QUANTUM) { fired = true }
220
-
221
- subject.wait
222
-
223
- expect(fired).to be true
224
- expect(timer.inspect).to match(/\A#<Timers::Timer:0x[\da-f]+ fired [-\.\de]+ seconds ago>\Z/)
225
- end
226
-
227
- it "recurring firing" do
228
- result = []
229
- timer = subject.every(TIMER_QUANTUM) { result << :foo }
230
-
231
- subject.wait
232
- expect(result).not_to be_empty
233
- regex = /\A#<Timers::Timer:0x[\da-f]+ fires in [-\.\de]+ seconds, recurs every #{format("%0.2f", TIMER_QUANTUM)}>\Z/
234
- expect(timer.inspect).to match(regex)
235
- end
236
- end
237
-
238
- describe "#fires_in" do
239
- let(:interval) { TIMER_QUANTUM * 2 }
240
-
241
- it "calculates the interval until the next fire if it's recurring" do
242
- timer = subject.every(interval) { true }
243
- expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(interval)
244
- end
245
-
246
- context "when timer is not recurring" do
247
- let!(:timer) { subject.after(interval) { true } }
248
-
249
- it "calculates the interval until the next fire if it hasn't already fired" do
250
- expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(interval)
251
- end
252
-
253
- it "calculates the interval since last fire if already fired" do
254
- subject.wait
255
- sleep(interval)
256
- expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(0 - interval)
257
- end
258
- end
259
- end
260
- end
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- require "spec_helper"
9
-
10
- # Event based timers:
11
-
12
- # Serviced 31812 events in 2.39075272 seconds, 13306.320832794887 e/s.
13
- # Thread ID: 7336700
14
- # Fiber ID: 30106340
15
- # Total: 2.384043
16
- # Sort by: self_time
17
-
18
- # %self total self wait child calls name
19
- # 13.48 0.510 0.321 0.000 0.189 369133 Timers::Events::Handle#<=>
20
- # 8.12 0.194 0.194 0.000 0.000 427278 Timers::Events::Handle#to_f
21
- # 4.55 0.109 0.109 0.000 0.000 427278 Float#<=>
22
- # 4.40 1.857 0.105 0.000 1.752 466376 *Timers::Events#bsearch
23
- # 4.30 0.103 0.103 0.000 0.000 402945 Float#to_f
24
- # 2.65 0.063 0.063 0.000 0.000 33812 Array#insert
25
- # 2.64 1.850 0.063 0.000 1.787 33812 Timers::Events#schedule
26
- # 2.40 1.930 0.057 0.000 1.873 33812 Timers::Timer#reset
27
- # 1.89 1.894 0.045 0.000 1.849 31812 Timers::Timer#fire
28
- # 1.69 1.966 0.040 0.000 1.926 31812 Timers::Events::Handle#fire
29
- # 1.35 0.040 0.032 0.000 0.008 33812 Timers::Events::Handle#initialize
30
- # 1.29 0.044 0.031 0.000 0.013 44451 Timers::Group#current_offset
31
-
32
- # SortedSet based timers:
33
-
34
- # Serviced 32516 events in 66.753277275 seconds, 487.1072288781219 e/s.
35
- # Thread ID: 15995640
36
- # Fiber ID: 38731780
37
- # Total: 66.716394
38
- # Sort by: self_time
39
-
40
- # %self total self wait child calls name
41
- # 54.73 49.718 36.513 0.000 13.205 57084873 Timers::Timer#<=>
42
- # 23.74 65.559 15.841 0.000 49.718 32534 Array#sort!
43
- # 19.79 13.205 13.205 0.000 0.000 57084873 Float#<=>
44
-
45
- # Max out events performance (on my computer):
46
- # Serviced 1142649 events in 11.194903921 seconds, 102068.70405115146 e/s.
47
-
48
- RSpec.describe Timers::Group do
49
- context "with profiler" do
50
- if defined? RubyProf
51
- before(:each) do
52
- # Running RubyProf makes the code slightly slower.
53
- RubyProf.start
54
- puts "*** Running with RubyProf reduces performance ***"
55
- end
56
-
57
- after(:each) do
58
- if RubyProf.running?
59
- # file = arg.metadata[:description].gsub(/\s+/, '-')
60
-
61
- result = RubyProf.stop
62
-
63
- printer = RubyProf::FlatPrinter.new(result)
64
- printer.print($stderr, min_percent: 1.0)
65
- end
66
- end
67
- end
68
-
69
- it "runs efficiently" do
70
- result = []
71
- range = (1..500)
72
- duration = 2.0
73
-
74
- total = 0
75
- range.each do |index|
76
- offset = index.to_f / range.max
77
- total += (duration / offset).floor
78
-
79
- subject.every(index.to_f / range.max, :strict) { result << index }
80
- end
81
-
82
- subject.wait while result.size < total
83
-
84
- rate = result.size.to_f / subject.current_offset
85
- puts "Serviced #{result.size} events in #{subject.current_offset} seconds, #{rate} e/s."
86
-
87
- expect(subject.current_offset).to be_within(20).percent_of(duration)
88
- end
89
- end
90
-
91
- it "runs efficiently at high volume" do
92
- results = []
93
- range = (1..300)
94
- groups = (1..20)
95
- duration = 11
96
-
97
- timers = []
98
- @mutex = Mutex.new
99
- start = Time.now
100
- groups.each do |gi|
101
- timers << Thread.new {
102
- result = []
103
- timer = Timers::Group.new
104
- total = 0
105
- range.each do |ri|
106
- offset = ri.to_f / range.max
107
- total += (duration / offset).floor
108
- timer.every(ri.to_f / range.max, :strict) { result << ri }
109
- end
110
- timer.wait while result.size < total
111
- @mutex.synchronize { results += result }
112
-
113
- }
114
- end
115
- timers.each { |t| t.join }
116
- finish = Time.now
117
-
118
- rate = results.size.to_f / ( runtime = finish - start )
119
-
120
- puts "Serviced #{results.size} events in #{runtime} seconds, #{rate} e/s; across #{groups.max} timers."
121
-
122
- expect(runtime).to be_within(20).percent_of(duration)
123
- end
124
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- RSpec.describe Timers::Group do
9
- it "should not diverge too much" do
10
- fired = :not_fired_yet
11
- count = 0
12
- quantum = 0.01
13
-
14
- start_offset = subject.current_offset
15
- Timers::Timer.new(subject, quantum, :strict, start_offset) do |offset|
16
- fired = offset
17
- count += 1
18
- end
19
-
20
- iterations = 1000
21
- subject.wait while count < iterations
22
-
23
- # In my testing on the JVM, without the :strict recurring, I noticed 60ms of error here.
24
- expect(fired - start_offset).to be_within(quantum).of(iterations * quantum)
25
- end
26
-
27
- it "should only fire 0-interval timer once per iteration" do
28
- count = 0
29
-
30
- start_offset = subject.current_offset
31
- Timers::Timer.new(subject, 0, :strict, start_offset) do |offset, timer|
32
- count += 1
33
- end
34
-
35
- subject.wait
36
-
37
- expect(count).to be == 1
38
- end
39
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- require "spec_helper"
9
- require "timers/wait"
10
-
11
- RSpec.describe Timers::Wait do
12
- it "repeats until timeout expired" do
13
- timeout = Timers::Wait.new(5)
14
- count = 0
15
-
16
- timeout.while_time_remaining do |remaining|
17
- expect(remaining).to be_within(TIMER_QUANTUM).of(timeout.duration - count)
18
-
19
- count += 1
20
- sleep 1
21
- end
22
-
23
- expect(count).to eq(5)
24
- end
25
-
26
- it "yields results as soon as possible" do
27
- timeout = Timers::Wait.new(5)
28
-
29
- result = timeout.while_time_remaining do |_remaining|
30
- break :done
31
- end
32
-
33
- expect(result).to eq(:done)
34
- end
35
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # This file is part of the "timers" project and released under the MIT license.
4
- #
5
- # Copyright, 2018, by Samuel Williams. All rights reserved.
6
- #
7
-
8
- require_relative 'lib/timers/version'
9
-
10
- Gem::Specification.new do |spec|
11
- spec.name = "timers"
12
- spec.version = Timers::VERSION
13
- spec.authors = ["Samuel Williams", "Tony Arcieri"]
14
- spec.email = ["samuel@codeotaku.com", "bascule@gmail.com"]
15
- spec.licenses = ["MIT"]
16
- spec.homepage = "https://github.com/socketry/timers"
17
- spec.summary = "Pure Ruby one-shot and periodic timers"
18
- spec.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
19
- Schedule procs to run after a certain time, or at periodic intervals,
20
- using any API that accepts a timeout.
21
- DESCRIPTION
22
-
23
- spec.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
24
- spec.executables = spec.files.grep(%r{^bin/}).map { |f| File.basename(f) }
25
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
26
- spec.require_paths = ["lib"]
27
-
28
- spec.required_ruby_version = '>= 2.2.1'
29
-
30
- spec.add_development_dependency "bundler"
31
- spec.add_development_dependency "rspec", "~> 3.6"
32
- spec.add_development_dependency "rake"
33
- end