carnivore 0.1.10 → 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.
- data/CHANGELOG.md +9 -0
- data/README.md +2 -2
- data/carnivore.gemspec +2 -2
- data/lib/carnivore/autoloader.rb +13 -0
- data/lib/carnivore/callback.rb +8 -3
- data/lib/carnivore/config.rb +4 -3
- data/lib/carnivore/container.rb +1 -1
- data/lib/carnivore/errors.rb +7 -0
- data/lib/carnivore/message.rb +15 -8
- data/lib/carnivore/runner.rb +26 -7
- data/lib/carnivore/source.rb +154 -44
- data/lib/carnivore/source_container.rb +30 -0
- data/lib/carnivore/spec_helper.rb +60 -0
- data/lib/carnivore/supervisor.rb +53 -0
- data/lib/carnivore/utils/logging.rb +28 -0
- data/lib/carnivore/utils/message_registry.rb +41 -0
- data/lib/carnivore/utils/params.rb +40 -0
- data/lib/carnivore/utils.rb +5 -39
- data/lib/carnivore/version.rb +3 -1
- data/lib/carnivore.rb +4 -1
- metadata +13 -16
- data/Gemfile +0 -5
- data/examples/test_block.rb +0 -10
- data/examples/test_class.rb +0 -20
- data/examples/test_http.rb +0 -10
- data/test/spec.rb +0 -11
- data/test/specs/config.rb +0 -31
- data/test/specs/container.rb +0 -13
- data/test/specs/message.rb +0 -29
- data/test/specs/source.rb +0 -82
- data/test/specs/utils.rb +0 -47
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# v0.2.0
|
2
|
+
* Remove `fog` from dependency list
|
3
|
+
* Add common spec helper for testing
|
4
|
+
* Only start sources if callbacks are defined
|
5
|
+
* Add custom supervisor with isolated registry
|
6
|
+
* Include auto-restart support
|
7
|
+
* Loop local messages internally instead of transmit/retrieve loop
|
8
|
+
* Use auto loading to clean things up
|
9
|
+
|
1
10
|
# v0.1.10
|
2
11
|
* Remove builtin sources
|
3
12
|
* Allow optional auto-symbolize
|
data/README.md
CHANGED
@@ -30,7 +30,7 @@ Under the hood, callbacks are built into `Carnivore::Callback`
|
|
30
30
|
instances. This class can be subclassed and provided directly
|
31
31
|
instead of a simple block. This has the added bonus of being
|
32
32
|
able to define the number of worker instances to be created
|
33
|
-
for the callback (blocks
|
33
|
+
for the callback (blocks only get 1):
|
34
34
|
|
35
35
|
```ruby
|
36
36
|
require 'carnivore'
|
@@ -56,7 +56,7 @@ end.start!
|
|
56
56
|
|
57
57
|
### Block execution
|
58
58
|
|
59
|
-
It is important to note that when providing blocks
|
59
|
+
It is important to note that when providing blocks they will
|
60
60
|
lose all reference to the scope in which they are defined. This
|
61
61
|
is due to how `Callback` is implemented and is by design. Simply
|
62
62
|
ensure that blocks are fully autonomous and everything will be
|
data/carnivore.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.homepage = 'https://github.com/carnivore-rb/carnivore'
|
10
10
|
s.description = 'Message processing helper'
|
11
11
|
s.require_path = 'lib'
|
12
|
-
s.add_dependency 'fog'
|
13
12
|
s.add_dependency 'celluloid'
|
14
13
|
s.add_dependency 'mixlib-config'
|
15
|
-
s.
|
14
|
+
s.add_dependency 'multi_json'
|
15
|
+
s.files = Dir['lib/**/*'] + %w(carnivore.gemspec README.md CHANGELOG.md)
|
16
16
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Register all base autoloading requirements
|
2
|
+
|
3
|
+
module Carnivore
|
4
|
+
autoload :Config, 'carnivore/config'
|
5
|
+
autoload :Callback, 'carnivore/callback'
|
6
|
+
autoload :Container, 'carnivore/container'
|
7
|
+
autoload :Error, 'carnivore/errors'
|
8
|
+
autoload :Message, 'carnivore/message'
|
9
|
+
autoload :Source, 'carnivore/source'
|
10
|
+
autoload :Supervisor, 'carnivore/supervisor'
|
11
|
+
autoload :Utils, 'carnivore/utils'
|
12
|
+
autoload :Version, 'carnivore/version'
|
13
|
+
end
|
data/lib/carnivore/callback.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'carnivore
|
1
|
+
require 'carnivore'
|
2
2
|
|
3
3
|
module Carnivore
|
4
4
|
class Callback
|
@@ -9,10 +9,14 @@ module Carnivore
|
|
9
9
|
end
|
10
10
|
|
11
11
|
include Celluloid
|
12
|
-
include Utils::Logging
|
12
|
+
include Carnivore::Utils::Logging
|
13
13
|
|
14
14
|
attr_reader :name
|
15
15
|
|
16
|
+
# name:: Name of the callback
|
17
|
+
# block:: Optional `Proc` to define the callback behavior
|
18
|
+
# Creates a new callback. Optional block to define callback
|
19
|
+
# behavior must be passed as a `Proc` instance, not a block.
|
16
20
|
def initialize(name, block=nil)
|
17
21
|
@name = name
|
18
22
|
if(block.nil? && self.class == Callback)
|
@@ -42,9 +46,10 @@ module Carnivore
|
|
42
46
|
# Pass message to registered callbacks
|
43
47
|
def call(message)
|
44
48
|
if(valid?(message))
|
49
|
+
debug ">> Received message is valid for this callback (#{message})"
|
45
50
|
execute(message)
|
46
51
|
else
|
47
|
-
debug
|
52
|
+
debug "Invalid message for this callback #{message})"
|
48
53
|
end
|
49
54
|
rescue => e
|
50
55
|
error "[callback: #{self}, source: #{message[:source]}, message: #{message[:message].object_id}]: #{e.class} - #{e}"
|
data/lib/carnivore/config.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'mixlib/config'
|
3
|
+
require 'carnivore'
|
3
4
|
|
4
5
|
module Carnivore
|
5
6
|
class Config
|
@@ -8,6 +9,8 @@ module Carnivore
|
|
8
9
|
|
9
10
|
class << self
|
10
11
|
|
12
|
+
# v:: Boolean value
|
13
|
+
# Set/get automatic symbolization of hash keys
|
11
14
|
def auto_symbolize(v=nil)
|
12
15
|
unless(v.nil?)
|
13
16
|
@hash_symbolizer = !!v
|
@@ -51,9 +54,7 @@ module Carnivore
|
|
51
54
|
# Config.get(:other_app, :port) => nil
|
52
55
|
# Config.get(:my_app, :mail, :server) => nil
|
53
56
|
def get(*ary)
|
54
|
-
value =
|
55
|
-
memo[key.to_s] || memo[key.to_sym] || break
|
56
|
-
end
|
57
|
+
value = Carnivore::Utils.retrieve(self, *ary)
|
57
58
|
if(value.is_a?(Hash) && auto_symbolize)
|
58
59
|
Carnivore::Utils.symbolize_hash(value)
|
59
60
|
else
|
data/lib/carnivore/container.rb
CHANGED
data/lib/carnivore/message.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'carnivore
|
1
|
+
require 'carnivore'
|
2
2
|
|
3
3
|
module Carnivore
|
4
4
|
class Message
|
@@ -12,22 +12,29 @@ module Carnivore
|
|
12
12
|
@args = args.dup
|
13
13
|
end
|
14
14
|
|
15
|
+
# Helper method to return keys available from `args`
|
16
|
+
def keys
|
17
|
+
args.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
# k:: key
|
21
|
+
# Accessor into message
|
15
22
|
def [](k)
|
16
|
-
|
17
|
-
Celluloid::Actor[@args[:source]]
|
18
|
-
else
|
19
|
-
@args[k.to_sym] || @args[k.to_s]
|
20
|
-
end
|
23
|
+
args[k.to_sym] || args[k.to_s]
|
21
24
|
end
|
22
25
|
|
26
|
+
# args:: Arguments
|
27
|
+
# Confirm message was received on source
|
23
28
|
def confirm!(*args)
|
24
|
-
self[:source].confirm(*([self] + args))
|
29
|
+
self[:source].confirm(*([self] + args).flatten(1).compact)
|
25
30
|
end
|
26
31
|
|
32
|
+
# Formatted inspection string
|
27
33
|
def inspect
|
28
|
-
"<Carnivore::Message[#{self.object_id}] @args=#{args}>"
|
34
|
+
"<Carnivore::Message[#{self.object_id}] @args=#{args.inspect}>"
|
29
35
|
end
|
30
36
|
|
37
|
+
# String representation
|
31
38
|
def to_s
|
32
39
|
"<Carnivore::Message:#{self.object_id}>"
|
33
40
|
end
|
data/lib/carnivore/runner.rb
CHANGED
@@ -1,29 +1,48 @@
|
|
1
|
-
require '
|
2
|
-
require 'carnivore/config'
|
3
|
-
require 'carnivore/source'
|
4
|
-
require 'carnivore/container'
|
1
|
+
require 'carnivore/autoloader'
|
5
2
|
|
6
3
|
module Carnivore
|
7
4
|
class << self
|
5
|
+
|
6
|
+
# block:: Block of configuration
|
7
|
+
# Add configuration to Carnivore
|
8
8
|
def configure(&block)
|
9
9
|
mod = Container.new
|
10
10
|
mod.instance_exec(mod, &block)
|
11
11
|
self
|
12
12
|
end
|
13
13
|
|
14
|
+
# Start carnivore
|
14
15
|
def start!
|
15
16
|
supervisor = nil
|
16
17
|
begin
|
17
18
|
require 'carnivore/supervisor'
|
18
|
-
supervisor = Carnivore::Supervisor.
|
19
|
+
supervisor = Carnivore::Supervisor.build!
|
19
20
|
Source.sources.each do |source|
|
21
|
+
source.klass.reset_comms!
|
20
22
|
supervisor.supervise_as(
|
21
23
|
source.source_hash[:name],
|
22
24
|
source.klass,
|
23
|
-
source.source_hash
|
25
|
+
source.source_hash.dup
|
24
26
|
)
|
25
27
|
end
|
26
|
-
|
28
|
+
loop do
|
29
|
+
# We do a sleep loop so we can periodically check on the
|
30
|
+
# supervisor and ensure it is still alive. If it has died,
|
31
|
+
# raise exception to allow cleanup and restart attempt
|
32
|
+
sleep Carnivore::Config.get(:carnivore, :supervisor, :poll) || 5 while supervisor.alive?
|
33
|
+
Celluloid::Logger.error 'Carnivore supervisor has died!'
|
34
|
+
raise Carnivore::Error::DeadSupervisor.new
|
35
|
+
end
|
36
|
+
rescue Carnivore::Error::DeadSupervisor
|
37
|
+
Celluloid::Logger.warn "Received dead supervisor exception. Attempting to restart."
|
38
|
+
begin
|
39
|
+
supervisor.terminate
|
40
|
+
rescue => e
|
41
|
+
Celluloid::Logger.debug "Exception raised during supervisor termination (restart cleanup): #{e}"
|
42
|
+
end
|
43
|
+
Celluloid::Logger.debug "Pausing restart for 10 seconds to prevent restart thrashing cycles"
|
44
|
+
sleep 10
|
45
|
+
retry
|
27
46
|
rescue Exception => e
|
28
47
|
supervisor.terminate
|
29
48
|
# Gracefully shut down
|
data/lib/carnivore/source.rb
CHANGED
@@ -1,31 +1,11 @@
|
|
1
|
+
require 'digest/sha2'
|
1
2
|
require 'celluloid'
|
2
|
-
require 'carnivore
|
3
|
-
require 'carnivore/callback'
|
4
|
-
require 'carnivore/message'
|
3
|
+
require 'carnivore'
|
5
4
|
|
6
5
|
module Carnivore
|
7
6
|
class Source
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
attr_reader :klass
|
12
|
-
attr_reader :source_hash
|
13
|
-
|
14
|
-
# class_name:: Name of source class
|
15
|
-
# args:: argument hash to pass to source instance
|
16
|
-
def initialize(class_name, args={})
|
17
|
-
@klass = class_name
|
18
|
-
@source_hash = args || {}
|
19
|
-
@source_hash[:callbacks] = {}
|
20
|
-
end
|
21
|
-
|
22
|
-
# name:: Name of callback
|
23
|
-
# klass:: Class of callback (optional)
|
24
|
-
# Add a callback to a source via Class or block
|
25
|
-
def add_callback(name, klass=nil, &block)
|
26
|
-
@source_hash[:callbacks][name] = klass || block
|
27
|
-
end
|
28
|
-
end
|
8
|
+
autoload :SourceContainer, 'carnivore/source_container'
|
29
9
|
|
30
10
|
class << self
|
31
11
|
|
@@ -48,12 +28,17 @@ module Carnivore
|
|
48
28
|
inst
|
49
29
|
end
|
50
30
|
|
31
|
+
# type:: Symbol of type of source
|
32
|
+
# require_path:: Path to feed to `require`
|
33
|
+
# Registers a source
|
51
34
|
def provide(type, require_path)
|
52
35
|
@source_klass ||= {}
|
53
36
|
@source_klass[type.to_sym] = require_path
|
54
37
|
true
|
55
38
|
end
|
56
39
|
|
40
|
+
# type: Symbol of source type
|
41
|
+
# Returns register path for given type of source
|
57
42
|
def require_path(type)
|
58
43
|
@source_klass ||= {}
|
59
44
|
@source_klass[type.to_sym]
|
@@ -82,6 +67,19 @@ module Carnivore
|
|
82
67
|
def sources
|
83
68
|
@sources ? @sources.values : []
|
84
69
|
end
|
70
|
+
|
71
|
+
def reset_comms!
|
72
|
+
self.class_eval do
|
73
|
+
unless(method_defined?(:reset_communications?))
|
74
|
+
alias_method :custom_transmit, :transmit
|
75
|
+
alias_method :transmit, :_transmit
|
76
|
+
def reset_communications?
|
77
|
+
true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
85
83
|
end
|
86
84
|
|
87
85
|
include Celluloid
|
@@ -93,14 +91,22 @@ module Carnivore
|
|
93
91
|
attr_reader :auto_process
|
94
92
|
attr_reader :run_process
|
95
93
|
attr_reader :callback_supervisor
|
94
|
+
attr_reader :message_registry
|
95
|
+
attr_reader :message_loop
|
96
|
+
attr_reader :processing
|
96
97
|
|
97
98
|
def initialize(args={})
|
98
99
|
@callbacks = []
|
100
|
+
@message_loop = []
|
99
101
|
@callback_names = {}
|
100
102
|
@auto_process = args.fetch(:auto_process, true)
|
101
|
-
@run_process =
|
103
|
+
@run_process = true
|
102
104
|
@auto_confirm = !!args[:auto_confirm]
|
103
|
-
@callback_supervisor =
|
105
|
+
@callback_supervisor = Carnivore::Supervisor.create!.last
|
106
|
+
if(args[:prevent_duplicates])
|
107
|
+
init_registry
|
108
|
+
end
|
109
|
+
@processing = false
|
104
110
|
@name = args[:name] || Celluloid.uuid
|
105
111
|
if(args[:callbacks])
|
106
112
|
args[:callbacks].each do |name, block|
|
@@ -109,45 +115,72 @@ module Carnivore
|
|
109
115
|
end
|
110
116
|
setup(args)
|
111
117
|
connect
|
112
|
-
|
118
|
+
if(auto_process && !callbacks.empty?)
|
119
|
+
async.process
|
120
|
+
end
|
113
121
|
rescue => e
|
114
122
|
debug "Failed to initialize: #{self} - #{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
115
123
|
raise
|
116
124
|
end
|
117
125
|
|
126
|
+
# Ensure we cleanup our internal supervisor before bailing out
|
127
|
+
def terminate
|
128
|
+
callback_supervisor.terminate
|
129
|
+
super
|
130
|
+
end
|
131
|
+
|
132
|
+
# Automatically confirm messages after dispatch
|
118
133
|
def auto_confirm?
|
119
134
|
@auto_confirm
|
120
135
|
end
|
121
136
|
|
137
|
+
# Return string for inspection
|
122
138
|
def inspect
|
123
139
|
"<#{self.class.name}:#{object_id} @name=#{name} @callbacks=#{Hash[*callbacks.map{|k,v| [k,v.object_id]}.flatten]}>"
|
124
140
|
end
|
125
141
|
|
142
|
+
# Return string of instance
|
126
143
|
def to_s
|
127
144
|
"<#{self.class.name}:#{object_id} @name=#{name}>"
|
128
145
|
end
|
129
146
|
|
147
|
+
# args:: Argument hash used to initialize instance
|
148
|
+
# Setup called during initialization for child sources to override
|
130
149
|
def setup(args={})
|
131
150
|
debug 'No custom setup declared'
|
132
151
|
end
|
133
152
|
|
153
|
+
# args:: Argument hash
|
154
|
+
# Connection method to be overridden in child sources
|
134
155
|
def connect(args={})
|
135
156
|
debug 'No custom connect declared'
|
136
157
|
end
|
137
158
|
|
159
|
+
# args:: number of messages to read
|
160
|
+
# Returns messages from source
|
138
161
|
def receive(n=1)
|
139
162
|
raise NoMethodError.new('Abstract method not valid for runtime')
|
140
163
|
end
|
141
164
|
|
142
|
-
|
165
|
+
# message:: Payload to transmit
|
166
|
+
# original_message:: Original `Carnivore::Message`
|
167
|
+
# args:: Custom arguments
|
168
|
+
# Transmit message on source
|
169
|
+
def transmit(message, original_message=nil, args={})
|
143
170
|
raise NoMethodError.new('Abstract method not valid for runtime')
|
144
171
|
end
|
145
172
|
|
173
|
+
# message:: Carnivore::Message
|
174
|
+
# Confirm receipt of the message on source
|
146
175
|
def confirm(message)
|
147
176
|
debug 'No custom confirm declared'
|
148
177
|
end
|
149
178
|
|
150
|
-
|
179
|
+
# callback_name:: Name of callback
|
180
|
+
# block_or_class:: Carnivore::Callback class or a block
|
181
|
+
# Adds the given callback to the source for message processing
|
182
|
+
def add_callback(callback_name, block_or_class)
|
183
|
+
name = "#{self.name}:#{callback_name}"
|
151
184
|
if(block_or_class.is_a?(Class))
|
152
185
|
size = block_or_class.workers || 1
|
153
186
|
if(size < 1)
|
@@ -155,19 +188,21 @@ module Carnivore
|
|
155
188
|
return self
|
156
189
|
elsif(size == 1)
|
157
190
|
debug "Adding callback class (#{block_or_class}) under supervision. Name: #{callback_name(name)}"
|
158
|
-
|
191
|
+
callback_supervisor.supervise_as callback_name(name), block_or_class, name
|
159
192
|
else
|
160
193
|
debug "Adding callback class (#{block_or_class}) under supervision pool (#{size} workers). Name: #{callback_name(name)}"
|
161
|
-
|
194
|
+
callback_supervisor.pool block_or_class, as: callback_name(name), size: size, args: [name]
|
162
195
|
end
|
163
196
|
else
|
164
197
|
debug "Adding custom callback class from block (#{block_or_class}) under supervision. Name: #{callback_name(name)}"
|
165
|
-
|
198
|
+
callback_supervisor.supervise_as callback_name(name), Callback, name, block_or_class
|
166
199
|
end
|
167
|
-
|
200
|
+
callbacks.push(name).uniq!
|
168
201
|
self
|
169
202
|
end
|
170
203
|
|
204
|
+
# name:: Name of callback
|
205
|
+
# Remove the named callback from the source
|
171
206
|
def remove_callback(name)
|
172
207
|
unless(@callbacks.include?(callback_name(name)))
|
173
208
|
raise NameError.new("Failed to locate callback named: #{name}")
|
@@ -177,6 +212,8 @@ module Carnivore
|
|
177
212
|
self
|
178
213
|
end
|
179
214
|
|
215
|
+
# name:: Name of callback
|
216
|
+
# Returns namespaced name (prefixed with source name and instance id)
|
180
217
|
def callback_name(name)
|
181
218
|
unless(@callback_names[name])
|
182
219
|
@callback_names[name] = [@name, self.object_id, name].join(':').to_sym
|
@@ -184,26 +221,99 @@ module Carnivore
|
|
184
221
|
@callback_names[name]
|
185
222
|
end
|
186
223
|
|
224
|
+
# msg:: New message received from source
|
225
|
+
# Returns formatted Carnivore::Message
|
187
226
|
def format(msg)
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
227
|
+
actor = Carnivore::Supervisor.supervisor[name]
|
228
|
+
if(actor)
|
229
|
+
Message.new(
|
230
|
+
:message => msg,
|
231
|
+
:source => actor
|
232
|
+
)
|
233
|
+
else
|
234
|
+
abort "Failed to locate self in registry (#{name})"
|
235
|
+
end
|
192
236
|
end
|
193
237
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
238
|
+
# m:: Carnivore::Message
|
239
|
+
# Returns true if message is valid to be processed
|
240
|
+
def valid_message?(m)
|
241
|
+
if(message_registry)
|
242
|
+
if(message_registry.valid?(m))
|
243
|
+
true
|
244
|
+
else
|
245
|
+
warn "Message was already received. Discarding: #{m.inspect}"
|
246
|
+
false
|
198
247
|
end
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
248
|
+
else
|
249
|
+
true
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# args:: Arguments
|
254
|
+
# Start processing messages from source
|
255
|
+
def process(*args)
|
256
|
+
begin
|
257
|
+
while(run_process && !callbacks.empty?)
|
258
|
+
@processing = true
|
259
|
+
loop_msgs = future.loop_receive unless loop_msgs
|
260
|
+
remote_msgs = future.receive unless remote_msgs
|
261
|
+
if(loop_msgs.ready?)
|
262
|
+
msgs = loop_msgs.value
|
263
|
+
loop_msgs = nil
|
264
|
+
elsif(remote_msgs.ready?)
|
265
|
+
msgs = remote_msgs.value
|
266
|
+
remote_msgs = nil
|
267
|
+
else
|
268
|
+
msgs = []
|
269
|
+
end
|
270
|
+
msgs = [msgs].flatten.compact.map do |m|
|
271
|
+
if(valid_message?(m))
|
272
|
+
format(m)
|
273
|
+
end
|
274
|
+
end.compact
|
275
|
+
msgs.each do |msg|
|
276
|
+
@callbacks.each do |name|
|
277
|
+
debug "Dispatching message<#{msg[:message].object_id}> to callback<#{name} (#{callback_name(name)})>"
|
278
|
+
callback_supervisor[callback_name(name)].async.call(msg)
|
279
|
+
end
|
203
280
|
end
|
281
|
+
sleep(1) if msgs.empty?
|
204
282
|
end
|
283
|
+
ensure
|
284
|
+
@processing = false
|
205
285
|
end
|
206
286
|
end
|
207
287
|
|
288
|
+
# args:: unused
|
289
|
+
# Return queued message from internal loop
|
290
|
+
def loop_receive(*args)
|
291
|
+
@message_loop.shift
|
292
|
+
end
|
293
|
+
|
294
|
+
# message:: Message for delivery
|
295
|
+
# original_message:: unused
|
296
|
+
# args:: unused
|
297
|
+
# Push message onto internal loop queue
|
298
|
+
def loop_transmit(message, original_message=nil, args={})
|
299
|
+
@message_loop.push message
|
300
|
+
end
|
301
|
+
|
302
|
+
# args:: transmit args
|
303
|
+
# Send to local loop if processing otherwise use regular transmit
|
304
|
+
def _transmit(*args)
|
305
|
+
if(processing)
|
306
|
+
loop_transmit(*args)
|
307
|
+
else
|
308
|
+
custom_transmit(*args)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# Load and initialize the message registry
|
313
|
+
def init_registry
|
314
|
+
require 'carnivore/message_registry'
|
315
|
+
@message_registry = MessageRegistry.new
|
316
|
+
end
|
317
|
+
|
208
318
|
end
|
209
319
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'carnivore'
|
2
|
+
|
3
|
+
module Carnivore
|
4
|
+
class Source
|
5
|
+
|
6
|
+
# Container for holding source configuration. This allows setup to
|
7
|
+
# occur prior to the supervisor actually starting the sources
|
8
|
+
class SourceContainer
|
9
|
+
|
10
|
+
attr_reader :klass
|
11
|
+
attr_reader :source_hash
|
12
|
+
|
13
|
+
# class_name:: Name of source class
|
14
|
+
# args:: argument hash to pass to source instance
|
15
|
+
def initialize(class_name, args={})
|
16
|
+
@klass = class_name
|
17
|
+
@source_hash = args || {}
|
18
|
+
@source_hash[:callbacks] = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
# name:: Name of callback
|
22
|
+
# klass:: Class of callback (optional)
|
23
|
+
# Add a callback to a source via Class or block
|
24
|
+
def add_callback(name, klass=nil, &block)
|
25
|
+
@source_hash[:callbacks][name] = klass || block
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'carnivore'
|
2
|
+
require 'celluloid'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
Celluloid.logger.level = 4
|
6
|
+
|
7
|
+
if(File.directory?(dir = File.join(Dir.pwd, 'test', 'specs')))
|
8
|
+
Dir.glob(File.join(dir, '*.rb')).each do |path|
|
9
|
+
require path
|
10
|
+
end
|
11
|
+
else
|
12
|
+
puts 'Failed to locate `test/specs` directory. Are you in project root directory?'
|
13
|
+
exit -1
|
14
|
+
end
|
15
|
+
|
16
|
+
MiniTest::Spec.before do
|
17
|
+
Celluloid.shutdown
|
18
|
+
Celluloid.boot
|
19
|
+
end
|
20
|
+
|
21
|
+
# Simple waiter method to stall testing
|
22
|
+
def source_wait(name='wait')
|
23
|
+
sleep(ENV.fetch("CARNIVORE_SOURCE_#{name.to_s.upcase}", 0.2).to_f)
|
24
|
+
end
|
25
|
+
|
26
|
+
# dummy store that should never be used for anything real
|
27
|
+
class MessageStore
|
28
|
+
class << self
|
29
|
+
|
30
|
+
def init
|
31
|
+
@messages = []
|
32
|
+
end
|
33
|
+
|
34
|
+
def messages
|
35
|
+
@messages
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# dummy source to hold final tranmission and stuff payload in store
|
42
|
+
module Carnivore
|
43
|
+
class Source
|
44
|
+
class Spec < Source
|
45
|
+
def setup(*args)
|
46
|
+
MessageStore.init
|
47
|
+
end
|
48
|
+
|
49
|
+
def receive(*args)
|
50
|
+
wait(:forever)
|
51
|
+
end
|
52
|
+
|
53
|
+
def transmit(*args)
|
54
|
+
MessageStore.messages << args.first
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Carnivore::Source.provide(:spec, 'carnivore/spec_helper')
|
data/lib/carnivore/supervisor.rb
CHANGED
@@ -1,4 +1,57 @@
|
|
1
|
+
require 'carnivore'
|
2
|
+
require 'celluloid/supervision_group'
|
3
|
+
|
1
4
|
module Carnivore
|
2
5
|
class Supervisor < Celluloid::SupervisionGroup
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
attr_reader :registry, :supervisor
|
10
|
+
|
11
|
+
# Build a new supervisor
|
12
|
+
def build!
|
13
|
+
@registry, @supervisor = create!
|
14
|
+
@supervisor
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new supervisor
|
18
|
+
# Returns [registry,supervisor]
|
19
|
+
def create!
|
20
|
+
registry = Celluloid::Registry.new
|
21
|
+
[registry, run!(registry)]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Destroy the registered supervisor
|
25
|
+
def terminate!
|
26
|
+
if(supervisor)
|
27
|
+
begin
|
28
|
+
supervisor.terminate
|
29
|
+
rescue Celluloid::DeadActorError
|
30
|
+
end
|
31
|
+
@supervisor = nil
|
32
|
+
@registry = nil
|
33
|
+
end
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# name:: Name of source
|
40
|
+
# Return source
|
41
|
+
def [](name)
|
42
|
+
instance = @registry[name]
|
43
|
+
unless(instance)
|
44
|
+
if(member = @members.detect{|m| m && m.name.to_s == name.to_s})
|
45
|
+
Celluloid::Logger.warn "Found missing actor in member list. Attempting to restart manually."
|
46
|
+
restart_actor(member.actor, true)
|
47
|
+
instance = @registry[name]
|
48
|
+
unless(instance)
|
49
|
+
Celluloid::Logger.error "Actor restart failed to make it available in the registry! (#{name})"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
instance
|
54
|
+
end
|
55
|
+
|
3
56
|
end
|
4
57
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
|
3
|
+
module Carnivore
|
4
|
+
module Utils
|
5
|
+
|
6
|
+
module Logging
|
7
|
+
|
8
|
+
# Define base logging types
|
9
|
+
%w(debug info warn error).each do |key|
|
10
|
+
define_method(key) do |string|
|
11
|
+
log(key, string)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Log message
|
16
|
+
def log(*args)
|
17
|
+
if(args.empty?)
|
18
|
+
Celluloid::Logger
|
19
|
+
else
|
20
|
+
severity, string = args
|
21
|
+
Celluloid::Logger.send(severity.to_sym, "#{self}: #{string}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Carnivore
|
2
|
+
module Utils
|
3
|
+
# Registry used for preventing duplicate message processing
|
4
|
+
class MessageRegistry
|
5
|
+
def initialize
|
6
|
+
@store = []
|
7
|
+
@size = 100
|
8
|
+
end
|
9
|
+
|
10
|
+
# message:: Carnivore::Message
|
11
|
+
# Returns true if message has not been processed
|
12
|
+
def valid?(message)
|
13
|
+
checksum = sha(message)
|
14
|
+
found = @store.include?(checksum)
|
15
|
+
unless(found)
|
16
|
+
push(checksum)
|
17
|
+
end
|
18
|
+
!found
|
19
|
+
end
|
20
|
+
|
21
|
+
# item:: checksum
|
22
|
+
# Pushes checksum into store
|
23
|
+
def push(item)
|
24
|
+
@store.push(item)
|
25
|
+
if(@store.size > @size)
|
26
|
+
@store.shift
|
27
|
+
end
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
# thing:: Instance
|
32
|
+
# Return checksum for give instance
|
33
|
+
def sha(thing)
|
34
|
+
unless(thing.is_a?(String))
|
35
|
+
thing = MultiJson.dump(thing)
|
36
|
+
end
|
37
|
+
(Digest::SHA512.new << thing).hexdigest
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Carnivore
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
module Params
|
5
|
+
|
6
|
+
# hash:: Hash
|
7
|
+
# Symbolize keys in hash
|
8
|
+
def symbolize_hash(hash)
|
9
|
+
Hash[*(
|
10
|
+
hash.map do |k,v|
|
11
|
+
if(k.is_a?(String))
|
12
|
+
key = k.gsub(/(?<![A-Z])([A-Z])/, '_\1').sub(/^_/, '').downcase.to_sym
|
13
|
+
else
|
14
|
+
key = k
|
15
|
+
end
|
16
|
+
[
|
17
|
+
key,
|
18
|
+
v.is_a?(Hash) ? symbolize_hash(v) : v
|
19
|
+
]
|
20
|
+
end.flatten(1)
|
21
|
+
)]
|
22
|
+
end
|
23
|
+
|
24
|
+
# hash:: Hash
|
25
|
+
# args:: Symbols or strings
|
26
|
+
# Follow path in hash provided by args and return value or nil
|
27
|
+
# if path is not valid
|
28
|
+
def retrieve(hash, *args)
|
29
|
+
valids = [::Hash, hash.is_a?(Class) ? hash : hash.class]
|
30
|
+
args.flatten.inject(hash) do |memo, key|
|
31
|
+
break unless valids.detect{ |valid_type|
|
32
|
+
memo.is_a?(valid_type) || memo == valid_type
|
33
|
+
}
|
34
|
+
memo[key.to_s] || memo[key.to_sym] || break
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
data/lib/carnivore/utils.rb
CHANGED
@@ -1,47 +1,13 @@
|
|
1
|
-
require '
|
1
|
+
require 'carnivore'
|
2
2
|
|
3
3
|
module Carnivore
|
4
|
-
module Utils
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
if(k.is_a?(String))
|
11
|
-
key = k.gsub(/(?<![A-Z])([A-Z])/, '_\1').sub(/^_/, '').downcase.to_sym
|
12
|
-
else
|
13
|
-
key = k
|
14
|
-
end
|
15
|
-
[
|
16
|
-
key,
|
17
|
-
v.is_a?(Hash) ? symbolize_hash(v) : v
|
18
|
-
]
|
19
|
-
end.flatten(1)
|
20
|
-
)]
|
21
|
-
end
|
22
|
-
end
|
5
|
+
module Utils
|
6
|
+
autoload :Params, 'carnivore/utils/params'
|
7
|
+
autoload :Logging, 'carnivore/utils/logging'
|
8
|
+
autoload :MessageRegistry, 'carnivore/utils/message_registry'
|
23
9
|
|
24
10
|
extend Params
|
25
|
-
|
26
|
-
module Logging
|
27
|
-
|
28
|
-
%w(debug info warn error).each do |key|
|
29
|
-
define_method(key) do |string|
|
30
|
-
log(key, string)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def log(*args)
|
35
|
-
if(args.empty?)
|
36
|
-
Celluloid::Logger
|
37
|
-
else
|
38
|
-
severity, string = args
|
39
|
-
Celluloid::Logger.send(severity.to_sym, "#{self}: #{string}")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
11
|
extend Logging
|
46
12
|
|
47
13
|
end
|
data/lib/carnivore/version.rb
CHANGED
data/lib/carnivore.rb
CHANGED
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.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,10 +9,10 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: celluloid
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
31
|
+
name: mixlib-config
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: multi_json
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
@@ -66,29 +66,26 @@ extensions: []
|
|
66
66
|
extra_rdoc_files: []
|
67
67
|
files:
|
68
68
|
- lib/carnivore/callback.rb
|
69
|
+
- lib/carnivore/errors.rb
|
69
70
|
- lib/carnivore/supervisor.rb
|
70
71
|
- lib/carnivore/source/test.rb
|
71
72
|
- lib/carnivore/source.rb
|
72
73
|
- lib/carnivore/version.rb
|
73
74
|
- lib/carnivore/runner.rb
|
75
|
+
- lib/carnivore/spec_helper.rb
|
76
|
+
- lib/carnivore/utils/message_registry.rb
|
77
|
+
- lib/carnivore/utils/logging.rb
|
78
|
+
- lib/carnivore/utils/params.rb
|
79
|
+
- lib/carnivore/autoloader.rb
|
74
80
|
- lib/carnivore/config.rb
|
75
81
|
- lib/carnivore/message.rb
|
82
|
+
- lib/carnivore/source_container.rb
|
76
83
|
- lib/carnivore/utils.rb
|
77
84
|
- lib/carnivore/container.rb
|
78
85
|
- lib/carnivore.rb
|
79
|
-
-
|
80
|
-
- test/specs/source.rb
|
81
|
-
- test/specs/config.rb
|
82
|
-
- test/specs/message.rb
|
83
|
-
- test/specs/utils.rb
|
84
|
-
- test/specs/container.rb
|
85
|
-
- examples/test_http.rb
|
86
|
-
- examples/test_class.rb
|
87
|
-
- examples/test_block.rb
|
88
|
-
- Gemfile
|
86
|
+
- carnivore.gemspec
|
89
87
|
- README.md
|
90
88
|
- CHANGELOG.md
|
91
|
-
- carnivore.gemspec
|
92
89
|
homepage: https://github.com/carnivore-rb/carnivore
|
93
90
|
licenses: []
|
94
91
|
post_install_message:
|
data/Gemfile
DELETED
data/examples/test_block.rb
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
require 'carnivore'
|
2
|
-
|
3
|
-
Carnivore.configure do
|
4
|
-
s = Carnivore::Source.build(:type => :test, :args => {})
|
5
|
-
|
6
|
-
s.add_callback(:printer) do |message|
|
7
|
-
info "GOT MESSAGE: #{message[:message]} - source: #{message[:source]} - instance: #{self}"
|
8
|
-
end
|
9
|
-
|
10
|
-
end.start!
|
data/examples/test_class.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'carnivore'
|
2
|
-
|
3
|
-
class CustomCallback < Carnivore::Callback
|
4
|
-
|
5
|
-
self.workers = 5
|
6
|
-
|
7
|
-
def setup
|
8
|
-
info "Custom callback setup called!"
|
9
|
-
end
|
10
|
-
|
11
|
-
def execute(message)
|
12
|
-
info "GOT MESSAGE: #{message[:message]} - source: #{message[:source]} - instance: #{self}"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
Carnivore.configure do
|
17
|
-
s = Carnivore::Source.build(:type => :test, :args => {})
|
18
|
-
s.add_callback(:printer, CustomCallback)
|
19
|
-
|
20
|
-
end.start!
|
data/examples/test_http.rb
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
require 'carnivore'
|
2
|
-
|
3
|
-
Carnivore.configure do
|
4
|
-
s = Carnivore::Source.build(:type => :http, :args => {:bind => '0.0.0.0', :port => 3000})
|
5
|
-
|
6
|
-
s.add_callback(:printer) do |message|
|
7
|
-
info "GOT MESSAGE: #{message[:message][:body]} - path: #{message[:message][:request].url} - method: #{message[:message][:request].method} - source: #{message[:source]} - instance: #{self}"
|
8
|
-
end
|
9
|
-
|
10
|
-
end.start!
|
data/test/spec.rb
DELETED
data/test/specs/config.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'carnivore/config'
|
3
|
-
|
4
|
-
describe 'Carnivore::Config' do
|
5
|
-
describe 'Direct Configuration' do
|
6
|
-
it 'allows direct configuration set' do
|
7
|
-
Carnivore::Config[:direct] = true
|
8
|
-
Carnivore::Config[:direct].must_equal true
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'returns nil when configuration is undefined' do
|
12
|
-
Carnivore::Config[:missing].must_be_nil
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'raises exception when accessing nested keys that do not exist' do
|
16
|
-
-> { Carnivore::Config[:missing][:key] }.must_raise NoMethodError
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
describe '#get helper' do
|
22
|
-
it 'returns the nested configuration value' do
|
23
|
-
Carnivore::Config[:nested] = {:value => 'hello world'}
|
24
|
-
Carnivore::Config.get(:nested, :value).must_equal 'hello world'
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'returns `nil` when nested configuration does not exist' do
|
28
|
-
Carnivore::Config.get(:value, :does, :not, :exist).must_be_nil
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/test/specs/container.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'carnivore/container'
|
3
|
-
|
4
|
-
describe 'Carnivore::Container' do
|
5
|
-
it 'provides logging helpers' do
|
6
|
-
c = Carnivore::Container.new
|
7
|
-
Carnivore::Container.must_respond_to :log
|
8
|
-
c.must_respond_to :log
|
9
|
-
%w(debug info warn error).each do |key|
|
10
|
-
c.must_respond_to key
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/test/specs/message.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'carnivore/message'
|
3
|
-
|
4
|
-
describe 'Carnivore::Message' do
|
5
|
-
|
6
|
-
it 'requires a Source to be provided' do
|
7
|
-
-> { Carnivore::Message.new(:message => 'hi') }.must_raise ArgumentError
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'provides argument access via `[]`' do
|
11
|
-
message = Carnivore::Message.new(:source => true, :message => 'hi')
|
12
|
-
message[:source].must_equal true
|
13
|
-
message[:message].must_equal 'hi'
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'provides direct argument hash access via `args`' do
|
17
|
-
message = Carnivore::Message.new(:source => true, :message => 'hi')
|
18
|
-
message.args.must_be_kind_of Hash
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'provides `confirm!` confirmation helper to Source' do
|
22
|
-
source = MiniTest::Mock.new
|
23
|
-
message = Carnivore::Message.new(:source => source, :message => 'hi')
|
24
|
-
source.expect(:confirm, true, [message])
|
25
|
-
message.confirm!
|
26
|
-
source.verify
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
data/test/specs/source.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'carnivore/source'
|
3
|
-
|
4
|
-
describe 'Carnivore::Source' do
|
5
|
-
describe 'Carnivore::Source::SourceContainer' do
|
6
|
-
before do
|
7
|
-
@src_ctn = Carnivore::Source::SourceContainer.new(:my_name, {:arg1 => true})
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should store name in `klass` attribute' do
|
11
|
-
@src_ctn.klass.must_equal :my_name
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'should store argument hash in `source_hash` attribute' do
|
15
|
-
@src_ctn.source_hash.must_equal :arg1 => true, :callbacks => {}
|
16
|
-
end
|
17
|
-
|
18
|
-
describe 'callback additions' do
|
19
|
-
before do
|
20
|
-
@block = lambda{ 'hi' }
|
21
|
-
@src_ctn.add_callback(:hi, &@block)
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'should store callback by name in `source_hash` under `:callbacks`' do
|
25
|
-
@src_ctn.source_hash.keys.must_include :callbacks
|
26
|
-
@src_ctn.source_hash[:callbacks].keys.must_include :hi
|
27
|
-
@src_ctn.source_hash[:callbacks].values.must_include @block
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe 'Custom source providers' do
|
33
|
-
|
34
|
-
before do
|
35
|
-
Carnivore::Source.provide(:meat_bag, 'carnivore-meat-bag/meat_bag')
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'gives expected require path if registered' do
|
39
|
-
Carnivore::Source.require_path(:meat_bag).must_equal 'carnivore-meat-bag/meat_bag'
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'gives `nil` require path if not registered' do
|
43
|
-
Carnivore::Source.require_path(:test).must_be_nil
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe 'Source registration' do
|
48
|
-
before do
|
49
|
-
@inst = Object.new
|
50
|
-
Carnivore::Source.register(:my_source, @inst)
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'provides list of registered sources' do
|
54
|
-
Carnivore::Source.sources.must_include @inst
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'allows accessing registered source by name' do
|
58
|
-
Carnivore::Source.source(:my_source).must_equal @inst
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe 'Processing with base Source instance' do
|
63
|
-
it 'should raise an exception' do
|
64
|
-
-> {
|
65
|
-
Carnivore::Source.new(:auto_process => false).process
|
66
|
-
}.must_raise NoMethodError
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe 'Source test instance' do
|
71
|
-
describe 'with no name argument' do
|
72
|
-
before do
|
73
|
-
require 'carnivore/source/test'
|
74
|
-
@source = Carnivore::Source::Test.new
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'should generate name if none provided' do
|
78
|
-
@source.name.wont_be :empty?
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
data/test/specs/utils.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'carnivore/utils'
|
3
|
-
|
4
|
-
describe 'Carnivore::Utils' do
|
5
|
-
describe 'Carnivore::Utils::Logging' do
|
6
|
-
before do
|
7
|
-
@obj = Object.new
|
8
|
-
@obj.extend(Carnivore::Utils::Logging)
|
9
|
-
Celluloid.logger.level = 0
|
10
|
-
end
|
11
|
-
|
12
|
-
after do
|
13
|
-
Celluloid.logger.level = 4
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'adds logging methods' do
|
17
|
-
%w(debug info warn error).each do |key|
|
18
|
-
@obj.must_respond_to(key)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'includes object information in logging output' do
|
23
|
-
out, err = capture_subprocess_io do
|
24
|
-
@obj.info 'hello world'
|
25
|
-
end
|
26
|
-
err.must_match %r{I,\s*\[.*?\]\s*INFO\s*--\s*:\s*#{Regexp.escape(@obj.inspect)}:\s*hello world\n}
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe 'Carnivore::Utils::Params' do
|
31
|
-
before do
|
32
|
-
@obj = Object.new
|
33
|
-
@obj.extend(Carnivore::Utils::Params)
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'adds `symbolize_hash` method' do
|
37
|
-
@obj.must_respond_to :symbolize_hash
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'converts hash keys to symbols' do
|
41
|
-
h = {'string' => {'another' => {'OneHere' => 'more'}}}
|
42
|
-
converted = @obj.symbolize_hash(h)
|
43
|
-
converted.keys.first.must_equal :string
|
44
|
-
converted[:string][:another].keys.first.must_equal :one_here
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|