ears 0.3.1 → 0.3.2

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: 8d16a56d89359232938fc2e04641e7db0f45440bd6cee7770b8e7d0be30fb014
4
- data.tar.gz: fd3f8ce9db2ec52e646593b57c0f0b868d13fc5edb09c66e4ee7f345e49cd605
3
+ metadata.gz: 3f0fa1b69a334f5ec5d649478a46d0c78298621a2c879c3b62457b8dd41723fe
4
+ data.tar.gz: e34d3bee6f15435ca5c9847b384aad75e6acd3ccd06dbb9a751a798f63f3a077
5
5
  SHA512:
6
- metadata.gz: d36a71c0a123865108370bdfa167a33128331b35626556794becb972b4ead16368df897f4cb6c998926c5b353e095580a67f7687cc111a2f54c2c80f84b10fb9
7
- data.tar.gz: 8ed9d81e0da9cc807f15a81faf72dc88763e0482d31db53fc0f8b720be032bb3ccc657e5caa03bbefdf1816e2b69dd069230f2ac6a223cb56814c4237ee3d8f9
6
+ metadata.gz: 4d914d9a7e5ce22b6595899952626bbbec3b1885a6ff0b4fbf768560d4382dadb64578a9c305d0573afba36918e0eccd8c704ccfb681a76f606a09cf8b23b2c6
7
+ data.tar.gz: f6f95145e4c70a565cd95755602116755e79000ca530883aadcf8d9461aacdf3d6828bf67533ed7f7458471473972839ef5745b1e44c933705678be119260f63
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.2 (2021-05-21)
4
+
5
+ ### Changes
6
+
7
+ - added YARD documentation and usage instructions to README
8
+ - introduced `Ears::Middleware` as an abstract base class for middlewares
9
+
3
10
  ## 0.3.1 (2021-05-07)
4
11
 
5
12
  ### Changes
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ears (0.3.1)
4
+ ears (0.3.2)
5
5
  bunny
6
6
  multi_json
7
7
 
@@ -19,6 +19,7 @@ GEM
19
19
  ast (~> 2.4.1)
20
20
  rainbow (3.0.0)
21
21
  rake (13.0.3)
22
+ redcarpet (3.5.1)
22
23
  regexp_parser (2.1.1)
23
24
  rexml (3.2.4)
24
25
  rspec (3.10.0)
@@ -52,6 +53,7 @@ GEM
52
53
  rubocop-ast (>= 1.1.0)
53
54
  ruby-progressbar (1.11.0)
54
55
  unicode-display_width (2.0.0)
56
+ yard (0.9.26)
55
57
 
56
58
  PLATFORMS
57
59
  x86_64-darwin-20
@@ -60,10 +62,12 @@ PLATFORMS
60
62
  DEPENDENCIES
61
63
  ears!
62
64
  rake
65
+ redcarpet
63
66
  rspec
64
67
  rubocop
65
68
  rubocop-rake
66
69
  rubocop-rspec
70
+ yard
67
71
 
68
72
  BUNDLED WITH
69
73
  2.2.3
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ears
2
2
 
