bigcommerce-multitrap 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +15 -0
- data/README.md +160 -0
- data/bigcommerce-multitrap.gemspec +22 -0
- data/lib/bigcommerce-multitrap.rb +3 -0
- data/lib/bigcommerce/multitrap.rb +28 -0
- data/lib/bigcommerce/multitrap/core_ext.rb +13 -0
- data/lib/bigcommerce/multitrap/patched_trap.rb +35 -0
- data/lib/bigcommerce/multitrap/trap.rb +108 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0f6b5bf04d0745286817f5a37fadaf83bd98a0785e6e315225768862d2ce158b
|
4
|
+
data.tar.gz: 2372b5016ab0893e62d0daaf938387303f428536c5bfb9f8b7506fd0765ba4fd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 62e88d91945e55594e7dd966bd2346b726f815c8bdd957b67804d38098980e9afe4fb51620cb49b8fd4e56d67cd5f9e4222d3a8283e5713c6a0d8d1f48d74b3d
|
7
|
+
data.tar.gz: a17fb32de84c9939d26d11832f206e64a036712f78975660e83407d872b8903a7fb5b5abcf13e8608adf8688629809286f15289079db920ccb2893a6c8534b1a
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Multitrap changelog
|
2
|
+
===================
|
3
|
+
|
4
|
+
### v0.1.0 (August, 9, 2015)
|
5
|
+
|
6
|
+
* Added support for JRuby
|
7
|
+
* Added support for Rubinius
|
8
|
+
* Added support for CRuby 1.9
|
9
|
+
* Added support for symbols as signal keys ([#1](https://github.com/kyrylo/multitrap/issues/1))
|
10
|
+
* Added support for previously defined signals ([#2](https://github.com/kyrylo/multitrap/issues/2))
|
11
|
+
* Changed order of execution of handlers (FIFO now)
|
12
|
+
|
13
|
+
### v0.0.1 (September 7, 2014)
|
14
|
+
|
15
|
+
* Initial release
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
Multitrap
|
2
|
+
=========
|
3
|
+
|
4
|
+
[![CircleCI](https://circleci.com/gh/bigcommerce/multitrap.svg?style=svg&circle-token=dc30a5b0d61a77d3547b795cca663e9309cf8cc0)](https://circleci.com/gh/bigcommerce/multitrap)
|
5
|
+
|
6
|
+
Introduction
|
7
|
+
------------
|
8
|
+
|
9
|
+
By default, all Ruby implementations allow you to attach only one signal handler
|
10
|
+
per signal (via `Signal.trap` aka `trap`). This is not very useful, if you want
|
11
|
+
to perform multiple actions. Whenever you define a new signal handler, it sends
|
12
|
+
shivers down your spine, because you never know if you're overwriting someone
|
13
|
+
else's handler (usually, the handler of a library you depend on). Well, now you
|
14
|
+
don't have to worry about that anymore, because Multitrap solved this problem
|
15
|
+
for you! Define as many handlers as you wish and be sure they will all execute.
|
16
|
+
|
17
|
+
Examples
|
18
|
+
--------
|
19
|
+
|
20
|
+
### Basic example
|
21
|
+
|
22
|
+
To use Multitrap just `require` it. No additional configuration is
|
23
|
+
needed. Internally, the library _redefines_ `trap`. The last defined signal
|
24
|
+
handler executes first.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'bigcommerce/multitrap'
|
28
|
+
|
29
|
+
trap(:INT) { puts 111 }
|
30
|
+
trap(:INT) { puts 222 }
|
31
|
+
trap(:INT) { puts 333 }
|
32
|
+
|
33
|
+
Process.kill(:INT, $$)
|
34
|
+
|
35
|
+
# Outputs:
|
36
|
+
# 333
|
37
|
+
# 222
|
38
|
+
# 111
|
39
|
+
```
|
40
|
+
|
41
|
+
### Nested traps
|
42
|
+
|
43
|
+
The library aims to be compatible with every Ruby implementation. For example,
|
44
|
+
JRuby doesn't support nested traps, but Rubinius and CRuby do. Multitrap obeys
|
45
|
+
this behaviour.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require 'bigcommerce/multitrap'
|
49
|
+
|
50
|
+
a = nil
|
51
|
+
|
52
|
+
trap(:INT) do
|
53
|
+
a = 1
|
54
|
+
trap(:INT) do
|
55
|
+
a = 2
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
puts a #=> nil
|
60
|
+
|
61
|
+
# On JRuby `a` will always be equal to 1.
|
62
|
+
Process.kill(:INT, $$)
|
63
|
+
puts a #=> 1
|
64
|
+
|
65
|
+
# CRuby and Rubinius will continue executing nested traps.
|
66
|
+
Process.kill(:INT, $$)
|
67
|
+
puts a #=> 2
|
68
|
+
|
69
|
+
Process.kill(:INT, $$)
|
70
|
+
puts a #=> 2
|
71
|
+
```
|
72
|
+
|
73
|
+
### Return value
|
74
|
+
|
75
|
+
With Multitrap, the `trap` method returns a hash with callbacks.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
require 'pp'
|
79
|
+
require 'bigcommerce/multitrap'
|
80
|
+
|
81
|
+
trap(:INT) {}
|
82
|
+
trap(:HUP) {}
|
83
|
+
3.times do
|
84
|
+
trap(:USR1) {}
|
85
|
+
end
|
86
|
+
handlers = trap(:USR2) {}
|
87
|
+
|
88
|
+
puts handlers
|
89
|
+
#=> {"INT"=>[#<Proc:0x00556161d34da8@test.rb:4>],
|
90
|
+
"HUP"=>[#<Proc:0x00556161d34420@test.rb:5>],
|
91
|
+
"USR1"=>
|
92
|
+
[#<Proc:0x00556161d36a68@test.rb:7>,
|
93
|
+
#<Proc:0x00556161d33750@test.rb:7>,
|
94
|
+
#<Proc:0x00556161d33048@test.rb:7>],
|
95
|
+
"USR2"=>[#<Proc:0x00556161d32ad0@test.rb:9>]}
|
96
|
+
```
|
97
|
+
|
98
|
+
You can access this hash to modify the handlers at runtime (but be extremely
|
99
|
+
careful about that). For example, imagine if you write a test for your program's
|
100
|
+
`:INT` signal handler and use RSpec. RSpec defines its own `:INT` handler and
|
101
|
+
with the default `trap` you would simply overwrite it. With Multitrap you can
|
102
|
+
remove the handler from the hash and then append it later.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
require 'spec_helper'
|
106
|
+
require 'multitrap'
|
107
|
+
|
108
|
+
RSpec.describe MyLibrary do
|
109
|
+
it "works" do
|
110
|
+
a = nil
|
111
|
+
handlers = trap(:INT) { a = 1 }
|
112
|
+
|
113
|
+
# Store the RSpecs handler. Usually, it's the first element in the array.
|
114
|
+
rspec_handler = handlers['INT'].shift
|
115
|
+
|
116
|
+
Process.kill(:INT, $$)
|
117
|
+
expect(a).to eq(1)
|
118
|
+
|
119
|
+
# Restore the handler.
|
120
|
+
handlers['INT'].unshift(rspec_handler)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
Installation
|
126
|
+
------------
|
127
|
+
|
128
|
+
Add this line to your application's Gemfile:
|
129
|
+
|
130
|
+
gem 'multitrap'
|
131
|
+
|
132
|
+
And then execute:
|
133
|
+
|
134
|
+
$ bundle
|
135
|
+
|
136
|
+
Or install it yourself as:
|
137
|
+
|
138
|
+
$ gem install multitrap
|
139
|
+
|
140
|
+
Limitations
|
141
|
+
-----------
|
142
|
+
|
143
|
+
### Rubies
|
144
|
+
|
145
|
+
* CRuby 1.9.2 >=
|
146
|
+
* Rubinius 2.5.8 >= (may work on older versions, untested)
|
147
|
+
* JRuby 9.0.0.0 >= (shouldn't work on older versions)
|
148
|
+
|
149
|
+
Roadmap
|
150
|
+
-------
|
151
|
+
|
152
|
+
### Provide consistency
|
153
|
+
|
154
|
+
I'm not sure we need this, but it would be possible to remove inconsistencies
|
155
|
+
with respect to nested traps on all Ruby platforms.
|
156
|
+
|
157
|
+
License
|
158
|
+
-------
|
159
|
+
|
160
|
+
The project uses the MIT License. See LICENSE.txt file for more information.
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'bigcommerce-multitrap'
|
5
|
+
s.version = File.read('VERSION')
|
6
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
7
|
+
s.summary = 'Allows Signal.trap to have multiple callbacks'
|
8
|
+
s.authors = ['Kyrylo Silin', 'Shaun McCormick']
|
9
|
+
s.email = %w[silin@kyrylo.org shaun.mccormick@bigcommerce.com]
|
10
|
+
s.homepage = 'https://github.com/kyrylo/multitrap'
|
11
|
+
s.licenses = 'MIT'
|
12
|
+
|
13
|
+
s.files = Dir['README.md', 'CHANGELOG.md', 'CODE_OF_CONDUCT.md', 'lib/**/*', 'bigcommerce-multitrap.gemspec']
|
14
|
+
s.require_paths = ['lib']
|
15
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
16
|
+
|
17
|
+
s.add_development_dependency 'pry', '~> 0.12'
|
18
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
19
|
+
s.add_development_dependency 'rspec', '~> 3.9'
|
20
|
+
s.add_development_dependency 'rspec_junit_formatter', '>= 0.4'
|
21
|
+
s.add_development_dependency 'rspec-wait', '~> 0.0.9'
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Bigcommerce
|
6
|
+
module Multitrap
|
7
|
+
# The VERSION file must be in the root directory of the library.
|
8
|
+
VERSION_FILE = File.expand_path('../../../VERSION', __FILE__)
|
9
|
+
|
10
|
+
VERSION = File.exist?(VERSION_FILE) ? File.read(VERSION_FILE).chomp : '(could not find VERSION file)'
|
11
|
+
|
12
|
+
def self.jruby?
|
13
|
+
RUBY_ENGINE == 'jruby'
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.mri?
|
17
|
+
RUBY_ENGINE == 'ruby'
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.rbx?
|
21
|
+
RUBY_ENGINE == 'rbx'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require_relative 'multitrap/trap'
|
27
|
+
require_relative 'multitrap/patched_trap'
|
28
|
+
require_relative 'multitrap/core_ext'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
case RUBY_ENGINE
|
4
|
+
when 'ruby'
|
5
|
+
[Kernel, Kernel.singleton_class, Signal, Signal.singleton_class].each do |klass|
|
6
|
+
klass.__send__(:include, Bigcommerce::Multitrap::PatchedTrap)
|
7
|
+
end
|
8
|
+
when 'rbx'
|
9
|
+
Signal.__send__(:include, Bigcommerce::Multitrap::PatchedTrap)
|
10
|
+
Signal.singleton_class.__send__(:include, Bigcommerce::Multitrap::PatchedTrap)
|
11
|
+
when 'jruby'
|
12
|
+
Signal.singleton_class.__send__(:include, Bigcommerce::Multitrap::PatchedTrap)
|
13
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bigcommerce
|
4
|
+
module Multitrap
|
5
|
+
module PatchedTrap
|
6
|
+
def self.included(mod)
|
7
|
+
original_trap = Signal.method(:trap)
|
8
|
+
|
9
|
+
mod.instance_eval do
|
10
|
+
define_method(:trap) do |*args, &block|
|
11
|
+
if args.size < 1
|
12
|
+
if Bigcommerce::Multitrap.rbx?
|
13
|
+
raise ArgumentError, "method 'trap': given 0, expected 2"
|
14
|
+
elsif Bigcommerce::Multitrap.jruby?
|
15
|
+
raise ArgumentError, "wrong number of arguments (0 for 1)"
|
16
|
+
else
|
17
|
+
raise ArgumentError, "wrong number of arguments (0 for 1..2)"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if block.nil?
|
22
|
+
if Bigcommerce::Multitrap.rbx? && !args[1].respond_to?(:call)
|
23
|
+
raise ArgumentError, "Handler must respond to #call (was #{args[1].class})"
|
24
|
+
elsif args[1].nil?
|
25
|
+
raise ArgumentError, 'tried to create Proc object without a block'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Bigcommerce::Multitrap::Trap.trap(original_trap, *args, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bigcommerce
|
4
|
+
module Multitrap
|
5
|
+
class Trap
|
6
|
+
OWN_MRI_FRAME = %r{/lib/multitrap/trap.rb:[0-9]{1,3}:in `block in store_trap'}
|
7
|
+
|
8
|
+
OWN_RBX_FRAME = %r{/lib/multitrap/trap.rb:[0-9]{1,3}:in `store_trap'}
|
9
|
+
|
10
|
+
TRAVIS_FRAME = %r{lib/jruby\.jar!/jruby/kernel/signal\.rb}
|
11
|
+
|
12
|
+
RESERVED_SIGNALS = %w|BUS SEGV ILL FPE VTALRM|
|
13
|
+
|
14
|
+
KNOWN_SIGNALS = Signal.list.keys - RESERVED_SIGNALS
|
15
|
+
|
16
|
+
def self.trap(original_trap, *args, &block)
|
17
|
+
@@multitrap ||= new(original_trap)
|
18
|
+
|
19
|
+
signal = args[0]
|
20
|
+
command = args[1]
|
21
|
+
|
22
|
+
@@multitrap.store_trap(signal, command, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.__clear_all_handlers!
|
26
|
+
@@multitrap ||= nil
|
27
|
+
@@multitrap && @@multitrap.__clear_all_handlers!
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(original_trap)
|
31
|
+
@original_trap = original_trap
|
32
|
+
@trap_list = create_trap_list
|
33
|
+
end
|
34
|
+
|
35
|
+
def store_trap(signal, command, &block)
|
36
|
+
signal = signal.to_s
|
37
|
+
command ||= block
|
38
|
+
|
39
|
+
trap_is_nested = nested_trap?
|
40
|
+
|
41
|
+
if trap_is_nested
|
42
|
+
# JRuby doesn't support nested traps.
|
43
|
+
return if Multitrap.jruby?
|
44
|
+
@trap_list[signal].pop
|
45
|
+
end
|
46
|
+
|
47
|
+
@trap_list[signal] << command
|
48
|
+
|
49
|
+
prev_trap_handler = @original_trap.call(signal) do |signo|
|
50
|
+
@trap_list[signal].reverse_each do |trap_handler|
|
51
|
+
trap_handler.call(signo || Signal.list[signal]) if trap_handler.respond_to?(:call)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if !trap_is_nested &&
|
56
|
+
@trap_list[signal].size == 1 &&
|
57
|
+
!default_handler?(prev_trap_handler) &&
|
58
|
+
!default_handler_path?(prev_trap_handler)
|
59
|
+
@trap_list[signal].unshift(prev_trap_handler)
|
60
|
+
end
|
61
|
+
|
62
|
+
@trap_list
|
63
|
+
end
|
64
|
+
|
65
|
+
def __clear_all_handlers!
|
66
|
+
@trap_list.keys.select {|s| KNOWN_SIGNALS.include?(s) }.each do |signal|
|
67
|
+
@original_trap.call(signal, 'DEFAULT')
|
68
|
+
end
|
69
|
+
|
70
|
+
@trap_list = create_trap_list
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
define_method(:nested_trap?) do
|
76
|
+
case RUBY_ENGINE
|
77
|
+
when 'ruby'
|
78
|
+
caller.any? { |stackframe| stackframe =~ OWN_MRI_FRAME }
|
79
|
+
when 'rbx'
|
80
|
+
caller.grep(OWN_RBX_FRAME).size > 1
|
81
|
+
when 'jruby'
|
82
|
+
if caller.any? { |stackframe| stackframe =~ TRAVIS_FRAME }
|
83
|
+
caller.grep(OWN_RBX_FRAME).size > 1
|
84
|
+
else
|
85
|
+
caller.grep(OWN_MRI_FRAME).size > 1
|
86
|
+
end
|
87
|
+
else
|
88
|
+
raise NotImplementedError, 'unsupported Ruby engine'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_trap_list
|
93
|
+
Hash.new { |h, k| h[k] = [] }
|
94
|
+
end
|
95
|
+
|
96
|
+
def default_handler?(prev)
|
97
|
+
%w[DEFAULT SYSTEM_DEFAULT IGNORE].any? { |h| h == prev }
|
98
|
+
end
|
99
|
+
|
100
|
+
def default_handler_path?(prev)
|
101
|
+
[%r{Proc:.+@kernel/loader\.rb:[0-9]{1,4}},
|
102
|
+
%r{Proc:.+@uri:classloader:/jruby/kernel/signal.rb:[0-9]{1,4}}].any? do |h|
|
103
|
+
h =~ prev.to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bigcommerce-multitrap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kyrylo Silin
|
8
|
+
- Shaun McCormick
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2019-11-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pry
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0.12'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0.12'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '13.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '13.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '3.9'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3.9'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec_junit_formatter
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0.4'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.4'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec-wait
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.0.9
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 0.0.9
|
84
|
+
description:
|
85
|
+
email:
|
86
|
+
- silin@kyrylo.org
|
87
|
+
- shaun.mccormick@bigcommerce.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- CHANGELOG.md
|
93
|
+
- README.md
|
94
|
+
- bigcommerce-multitrap.gemspec
|
95
|
+
- lib/bigcommerce-multitrap.rb
|
96
|
+
- lib/bigcommerce/multitrap.rb
|
97
|
+
- lib/bigcommerce/multitrap/core_ext.rb
|
98
|
+
- lib/bigcommerce/multitrap/patched_trap.rb
|
99
|
+
- lib/bigcommerce/multitrap/trap.rb
|
100
|
+
homepage: https://github.com/kyrylo/multitrap
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
metadata: {}
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubygems_version: 3.0.1
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Allows Signal.trap to have multiple callbacks
|
123
|
+
test_files: []
|