rabbit_feed 2.4.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +81 -0
  4. data/README.md +39 -5
  5. data/Rakefile +3 -19
  6. data/bin/rabbit_feed +0 -1
  7. data/example/non_rails_app/Gemfile.lock +29 -32
  8. data/example/non_rails_app/Rakefile +1 -1
  9. data/example/non_rails_app/bin/benchmark +3 -3
  10. data/example/non_rails_app/lib/non_rails_app/event_handler.rb +1 -1
  11. data/example/non_rails_app/spec/lib/non_rails_app/event_handler_spec.rb +3 -4
  12. data/example/non_rails_app/spec/lib/non_rails_app/event_routing_spec.rb +3 -3
  13. data/example/rails_app/Gemfile +4 -16
  14. data/example/rails_app/Gemfile.lock +131 -137
  15. data/example/rails_app/app/assets/javascripts/application.js +0 -1
  16. data/example/rails_app/app/controllers/application_controller.rb +0 -3
  17. data/example/rails_app/app/controllers/beavers_controller.rb +14 -15
  18. data/example/rails_app/bin/rails +1 -1
  19. data/example/rails_app/config/environments/development.rb +1 -1
  20. data/example/rails_app/config/environments/test.rb +2 -2
  21. data/example/rails_app/config/initializers/cookies_serializer.rb +1 -1
  22. data/example/rails_app/config/unicorn.rb +1 -1
  23. data/example/rails_app/config.ru +1 -1
  24. data/example/rails_app/db/schema.rb +5 -7
  25. data/example/rails_app/lib/event_handler.rb +1 -1
  26. data/example/rails_app/spec/controllers/beavers_controller_spec.rb +9 -10
  27. data/example/rails_app/spec/event_routing_spec.rb +1 -2
  28. data/example/rails_app/test/controllers/beavers_controller_test.rb +12 -12
  29. data/lib/dsl.rb +4 -4
  30. data/lib/rabbit_feed/client.rb +17 -23
  31. data/lib/rabbit_feed/configuration.rb +10 -9
  32. data/lib/rabbit_feed/connection.rb +3 -3
  33. data/lib/rabbit_feed/console_consumer.rb +22 -24
  34. data/lib/rabbit_feed/consumer.rb +2 -2
  35. data/lib/rabbit_feed/consumer_connection.rb +21 -22
  36. data/lib/rabbit_feed/event.rb +8 -28
  37. data/lib/rabbit_feed/event_definitions.rb +14 -15
  38. data/lib/rabbit_feed/event_routing.rb +26 -27
  39. data/lib/rabbit_feed/json_log_formatter.rb +1 -1
  40. data/lib/rabbit_feed/producer.rb +13 -13
  41. data/lib/rabbit_feed/producer_connection.rb +8 -9
  42. data/lib/rabbit_feed/testing_support/rspec_matchers/publish_event.rb +52 -89
  43. data/lib/rabbit_feed/testing_support/test_rabbit_feed_consumer.rb +1 -2
  44. data/lib/rabbit_feed/testing_support/testing_helpers.rb +0 -1
  45. data/lib/rabbit_feed/testing_support.rb +5 -6
  46. data/lib/rabbit_feed/version.rb +1 -1
  47. data/lib/rabbit_feed.rb +12 -13
  48. data/rabbit_feed.gemspec +16 -14
  49. data/run_benchmark +4 -3
  50. data/run_example +1 -1
  51. data/spec/features/step_definitions/connectivity_steps.rb +6 -9
  52. data/spec/lib/rabbit_feed/client_spec.rb +8 -9
  53. data/spec/lib/rabbit_feed/configuration_spec.rb +20 -23
  54. data/spec/lib/rabbit_feed/console_consumer_spec.rb +11 -13
  55. data/spec/lib/rabbit_feed/consumer_connection_spec.rb +26 -28
  56. data/spec/lib/rabbit_feed/event_definitions_spec.rb +31 -31
  57. data/spec/lib/rabbit_feed/event_routing_spec.rb +35 -62
  58. data/spec/lib/rabbit_feed/event_spec.rb +40 -87
  59. data/spec/lib/rabbit_feed/producer_connection_spec.rb +11 -7
  60. data/spec/lib/rabbit_feed/producer_spec.rb +16 -19
  61. data/spec/lib/rabbit_feed/testing_support/rspec_matchers/publish_event_spec.rb +82 -87
  62. data/spec/lib/rabbit_feed/testing_support/testing_helper_spec.rb +2 -2
  63. data/spec/spec_helper.rb +4 -10
  64. metadata +67 -45
  65. data/example/rails_app/README.rdoc +0 -28
