ruby_nest_nats 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12ced8e11e87c01a5106285c4b01e7cb75f338adbb952b95d2362d928c76133c
4
- data.tar.gz: '049dd24c5e1015e8b3e90be3f77f352bd934c7837c71881e8f4235a47498e2ec'
3
+ metadata.gz: c27d22ced425f310876883bb15afd2aaa52b24235bb095551b7981bedca4b210
4
+ data.tar.gz: 2537c259848226de1481ce0579b2036200b7d0e45a2a6b098fddd988bae16b4d
5
5
  SHA512:
6
- metadata.gz: 3340f499fe967b290f3b2b21e2f34b69a55ed8b8a003c9e0af897df556890fcb884bdf99f25f67e5195a614c4fde21f311d395d7376bab07b1f51fe88bd37b56
7
- data.tar.gz: 23eabe3e8b26ba41f9e4ca38f55e8ae48c7362a4658d16d92a9b6284843d55ce34a912c3eae8ad8d312a14457b5ea230cc85422bbde3539c66b3788f1c52ba6d
6
+ metadata.gz: b8b7397a66a1f2984d54ae60bc3f299b384695f450a066cb00a64386fcfaf86be7dcad7e1c9e6f9fac4ede7994f41a2f1fa1cbd267563d5551dc2b53ac3512b0
7
+ data.tar.gz: a998c0f7015d4e6a1700ac23db6516cdd29572b92a1aaa18fe784b144862f5a229123820467a4d1e2e9baa5d5e30a618fbbe3bd526ac5e67b6640e08ca6b7e73
data/README.md CHANGED
@@ -6,11 +6,13 @@ The `ruby_nest_nats` gem allows you to listen for (and reply to) NATS messages a
6
6
 
7
7
  - [x] docs
8
8
  - [ ] tests
9
- - [ ] "controller"-style classes for reply organization
9
+ - [x] "controller"-style classes for reply organization
10
+ - [x] runtime subscription additions
10
11
  - [x] multiple queues