3
- TODO: Write description here
3
+ `Ears` is a small, simple library for writing RabbitMQ consumers.
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,16 +20,141 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ ### Basic usage
24
+
25
+ First, you should configure where `Ears` should connect to.
26
+
27
+ ```ruby
28
+ require 'ears'
29
+
30
+ Ears.configure do |config|
31
+ config.rabbitmq_url = 'amqp://user:password@myrmq:5672'
32
+ end
33
+ ```
34
+
35
+ Next, define your exchanges, queues, and consumers by calling `Ears.setup`.
36
+
37
+ ```ruby
38
+ Ears.setup do
39
+ # define a durable topic exchange
40
+ my_exchange = exchange('my_exchange', :topic, durable: true)
41
+
42
+ # define a queue
43
+ my_queue = queue('my_queue', durable: true)
44
+
45
+ # bind your queue to the exchange
46
+ my_queue.bind(my_exchange, routing_key: 'my.routing.key')
47
+
48
+ # define a consumer that handles messages for that queue
49
+ consumer(my_queue, MyConsumer)
50
+ end
51
+ ```
52
+
53
+ Finally, you need to implement `MyConsumer` by subclassing `Ears::Consumer`.
54
+
55
+ ```ruby
56
+ class MyConsumer < Ears::Consumer
57
+ def work(delivery_info, metadata, payload)
58
+ message = JSON.parse(payload)
59
+ do_stuff(message)
60
+
61
+ ack
62
+ end
63
+ end
64
+ ```
65
+
66
+ At the end of the `#work` method, you must always return `ack`, `reject`, or `requeue` to signal what should be done with the message.
67
+
68
+ ### Middlewares
69
+
70
+ `Ears` supports middlewares that you can use for recurring tasks that you don't always want to reimplement. It comes with some built-in middlewares:
71
+
72
+ - `Ears::JSON` for automatically parsing JSON payloads
73
+ - `Ears::Appsignal` for automatically wrapping `#work` in an Appsignal transaction
74
+
75
+ You can use a middleware by just calling `use` with the middleware you want to register in your consumer.
76
+
77
+ ```ruby
78
+ require 'ears/middlewares/json'
79
+
80
+ class MyConsumer < Ears::Consumer
81
+ # register the JSON middleware and don't symbolize keys (this can be omitted, the default is true)
82
+ use Ears::Middlewares::JSON, symbolize_keys: false
83
+
84
+ def work(delivery_info, metadata, payload)
85
+ return ack unless payload['data'].nil? # this now just works
86
+ end
87
+ end
88
+ ```
89
+
90
+ If you want to implement your own middleware, just subclass `Ears::Middleware` and implement `#call` (and if you need it `#initialize`).
91
+
92
+ ```ruby
93
+ class MyMiddleware < Ears::Middleware
94
+ def initialize(opts = {})
95
+ @my_option = opts.fetch(:my_option, nil)
96
+ end
97
+
98
+ def call(delivery_info, metadata, payload, app)
99
+ do_stuff
100
+
101
+ # always call the next middleware in the chain or your consumer will never be called
102
+ app.call(delivery_info, metadata, payload)
103
+ end
104
+ end
105
+ ```
106
+
107
+ ### Multiple threads
108
+
109
+ If you need to handle a lot of messages, you might want to have multiple instances of the same consumer all working on a dedicated thread. This is supported out of the box. You just have to define how many consumers you want when calling `consumer` in `Ears.setup`.
110
+
111
+ ```ruby
112
+ Ears.setup do
113
+ my_exchange = exchange('my_exchange', :topic, durable: true)
114
+ my_queue = queue('my_queue', durable: true)
115
+ my_queue.bind(my_exchange, routing_key: 'my.routing.key')
116
+
117
+ # this will instantiate MyConsumer 10 times and run every instance on a dedicated thread
118
+ consumer(my_queue, MyConsumer, 10)
119
+ end
120
+ ```
121
+
122
+ It may also be interesting for you to increase the prefetch amount. The default prefetch amount is 1, but if you have a lot of very small, fast to process messages, a higher prefetch is a good idea. Just set it when defining your consumer.
123
+
124
+ ```ruby
125
+ Ears.setup do
126
+ my_exchange = exchange('my_exchange', :topic, durable: true)
127
+ my_queue = queue('my_queue', durable: true)
128
+ my_queue.bind(my_exchange, routing_key: 'my.routing.key')
129
+
130
+ # this will instantiate one consumer but with a prefetch value of 10
131
+ consumer(my_queue, MyConsumer, 1, prefetch: 10)
132
+ end
133
+ ```
134
+
135
+ ### Setting arbitrary exchange/queue parameters
136
+
137
+ If you need some custom arguments on your exchange or queue, you can just pass these to `queue` or `exchange` inside `Ears.setup`. These are then just passed on to `Bunny::Queue` and `Bunny::Exchange`.
138
+
139
+ ```ruby
140
+ Ears.setup do
141
+ my_queue =
142
+ queue('my_queue', durable: true, arguments: { 'x-message-ttl' => 10_000 })
143
+ end
144
+ ```
145
+
146
+ ## Documentation
147
+
148
+ If you need more in-depth information, look at [our API documentation](https://www.rubydoc.info/gems/ears).
24
149
 
25
150
  ## Contributing
26
151
 
27
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ears. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/ears/blob/master/CODE_OF_CONDUCT.md).
152
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ivx/ears. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/ivx/ears/blob/master/CODE_OF_CONDUCT.md).
28
153
 
29
154
  ## License
30
155
 
31
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
156
+ The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
32
157
 
33
158
  ## Code of Conduct
34
159
 
35
- Everyone interacting in the Ears project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/ears/blob/master/CODE_OF_CONDUCT.md).
160
+ Everyone interacting in the Ears project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/ivx/ears/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
+ require 'yard'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
5
6
 