@@ -10,30 +10,27 @@ module RabbitFeed
10
10
  require_path: '.',
11
11
  config_file: 'config/rabbit_feed.yml',
12
12
  logfile: 'log/rabbit_feed.log',
13
- pidfile: 'tmp/pids/rabbit_feed.pid',
14
- }
13
+ pidfile: 'tmp/pids/rabbit_feed.pid'
14
+ }.freeze
15
15
  DEFAULTS.freeze
16
16
 
17
17
  attr_reader :command, :options
18
18
  validates_presence_of :command, :options
19
- validates :command, inclusion: { in: %w(consume produce shutdown console), message: "%{value} is not a valid command" }
19
+ validates :command, inclusion: { in: %w(consume produce shutdown console), message: '%{value} is not a valid command' }
20
20
  validate :log_file_path_exists
21
21
  validate :config_file_exists
22
22
  validate :require_path_valid, unless: :console?
23
23
  validate :pidfile_path_exists, if: :daemonize?
24
24
  validate :environment_specified
25
25
 
26
- def initialize arguments=ARGV
26
+ def initialize(arguments = ARGV)
27
27
  @command = arguments[0]
28
28
  @options = parse_options arguments
29
-
30
- unless shutdown?
31
- validate!
32
-
33
- set_logging
34
- set_configuration
35
- load_dependancies unless console?
36
- end
29
+ return if shutdown?
30
+ validate!
31
+ set_logging
32
+ set_configuration
33
+ load_dependancies unless console?
37
34
  end
38
35
 
39
36
  def run
@@ -43,25 +40,24 @@ module RabbitFeed
43
40
  private
44
41
 
45
42
  def validate!
46
- raise Error.new errors.messages if invalid?
43
+ raise Error, errors.messages if invalid?
47
44
  end
48
45
 
49
46
  def log_file_path_exists
50
- errors.add(:options, "log file path not found: '#{options[:logfile]}', specify this using the --logfile option") unless Dir.exists?(File.dirname(options[:logfile]))
47
+ errors.add(:options, "log file path not found: '#{options[:logfile]}', specify this using the --logfile option") unless Dir.exist?(File.dirname(options[:logfile]))
51
48
  end
52
49
 
53
50
  def config_file_exists
54
- errors.add(:options, "configuration file not found: '#{options[:config_file]}', specify this using the --config option") unless File.exists?(options[:config_file])
51
+ errors.add(:options, "configuration file not found: '#{options[:config_file]}', specify this using the --config option") unless File.exist?(options[:config_file])
55
52
  end
56
53
 
57
54
  def require_path_valid
58
- if require_rails? && !File.exist?("#{options[:require_path]}/config/application.rb")
59
- errors.add(:options, 'point rabbit_feed to a Rails 3/4 application or a Ruby file to load your worker classes with --require')
60
- end
55
+ return unless require_rails? && !File.exist?("#{options[:require_path]}/config/application.rb")
56
+ errors.add(:options, 'point rabbit_feed to a Rails 3/4 application or a Ruby file to load your worker classes with --require')
61
57
  end
62
58
 
63
59
  def pidfile_path_exists
64
- errors.add(:options, "pid file path not found: '#{options[:pidfile]}', specify this using the --pidfile option") unless Dir.exists?(File.dirname(options[:pidfile]))
60
+ errors.add(:options, "pid file path not found: '#{options[:pidfile]}', specify this using the --pidfile option") unless Dir.exist?(File.dirname(options[:pidfile]))
65
61
  end
66
62
 
67
63
  def environment_specified
