stapfen 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changes to Stapfen
2
+
3
+
4
+ ## 2.0.0
5
+
6
+ * Add support for JMS-backed `Stapfen::Worker` classes
7
+ * Deep copy the configuration passed into `Stomp::Client` to work-around [stomp #80](https://github.com/stompgem/stomp/issues/80)
8
+ * Support per-instance log configuration [#3](https://github.com/lookout/stapfen/issues/3)
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Stapfen
2
2
 
3
- Stapfen is a simple gem to make writing stand-alone STOMP workers easier.
3
+
4
+ Stapfen is a simple gem to make writing workers that consume messages via
5
+ [STOMP](http://stomp.github.io/) or
6
+ [JMS](https://en.wikipedia.org/wiki/Java_Message_Service) easier.
7
+
8
+ Stapfen allows you to write one worker class, and use either protocol
9
+ depending on the environment and needs.
4
10
 
5
11
 
6
12
  ## Usage
@@ -10,37 +16,63 @@ Stapfen is a simple gem to make writing stand-alone STOMP workers easier.
10
16
 
11
17
  Consider the following `myworker.rb` file:
12
18
 
13
- class MyWorker < Stapfen::Worker
14
- configure do
15
- {:hosts => [
16
- {
17
- :host => 'localhost',
18
- :port => 61613,
19
- :login => 'guest',
20
- :passcode => 'guest',
21
- :ssl => false
22
- }
23
- ]}
24
- end
25
-
26
- consume 'thequeue', :dead_letter_queue => '/queue/dlq',
27
- :max_redeliveries => 0 do |message|
28
- data = expensive_computation(message.body)
29
- persist(data)
30
- end
31
- end
32
-
33
- MyWorker.run!
34
-
35
-
36
- The value returned from the `configure` block is expected to be a valid
19
+ ```ruby
20
+ class MyWorker < Stapfen::Worker
21
+ use_stomp!
22
+
23
+ configure do
24
+ {
25
+ :hosts => [
26
+ {
27
+ :host => 'localhost',
28
+ :port => 61613,
29
+ :login => 'guest',
30
+ :passcode => 'guest',
31
+ :ssl => false
32
+ }
33
+ ]
34
+ }
35
+ end
36
+
37
+ # [Optional] Set up a logger for each worker instance
38
+ log do
39
+ Logger.new(STDOUT)
40
+ end
41
+
42
+ consume 'thequeue', :dead_letter_queue => '/queue/dlq',
43
+ :max_redeliveries => 0 do |message|
44
+
45
+ data = expensive_computation(message.body)
46
+ # Save my data, or do something worker-specific with it
47
+ persist(data)
48
+
49
+ # Send another message
50
+ client.publish('/topic/computation-acks', "finished with #{message.message_id}")
51
+ end
52
+
53
+ end
54
+
55
+ MyWorker.run!
56
+ ```
57
+
58
+
59
+ When using the STOMP protocol, the value returned from the `configure` block is expected to be a valid
37
60
  `Stomp::Client` [connection
38
61
  hash](https://github.com/stompgem/stomp#hash-login-example-usage-this-is-the-recommended-login-technique).
39
62
 
63
+ In the case of the JMS protocol, the value returned from the `configure` block
64
+ is expected to be a valid [configuration
65
+ hash](https://github.com/reidmorrison/jruby-jms#consumer) for the
66
+ [jruby-jms](https://github.com/reidmorrison/jruby-jms) gem.
67
+
68
+ ---
69
+
40
70
  It is also important to note that the `consume` block will be invoked inside an
41
71
  **instance** of `MyWorker` and will execute inside its own `Thread`, so take
42
72
  care when accessing other shared resources.
43
73
 
74
+ ### STOMP-specific support
75
+
44
76
  The consume block accepts the usual
45
77
  [Stomp::Client](https://github.com/stompgem/stomp) subscription headers, as well
46
78
  as :dead_letter_queue and :max\_redeliveries. If either of the latter two is
@@ -48,6 +80,7 @@ present, the consumer will unreceive any messages for which the block returns
48
80
  false; after :max\_redeliveries, it will send the message to :dead_letter_queue.
49
81
  `consume` blocks without these headers will fail silently rather than unreceive.
50
82
 
83
+
51
84
  ## Installation
52
85
 
53
86
  Add this line to your application's Gemfile:
@@ -0,0 +1,91 @@
1
+ require 'jms'
2
+ require 'stapfen/destination'
3
+
4
+ module Stapfen
5
+ module Client
6
+ class JMS
7
+ attr_reader :connection
8
+
9
+ def initialize(configuration)
10
+ super()
11
+ @config = configuration
12
+ @connection = nil
13
+ end
14
+
15
+ # Connect to the broker via JMS and start the JMS session
16
+ #
17
+ # @return [JMS::Connection]
18
+ def connect(*args)
19
+ @connection = ::JMS::Connection.new(@config)
20
+ @connection.start
21
+ return @connection
22
+ end
23
+
24
+ # Accessor method which will cache the session if we've already created
25
+ # it once
26
+ #
27
+ # @return [JMS::Session] Instantiated +JMS::Session+ for our
28
+ # +connection+
29
+ def session
30
+ @session ||= connection.create_session
31
+ end
32
+
33
+ def publish(destination, body, headers={})
34
+ destination = Stapfen::Destination.from_string(destination)
35
+
36
+ session.producer(destination.jms_opts) do |p|
37
+ # Create the JMS typed Message
38
+ message = session.message(body)
39
+
40
+ message.delivery_mode = ::JMS::DeliveryMode::PERSISTENT if headers.delete(:persistent)
41
+
42
+ # Take the remainder of the headers and push them into the message
43
+ # properties.
44
+ headers.each_pair do |key, value|
45
+ message.setStringProperty(key.to_s, value.to_s)
46
+ end
47
+
48
+ p.send(message)
49
+ end
50
+ end
51
+
52
+ def subscribe(destination, headers={}, &block)
53
+ destination = Stapfen::Destination.from_string(destination)
54
+ connection.on_message(destination.jms_opts) do |m|
55
+ block.call(m)
56
+ end
57
+ end
58
+
59
+ # Close the JMS::Connection and the JMS::Session if it's been created
60
+ # for this client
61
+ #
62
+ # @return [Boolean] True/false depending on whether we actually closed
63
+ # the connection
64
+ def close
65
+ return false unless @connection
66
+ @session.close if @session
67
+ @connection.close
68
+ @connection = nil
69
+ return true
70
+ end
71
+
72
+ # API compatibilty method, doesn't actually indicate that the connection
73
+ # is closed. Will only return true if no connection currently exists
74
+ #
75
+ # @return [Boolean]
76
+ def closed?
77
+ return connection.nil?
78
+ end
79
+
80
+ def runloop
81
+ loop do
82
+ sleep 1
83
+ end
84
+ end
85
+
86
+ def can_unreceive?
87
+ false
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,35 @@
1
+ require 'stomp'
2
+
3
+ module Stapfen
4
+ module Client
5
+ class Stomp < ::Stomp::Client
6
+
7
+ def initialize(config)
8
+ # Perform a deep-copy of the configuration since +Stomp::Client+ will
9
+ # mutate/mess up the configuration +Hash+ passed in here, see:
10
+ # <https://github.com/stompgem/stomp/issues/80>
11
+ super(Marshal.load(Marshal.dump(config)))
12
+ end
13
+
14
+ def connect(*args)
15
+ # No-op, since Stomp::Client will connect on instantiation
16
+ end
17
+
18
+ def can_unreceive?
19
+ true
20
+ end
21
+
22
+ def runloop
23
+ # Performing this join/runningloop to make sure that we don't
24
+ # experience potential deadlocks between signal handlers who might
25
+ # close the connection, and an infinite Client#join call
26
+ #
27
+ # Instead of using client#open? we use #running which will still be
28
+ # true even if the client is currently in an exponential reconnect loop
29
+ while self.running do
30
+ self.join(1)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Stapfen
3
+ module Client
4
+ #def publish(destination, body)
5
+ # destination = Stapfen::Destination.from_string(destination)
6
+ #end
7
+ end
8
+ end
@@ -20,6 +20,26 @@ module Stapfen
20
20
  end
21
21
  end
22
22
 
23
+ def as_jms
24
+ if queue?
25
+ return "queue://#{@name}"
26
+ end
27
+
28
+ if topic?
29
+ return "topic://#{@name}"
30
+ end
31
+ end
32
+
33
+ def jms_opts
34
+ if queue?
35
+ return {:queue_name => name}
36
+ end
37
+
38
+ if topic?
39
+ return {:topic_name => name}
40
+ end
41
+ end
42
+
23
43
  # Create a {Stapfen::Destination} from the given string
24
44
  #
25
45
  # @param [String] name
@@ -18,7 +18,7 @@ module Stapfen
18
18
 
19
19
  def proxy_log_method(method, arguments)
20
20
  if self.logger
21
- self.logger.send(method, *arguments)
21
+ self.logger.call.send(method, *arguments)
22
22
  return true
23
23
  end
24
24
  return false
@@ -39,7 +39,7 @@ module Stapfen
39
39
 
40
40
  def proxy_log_method(method, arguments)
41
41
  if self.class.logger
42
- self.class.logger.send(method, *arguments)
42
+ self.class.logger.call.send(method, *arguments)
43
43
  return true
44
44
  end
45
45
  return false
@@ -1,15 +1,3 @@
1
- begin
2
- require 'stomp'
3
- rescue LoadError
4
- # Can't process Stomp
5
- end
6
-
7
- begin
8
- require 'java'
9
- require 'jms'
10
- rescue LoadError
11
- # Can't process JMS
12
- end
13
1
 
14
2
  module Stapfen
15
3
  class Message
@@ -1,3 +1,3 @@
1
1
  module Stapfen
2
- VERSION = '1.5.0'
2
+ VERSION = '2.0.0'
3
3
  end
@@ -11,12 +11,8 @@ module Stapfen
11
11
  @@signals_handled = false
12
12
  @@workers = []
13
13
 
14
- # Class instance variables!
15
- @use_stomp = true
16
-
17
14
  class << self
18
15
  attr_accessor :configuration, :consumers, :logger, :destructor
19
-
20
16
  end
21
17
 
22
18
  # Instantiate a new +Worker+ instance and run it
@@ -56,7 +52,7 @@ module Stapfen
56
52
  end
57
53
 
58
54
  def self.stomp?
59
- @use_stomp
55
+ @use_stomp.nil? || @use_stomp
60
56
  end
61
57
 
62
58
  # Force the worker to use JMS as the messaging protocol.
@@ -82,13 +78,13 @@ module Stapfen
82
78
  end
83
79
 
84
80
  def self.jms?
85
- !(@use_stomp)
81
+ !(stomp?)
86
82
  end
87
83
 
88
84
  # Optional method, should be passed a block which will yield a {{Logger}}
89
85
  # instance for the Stapfen worker to use
90
- def self.log
91
- @logger = yield
86
+ def self.log(&block)
87
+ @logger = block
92
88
  end
93
89
 
94
90
  # Main message consumption block
@@ -158,55 +154,17 @@ module Stapfen
158
154
 
159
155
  def run
160
156
  if self.class.stomp?
161
- run_stomp
157
+ require 'stapfen/client/stomp'
158
+ @client = Stapfen::Client::Stomp.new(self.class.configuration.call)
162
159
  elsif self.class.jms?
163
- run_jms
164
- end
165
- end
166
-
167
- def run_jms
168
- JMS::Connection.start(self.class.configuration.call) do |connection|
169
- @client = connection
170
- debug("Running with #{@client} inside of Thread:#{Thread.current.inspect}")
171
-
172
- self.class.consumers.each do |name, headers, block|
173
- destination = Stapfen::Destination.from_string(name)
174
- type = 'queue'
175
- options = {}
176
-
177
- if destination.queue?
178
- options[:queue_name] = destination.name
179
- end
180
-
181
- if destination.topic?
182
- type = 'topic'
183
- options[:topic_name] = destination.name
184
- end
185
-
186
- method_name = "handle_#{type}_#{name}".to_sym
187
- self.class.send(:define_method, method_name, &block)
188
-
189
- connection.on_message(options) do |m|
190
- message = Stapfen::Message.from_jms(m)
191
- self.send(method_name, message)
192
- end
193
- end
194
-
195
- begin
196
- loop do
197
- sleep 1
198
- end
199
- debug("Exiting the JMS runloop for #{self}")
200
- rescue Interrupt
201
- exit_cleanly
202
- end
160
+ require 'stapfen/client/jms'
161
+ @client = Stapfen::Client::JMS.new(self.class.configuration.call)
203
162
  end
204
- end
205
163
 
206
- def run_stomp
207
- @client = Stomp::Client.new(self.class.configuration.call)
208
164
  debug("Running with #{@client} inside of Thread:#{Thread.current.inspect}")
209
165
 
166
+ @client.connect
167
+
210
168
  self.class.consumers.each do |name, headers, block|
211
169
  unreceive_headers = {}
212
170
  [:max_redeliveries, :dead_letter_queue].each do |sym|
@@ -219,25 +177,28 @@ module Stapfen
219
177
  method_name = name.gsub(/[.|\-]/, '_').to_sym
220
178
  self.class.send(:define_method, method_name, &block)
221
179
 
222
- client.subscribe(name, headers) do |message|
180
+ client.subscribe(name, headers) do |m|
181
+ message = nil
182
+ if self.class.stomp?
183
+ message = Stapfen::Message.from_stomp(m)
184
+ end
185
+
186
+ if self.class.jms?
187
+ message = Stapfen::Message.from_jms(m)
188
+ end
189
+
223
190
  success = self.send(method_name, message)
224
191
 
225
- if !success && !unreceive_headers.empty?
226
- client.unreceive(message, unreceive_headers)
192
+ unless success
193
+ if client.can_unreceive? && !unreceive_headers.empty?
194
+ client.unreceive(m, unreceive_headers)
195
+ end
227
196
  end
228
197
  end
229
198
  end
230
199
 
231
200
  begin
232
- # Performing this join/runningloop to make sure that we don't
233
- # experience potential deadlocks between signal handlers who might
234
- # close the connection, and an infinite Client#join call
235
- #
236
- # Instead of using client#open? we use #running which will still be
237
- # true even if the client is currently in an exponential reconnect loop
238
- while client.running do
239
- client.join(1)
240
- end
201
+ client.runloop
241
202
  warn("Exiting the runloop for #{self}")
242
203
  rescue Interrupt
243
204
  exit_cleanly
@@ -251,8 +212,10 @@ module Stapfen
251
212
  self.class.destructor.call if self.class.destructor
252
213
 
253
214
  # Only close the client if we have one sitting around
254
- if client && !client.closed?
255
- client.close
215
+ if client
216
+ unless client.closed?
217
+ client.close
218
+ end
256
219
  end
257
220
  end
258
221
  end
data/lib/stapfen.rb CHANGED
@@ -1,4 +1,19 @@
1
+ begin
2
+ require 'stomp'
3
+ rescue LoadError
4
+ # Can't process Stomp
5
+ end
6
+
7
+ begin
8
+ require 'java'
9
+ require 'jms'
10
+ rescue LoadError
11
+ # Can't process JMS
12
+ end
13
+
14
+
1
15
  require 'stapfen/version'
16
+ require 'stapfen/client'
2
17
  require 'stapfen/worker'
3
18
 
4
19
  module Stapfen
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ if RUBY_PLATFORM == 'java'
4
+ require 'stapfen/client/jms'
5
+
6
+ describe Stapfen::Client::JMS, :java => true do
7
+ let(:config) { {} }
8
+ subject(:client) { described_class.new(config) }
9
+
10
+ it { should respond_to :connect }
11
+
12
+ describe '#can_unreceive?' do
13
+ subject { client.can_unreceive? }
14
+
15
+ it { should_not be_true }
16
+ end
17
+
18
+ describe '#connect' do
19
+ subject(:connection) { client.connect }
20
+ let(:jms_conn) { double('JMS::Connection') }
21
+
22
+ before :each do
23
+ ::JMS::Connection.should_receive(:new).and_return(jms_conn)
24
+ end
25
+
26
+ it 'should start the connection' do
27
+ jms_conn.should_receive(:start)
28
+ expect(connection).to eql(jms_conn)
29
+ end
30
+ end
31
+
32
+ describe '#session' do
33
+ let(:session) { double('JMS::Session') }
34
+ let(:connection) { double('JMS::Connection') }
35
+
36
+ before :each do
37
+ client.stub(:connection => connection)
38
+ end
39
+
40
+ context 'without a session already' do
41
+ it 'should create a new session' do
42
+ connection.should_receive(:create_session).and_return(session)
43
+ expect(client.session).to eql(session)
44
+ end
45
+ end
46
+
47
+ context 'with an existing session' do
48
+ it 'should return that existing session' do
49
+ connection.should_receive(:create_session).once.and_return(session)
50
+ 3.times do
51
+ expect(client.session).to eql(session)
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#publish' do
58
+ end
59
+
60
+ describe '#closed?' do
61
+ subject(:result) { client.closed? }
62
+
63
+ context 'if a connection exists' do
64
+ before :each do
65
+ client.stub(:connection).and_return(double('JMS::Connection'))
66
+ end
67
+
68
+ it { should be_false }
69
+ end
70
+
71
+ context 'without a connection' do
72
+ it { should be_true }
73
+ end
74
+ end
75
+
76
+ describe '#close' do
77
+ subject(:result) { client.close }
78
+ let(:connection) { double('JMS::Connection') }
79
+
80
+ before :each do
81
+ client.instance_variable_set(:@connection, connection)
82
+ end
83
+
84
+ context 'without an existing session' do
85
+ it 'should close the client' do
86
+ connection.should_receive(:close)
87
+ expect(result).to be_true
88
+ end
89
+ end
90
+
91
+ context 'with an existing session' do
92
+ let(:session) { double('JMS::Session') }
93
+
94
+ before :each do
95
+ client.instance_variable_set(:@session, session)
96
+ end
97
+
98
+ it 'should close the client and session' do
99
+ session.should_receive(:close)
100
+ connection.should_receive(:close)
101
+ expect(result).to be_true
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+ require 'stapfen/client/stomp'
3
+
4
+ describe Stapfen::Client::Stomp do
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+ require 'stapfen/client'
3
+
4
+ describe Stapfen::Client do
5
+ end
@@ -5,6 +5,19 @@ describe Stapfen::Destination do
5
5
  it { should respond_to :name }
6
6
  it { should respond_to :type }
7
7
 
8
+ describe '#as_jms' do
9
+ let(:name) { 'rspec/dlq' }
10
+ subject(:destination) do
11
+ d = described_class.new
12
+ d.type = :queue
13
+ d.name = name
14
+ d.as_jms
15
+ end
16
+
17
+ it { should be_instance_of String }
18
+ it { should eql "queue://#{name}" }
19
+ end
20
+
8
21
  describe '#as_stomp' do
9
22
  let(:name) { 'rspec/dlq' }
10
23
 
data/spec/logger_spec.rb CHANGED
@@ -29,7 +29,7 @@ describe Stapfen::Logger do
29
29
  let(:plogger) { double('RSpec Logger') }
30
30
 
31
31
  before :each do
32
- logger.class.stub(:logger).and_return(plogger)
32
+ logger.class.stub(:logger).and_return(lambda { plogger })
33
33
  end
34
34
 
35
35
  it 'should pass info messages along' do
data/spec/worker_spec.rb CHANGED
@@ -38,6 +38,22 @@ describe Stapfen::Worker do
38
38
  end
39
39
  end
40
40
 
41
+ describe '#log' do
42
+ it "should store the block it's passed" do
43
+ logger = double('Mock Logger')
44
+
45
+ worker.log do
46
+ logger
47
+ end
48
+
49
+ expect(worker.logger).to be_instance_of Proc
50
+ end
51
+
52
+ after :each do
53
+ worker.logger = nil
54
+ end
55
+ end
56
+
41
57
  describe '#configure' do
42
58
  it 'should error when not passed a block' do
43
59
  expect {
@@ -52,11 +68,10 @@ describe Stapfen::Worker do
52
68
  config
53
69
  end
54
70
 
55
- worker.configuration.call.should == config
71
+ expect(worker.configuration.call).to eql(config)
56
72
  end
57
73
  end
58
74
 
59
-
60
75
  describe '#exit_cleanly' do
61
76
  subject(:result) { worker.exit_cleanly }
62
77
 
@@ -120,14 +135,28 @@ describe Stapfen::Worker do
120
135
  end
121
136
 
122
137
  context 'unreceive behavior' do
123
- let(:client) { double('Stomp::Client', :running => false) }
138
+ let(:client) do
139
+ c = double('Mock Stapfen::Client')
140
+ c.stub(:connect)
141
+ c.stub(:can_unreceive? => true)
142
+ c.stub(:runloop)
143
+ c
144
+ end
145
+
124
146
  let(:name) { '/queue/some_queue' }
147
+ let(:message) do
148
+ m = Stomp::Message.new(nil)
149
+ m.stub(:body => 'rspec msg')
150
+ m
151
+ end
152
+
153
+
125
154
  before :each do
126
- Stomp::Client.stub(:new).and_return(client)
155
+ Stapfen::Client::Stomp.stub(:new).and_return(client)
127
156
 
128
157
  # Get a subscription? Call the message handler block.
129
158
  client.stub(:subscribe) do |name, headers, &block|
130
- block.call('msg')
159
+ block.call(message)
131
160
  end
132
161
  end
133
162
 
@@ -164,7 +193,7 @@ describe Stapfen::Worker do
164
193
  worker.new.run
165
194
  end
166
195
  it 'should pass :unreceive_headers through to the unreceive call' do
167
- client.should_receive(:unreceive).with('msg', unrec_headers).once
196
+ client.should_receive(:unreceive).with(message, unrec_headers).once
168
197
 
169
198
  worker.consume(name, raw_headers) {|msg| false }
170
199
  worker.new.run
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stapfen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 2.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-27 00:00:00.000000000 Z
12
+ date: 2013-10-03 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A simple gem for writing good basic STOMP workers
15
15
  email:
@@ -19,6 +19,7 @@ extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
21
  - .gitignore
22
+ - CHANGES.md
22
23
  - Gemfile
23
24
  - Guardfile
24
25
  - LICENSE.txt
@@ -26,11 +27,17 @@ files:
26
27
  - Rakefile
27
28
  - examples/simple.rb
28
29
  - lib/stapfen.rb
30
+ - lib/stapfen/client.rb
31
+ - lib/stapfen/client/jms.rb
32
+ - lib/stapfen/client/stomp.rb
29
33
  - lib/stapfen/destination.rb
30
34
  - lib/stapfen/logger.rb
31
35
  - lib/stapfen/message.rb
32
36
  - lib/stapfen/version.rb
33
37
  - lib/stapfen/worker.rb
38
+ - spec/client/jms_spec.rb
39
+ - spec/client/stomp_spec.rb
40
+ - spec/client_spec.rb
34
41
  - spec/destination_spec.rb
35
42
  - spec/logger_spec.rb
36
43
  - spec/message_spec.rb
@@ -51,7 +58,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
51
58
  version: '0'
52
59
  segments:
53
60
  - 0
54
- hash: -1455385429346077259
61
+ hash: 497669016429276389
55
62
  required_rubygems_version: !ruby/object:Gem::Requirement
56
63
  none: false
57
64
  requirements:
@@ -60,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
67
  version: '0'
61
68
  segments:
62
69
  - 0
63
- hash: -1455385429346077259
70
+ hash: 497669016429276389
64
71
  requirements: []
65
72
  rubyforge_project:
66
73
  rubygems_version: 1.8.25
@@ -68,6 +75,9 @@ signing_key:
68
75
  specification_version: 3
69
76
  summary: A simple gem for writing good basic STOMP workers
70
77
  test_files:
78
+ - spec/client/jms_spec.rb
79
+ - spec/client/stomp_spec.rb
80
+ - spec/client_spec.rb
71
81
  - spec/destination_spec.rb
72
82
  - spec/logger_spec.rb
73
83
  - spec/message_spec.rb