carnivore 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # v0.2.4
2
+ * Move receive starts out of processing loop
3
+ * Extract source name from arguments on setup
4
+ * Deep force smash type on conversion
5
+ * Add optional disablement of multiple callback matches
6
+
1
7
  # v0.2.2
2
8
  * Local loopback is optional and disabled by default
3
9
  * Include Smash utility for Hash management
@@ -1,4 +1,5 @@
1
1
  require 'carnivore'
2
+ require 'celluloid/autostart'
2
3
 
3
4
  module Carnivore
4
5
  # Payload modifier
@@ -122,6 +122,10 @@ module Carnivore
122
122
  attr_reader :message_remote
123
123
  # @return [TrueClass, FalseClass] currently processing a message
124
124
  attr_reader :processing
125
+ # @return [TrueClass, FalseClass] allow multiple callback matches
126
+ attr_reader :allow_multiple_matches
127
+ # @return [Hash] original options hash
128
+ attr_reader :arguments
125
129
 
126
130
  # Create new Source
127
131
  #
@@ -130,9 +134,13 @@ module Carnivore
130
134
  # @option args [TrueClass, FalseClass] :auto_process start processing on initialization
131
135
  # @option args [TrueClass, FalseClass] :auto_confirm confirm messages automatically on receive
132
136
  # @option args [Proc] :orphan_callback execute block when no callbacks are valid for message
137
+ # @option args [Proc] :multiple_callback execute block when multiple callbacks are valid and multiple support is disabled
133
138
  # @option args [TrueClass, FalseClass] :prevent_duplicates setup and use message registry
139
+ # @option args [TrueClass, FalseClass] :allow_multiple_matches allow multiple callback matches (defaults true)
134
140
  # @option args [Array<Callback>] :callbacks callbacks to register on this source
135
141
  def initialize(args={})
142
+ @arguments = args.dup
143
+ @name = args[:name]
136
144
  @args = Smash.new(args)
137
145
  @callbacks = []
138
146
  @message_loop = Queue.new
@@ -142,11 +150,14 @@ module Carnivore
142
150
  @run_process = true
143
151
  @auto_confirm = !!args[:auto_confirm]
144
152
  @callback_supervisor = Carnivore::Supervisor.create!.last
145
- if(args[:orphan_callback])
146
- unless(args[:orphan_callback].is_a?(Proc))
147
- raise TypeError.new("Expected `Proc` type for `orphan_callback` but received `#{args[:orphan_callback].class}`")
153
+ @allow_multiple_matches = !!args.fetch(:allow_multiple_matches, true)
154
+ [:orphan_callback, :multiple_callback].each do |key|
155
+ if(args[key])
156
+ unless(args[key].is_a?(Proc))
157
+ raise TypeError.new("Expected `Proc` type for `#{key}` but received `#{args[key].class}`")
158
+ end
159
+ define_singleton_method(key, &args[key])
148
160
  end
149
- define_singleton_method(:orphan_callback, &args[:orphan_callback])
150
161
  end
151
162
  if(args[:prevent_duplicates])
152
163
  init_registry
@@ -162,7 +173,10 @@ module Carnivore
162
173
  connect
163
174
  if(auto_process && !callbacks.empty?)
164
175
  async.process
176
+ else
177
+ warn 'Processing is disabled'
165
178
  end
179
+ info 'Source initialization is complete'
166
180
  rescue => e
167
181
  debug "Failed to initialize: #{self} - #{e.class}: #{e}\n#{e.backtrace.join("\n")}"
168
182
  raise
@@ -320,9 +334,9 @@ module Carnivore
320
334
  # @return [TrueClass]
321
335
  def process(*args)
322
336
  begin
337
+ async.receive_messages
338
+ @processing = true
323
339
  while(run_process && !callbacks.empty?)
324
- @processing = true
325
- async.receive_messages
326
340
  if(message_loop.empty? && message_remote.empty?)
327
341
  wait(:messages_available)
328
342
  end
@@ -335,20 +349,24 @@ module Carnivore
335
349
  end
336
350
  end.compact
337
351
  msgs.each do |msg|
338
- if(respond_to?(:orphan_callback))
352
+ if(multiple_callbacks? || respond_to?(:orphan_callback))
339
353
  valid_callbacks = callbacks.find_all do |name|
340
354
  callback_supervisor[callback_name(name)].valid?(msg)
341
355
  end
342
356
  else
343
357
  valid_callbacks = callbacks
344
358
  end