@@ -145,11 +141,10 @@ module RabbitFeed
145
141
  File.directory?(options[:require_path])
146
142
  end
147
143
 
148
- def parse_options argv
144
+ def parse_options(argv)
149
145
  opts = {}
150
146
 
151
147
  parser = OptionParser.new do |o|
152
-
153
148
  o.on '-a', '--application VAL', 'Name of the application' do |arg|
154
149
  opts[:application] = arg
155
150
  end
@@ -190,7 +185,7 @@ module RabbitFeed
190
185
  opts[:pidfile] = arg
191
186
  end
192
187
 
193
- o.on '-V', '--version', 'Print version and exit' do |arg|
188
+ o.on '-V', '--version', 'Print version and exit' do |_arg|
194
189
  puts "RabbitFeed #{RabbitFeed::VERSION}"
195
190
  exit 0
196
191
  end
@@ -204,6 +199,5 @@ module RabbitFeed
204
199
  parser.parse! argv
205
200
  DEFAULTS.merge opts
206
201
  end
207
-
208
202
  end
209
203
  end
@@ -7,8 +7,8 @@ module RabbitFeed
7
7
  :consumer_exit_after_fail
8
8
  validates_presence_of :application, :environment, :exchange
9
9
 
10
- def initialize options
11
- RabbitFeed.log.info {{ event: :initialize_configuration, options: options.merge({password: :redacted}) }}
10
+ def initialize(options)
11
+ RabbitFeed.log.info { { event: :initialize_configuration, options: options.merge(password: :redacted) } }
12
12
 
13
13
  @host = options[:host]
14
14
  @hosts = options[:hosts]
@@ -28,10 +28,10 @@ module RabbitFeed
28
28
  validate!
29
29
  end
30
30
 
31
- def self.load file_path, environment, application
32
- RabbitFeed.log.info {{ event: :load_configuration_file, file_path: file_path, environment: environment, application: application }}
31
+ def self.load(file_path, environment, application)
32
+ RabbitFeed.log.info { { event: :load_configuration_file, file_path: file_path, environment: environment, application: application } }
33
33
 
34
- raise ConfigurationError.new "The RabbitFeed configuration file path specified does not exist: #{file_path}" unless (File.exist? file_path)
34
+ raise ConfigurationError, "The RabbitFeed configuration file path specified does not exist: #{file_path}" unless File.exist? file_path
35
35
 
36
36
  options = read_configuration_file file_path, environment
37
37
  options[:environment] = environment
@@ -48,7 +48,7 @@ module RabbitFeed
48
48
  end
49
49
 
50
50
  def connection_options
51
- Hash.new.tap do |options|
51
+ {}.tap do |options|
52
52
  options[:heartbeat] = heartbeat if heartbeat
53
53
  options[:connect_timeout] = connect_timeout if connect_timeout
54
54
  options[:host] = host if host
@@ -65,13 +65,14 @@ module RabbitFeed
65
65
 
66
66
  private
67
67
 
68
- def self.read_configuration_file file_path, environment
68
+ def self.read_configuration_file(file_path, environment)
69
69
  raw_configuration = YAML.load(ERB.new(File.read(file_path)).result)
70
- HashWithIndifferentAccess.new (raw_configuration[environment] || {})
70
+ HashWithIndifferentAccess.new(raw_configuration[environment] || {})
71
71
  end
72
+ private_class_method :read_configuration_file
72
73
 
73
74
  def validate!
74
- raise ConfigurationError.new errors.messages if invalid?
75
+ raise ConfigurationError, errors.messages if invalid?
75
76
  end
76
77
  end
77
78
  end
@@ -3,10 +3,10 @@ module RabbitFeed
3
3
  include Singleton
4
4
 
5
5
  def initialize
6
- RabbitFeed.log.info {{ event: :connecting_to_rabbitmq, options: RabbitFeed.configuration.connection_options.merge({password: :redacted, logger: :redacted}) }}
6
+ RabbitFeed.log.info { { event: :connecting_to_rabbitmq, options: RabbitFeed.configuration.connection_options.merge(password: :redacted, logger: :redacted) } }
7
7
  @connection = Bunny.new RabbitFeed.configuration.connection_options