11
12
  - [ ] `on_error` handler so you can send a response (what's standard?)
12
13
  - [ ] config options for URL/host/port/etc.
13
14
  - [ ] config for restart behavior (default is to restart listening on any `StandardError`)
15
+ - [ ] consider using child processes instead of threads
14
16
 
15
17
  ## Installation
16
18
 
@@ -36,6 +38,10 @@ Alternatively, install it globally:
36
38
  gem install ruby_nest_nats
37
39
  ```
38
40
 
41
+ ### NATS server
42
+
43
+ **IMPORTANT:** This gem also requires a NATS server to be installed and running before use. See [the NATS documentation](https://docs.nats.io/nats-server/installation) for more details.
44
+
39
45
  ## Usage
40
46
 
41
47
  ### Logging
@@ -45,6 +51,7 @@ gem install ruby_nest_nats
45
51
  Attach a logger to have `ruby_nest_nats` write out logs for messages received, responses sent, errors raised, lifecycle events, etc.
46
52
 
47
53
  ```rb
54
+ require 'ruby_nest_nats'
48
55
  require 'logger'
49
56
 
50
57
  nats_logger = Logger.new(STDOUT)
@@ -68,6 +75,8 @@ The following will be logged at the specified log levels
68
75
  - `WARN`: Error handled gracefully (listening restarted due to some exception, etc.), as well as everything under `ERROR`
69
76
  - `ERROR`: Some exception was raised in-thread (error in handler, error in subscription, etc.)
70
77
 
78
+ <a id="default-queue-section"></a>
79
+
71
80
  ### Setting a default queue
72
81
 
73
82
  Set a default queue for subscriptions.
@@ -82,6 +91,8 @@ Leave the `::default_queue` blank (or assign `nil`) to use no default queue.
82
91
  RubyNestNats::Client.default_queue = nil
83
92
  ```
84
93
 
94
+ <a id="reply-to-section"></a>
95
+
85
96
  ### Registering message handlers
86
97
 
87
98
  Register a message handler with the `RubyNestNats::Client::reply_to` method. Pass a subject string as the first argument (either a static subject string or a pattern to match more than one subject). Specify a queue (or don't) with the `queue:` option. If you don't provide the `queue:` option, it will be set to the value of `default_queue`, or to `nil` (no queue) if a default queue hasn't been set.
@@ -116,10 +127,20 @@ Start listening for messages with the `RubyNestNats::Client::start!` method. Thi
116
127
  RubyNestNats::Client.start!
117
128
  ```
118
129
 
119
- ### Full example
130
+ ### Basic full working example (in vanilla Ruby)
131
+
132
+ The following should be enough to start a `ruby_nest_nats` setup in your Ruby application, using what we've learned so far.
133
+
134
+ > **NOTE:** For a more organized structure and implementation in a larger app (like a Rails project), see the ["controller" section below](#controller-section).
120
135
 
121
136
  ```rb
122
- RubyNestNats::Client.logger = Rails.logger
137
+ require 'ruby_nest_nats'
138
+ require 'logger'
139
+
140
+ nats_logger = Logger.new(STDOUT)
141
+ nats_logger.level = Logger::DEBUG
142
+
143
+ RubyNestNats::Client.logger = nats_logger
123
144
  RubyNestNats::Client.default_queue = "foobar"
124
145
 
125
146
  RubyNestNats::Client.reply_to("some.subject") { |data| "Got it! #{data.inspect}" }
@@ -129,6 +150,86 @@ RubyNestNats::Client.reply_to("subject.in.queue", queue: "barbaz") { { msg: "My
129
150
  RubyNestNats::Client.start!
130
151
  ```
131
152
 
153
+ > **NOTE:** You _can_ invoke `::reply_to` to create additional message subscriptions after `RubyNestNats::Client.start!`, but be aware that this forces the client to restart. You may see (benign, already-handled) errors in the logs generated when this restart happens. It will force the client to restart and re-subscribe after _each additional `::reply_to` invoked after `::start!`._ So, if you have a lot of additional `::reply_to` invocations, you may want to consider refactoring so that your call to `RubyNestNats::Client.start!` occurs _after_ those additions.
154
+
155
+ > **NOTE:** The `::start!` method can be safely called multiple times; only the first will be honored, and any subsequent calls to `::start!` after the client is already started will do nothing (except write a _"NATS is already running"_ log to the logger at the `DEBUG` level).
156
+
157
+ <a id="controller-section"></a>
158
+
159
+ ### Creating "controller"-style classes for listener organization
160
+
161
+ Create controller classes which inherit from `RubyNestNats::Controller` in order to give your message listeners some structure.
162
+
163
+ Use the `::default_queue` macro to set a default queue string. If omitted, the controller will fall back on the default queue assigned with `RubyNestNats::Client::default_queue=` (as described [here](#default-queue-section)). If no default queue is set in either the controller or globally, then the default queue will be blank.
164
+
165
+ Use the `::subject` macro to create a block for listening to that subject segment. Nested calls to `::subject` will append each subsequent subject/pattern string to the last (joined by a periods). There is no limit to the level of nesting.
166
+
167
+ You can register a response for the built-up subject/pattern string using the `::response` macro. Pass a block to `::response` which optionally takes two arguments ([the same arguments supplied to `RubyNestNats::Client::reply_to`](#reply-to-section)). The result of that block will be sent as a response to the message received.
168
+
169
+ ```rb
170
+ class HelloController < RubyNestNats::Controller
171
+ default_queue "foobar"
172
+
173
+ subject "hello" do
174
+ subject "jerk" do
175
+ response do |data|
176
+ # The subject at this point is "hello.jerk"
177
+ "Hey #{data['name']}... that's not cool, man."
178
+ end
179
+ end
180
+
181
+ subject "and" do
182
+ subject "wassup" do
183
+ response do |data|
184
+ # The subject at this point is "hello.and.wassup"
185
+ "Hey, how ya doin', #{data['name']}?"
186
+ end
187
+ end
188
+
189
+ subject "goodbye" do
190
+ response do |data|
191
+ # The subject at this point is "hello.and.goodbye"
192
+ "Hi #{data['name']}! But also GOODBYE."
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ subject "hows" do
199
+ subject "*" do
200
+ subject "doing" do
201
+ response do |data, subject|
202
+ # The subject at this point is "hows.<wildcard>.doing" (i.e., the
203
+ # subjects "hows.jack.doing" and "hows.jill.doing" will both match)
204
+ sender_name = data["name"]
205
+ other_person_name = subject.split(".")[1]
206
+ desc = rand < 0.5 ? "terribly" : "great"
207
+ "Well, #{sender_name}, #{other_person_name} is actually doing #{desc}."
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ ```
214
+
215
+ > **NOTE:** If you implement controllers like this and you are using code-autoloading machinery (like Zeitwerk in Rails), you will need to make sure these paths are eager-loaded when your app starts. **If you don't, `ruby_nest_nats` will not register the listeners,** and will not respond to messages for the specified subjects.
216
+ >
217
+ > For example: in a Rails project (assuming you have your NATS controllers in a directory called `app/nats/`), you may want to put something like the following in an initializer (such as `config/initializers/nats.rb`):
218
+ >
219
+ > ```rb
220
+ > RubyNestNats::Client.logger = Rails.logger
221
+ > RubyNestNats::Client.default_queue = "foobar"
222
+ >
223
+ > # ...
224
+ >
225
+ > Rails.application.config.after_initialize do
226
+ > nats_controller_paths = Dir[Rails.root.join("app", "nats", "**", "*_controller.rb")]
227
+ > nats_controller_paths.each { |file_path| require_dependency(file_path) }
228
+ >
229
+ > RubyNestNats::Client.start!
230
+ > end
231
+ > ```
232
+
132
233
  ## Development
133
234
 
134
235
  ### Install dependencies
@@ -139,7 +240,10 @@ To install the Ruby dependencies, run:
139
240
  bin/setup
140
241
  ```
141
242
 
142
- This gem also requires a NATS server to be running. See [the NATS documentation](https://docs.nats.io/nats-server/installation) for more details.
243
+ This gem also requires a NATS server to be installed and running. See [the NATS documentation](https://docs.nats.io/nats-server/installation) for more details.
244
+ <!-- sudo docker run -p 4222:4222 -p 8222:8222 -p 6222:6222 -ti nats:latest -->
245
+ <!-- nats-tail -s nats://localhost:4222 ">" -->
246
+ <!-- curl --data '{"name":"Keegan"}' --header 'Content-Type: application/json' http://localhost:3000/hello -->
143
247
 
144
248
  ### Open a console
145
249
 
@@ -1,164 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "ruby_nest_nats/version"
4
3
  require "nats/client"
4
+ require_relative "ruby_nest_nats/version"
5
+ require_relative "ruby_nest_nats/utils"
6
+ require_relative "ruby_nest_nats/client"
7
+ require_relative "ruby_nest_nats/controller"
5
8
 
6
9
  module RubyNestNats
7
10
  class Error < StandardError; end
8
-
9
- class Client
10
- class << self
11
- def logger=(some_logger)
12
- log("Setting the logger to #{some_logger.inspect}")
13
- @logger = some_logger
14
- end
15
-
16
- def logger
17
- @logger
18
- end
19
-
20
- def default_queue=(some_queue)
21
- queue = presence(some_queue.to_s)
22
- log("Setting the default queue to #{queue}", level: :debug)
23
- @default_queue = queue
24
- end
25
-
26
- def default_queue
27
- @default_queue
28
- end
29
-
30
- def started?
31
- @started ||= false
32
- end
33
-
34
- def stopped?
35
- !started?
36
- end
37
-
38
- def reply_to(subject, queue: nil, &block)
39
- subject = subject.to_s
40
- queue = (presence(queue) || default_queue).to_s
41
- log("Registering a reply handler for subject '#{subject}'#{" in queue '#{queue}'" if queue}", level: :debug)
42
- register_reply!(subject: subject, handler: block, queue: queue)
43
- end
44
-
45
- def listen
46
- NATS.start do
47
- replies.each do |replier|
48
- log("Subscribing to subject '#{replier[:subject]}'#{" in queue '#{replier[:queue]}'" if replier[:queue]}", level: :debug)
49
-
50
- NATS.subscribe(replier[:subject], queue: replier[:queue]) do |message, inbox, subject|
51
- parsed_message = JSON.parse(message)
52
- id, data, pattern = parsed_message.values_at("id", "data", "pattern")
53
-
54
- log("Received a message!")
55
- message_desc = <<~LOG_MESSAGE
56
- id: #{id || '(none)'}
57
- pattern: #{pattern || '(none)'}
58
- subject: #{subject || '(none)'}
59
- data: #{data.to_json}
60
- inbox: #{inbox || '(none)'}
61
- LOG_MESSAGE
62
- log(message_desc, indent: 2)
63
-
64
- response_data = replier[:handler].call(data)
65
-
66
- log("Responding with '#{response_data}'")
67
-
68
- NATS.publish(inbox, response_data.to_json, queue: replier[:queue])
69
- end
70
- end
71
- end
72
- end
73
-
74
- def stop!
75
- log("Stopping NATS", level: :debug)
76
- NATS.stop rescue nil
77
- stopped!
78
- end
79
-
80
- def restart!
81
- log("Restarting NATS", level: :warn)
82
- stop!
83
- start!
84
- end
85
-
86
- def start!
87
- log("Starting NATS", level: :debug)
88
-
89
- if started?
90
- log("NATS is already running", level: :debug)
91
- return
92
- end
93
-
94
- started!
95
-
96
- Thread.new do
97
- Thread.handle_interrupt(StandardError => :never) do
98
- begin
99
- Thread.handle_interrupt(StandardError => :immediate) { listen }
100
- rescue => e
101
- log("Encountered an error:", level: :error)
102
- log(e.full_message, level: :error, indent: 2)
103
-
104
- restart!
105
- raise e
106
- end
107
- end
108
- end
109
- end
110
-
111
- private
112
-
113
- def log(text, level: :info, indent: 0)
114
- return unless logger
115
-
116
- timestamp = Time.now.to_s
117
- text_lines = text.split("\n")
118
- indentation = indent.is_a?(String) ? indent : (" " * indent)
119
-
120
- text_lines.each do |line|
121
- logger.send(level, "[#{timestamp}] RubyNestNats | #{indentation}#{line}")
122
- end
123
- end
124
-
125
- def started!
126
- @started = true
127
- end
128
-
129
- def stopped!
130
- @started = false
131
- end
132
-
133
- def replies
134
- @replies ||= []
135
- end
136
-
137
- def reply_registered?(raw_subject)
138
- subject = raw_subject.to_s
139
- replies.any? { |reply| reply[:subject] == subject }
140
- end
141
-
142
- def register_reply!(subject:, handler:, queue: nil)
143
- raise StandardError, "NATS already started" if started? # TODO: remove when runtime additions are implemented
144
- raise ArgumentError, "Subject must be a string" unless subject.is_a?(String)
145
- raise ArgumentError, "Must provide a message handler for #{subject}" unless handler.respond_to?(:call)
146
- raise ArgumentError, "Already registered a reply to #{subject}" if reply_registered?(subject)
147
-
148
- replies << { subject: subject, handler: handler, queue: presence(queue) || default_queue }
149
- end
150
-
151
- def blank?(value)
152
- value.respond_to?(:empty?) ? value.empty? : !value
153
- end
154
-
155
- def present?(value)
156
- !blank?(value)
157
- end
158
-
159
- def presence(value)
160
- present?(value) ? value : nil
161
- end
162
- end
163
- end
11
+ class NewSubscriptionsError < StandardError; end
164
12
  end
@@ -0,0 +1,170 @@
1
+ require "json"
2
+ require "nats/client"
3
+ require_relative "./utils"
4
+
5
+ module RubyNestNats
6
+ class Client
7
+ class << self
8
+ def logger=(some_logger)
9
+ log("Setting the logger to #{some_logger.inspect}")
10
+ @logger = some_logger
11
+ end
12
+
13
+ def logger
14
+ @logger
15
+ end
16
+
17
+ def default_queue=(some_queue)
18
+ queue = Utils.presence(some_queue.to_s)
19
+ log("Setting the default queue to #{queue || '(none)'}", level: :debug)
20
+ @default_queue = queue
21
+ end
22
+
23
+ def default_queue
24
+ @default_queue
25
+ end
26
+
27
+ def started?
28
+ @started ||= false
29
+ end
30
+
31
+ def stopped?
32
+ !started?
33
+ end
34
+
35
+ def reply_to(subject, queue: nil, &block)
36
+ queue = Utils.presence(queue) || default_queue
37
+ log("Registering a reply handler for subject '#{subject}'#{" in queue '#{queue}'" if queue}", level: :debug)
38
+ register_reply!(subject: subject.to_s, handler: block, queue: queue.to_s)
39
+ end
40
+
41
+ def start!
42
+ log("Starting NATS", level: :debug)
43
+
44
+ if started?
45
+ log("NATS is already running", level: :debug)
46
+ return
47
+ end
48
+
49
+ started!
50
+
51
+ self.current_thread = Thread.new do
52
+ Thread.handle_interrupt(StandardError => :never) do
53
+ begin
54
+ Thread.handle_interrupt(StandardError => :immediate) { listen }
55
+ rescue NATS::ConnectError => e
56
+ log("Could not connect to NATS server:", level: :error)
57
+ log(e.full_message, level: :error, indent: 2)
58
+ Thread.current.exit
59
+ rescue NewSubscriptionsError => e
60
+ log("New subscriptions! Restarting...", level: :info)
61
+ restart!
62
+ raise e # TODO: there has to be a better way
63
+ rescue StandardError => e
64
+ log("Encountered an error:", level: :error)
65
+ log(e.full_message, level: :error, indent: 2)
66
+ restart!
67
+ raise e
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def log(text, level: :info, indent: 0)
76
+ return unless logger
77
+
78
+ timestamp = Time.now.to_s
79
+ text_lines = text.split("\n")
80
+ indentation = indent.is_a?(String) ? indent : (" " * indent)
81
+
82
+ text_lines.each do |line|
83
+ logger.send(level, "[#{timestamp}] RubyNestNats | #{indentation}#{line}")
84
+ end
85
+ end
86
+
87
+ def stop!
88
+ log("Stopping NATS", level: :debug)
89
+ NATS.stop rescue nil
90
+ stopped!
91
+ end
92
+
93
+ def restart!
94
+ log("Restarting NATS", level: :warn)
95
+ stop!
96
+ start!
97
+ end
98
+
99
+ def started!
100
+ @started = true
101
+ end
102
+
103
+ def stopped!
104
+ @started = false
105
+ end
106
+
107
+ def replies
108
+ @replies ||= []
109
+ end
110
+
111
+ def current_thread
112
+ @current_thread
113
+ end
114
+
115
+ def current_thread=(some_thread)
116
+ @current_thread = some_thread
117
+ end
118
+
119
+ def reply_registered?(raw_subject)
120
+ subject = raw_subject.to_s
121
+ replies.any? { |reply| reply[:subject] == subject }
122
+ end
123
+
124
+ def register_reply!(subject:, handler:, queue: nil)
125
+ raise ArgumentError, "Subject must be a string" unless subject.is_a?(String)
126
+ raise ArgumentError, "Must provide a message handler for #{subject}" unless handler.respond_to?(:call)
127
+ raise ArgumentError, "Already registered a reply to #{subject}" if reply_registered?(subject)
128
+
129
+ reply = {
130
+ subject: subject,
131
+ handler: handler,
132
+ queue: Utils.presence(queue) || default_queue
133
+ }
134
+
135
+ replies << reply
136
+
137
+ self.current_thread.raise(NewSubscriptionsError, "New reply registered") if started?
138
+ end
139
+
140
+ def listen
141
+ NATS.start do
142
+ replies.each do |replier|
143
+ log("Subscribing to subject '#{replier[:subject]}'#{" in queue '#{replier[:queue]}'" if replier[:queue]}", level: :debug)
144
+
145
+ NATS.subscribe(replier[:subject], queue: replier[:queue]) do |message, inbox, subject|
146
+ parsed_message = JSON.parse(message)
147
+ id, data, pattern = parsed_message.values_at("id", "data", "pattern")
148
+
149
+ log("Received a message!")
150
+ message_desc = <<~LOG_MESSAGE
151
+ id: #{id || '(none)'}
152
+ pattern: #{pattern || '(none)'}
153
+ subject: #{subject || '(none)'}
154
+ data: #{data.to_json}
155
+ inbox: #{inbox || '(none)'}
156
+ LOG_MESSAGE
157
+ log(message_desc, indent: 2)
158
+
159
+ response_data = replier[:handler].call(data)
160
+
161
+ log("Responding with '#{response_data}'")
162
+
163
+ NATS.publish(inbox, response_data.to_json, queue: replier[:queue])
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,67 @@
1
+ require_relative "./utils"
2
+
3
+ module RubyNestNats
4
+ class Controller
5
+ NO_QUEUE_GIVEN = :ruby_nest_nats_super_special_no_op_queue_symbol_qwertyuiop_1234567890
6
+
7
+ class << self
8
+ # Default queue for the controller. Falls back to the client's default
9
+ # queue if the controller's default queue is `nil`.
10
+ #
11
+ # - Call with no argument (`::default_queue`) to get the default queue.
12
+ # - Call as a macro with an argument (`default_queue "something"`) to set
13
+ # the default queue.
14
+ #
15
+ # Example:
16
+ #
17
+ # class FoobarNatsController < RubyNatsController
18
+ # default_queue "foobar"
19
+ #
20
+ # # ...
21
+ # end
22
+ #
23
+ def default_queue(some_queue = NO_QUEUE_GIVEN)
24
+ # `NO_QUEUE_GIVEN` is a special symbol (rather than `nil`) so that the
25
+ # default queue can be "unset" to `nil` (given a non-`nil` global
26
+ # default set with `RubyNestNats::Client::default_queue=`).
27
+ if some_queue == NO_QUEUE_GIVEN
28
+ @default_queue || Client.default_queue
29
+ else
30
+ @default_queue = Utils.presence(some_queue.to_s)
31
+ end
32
+ end
33
+
34
+ def subject(subject_segment, queue: nil)
35
+ subject_chain.push(subject_segment)
36
+ old_queue = current_queue
37
+ self.current_queue = queue if Utils.present?(queue)
38
+ yield
39
+ self.current_queue = old_queue
40
+ subject_chain.pop
41
+ end
42
+
43
+ def response(queue: nil, &block)
44
+ response_queue = Utils.presence(queue.to_s) || current_queue || default_queue
45
+ Client.reply_to(current_subject, queue: response_queue, &block)
46
+ end
47
+
48
+ private
49
+
50
+ def subject_chain
51
+ @subject_chain ||= []
52
+ end
53
+
54
+ def current_subject
55
+ subject_chain.join(".")
56
+ end
57
+
58
+ def current_queue
59
+ @current_queue ||= nil
60
+ end
61
+
62
+ def current_queue=(some_queue)
63
+ @current_queue = Utils.presence(some_queue)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ module RubyNestNats
2
+ class Utils
3
+ class << self
4
+ def blank?(value)
5
+ value.respond_to?(:empty?) ? value.empty? : !value
6
+ end
7
+
8
+ def present?(value)
9
+ !blank?(value)
10
+ end
11
+
12
+ def presence(value)
13
+ present?(value) ? value : nil
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyNestNats
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_nest_nats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keegan Leitz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-12 00:00:00.000000000 Z
11
+ date: 2021-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -155,6 +155,9 @@ files:
155
155
  - bin/console
156
156
  - bin/setup
157
157
  - lib/ruby_nest_nats.rb
158
+ - lib/ruby_nest_nats/client.rb
159
+ - lib/ruby_nest_nats/controller.rb
160
+ - lib/ruby_nest_nats/utils.rb
158
161
  - lib/ruby_nest_nats/version.rb
159
162
  - ruby_nest_nats.gemspec
160
163
  homepage: https://github.com/openbay/ruby_nest_nats