7
+ YARD::Rake::YardocTask.new { |t| t.files = ['lib/**/*.rb'] }
8
+
6
9
  task default: :spec
data/ears.gemspec CHANGED
@@ -33,8 +33,10 @@ Gem::Specification.new do |spec|
33
33
  spec.add_dependency 'multi_json'
34
34
 
35
35
  spec.add_development_dependency 'rake'
36
+ spec.add_development_dependency 'redcarpet'
36
37
  spec.add_development_dependency 'rspec'
37
38
  spec.add_development_dependency 'rubocop'
38
39
  spec.add_development_dependency 'rubocop-rake'
39
40
  spec.add_development_dependency 'rubocop-rspec'
41
+ spec.add_development_dependency 'yard'
40
42
  end
data/lib/ears.rb CHANGED
@@ -1,26 +1,35 @@
1
1
  require 'bunny'
2
2
  require 'ears/configuration'
3
3
  require 'ears/consumer'
4
+ require 'ears/middleware'
4
5
  require 'ears/setup'
5
6
  require 'ears/version'
6
7
 
7
8
  module Ears
8
- class Error < StandardError
9
- end
10
-
11
9
  class << self
10
+ # The global configuration for Ears.
11
+ #
12
+ # @return [Ears::Configuration]
12
13
  def configuration
13
14
  @configuration ||= Ears::Configuration.new
14
15
  end
15
16
 
17
+ # Yields the global configuration instance so you can modify it.
18
+ # @yieldparam configuration [Ears::Configuration] The global configuration instance.
16
19
  def configure
17
20
  yield(configuration)
18
21
  end
19
22
 
23
+ # The global RabbitMQ connection used by Ears.
24
+ #
25
+ # @return [Bunny::Session]
20
26
  def connection
21
27
  @connection ||= Bunny.new.tap { |conn| conn.start }
22
28
  end
23
29
 
30
+ # The channel for the current thread.
31
+ #
32
+ # @return [Bunny::Channel]
24
33
  def channel
25
34
  Thread.current[:ears_channel] ||=
26
35
  connection
@@ -31,10 +40,13 @@ module Ears
31
40
  end
32
41
  end
33
42
 
43
+ # Used to set up your exchanges, queues and consumers. See {Ears::Setup} for implementation details.
34
44
  def setup(&block)
35
45
  Ears::Setup.new.instance_eval(&block)
36
46
  end
37
47
 
48
+ # Blocks the calling thread until +SIGTERM+ or +SIGINT+ is received.
49
+ # Used to keep the process alive while processing messages.
38
50
  def run!
39
51
  running = true
40
52
  Signal.trap('INT') { running = false }
@@ -42,6 +54,7 @@ module Ears
42
54
  sleep 1 while running
43
55
  end
44
56
 
57
+ # Used internally for testing.
45
58
  def reset!
46
59
  @connection = nil
47
60
  Thread.current[:ears_channel] = nil
@@ -1,7 +1,9 @@
1
1
  module Ears
2
+ # The class representing the global {Ears} configuration.
2
3
  class Configuration
3
4
  DEFAULT_RABBITMQ_URL = 'amqp://guest:guest@localhost:5672'
4
5
 
6
+ # @return [String] the connection string for RabbitMQ.
5
7
  attr_accessor :rabbitmq_url
6
8
 
7
9
  def initialize
data/lib/ears/consumer.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  require 'bunny'
2
2
 
3
3
  module Ears
4
+ # The abstract base class for consumers processing messages from queues.
5
+ # @abstract Subclass and override {#work} to implement.
4
6
  class Consumer
7
+ # Error that is raised when an invalid value is returned from {#work}
5
8
  class InvalidReturnError < StandardError
6
9
  def initialize(value)