8
8
  @connection.start
9
- RabbitFeed.log.info {{ event: :connected_to_rabbitmq }}
9
+ RabbitFeed.log.info { { event: :connected_to_rabbitmq } }
10
10
  @channel = @connection.create_channel
11
11
  @mutex = Mutex.new
12
12
  end
@@ -15,7 +15,7 @@ module RabbitFeed
15
15
 
16
16
  attr_reader :channel, :mutex
17
17
 
18
- def synchronized &block
18
+ def synchronized
19
19
  mutex.synchronize do
20
20
  yield
21
21
  end
@@ -2,7 +2,7 @@ module RabbitFeed
2
2
  module ConsoleConsumer
3
3
  extend self
4
4
 
5
- APPLICATION_NAME = 'rabbit_feed_console'
5
+ APPLICATION_NAME = 'rabbit_feed_console'.freeze
6
6
 
7
7
  def init
8
8
  @event_count = 0
@@ -10,10 +10,10 @@ module RabbitFeed
10
10
  route_all_events
11
11
  puts welcome_message
12
12
  ask_to_purge_queue unless queue_empty?
13
- puts "Ready. Press CTRL+C to exit."
13
+ puts 'Ready. Press CTRL+C to exit.'
14
14
  end
15
15
 
16
- def formatted event
16
+ def formatted(event)
17
17
  Formatter.new(event).to_s
18
18
  end
19
19
 
@@ -28,10 +28,9 @@ module RabbitFeed
28
28
  private
29
29
 
30
30
  def welcome_message
31
- """RabbitFeed console starting at #{Time.now.utc}...
32
- Environment: #{RabbitFeed.environment}
33
- Queue: #{RabbitFeed.configuration.queue}
34
- """
31
+ "RabbitFeed console starting at #{Time.now.utc}...\n"\
32
+ "Environment: #{RabbitFeed.environment}\n"\
33
+ "Queue: #{RabbitFeed.configuration.queue}"
35
34
  end
36
35
 
37
36
  def queue_empty?
@@ -39,15 +38,15 @@ Queue: #{RabbitFeed.configuration.queue}
39
38
  end
40
39
 
41
40
  def ask_to_purge_queue
42
- puts "There are currently #{ConsumerConnection.instance.queue_depth} message(s) in the console's queue.\n"+
43
- "Would you like to purge the queue before proceeding? (y/N)>"
41
+ puts "There are currently #{ConsumerConnection.instance.queue_depth} message(s) in the console's queue.\n"\
42
+ 'Would you like to purge the queue before proceeding? (y/N)>'
44
43
  response = STDIN.gets.chomp
45
44
  purge_queue if response == 'y'
46
45
  end
47
46
 
48
47
  def purge_queue
49
48
  ConsumerConnection.instance.purge_queue
50
- puts "Queue purged."
49
+ puts 'Queue purged.'
51
50
  end
52
51
 
53
52
  def route_all_events
@@ -56,7 +55,7 @@ Queue: #{RabbitFeed.configuration.queue}
56
55
  accept_from(:any) do
57
56
  event(:any) do |event|
58
57
  scope.increment_event_count
59
- puts (scope.formatted event)
58
+ puts scope.formatted(event)
60
59
  puts scope.event_count_message
61
60
  end
62
61
  end
@@ -68,15 +67,14 @@ Queue: #{RabbitFeed.configuration.queue}
68
67
  end
69
68
 
70
69
  class Formatter
71
-
72
70
  BORDER_WIDTH = 100
73
- BORDER_CHAR = "-"
74
- DIVIDER_CHAR = "*"
75
- NEWLINE = "\n"
71
+ BORDER_CHAR = '-'.freeze
72
+ DIVIDER_CHAR = '*'.freeze
73
+ NEWLINE = "\n".freeze
76
74
 
77
75
  attr_reader :event
78
76
 
79
- def initialize event
77
+ def initialize(event)
80
78
  @event = event
81
79
  end
82
80
 
