fastly_nsq 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/fastly_nsq.gemspec +1 -1
- data/lib/fastly_nsq/fake_message_queue.rb +17 -5
- data/lib/fastly_nsq/message_queue/consumer.rb +10 -10
- data/lib/fastly_nsq/message_queue/listener.rb +8 -9
- data/lib/fastly_nsq/version.rb +1 -1
- data/spec/lib/fastly_nsq/fake_message_queue_spec.rb +38 -48
- data/spec/lib/fastly_nsq/message_queue/consumer_spec.rb +42 -64
- data/spec/lib/fastly_nsq/message_queue/listener_spec.rb +66 -54
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b927006ea75538d36b77a9988c99f159327e72c
|
4
|
+
data.tar.gz: 0ba8e537719bcb36721c65292741d779f9d4da4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acaa3eb91200476a12e5f4099ef6515803293007f8643d49cd9651d5f786a6c9e2f36f39ff8086cff38a339a2767346ffada9131bb584db7d6155343d08788ed
|
7
|
+
data.tar.gz: 667ebee86054600dbd16e1f0450f51ce0186d759210c4c4c5e3fbac1f1d84e994124c4496cbcfce2ce6281da1398a5e3e0b8c22e45fdf3b1700511081be008bf
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ Please use [GitHub Issues] to report bugs.
|
|
29
29
|
|
30
30
|
`fastly_nsq` is a Ruby Gem
|
31
31
|
tested against Rails `>= 4.2`
|
32
|
-
and Ruby `>= 2.
|
32
|
+
and Ruby `>= 2.1.8`.
|
33
33
|
|
34
34
|
To get started,
|
35
35
|
add `fastly_nsq` to your `Gemfile`
|
@@ -88,7 +88,7 @@ read messages off of the queue:
|
|
88
88
|
consumer = MessageQueue::Consumer.new(
|
89
89
|
topic: 'topic',
|
90
90
|
channel: 'channel'
|
91
|
-
)
|
91
|
+
)
|
92
92
|
|
93
93
|
consumer.size #=> 1
|
94
94
|
message = consumer.pop
|
data/fastly_nsq.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.require_paths = ['lib']
|
22
22
|
|
23
23
|
gem.add_development_dependency 'awesome_print', '~> 1.6'
|
24
|
-
gem.add_development_dependency 'bundler', '~> 1.
|
24
|
+
gem.add_development_dependency 'bundler', '~> 1.12'
|
25
25
|
gem.add_development_dependency 'bundler-audit', '~> 0.5.0'
|
26
26
|
gem.add_development_dependency 'overcommit', '~> 0.32.0'
|
27
27
|
gem.add_development_dependency 'pry-byebug', '~> 3.3'
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module FakeMessageQueue
|
2
2
|
@@logger = Logger.new(nil)
|
3
|
+
@@delay = 0.5
|
4
|
+
@@queue = []
|
3
5
|
|
4
6
|
def self.queue
|
5
7
|
@@queue
|
@@ -21,6 +23,14 @@ module FakeMessageQueue
|
|
21
23
|
@@logger
|
22
24
|
end
|
23
25
|
|
26
|
+
def self.delay
|
27
|
+
@@delay
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.delay=(delay)
|
31
|
+
@@delay = delay
|
32
|
+
end
|
33
|
+
|
24
34
|
class Producer
|
25
35
|
def initialize(nsqd:, topic:, ssl_context: nil)
|
26
36
|
end
|
@@ -42,22 +52,24 @@ module FakeMessageQueue
|
|
42
52
|
end
|
43
53
|
|
44
54
|
class Consumer
|
45
|
-
|
46
|
-
|
47
|
-
def initialize(nsqlookupd:, topic:, channel:, ssl_context: nil)
|
55
|
+
def initialize(nsqlookupd: nil, topic:, channel:, ssl_context: nil)
|
48
56
|
end
|
49
57
|
|
50
|
-
def pop
|
58
|
+
def pop(delay = FakeMessageQueue.delay)
|
51
59
|
message = nil
|
52
60
|
|
53
61
|
until message
|
54
62
|
message = queue.pop
|
55
|
-
sleep
|
63
|
+
sleep delay
|
56
64
|
end
|
57
65
|
|
58
66
|
message
|
59
67
|
end
|
60
68
|
|
69
|
+
def pop_without_blocking
|
70
|
+
queue.pop
|
71
|
+
end
|
72
|
+
|
61
73
|
def size
|
62
74
|
queue.size
|
63
75
|
end
|
@@ -1,27 +1,27 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
class InvalidParameterError < StandardError; end
|
2
4
|
|
3
5
|
module MessageQueue
|
4
6
|
class Consumer
|
7
|
+
extend Forwardable
|
8
|
+
def_delegator :connection, :pop
|
9
|
+
def_delegator :connection, :pop_without_blocking
|
10
|
+
def_delegator :connection, :size
|
11
|
+
def_delegator :connection, :terminate
|
12
|
+
|
5
13
|
def initialize(topic:, channel:, ssl_context: nil)
|
6
14
|
@topic = topic
|
7
15
|
@channel = channel
|
8
16
|
@ssl_context = SSLContext.new(ssl_context)
|
9
17
|
end
|
10
18
|
|
11
|
-
def connection
|
12
|
-
@connection ||= consumer.new(params)
|
13
|
-
end
|
14
|
-
|
15
|
-
def terminate
|
16
|
-
@connection.terminate
|
17
|
-
end
|
18
|
-
|
19
19
|
private
|
20
20
|
|
21
21
|
attr_reader :channel, :topic, :ssl_context
|
22
22
|
|
23
|
-
def
|
24
|
-
Strategy.for_queue::Consumer
|
23
|
+
def connection
|
24
|
+
Strategy.for_queue::Consumer.new(params)
|
25
25
|
end
|
26
26
|
|
27
27
|
def params
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module MessageQueue
|
2
2
|
class Listener
|
3
|
-
def initialize(topic:, channel:)
|
4
|
-
@topic
|
5
|
-
@channel
|
3
|
+
def initialize(topic:, channel:, processor: nil, consumer: nil)
|
4
|
+
@topic = topic
|
5
|
+
@channel = channel
|
6
|
+
@processor = processor || DEFAULT_PROCESSOR
|
7
|
+
@consumer = consumer || MessageQueue::Consumer.new(consumer_params)
|
6
8
|
end
|
7
9
|
|
8
10
|
def go
|
@@ -26,18 +28,15 @@ module MessageQueue
|
|
26
28
|
|
27
29
|
private
|
28
30
|
|
29
|
-
attr_reader :channel, :topic
|
31
|
+
attr_reader :channel, :topic, :processor, :consumer
|
32
|
+
DEFAULT_PROCESSOR = ->(body, topic) { MessageProcessor.new(message_body: body, topic: topic).go }
|
30
33
|
|
31
34
|
def process_one_message
|
32
35
|
message = consumer.pop
|
33
|
-
|
36
|
+
processor.call(message.body, topic)
|
34
37
|
message.finish
|
35
38
|
end
|
36
39
|
|
37
|
-
def consumer
|
38
|
-
@consumer ||= MessageQueue::Consumer.new(consumer_params).connection
|
39
|
-
end
|
40
|
-
|
41
40
|
def consumer_params
|
42
41
|
{ topic: topic, channel: channel }
|
43
42
|
end
|
data/lib/fastly_nsq/version.rb
CHANGED
@@ -88,65 +88,55 @@ RSpec.describe FakeMessageQueue::Message do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
RSpec.describe FakeMessageQueue::Consumer do
|
91
|
+
let(:topic) { 'death_star' }
|
92
|
+
let(:channel) { 'star_killer_base' }
|
93
|
+
let(:consumer) { FakeMessageQueue::Consumer.new topic: topic, channel: channel }
|
94
|
+
|
91
95
|
after do
|
92
96
|
FakeMessageQueue.reset!
|
93
97
|
end
|
94
98
|
|
95
|
-
describe '
|
96
|
-
it 'tells you
|
97
|
-
|
98
|
-
|
99
|
-
channel = 'star_killer_base'
|
99
|
+
describe 'when there are no messages on the queue' do
|
100
|
+
it 'tells you there are 0 messages in the queue' do
|
101
|
+
expect(consumer.size).to eq 0
|
102
|
+
end
|
100
103
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
it 'blocks forever (until timeout) from #pop' do
|
105
|
+
FakeMessageQueue.delay = 0.1
|
106
|
+
delay = FakeMessageQueue.delay + 0.1
|
107
|
+
|
108
|
+
expect do
|
109
|
+
Timeout.timeout(delay) do
|
110
|
+
consumer.pop
|
111
|
+
end
|
112
|
+
end.to raise_error(Timeout::Error)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'returns nil from #pop_without_blocking' do
|
116
|
+
popped_message = consumer.pop_without_blocking
|
107
117
|
|
108
|
-
expect(
|
118
|
+
expect(popped_message).to be_nil
|
109
119
|
end
|
110
120
|
end
|
111
121
|
|
112
|
-
describe '
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
channel = 'star_killer_base'
|
119
|
-
|
120
|
-
consumer = FakeMessageQueue::Consumer.new(
|
121
|
-
nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
|
122
|
-
topic: topic,
|
123
|
-
channel: channel,
|
124
|
-
)
|
125
|
-
popped_message = consumer.pop
|
126
|
-
|
127
|
-
expect(popped_message).to eq message
|
128
|
-
end
|
122
|
+
describe 'when there is a message on the queue' do
|
123
|
+
let(:message) { FakeMessageQueue::Message.new 'hello' }
|
124
|
+
before { FakeMessageQueue.queue = [message] }
|
125
|
+
|
126
|
+
it 'tells you there are messages in the queue' do
|
127
|
+
expect(consumer.size).to eq 1
|
129
128
|
end
|
130
129
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
channel: channel,
|
142
|
-
)
|
143
|
-
|
144
|
-
expect do
|
145
|
-
Timeout.timeout(delay) do
|
146
|
-
consumer.pop
|
147
|
-
end
|
148
|
-
end.to raise_error(Timeout::Error)
|
149
|
-
end
|
130
|
+
it 'returns a message immediately from #pop' do
|
131
|
+
popped_message = consumer.pop
|
132
|
+
|
133
|
+
expect(popped_message).to eq message
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'returns a message immediately from #pop_without_blocking' do
|
137
|
+
popped_message = consumer.pop_without_blocking
|
138
|
+
|
139
|
+
expect(popped_message).to eq message
|
150
140
|
end
|
151
141
|
end
|
152
142
|
|
@@ -1,87 +1,65 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe MessageQueue::Consumer do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
allow(Nsq::Consumer).to receive(:new)
|
8
|
-
topic = 'death_star'
|
9
|
-
channel = 'star_killer_base'
|
4
|
+
let(:channel) { 'star_killer_base' }
|
5
|
+
let(:topic) { 'death_star' }
|
6
|
+
let(:consumer) { MessageQueue::Consumer.new(topic: topic, channel: channel) }
|
10
7
|
|
11
|
-
|
8
|
+
def fake_consumer
|
9
|
+
double 'Consumer', connection: nil, terminate: nil, pop: :popped, size: 0
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
topic: topic,
|
17
|
-
channel: channel,
|
18
|
-
ssl_context: nil,
|
19
|
-
).at_least(:once)
|
20
|
-
end
|
21
|
-
end
|
12
|
+
describe 'when the ENV is set incorrectly' do
|
13
|
+
it 'raises with a helpful error' do
|
14
|
+
allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
|
22
15
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
topic = 'death_star'
|
27
|
-
channel = 'star_killer_base'
|
16
|
+
expect { consumer.terminate }.to raise_error(InvalidParameterError)
|
17
|
+
end
|
18
|
+
end
|
28
19
|
|
29
|
-
|
20
|
+
describe 'when using the real queue', fake_queue: false do
|
21
|
+
before(:example) do
|
22
|
+
@fake_consumer = fake_consumer
|
23
|
+
allow(Nsq::Consumer).to receive(:new).and_return(@fake_consumer)
|
24
|
+
end
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
topic: topic,
|
35
|
-
channel: channel,
|
36
|
-
ssl_context: nil,
|
37
|
-
).at_least(:once)
|
38
|
-
end
|
26
|
+
it 'forwards #pop to Nsq::Consumer' do
|
27
|
+
consumer.pop
|
28
|
+
expect(@fake_consumer).to have_received(:pop)
|
39
29
|
end
|
40
|
-
end
|
41
30
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
channel = 'star_killer_base'
|
31
|
+
it 'forwards #size to Nsq::Consumer' do
|
32
|
+
consumer.size
|
33
|
+
expect(@fake_consumer).to have_received(:size)
|
34
|
+
end
|
47
35
|
|
48
|
-
|
36
|
+
it 'forwards #terminate to Nsq::Consumer' do
|
37
|
+
consumer.terminate
|
49
38
|
|
50
|
-
expect
|
39
|
+
expect(@fake_consumer).to have_received(:terminate)
|
51
40
|
end
|
52
41
|
end
|
53
42
|
|
54
|
-
describe '
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
topic = 'death_star'
|
60
|
-
channel = 'star_killer_base'
|
61
|
-
params = { topic: topic, channel: channel }
|
62
|
-
|
63
|
-
live_consumer = MessageQueue::Consumer.new(params)
|
64
|
-
live_consumer.connection
|
65
|
-
live_consumer.terminate
|
43
|
+
describe 'when using the fake queue', fake_queue: true do
|
44
|
+
before(:example) do
|
45
|
+
@fake_consumer = fake_consumer
|
46
|
+
allow(FakeMessageQueue::Consumer).to receive(:new).and_return(@fake_consumer)
|
47
|
+
end
|
66
48
|
|
67
|
-
|
68
|
-
|
49
|
+
it 'forwards #pop to FakeMessageQueue::Consumer' do
|
50
|
+
consumer.pop
|
51
|
+
expect(@fake_consumer).to have_received(:pop)
|
69
52
|
end
|
70
53
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
topic = 'death_star'
|
76
|
-
channel = 'star_killer_base'
|
77
|
-
params = { topic: topic, channel: channel }
|
54
|
+
it 'forwards #size to FakeMessageQueue::Consumer' do
|
55
|
+
consumer.size
|
56
|
+
expect(@fake_consumer).to have_received(:size)
|
57
|
+
end
|
78
58
|
|
79
|
-
|
80
|
-
|
81
|
-
live_consumer.terminate
|
59
|
+
it 'forwards #terminate to FakeMessageQueue::Consumer' do
|
60
|
+
consumer.terminate
|
82
61
|
|
83
|
-
|
84
|
-
end
|
62
|
+
expect(@fake_consumer).to have_received(:terminate)
|
85
63
|
end
|
86
64
|
end
|
87
65
|
end
|
@@ -1,67 +1,87 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe MessageQueue::Listener do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
let(:topic) { 'testing_topic' }
|
5
|
+
let(:channel) { 'testing_channel' }
|
6
|
+
let(:consumer) { FakeMessageQueue::Consumer.new topic: topic, channel: channel }
|
7
|
+
|
8
|
+
module TestMessageProcessor
|
9
|
+
@@messages_processed = []
|
10
|
+
Message = Struct.new(:body, :topic) do
|
11
|
+
def finish
|
12
|
+
@did_finish = true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.call(body, topic)
|
17
|
+
@@messages_processed.push Message.new(body, topic)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.messages_processed
|
21
|
+
@@messages_processed
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.clear
|
25
|
+
@@messages_processed = []
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:listener) do
|
30
|
+
MessageQueue::Listener.new topic: topic,
|
31
|
+
channel: channel,
|
32
|
+
processor: TestMessageProcessor,
|
33
|
+
consumer: consumer
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:message) { TestMessageProcessor::Message.new 'this is message body', topic }
|
37
|
+
let(:messages_processed) { TestMessageProcessor.messages_processed }
|
38
|
+
let(:expected_message) { TestMessageProcessor::Message.new('this is message body', topic) }
|
39
|
+
let(:expected_messages) { [expected_message] }
|
40
|
+
|
41
|
+
describe 'instantiating without a consumer' do
|
42
|
+
it 'instantiates a consumer, passing the topic and channel' do
|
43
|
+
allow(MessageQueue::Consumer).to receive(:new)
|
44
|
+
|
45
|
+
MessageQueue::Listener.new topic: topic,
|
46
|
+
channel: channel,
|
47
|
+
processor: TestMessageProcessor,
|
48
|
+
consumer: nil
|
16
49
|
|
17
50
|
expect(MessageQueue::Consumer).to have_received(:new).
|
18
51
|
with(topic: topic, channel: channel)
|
19
52
|
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'when processing next message' do
|
56
|
+
before(:each) { TestMessageProcessor.clear }
|
57
|
+
|
58
|
+
it 'processes the next message' do
|
59
|
+
allow(consumer).to receive(:pop).and_return(message)
|
60
|
+
listener.process_next_message
|
20
61
|
|
21
|
-
|
22
|
-
process_message = double(go: nil)
|
23
|
-
allow(MessageProcessor).to receive(:new).and_return(process_message)
|
24
|
-
message_body = { data: 'value' }.to_json
|
25
|
-
message = double('Message', finish: nil, body: message_body)
|
26
|
-
connection = double('Connection', pop: message, terminate: nil)
|
27
|
-
consumer = double('Consumer', connection: connection)
|
28
|
-
allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
|
29
|
-
topic = 'testing_topic'
|
30
|
-
channel = 'testing_channel'
|
31
|
-
|
32
|
-
MessageQueue::Listener.new(topic: topic, channel: channel).
|
33
|
-
process_next_message
|
34
|
-
|
35
|
-
expect(MessageProcessor).to have_received(:new).
|
36
|
-
with(topic: topic, message_body: message_body)
|
37
|
-
expect(process_message).to have_received(:go)
|
62
|
+
expect(messages_processed).to eql(expected_messages)
|
38
63
|
end
|
39
64
|
|
40
65
|
it 'finishes the message' do
|
41
|
-
allow(
|
42
|
-
message
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
channel = 'testing_channel'
|
48
|
-
|
49
|
-
MessageQueue::Listener.new(topic: topic, channel: channel).
|
50
|
-
process_next_message
|
51
|
-
|
52
|
-
expect(message).to have_received(:finish)
|
66
|
+
allow(consumer).to receive(:pop).and_return(message)
|
67
|
+
allow(message).to receive(:finish)
|
68
|
+
|
69
|
+
listener.process_next_message
|
70
|
+
|
71
|
+
expect(message).to have_received(:finish).once
|
53
72
|
end
|
54
73
|
|
55
74
|
context 'when using the fake queue and it is empty', fake_queue: true do
|
75
|
+
before do
|
76
|
+
FakeMessageQueue.delay = 0.1
|
77
|
+
end
|
78
|
+
|
56
79
|
it 'blocks on the process for longer than the check cycle' do
|
57
|
-
|
58
|
-
channel = 'testing_channel'
|
59
|
-
delay = FakeMessageQueue::Consumer::SECONDS_BETWEEN_QUEUE_CHECKS + 0.1
|
80
|
+
delay = FakeMessageQueue.delay + 0.1
|
60
81
|
|
61
82
|
expect do
|
62
83
|
Timeout.timeout(delay) do
|
63
|
-
|
64
|
-
process_next_message
|
84
|
+
listener.process_next_message
|
65
85
|
end
|
66
86
|
end.to raise_error(Timeout::Error)
|
67
87
|
end
|
@@ -71,14 +91,6 @@ RSpec.describe MessageQueue::Listener do
|
|
71
91
|
describe '#go' do
|
72
92
|
describe 'when a SIGTERM is received' do
|
73
93
|
it 'closes the consumer connection' do
|
74
|
-
allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
|
75
|
-
message = double(finish: nil, body: nil)
|
76
|
-
connection = double('Connection', pop: message, terminate: nil)
|
77
|
-
consumer = double('Consumer', connection: connection)
|
78
|
-
allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
|
79
|
-
topic = 'testing_topic'
|
80
|
-
channel = 'testing_channel'
|
81
|
-
|
82
94
|
pid = fork do
|
83
95
|
MessageQueue::Listener.new(topic: topic, channel: channel).go
|
84
96
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastly_nsq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tommy O'Neil
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-05-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: awesome_print
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 1.
|
34
|
+
version: '1.12'
|
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: 1.
|
41
|
+
version: '1.12'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: bundler-audit
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|