345
- valid_callbacks.each do |name|
346
- debug "Dispatching message<#{msg[:message].object_id}> to callback<#{name} (#{callback_name(name)})>"
347
- callback_supervisor[callback_name(name)].async.call(msg)
348
- end
349
359
  if(valid_callbacks.empty?)
350
360
  warn "Received message was not processed through any callbacks on this source: #{msg}"
351
- orphan_callback(current_actor, msg) if respond_to?(:orphan_callback)
361
+ orphan_callback(msg) if respond_to?(:orphan_callback)
362
+ elsif(valid_callbacks.size > 1 && !multiple_callbacks?)
363
+ error "Received message is valid for multiple callbacks but multiple callbacks are disabled: #{msg}"
364
+ multiple_callback(msg) if respond_to?(:multiple_callback)
365
+ else
366
+ valid_callbacks.each do |name|
367
+ debug "Dispatching message<#{msg[:message].object_id}> to callback<#{name} (#{callback_name(name)})>"
368
+ callback_supervisor[callback_name(name)].async.call(msg)
369
+ end
352
370
  end
353
371
  end
354
372
  end
@@ -409,6 +427,15 @@ module Carnivore
409
427
  false
410
428
  end
411
429
 
430
+ # Allow sending payload to multiple matching callbacks. Custom
431
+ # sources should override this method to disable multiple
432
+ # callback matches if desired.
433
+ #
434
+ # @return [TrueClass, FalseClass]
435
+ def multiple_callbacks?
436
+ allow_multiple_matches
437
+ end
438
+
412
439
  # Load and initialize the message registry
413
440
  #
414
441
  # @return [MessageRegistry] new registry
@@ -58,6 +58,13 @@ module Carnivore
58
58
  true
59
59
  end
60
60
 
61
+ # Check if default supervisor is alive
62
+ #
63
+ # @return [TrueClass, FalseClass]
64
+ def alive?
65
+ supervisor && supervisor.alive?
66
+ end
67
+
61
68
  end
62
69
 
63
70
  # @return [Celluloid::Registry]
@@ -26,6 +26,14 @@ module Carnivore
26
26
  end
27
27
  end
28
28
 
29
+ # Log exception
30
+ #
31
+ # @param e [Exception]
32
+ def exception_log(e)
33
+ error "#{e.class}: #{e}"
34
+ debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
35
+ end
36
+
29
37
  end
30
38
 
31
39
  end
@@ -6,6 +6,7 @@ module Carnivore
6
6
  # Customized Hash
7
7
  class Smash < Hash
8
8
  include Hashie::Extensions::IndifferentAccess
9
+ include Hashie::Extensions::MergeInitializer
9
10
  include Hashie::Extensions::DeepMerge
10
11
  include Hashie::Extensions::Coercion
11
12
 
@@ -21,10 +22,15 @@ module Carnivore
21
22
  end
22
23
  super *args
23
24
  if(base)
24
- self.replace(base)
25
+ self.replace(base.to_smash)
25
26
  end
26
27
  end
27
28
 
29
+ def merge!(hash)
30
+ hash = hash.to_smash unless hash.is_a?(::Smash)
31
+ super(hash)
32
+ end
33
+
28
34
  # Get value at given path
29
35
  #
30
36
  # @param args [String, Symbol] key path to walk
@@ -81,7 +87,11 @@ class Hash
81
87
  #
82
88
  # @return [Smash]
83
89
  def to_smash
84
- ::Smash.new.replace(self)
90
+ ::Smash.new.tap do |smash|
91
+ self.each do |k,v|
92
+ smash[k.is_a?(Symbol) ? k.to_s : k] = v.is_a?(::Hash) && !v.is_a?(::Smash) ? v.to_smash : v
93
+ end
94
+ end
85
95
  end
86
96
  alias_method :hulk_smash, :to_smash
87
97
 
@@ -3,5 +3,5 @@ module Carnivore
3
3
  class Version < Gem::Version
4
4
  end
5
5
  # Current version of library
6
- VERSION = Version.new('0.2.2')
6
+ VERSION = Version.new('0.2.4')
7
7
  end
data/lib/carnivore.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  require 'carnivore/runner'
2
2
  require 'carnivore/version'
3
- # Load in celluloid as required
4
- require 'celluloid/autostart'
5
3
 
6
4
  # Message consumer and processor
7
5
  module Carnivore
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carnivore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.4
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: 2014-05-13 00:00:00.000000000 Z
12
+ date: 2014-06-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: celluloid