@@ -88,12 +86,12 @@ Queue: #{RabbitFeed.configuration.queue}
88
86
 
89
87
  def header
90
88
  event_detail = "#{event.name}: #{event.created_at_utc}"
91
- border_filler = BORDER_CHAR*((BORDER_WIDTH - event_detail.length)/2)
92
- border_filler+event_detail+border_filler
89
+ border_filler = BORDER_CHAR * ((BORDER_WIDTH - event_detail.length) / 2)
90
+ border_filler + event_detail + border_filler
93
91
  end
94
92
 
95
93
  def footer
96
- BORDER_CHAR*BORDER_WIDTH
94
+ BORDER_CHAR * BORDER_WIDTH
97
95
  end
98
96
 
99
97
  def metadata
@@ -101,18 +99,18 @@ Queue: #{RabbitFeed.configuration.queue}
101
99
  end
102
100
 
103
101
  def divider
104
- DIVIDER_CHAR*BORDER_WIDTH
102
+ DIVIDER_CHAR * BORDER_WIDTH
105
103
  end
106
104
 
107
105
  def payload
108
106
  pretty_print_hash 'Event payload', event.payload
109
107
  end
110
108
 
111
- def pretty_print_hash description, hash
109
+ def pretty_print_hash(description, hash)
112
110
  '#' + description + NEWLINE +
113
- hash.keys.sort.map do |key|
114
- "#{key}: #{hash[key]}"
115
- end.join(NEWLINE)
111
+ hash.keys.sort.map do |key|
112
+ "#{key}: #{hash[key]}"
113
+ end.join(NEWLINE)
116
114
  end
117
115
  end
118
116
  end
@@ -7,9 +7,9 @@ module RabbitFeed
7
7
  def run
8
8
  ConsumerConnection.instance.consume do |raw_event|
9
9
  event = Event.deserialize raw_event
10
- RabbitFeed.log.info {{ event: :message_received, metadata: event.metadata }}
10
+ RabbitFeed.log.info { { event: :message_received, metadata: event.metadata } }
11
11
  event_routing.handle_event event
12
- RabbitFeed.log.info {{ event: :message_processed, metadata: event.metadata }}
12
+ RabbitFeed.log.info { { event: :message_processed, metadata: event.metadata } }
13
13
  end
14
14
  end
15
15
  end
@@ -1,6 +1,5 @@
1
1
  module RabbitFeed
2
2
  class ConsumerConnection < RabbitFeed::Connection
3
-
4
3
  SUBSCRIPTION_OPTIONS = {
5
4
  consumer_tag: Socket.gethostname, # Use the host name of the server
6
5
  manual_ack: true, # Manually acknowledge messages once they've been processed
@@ -15,30 +14,30 @@ module RabbitFeed
15
14
  arguments: {
16
15
  'x-ha-policy' => 'all', # Apply the queue on all mirrors
17
16
  'x-expires' => SEVEN_DAYS_IN_MS, # Auto-delete the queue after a period of inactivity (in ms)
18
- },
17
+ }
19
18
  }.freeze
20
19
 
21
20
  def initialize
22
21
  super
23
22
  channel.prefetch(1)
24
23
  @queue = channel.queue RabbitFeed.configuration.queue, queue_options
25
- RabbitFeed.log.info {{ event: :queue_declared, queue: RabbitFeed.configuration.queue, options: queue_options }}
24
+ RabbitFeed.log.info { { event: :queue_declared, queue: RabbitFeed.configuration.queue, options: queue_options } }
26
25
  bind_on_accepted_routes
27
26
  end
28
27
 
29
- def consume &block
28
+ def consume(&block)
30
29
  raise 'This connection already has a consumer subscribed' if connection_in_use?
31
30
  synchronized do
32
31
  begin
33
- RabbitFeed.log.info {{ event: :subscribe_to_queue, queue: RabbitFeed.configuration.queue }}
32
+ RabbitFeed.log.info { { event: :subscribe_to_queue, queue: RabbitFeed.configuration.queue } }
34
33
 