7
10
  super(
@@ -10,18 +13,38 @@ module Ears
10
13
  end
11
14
  end
12
15
 
16
+ # List of registered middlewares. Register new middlewares with {.use}.
17
+ # @return [Array<Ears::Middleware>]
13
18
  def self.middlewares
14
19
  @middlewares ||= []
15
20
  end
16
21
 
22
+ # Registers a new middleware by instantiating +middleware+ and passing it +opts+.
23
+ #
24
+ # @param [Class<Ears::Middleware>] middleware The middleware class to instantiate and register.
25
+ # @param [Hash] opts The options for instantiating the middleware.
17
26
  def self.use(middleware, opts = {})
18
27
  middlewares << middleware.new(opts)
19
28
  end
20
29
 
30
+ # The method that is called when a message from the queue is received.
31
+ # Keep in mind that the parameters received can be altered by middlewares!
32
+ #
33
+ # @param [Bunny::DeliveryInfo] delivery_info The delivery info of the message.
34
+ # @param [Bunny::MessageProperties] metadata The metadata of the message.
35
+ # @param [String] payload The payload of the message.
36
+ #
37
+ # @return [:ack, :reject, :requeue] A symbol denoting what should be done with the message.
21
38
  def work(delivery_info, metadata, payload)
22
39
  raise NotImplementedError
23
40
  end
24
41
 
42
+ # Wraps #work to add middlewares. This is being called by Ears when a message is received for the consumer.
43
+ #
44
+ # @param [Bunny::DeliveryInfo] delivery_info The delivery info of the received message.
45
+ # @param [Bunny::MessageProperties] metadata The metadata of the received message.
46
+ # @param [String] payload The payload of the received message.
47
+ # @raise [InvalidReturnError] if you return something other than +:ack+, +:reject+ or +:requeue+ from {#work}.
25
48
  def process_delivery(delivery_info, metadata, payload)
26
49
  self.class.middlewares.reverse.reduce(
27
50
  work_proc,
@@ -32,14 +55,24 @@ module Ears
32
55
 
33
56
  protected
34
57
 
58
+ # Helper method to ack a message.
59
+ #
60
+ # @return [:ack]
35
61
  def ack
36
62
  :ack
37
63
  end
38
64
 
65
+ # Helper method to reject a message.
66
+ #
67
+ # @return [:reject]
68
+ #
39
69
  def reject
40
70
  :reject
41
71
  end
42
72
 
73
+ # Helper method to requeue a message.
74
+ #
75
+ # @return [:requeue]
43
76
  def requeue
44
77
  :requeue
45
78
  end
@@ -1,12 +1,23 @@
1
1
  require 'bunny'
2
2
 
3
3
  module Ears
4
+ # Wraps the user-defined consumer to provide the expected interface to Bunny.
4
5
  class ConsumerWrapper < Bunny::Consumer
6
+ # @param [Ears::Consumer] consumer The user-defined consumer implementation derived from {Ears::Consumer}.
7
+ # @param [Bunny::Channel] channel The channel used for the consumer.
8
+ # @param [Bunny::Queue] queue The queue the consumer is subscribed to.
9
+ # @param [String] consumer_tag A string identifying the consumer instance.
10
+ # @param [Hash] arguments Arguments that are passed on to +Bunny::Consumer.new+.
5
11
  def initialize(consumer, channel, queue, consumer_tag, arguments = {})
6
12
  @consumer = consumer
7
13
  super(channel, queue, consumer_tag, false, false, arguments)
8
14
  end
9
15
 
16
+ # Called when a message is received from the subscribed queue.
17
+ #
18
+ # @param [Bunny::DeliveryInfo] delivery_info The delivery info of the received message.
19
+ # @param [Bunny::MessageProperties] metadata The metadata of the received message.
20
+ # @param [String] payload The payload of the received message.
10
21
  def process_delivery(delivery_info, metadata, payload)
11
22
  consumer
12
23
  .process_delivery(delivery_info, metadata, payload)
@@ -0,0 +1,15 @@
1
+ module Ears
2
+ # The abstract base class for middlewares.
3
+ # @abstract Subclass and override {#call} (and maybe +#initialize+) to implement.
4
+ class Middleware
5
+ # Invokes the middleware.
6
+ #
7
+ # @param [Bunny::DeliveryInfo] delivery_info The delivery info of the received message.
8
+ # @param [Bunny::MessageProperties] metadata The metadata of the received message.
9
+ # @param [String] payload The payload of the received message.
10
+ # @param app The next middleware to call or the actual consumer instance.
11
+ def call(delivery_info, metadata, payload, app)
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
@@ -1,9 +1,14 @@
1
+ require 'ears/middleware'
2
+
1
3
  module Ears
2
4
  module Middlewares
3
- class Appsignal
4
- attr_reader :transaction_name, :class_name, :method
5
-
5
+ # A middleware that automatically wraps {Ears::Consumer#work} in an Appsignal transaction.
6
+ class Appsignal < Middleware
7
+ # @param [Hash] opts The options for the middleware.
8
+ # @option opts [String] :transaction_name The name of the Appsignal transaction.
9
+ # @option opts [String] :class_name The name of the class you want to monitor.
6
10
  def initialize(opts)
11
+ super()
7
12
  @transaction_name = opts.fetch(:transaction_name)
8
13
  @class_name = opts.fetch(:class_name)
9
14
  end
@@ -16,6 +21,10 @@ module Ears
16
21
  queue_start: Time.now.utc,
17
22
  ) { app.call(delivery_info, metadata, payload) }
18
23
  end
24
+
25
+ private
26
+
27
+ attr_reader :transaction_name, :class_name
19
28
  end
20
29
  end
21
30
  end
@@ -1,11 +1,14 @@
1
+ require 'ears/middleware'
1
2
  require 'multi_json'
2
3
 
3
4
  module Ears
4
5
  module Middlewares
5
- class JSON
6
- attr_reader :symbolize_keys
7
-
6
+ # A middleware that automatically parses your JSON payload.
7
+ class JSON < Middleware
8
+ # @param [Hash] opts The options for the middleware.
9
+ # @option opts [Boolean] :symbolize_keys Whether to symbolize the keys of your payload.
8
10
  def initialize(opts = {})
11
+ super()
9
12
  @symbolize_keys = opts.fetch(:symbolize_keys, true)
10
13
  end
11
14
 
@@ -13,6 +16,10 @@ module Ears
13
16
  parsed_payload = MultiJson.load(payload, symbolize_keys: symbolize_keys)
14
17
  app.call(delivery_info, metadata, parsed_payload)
15
18
  end
19
+
20
+ private
21
+
22
+ attr_reader :symbolize_keys
16
23
  end
17
24
  end
18
25
  end
data/lib/ears/setup.rb CHANGED
@@ -3,15 +3,34 @@ require 'ears/consumer'
3
3
  require 'ears/consumer_wrapper'
4
4
 
5
5
  module Ears
6
+ # Contains methods used in {Ears.setup} to set up your exchanges, queues and consumers.
6
7
  class Setup
8
+ # Creates a new exchange if it does not already exist.
9
+ #
10
+ # @param [String] name The name of the exchange.
11
+ # @param [Symbol] type The type of the exchange (:direct, :fanout, :topic or :headers).
12
+ # @param [Hash] opts The options for the exchange. These are passed on to +Bunny::Exchange.new+.
13
+ # @return [Bunny::Exchange] The exchange that was either newly created or was already there.
7
14
  def exchange(name, type, opts = {})
8
15
  Bunny::Exchange.new(Ears.channel, type, name, opts)
9
16
  end
10
17
 
18
+ # Creates a new queue if it does not already exist.
19
+ #
20
+ # @param [String] name The name of the queue.
21
+ # @param [Hash] opts The options for the queue. These are passed on to +Bunny::Exchange.new+.
22
+ # @return [Bunny::Queue] The queue that was either newly created or was already there.
11
23
  def queue(name, opts = {})
12
24
  Bunny::Queue.new(Ears.channel, name, opts)
13
25
  end
14
26
 
27
+ # Creates and starts one or many consumers bound to the given queue.
28
+ #
29
+ # @param [Bunny::Queue] queue The queue the consumers should be subscribed to.
30
+ # @param [Class<Ears::Consumer>] consumer_class A class implementing {Ears::Consumer} that holds the consumer behavior.
31
+ # @param [Integer] threads The number of threads that should be used to process messages from the queue.
32
+ # @param [Hash] args The arguments for the consumer. These are passed on to +Bunny::Consumer.new+.
33
+ # @option args [Integer] :prefetch (1) The prefetch count used for this consumer.
15
34
  def consumer(queue, consumer_class, threads = 1, args = {})
16
35
  threads.times do |n|
17
36
  consumer_queue = create_consumer_queue(queue, args)
data/lib/ears/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ears
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ears
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mario Mainz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-07 00:00:00.000000000 Z
11
+ date: 2021-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: redcarpet
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +122,20 @@ dependencies:
108
122
  - - ">="
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yard
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
111
139
  description: A gem for building RabbitMQ consumers.
112
140
  email:
113
141
  - mario.mainz@invision.de
@@ -132,6 +160,7 @@ files:
132
160
  - lib/ears/configuration.rb
133
161
  - lib/ears/consumer.rb
134
162
  - lib/ears/consumer_wrapper.rb
163
+ - lib/ears/middleware.rb
135
164
  - lib/ears/middlewares/appsignal.rb
136
165
  - lib/ears/middlewares/json.rb
137
166
  - lib/ears/setup.rb