35
- consumer = queue.subscribe(SUBSCRIPTION_OPTIONS) do |delivery_info, properties, payload|
34
+ consumer = queue.subscribe(SUBSCRIPTION_OPTIONS) do |delivery_info, _properties, payload|
36
35
  handle_message delivery_info, payload, &block
37
36
  end
38
37
 
39
38
  sleep # Sleep indefinitely, as the consumer runs in its own thread
40
- rescue SystemExit, Interrupt, SignalException
41
- RabbitFeed.log.info {{ event: :unsubscribe_from_queue, queue: RabbitFeed.configuration.queue }}
39
+ rescue SystemExit, SignalException
40
+ RabbitFeed.log.info { { event: :unsubscribe_from_queue, queue: RabbitFeed.configuration.queue } }
42
41
  ensure
43
42
  (cancel_consumer consumer) if consumer.present?
44
43
  end
@@ -59,29 +58,29 @@ module RabbitFeed
59
58
 
60
59
  def queue_options
61
60
  {
62
- auto_delete: RabbitFeed.configuration.auto_delete_queue,
61
+ auto_delete: RabbitFeed.configuration.auto_delete_queue
63
62
  }.merge QUEUE_OPTIONS
64
63
  end
65
64
 
66
65
  def bind_on_accepted_routes
67
66
  if RabbitFeed::Consumer.event_routing.present?
68
67
  RabbitFeed::Consumer.event_routing.accepted_routes.each do |accepted_route|
69
- queue.bind(RabbitFeed.configuration.exchange, { routing_key: accepted_route })
70
- RabbitFeed.log.info {{ event: :queue_bound, queue: RabbitFeed.configuration.queue, exchange: RabbitFeed.configuration.exchange, routing_key: accepted_route }}
68
+ queue.bind(RabbitFeed.configuration.exchange, routing_key: accepted_route)
69
+ RabbitFeed.log.info { { event: :queue_bound, queue: RabbitFeed.configuration.queue, exchange: RabbitFeed.configuration.exchange, routing_key: accepted_route } }
71
70
  end
72
71
  else
73
72
  queue.bind(RabbitFeed.configuration.exchange)
74
- RabbitFeed.log.info {{ event: :queue_bound, queue: RabbitFeed.configuration.queue, exchange: RabbitFeed.configuration.exchange }}
73
+ RabbitFeed.log.info { { event: :queue_bound, queue: RabbitFeed.configuration.queue, exchange: RabbitFeed.configuration.exchange } }
75
74
  end
76
75
  end
77
76
 
78
- def acknowledge delivery_info
77
+ def acknowledge(delivery_info)
79
78
  queue.channel.ack(delivery_info.delivery_tag)
80
- RabbitFeed.log.debug {{ event: :acknowledge, delivery_tag: delivery_info.delivery_tag }}
79
+ RabbitFeed.log.debug { { event: :acknowledge, delivery_tag: delivery_info.delivery_tag } }
81
80
  end
82
81
 
83
- def handle_message delivery_info, payload, &block
84
- RabbitFeed.log.debug {{ event: :handling_message, delivery_tag: delivery_info.delivery_tag }}
82
+ def handle_message(delivery_info, payload)
83
+ RabbitFeed.log.debug { { event: :handling_message, delivery_tag: delivery_info.delivery_tag } }
85
84
  begin
86
85
  yield payload
87
86
  acknowledge delivery_info
@@ -91,21 +90,21 @@ module RabbitFeed
91
90
  end
92
91
  end
93
92
 
94
- def cancel_consumer consumer
93
+ def cancel_consumer(consumer)
95
94
  cancel_ok = consumer.cancel
96
- RabbitFeed.log.debug {{ event: :consumer_cancelled, status: cancel_ok, queue: RabbitFeed.configuration.queue }}
95
+ RabbitFeed.log.debug { { event: :consumer_cancelled, status: cancel_ok, queue: RabbitFeed.configuration.queue } }
97
96
  end
98
97
 
99
- def negative_acknowledge delivery_info
98
+ def negative_acknowledge(delivery_info)
100
99
  # Tell rabbit that we were unable to process the message
101
100
  # This will re-queue the message
102
101
  queue.channel.nack(delivery_info.delivery_tag, false, true)
103
- RabbitFeed.log.debug {{ event: :negative_acknowledge, delivery_tag: delivery_info.delivery_tag }}
102
+ RabbitFeed.log.debug { { event: :negative_acknowledge, delivery_tag: delivery_info.delivery_tag } }
104
103
  end
105
104
 
106
- def handle_processing_exception delivery_info, exception
105
+ def handle_processing_exception(delivery_info, exception)
107
106
  negative_acknowledge delivery_info
108
- RabbitFeed.log.error {{ event: :processing_exception, delivery_tag: delivery_info.delivery_tag, message: exception.message, backtrace: exception.backtrace.join(',') }}
107
+ RabbitFeed.log.error { { event: :processing_exception, delivery_tag: delivery_info.delivery_tag, message: exception.message, backtrace: exception.backtrace.join(',') } }
109
108
  RabbitFeed.exception_notify exception
110
109
  end
111
110
  end
@@ -2,14 +2,14 @@ module RabbitFeed
2
2
  class Event
3
3
  include ActiveModel::Validations
4
4
 
5
- SCHEMA_VERSION = '2.0.0'
5
+ SCHEMA_VERSION = '2.0.0'.freeze
6
6
 
7
7
  attr_reader :schema, :payload, :metadata, :sensitive_fields
8
8
  validates :metadata, presence: true
9
9
  validates :payload, length: { minimum: 0, allow_nil: false, message: 'can\'t be nil' }
10
10
  validate :required_metadata
11
11
 
12
- def initialize metadata, payload={}, schema=nil, sensitive_fields=[]
12
+ def initialize(metadata, payload = {}, schema = nil, sensitive_fields = [])
13
13
  @schema = schema
14
14
  @payload = payload.with_indifferent_access if payload
15
15
  @metadata = metadata.with_indifferent_access if metadata
@@ -40,8 +40,7 @@ module RabbitFeed
40
40
  end
41
41
 
42
42
  class << self
43
-
44
- def deserialize serialized_event
43
+ def deserialize(serialized_event)
45
44
  datum_reader = Avro::IO::DatumReader.new
46
45
  reader = Avro::DataFile::Reader.new (StringIO.new serialized_event), datum_reader
47
46
  event_hash = nil
@@ -49,25 +48,7 @@ module RabbitFeed
49
48
  event_hash = datum
50
49
  end
51
50
  reader.close
52
- if (version_1? event_hash)
53
- new_from_version_1 event_hash, datum_reader.readers_schema
54
- else
55
- new event_hash['metadata'], event_hash['payload'], datum_reader.readers_schema
56
- end
57
- end
58
-
59
- private
60
-
61
- def version_1? event_hash
62
- %w(metadata payload).none?{|key| event_hash.has_key? key}
63
- end
64
-
65
- def new_from_version_1 metadata_and_payload, schema
66
- metadata = {}
67
- %w(application name host version environment created_at_utc).each do |field|
68
- metadata[field] = metadata_and_payload.delete field
69
- end
70
- new metadata, metadata_and_payload, schema
51
+ new event_hash['metadata'], event_hash['payload'], datum_reader.readers_schema
71
52
  end
72
53
  end
73
54
 
@@ -75,18 +56,17 @@ module RabbitFeed
75
56
 
76
57
  def sensitive_proof_payload
77
58
  sensitive_fields.each_with_object(payload.dup) do |field, clean_payload|
78
- clean_payload[field] = "[REMOVED]" if clean_payload.key?(field)
59
+ clean_payload[field] = '[REMOVED]' if clean_payload.key?(field)
79
60
  end
80
61
  end
81
62
 
82
63
  def validate!
83
- raise Error.new "Invalid event: #{errors.messages}" if invalid?
64
+ raise Error, "Invalid event: #{errors.messages}" if invalid?
84
65
  end
85
66
 
86
67
  def required_metadata
87
- if metadata
88
- errors.add(:metadata, 'name field is required') if metadata[:name].blank?
89
- end
68
+ return unless metadata
69
+ errors.add(:metadata, 'name field is required') if metadata[:name].blank?
90
70
  end
91
71
  end
92
72
  end
@@ -1,13 +1,12 @@
1
1
  module RabbitFeed
2
2
  class EventDefinitions
3
-
4
3
  class Field
5
4
  include ActiveModel::Validations
6
5
 
7
6
  attr_reader :name, :type, :definition
8
7
  validates_presence_of :name, :type, :definition
9
8
 
10
- def initialize name, type, definition
9
+ def initialize(name, type, definition)
11
10
  @name = name
12
11
  @type = type
13
12
  @definition = definition
@@ -21,7 +20,7 @@ module RabbitFeed
21
20
  private
22
21
 
23
22
  def validate!
24
- raise ConfigurationError.new "Bad field specification for #{name}: #{errors.messages}" if invalid?
23
+ raise ConfigurationError, "Bad field specification for #{name}: #{errors.messages}" if invalid?
25
24
  end
26
25
  end
27
26
 
@@ -33,24 +32,24 @@ module RabbitFeed
33
32
  validate :schema_parseable
34
33
  validates :version, format: { with: /\A\d+\.\d+\.\d+\z/, message: 'must be in *.*.* format' }
35
34
 
36
- def initialize name, version
35
+ def initialize(name, version)
37
36
  @name = name
38
37
  @version = version
39
38
  @fields = []
40
39
  @sensitive_fields = []
41
40
  end
42
41
 
43
- def payload_contains &block
44
- self.instance_eval(&block)
42
+ def payload_contains(&block)
43
+ instance_eval(&block)
45
44
  end
46
45
 
47
- def field name, options
46
+ def field(name, options)
48
47
  sensitive_fields << name.to_s if options.delete(:sensitive)
49
48
  fields << (Field.new name, options[:type], options[:definition])
50
49
  end
51
50
 
52
- def defined_as &block
53
- @definition = block.call if block.present?
51
+ def defined_as(&block)
52
+ @definition = yield if block.present?
54
53
  end
55
54
 
56
55
  def payload_schema
@@ -65,23 +64,23 @@ module RabbitFeed
65
64
  (Field.new 'version', 'string', 'The version of the event payload'),
66
65
  (Field.new 'schema_version', 'string', 'The version of the event schema'),
67
66
  (Field.new 'name', 'string', 'The name of the event'),
68
- (Field.new 'created_at_utc', 'string', 'The UTC time that the event was created'),
67
+ (Field.new 'created_at_utc', 'string', 'The UTC time that the event was created')
69
68
  ].map(&:schema) }
70
69
  end
71
70
 
72
71
  def event_schema
73
72
  [
74
73
  { name: 'payload', type: payload_schema, doc: 'The event payload (defined by the source system)' },
75
- { name: 'metadata', type: metadata_schema, doc: 'The event metadata (defined by rabbit feed)' },
74
+ { name: 'metadata', type: metadata_schema, doc: 'The event metadata (defined by rabbit feed)' }
76
75
  ]
77
76
  end
78
77
 
79
78
  def schema
80
- @schema ||= (Avro::Schema.parse ({ name: name, type: 'record', doc: definition, fields: event_schema }.to_json))
79
+ @schema ||= Avro::Schema.parse({ name: name, type: 'record', doc: definition, fields: event_schema }.to_json)
81
80
  end
82
81
 
83
82
  def validate!
84
- raise ConfigurationError.new "Bad event specification for #{name}: #{errors.messages}" if invalid?
83
+ raise ConfigurationError, "Bad event specification for #{name}: #{errors.messages}" if invalid?
85
84
  end
86
85
 
87
86
  private
@@ -99,13 +98,13 @@ module RabbitFeed
99
98
  @events = {}
100
99
  end
101
100
 
102
- def define_event name, options, &block
101
+ def define_event(name, options, &block)
103
102
  events[name] = Event.new name, options[:version]
104
103
  events[name].instance_eval(&block)
105
104
  events[name].validate!
106
105
  end
107
106
 
108
- def [] name
107
+ def [](name)
109
108
  events[name]
110
109
  end
111
110
  end