serf 0.11.0 → 0.12.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/Gemfile +1 -0
- data/Guardfile +1 -2
- data/README.md +131 -15
- data/example/components/logger.serf +7 -0
- data/example/serfs/create_widget.serf +24 -0
- data/lib/serf/builder.rb +7 -6
- data/lib/serf/loader.rb +16 -0
- data/lib/serf/loader/loader.rb +103 -0
- data/lib/serf/loader/registry.rb +86 -0
- data/lib/serf/middleware/error_handler.rb +4 -4
- data/lib/serf/middleware/parcel_freezer.rb +3 -6
- data/lib/serf/middleware/parcel_masher.rb +3 -6
- data/lib/serf/middleware/policy_checker.rb +3 -5
- data/lib/serf/middleware/request_timer.rb +47 -0
- data/lib/serf/middleware/uuid_tagger.rb +3 -5
- data/lib/serf/parcel_builder.rb +3 -6
- data/lib/serf/serfer.rb +5 -7
- data/lib/serf/util/uuidable.rb +3 -6
- data/lib/serf/version.rb +1 -1
- data/serf.gemspec +1 -0
- data/spec/serf/builder_spec.rb +4 -5
- data/spec/serf/errors/policy_failure_spec.rb +1 -1
- data/spec/serf/loader/loader_spec.rb +73 -0
- data/spec/serf/loader/registry_spec.rb +62 -0
- data/spec/serf/loader_spec.rb +57 -0
- data/spec/serf/middleware/error_handler_spec.rb +2 -2
- data/spec/serf/middleware/parcel_freezer_spec.rb +2 -2
- data/spec/serf/middleware/parcel_masher_spec.rb +5 -5
- data/spec/serf/middleware/policy_checker_spec.rb +3 -3
- data/spec/serf/middleware/request_timer_spec.rb +43 -0
- data/spec/serf/middleware/uuid_tagger_spec.rb +4 -4
- data/spec/serf/parcel_builder_spec.rb +7 -7
- data/spec/serf/serfer_spec.rb +4 -4
- data/spec/serf/util/error_handling_spec.rb +3 -3
- data/spec/serf/util/null_object_spec.rb +4 -4
- data/spec/serf/util/protected_call_spec.rb +4 -4
- data/spec/serf/util/uuidable_spec.rb +15 -15
- data/spec/support/factories.rb +7 -0
- metadata +34 -9
- data/lib/serf/util/options_extraction.rb +0 -117
- data/spec/serf/util/options_extraction_spec.rb +0 -62
- data/spec/support/options_extraction_wrapper.rb +0 -10
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'hashie'
|
2
|
+
require 'optser'
|
2
3
|
|
3
4
|
require 'serf/parcel_builder'
|
4
5
|
require 'serf/util/error_handling'
|
@@ -13,7 +14,6 @@ module Middleware
|
|
13
14
|
#
|
14
15
|
class ErrorHandler
|
15
16
|
include Serf::Util::ErrorHandling
|
16
|
-
include Serf::Util::OptionsExtraction
|
17
17
|
|
18
18
|
attr_reader :app
|
19
19
|
attr_reader :parcel_builder
|
@@ -23,12 +23,12 @@ module Middleware
|
|
23
23
|
# @param app the app
|
24
24
|
#
|
25
25
|
def initialize(app, *args)
|
26
|
-
extract_options! args
|
26
|
+
opts = Optser.extract_options! args
|
27
27
|
@app = app
|
28
28
|
|
29
29
|
# Tunable knobs
|
30
|
-
@parcel_builder = opts(:parcel_builder) { Serf::ParcelBuilder.new }
|
31
|
-
@uuidable = opts(:uuidable) { Serf::Util::Uuidable.new }
|
30
|
+
@parcel_builder = opts.get(:parcel_builder) { Serf::ParcelBuilder.new }
|
31
|
+
@uuidable = opts.get(:uuidable) { Serf::Util::Uuidable.new }
|
32
32
|
end
|
33
33
|
|
34
34
|
def call(parcel)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'ice_nine'
|
2
|
-
|
3
|
-
require 'serf/util/options_extraction'
|
2
|
+
require 'optser'
|
4
3
|
|
5
4
|
module Serf
|
6
5
|
module Middleware
|
@@ -9,8 +8,6 @@ module Middleware
|
|
9
8
|
# Middleware to add uuids to the headers of the parcel hash.
|
10
9
|
#
|
11
10
|
class ParcelFreezer
|
12
|
-
include Serf::Util::OptionsExtraction
|
13
|
-
|
14
11
|
attr_reader :app
|
15
12
|
attr_reader :freezer
|
16
13
|
|
@@ -18,9 +15,9 @@ module Middleware
|
|
18
15
|
# @param app the app
|
19
16
|
#
|
20
17
|
def initialize(app, *args)
|
21
|
-
extract_options! args
|
18
|
+
opts = Optser.extract_options! args
|
22
19
|
@app = app
|
23
|
-
@freezer = opts :freezer, IceNine
|
20
|
+
@freezer = opts.get :freezer, IceNine
|
24
21
|
end
|
25
22
|
|
26
23
|
##
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'hashie'
|
2
|
-
|
3
|
-
require 'serf/util/options_extraction'
|
2
|
+
require 'optser'
|
4
3
|
|
5
4
|
module Serf
|
6
5
|
module Middleware
|
@@ -9,8 +8,6 @@ module Middleware
|
|
9
8
|
# Middleware to add uuids to the headers of the parcel hash.
|
10
9
|
#
|
11
10
|
class ParcelMasher
|
12
|
-
include Serf::Util::OptionsExtraction
|
13
|
-
|
14
11
|
attr_reader :app
|
15
12
|
attr_reader :masher_class
|
16
13
|
|
@@ -18,9 +15,9 @@ module Middleware
|
|
18
15
|
# @param app the app
|
19
16
|
#
|
20
17
|
def initialize(app, *args)
|
21
|
-
extract_options! args
|
18
|
+
opts = Optser.extract_options! args
|
22
19
|
@app = app
|
23
|
-
@masher_class = opts :masher_class, Hashie::Mash
|
20
|
+
@masher_class = opts.get :masher_class, Hashie::Mash
|
24
21
|
end
|
25
22
|
|
26
23
|
##
|
@@ -1,18 +1,16 @@
|
|
1
|
-
require '
|
1
|
+
require 'optser'
|
2
2
|
|
3
3
|
module Serf
|
4
4
|
module Middleware
|
5
5
|
|
6
6
|
class PolicyChecker
|
7
|
-
include Serf::Util::OptionsExtraction
|
8
|
-
|
9
7
|
attr_reader :app
|
10
8
|
attr_reader :policy_chain
|
11
9
|
|
12
10
|
def initialize(app, *args)
|
13
|
-
extract_options! args
|
11
|
+
opts = Optser.extract_options! args
|
14
12
|
@app = app
|
15
|
-
@policy_chain = opts :policy_chain, []
|
13
|
+
@policy_chain = opts.get :policy_chain, []
|
16
14
|
end
|
17
15
|
|
18
16
|
##
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'optser'
|
2
|
+
|
3
|
+
module Serf
|
4
|
+
module Middleware
|
5
|
+
|
6
|
+
class RequestTimer
|
7
|
+
attr_reader :app
|
8
|
+
attr_reader :timer
|
9
|
+
|
10
|
+
def initialize(app, *args)
|
11
|
+
opts = Optser.extract_options! args
|
12
|
+
@app = app
|
13
|
+
@timer = opts.get :timer, Serf::Middleware::RequestTimer::Timer
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(parcel)
|
17
|
+
t = timer.start
|
18
|
+
response_parcel = app.call parcel
|
19
|
+
response_parcel.headers[:elapsed_time] = t.mark
|
20
|
+
return response_parcel
|
21
|
+
end
|
22
|
+
|
23
|
+
class Timer
|
24
|
+
attr_reader :start_time
|
25
|
+
|
26
|
+
class << self
|
27
|
+
alias_method :start, :new
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@start_time = now
|
32
|
+
end
|
33
|
+
|
34
|
+
def mark
|
35
|
+
(now - @start_time).to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def now
|
39
|
+
Time.now.to_f * 1_000_000
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'hashie'
|
2
|
+
require 'optser'
|
2
3
|
|
3
|
-
require 'serf/util/options_extraction'
|
4
4
|
require 'serf/util/uuidable'
|
5
5
|
|
6
6
|
module Serf
|
@@ -10,8 +10,6 @@ module Middleware
|
|
10
10
|
# Middleware to add uuids to the headers of the parcel hash.
|
11
11
|
#
|
12
12
|
class UuidTagger
|
13
|
-
include Serf::Util::OptionsExtraction
|
14
|
-
|
15
13
|
attr_reader :app
|
16
14
|
attr_reader :uuidable
|
17
15
|
|
@@ -19,9 +17,9 @@ module Middleware
|
|
19
17
|
# @param app the app
|
20
18
|
#
|
21
19
|
def initialize(app, *args)
|
22
|
-
extract_options! args
|
20
|
+
opts = Optser.extract_options! args
|
23
21
|
@app = app
|
24
|
-
@uuidable = opts(:uuidable) { Serf::Util::Uuidable.new }
|
22
|
+
@uuidable = opts.get(:uuidable) { Serf::Util::Uuidable.new }
|
25
23
|
end
|
26
24
|
|
27
25
|
def call(parcel)
|
data/lib/serf/parcel_builder.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'hashie'
|
2
|
-
|
3
|
-
require 'serf/util/options_extraction'
|
2
|
+
require 'optser'
|
4
3
|
|
5
4
|
module Serf
|
6
5
|
|
@@ -8,14 +7,12 @@ module Serf
|
|
8
7
|
# Builds Parcels as Hashie::Mash objects with headers and messages.
|
9
8
|
#
|
10
9
|
class ParcelBuilder
|
11
|
-
include Serf::Util::OptionsExtraction
|
12
|
-
|
13
10
|
attr_reader :mash_class
|
14
11
|
|
15
12
|
def initialize(*args)
|
16
|
-
extract_options! args
|
13
|
+
opts = Optser.extract_options! args
|
17
14
|
|
18
|
-
@mash_class = opts :mash_class, Hashie::Mash
|
15
|
+
@mash_class = opts.get :mash_class, Hashie::Mash
|
19
16
|
end
|
20
17
|
|
21
18
|
def build(headers=nil, message=nil)
|
data/lib/serf/serfer.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'hashie'
|
2
|
+
require 'optser'
|
2
3
|
|
3
4
|
require 'serf/parcel_builder'
|
4
|
-
require 'serf/util/options_extraction'
|
5
5
|
require 'serf/util/uuidable'
|
6
6
|
|
7
7
|
module Serf
|
@@ -10,21 +10,19 @@ module Serf
|
|
10
10
|
# Class to drive the Interactor execution.
|
11
11
|
#
|
12
12
|
class Serfer
|
13
|
-
include Serf::Util::OptionsExtraction
|
14
|
-
|
15
13
|
attr_reader :interactor
|
16
14
|
attr_reader :parcel_builder
|
17
15
|
attr_reader :uuidable
|
18
16
|
|
19
17
|
def initialize(interactor, *args)
|
20
|
-
extract_options! args
|
18
|
+
opts = Optser.extract_options! args
|
21
19
|
|
22
20
|
# How to and when to handle requests
|
23
21
|
@interactor = interactor
|
24
22
|
|
25
23
|
# Tunable knobs
|
26
|
-
@parcel_builder = opts(:parcel_builder) { Serf::ParcelBuilder.new }
|
27
|
-
@uuidable = opts(:uuidable) { Serf::Util::Uuidable.new }
|
24
|
+
@parcel_builder = opts.get(:parcel_builder) { Serf::ParcelBuilder.new }
|
25
|
+
@uuidable = opts.get(:uuidable) { Serf::Util::Uuidable.new }
|
28
26
|
end
|
29
27
|
|
30
28
|
##
|
@@ -35,7 +33,7 @@ module Serf
|
|
35
33
|
message = parcel[:message]
|
36
34
|
|
37
35
|
# 1. Execute interactor
|
38
|
-
|
36
|
+
response_kind, response_message = interactor.call message
|
39
37
|
|
40
38
|
# 2. Create the response headers
|
41
39
|
response_headers = uuidable.create_uuids headers
|
data/lib/serf/util/uuidable.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
require 'base64'
|
2
2
|
require 'hashie'
|
3
|
+
require 'optser'
|
3
4
|
require 'uuidtools'
|
4
5
|
|
5
|
-
require 'serf/util/options_extraction'
|
6
|
-
|
7
6
|
module Serf
|
8
7
|
module Util
|
9
8
|
|
@@ -14,13 +13,11 @@ module Util
|
|
14
13
|
# base64 encoded UUIDs without trailing '='.
|
15
14
|
#
|
16
15
|
class Uuidable
|
17
|
-
include Serf::Util::OptionsExtraction
|
18
|
-
|
19
16
|
attr_reader :uuid_tool
|
20
17
|
|
21
18
|
def initialize(*args)
|
22
|
-
extract_options! args
|
23
|
-
@uuid_tool = opts :uuid_tool, UUIDTools::UUID
|
19
|
+
opts = Optser.extract_options! args
|
20
|
+
@uuid_tool = opts.get :uuid_tool, UUIDTools::UUID
|
24
21
|
end
|
25
22
|
|
26
23
|
##
|
data/lib/serf/version.rb
CHANGED
data/serf.gemspec
CHANGED
data/spec/serf/builder_spec.rb
CHANGED
@@ -11,7 +11,7 @@ describe Serf::Builder do
|
|
11
11
|
}
|
12
12
|
let(:app) {
|
13
13
|
lambda { |parcel|
|
14
|
-
return
|
14
|
+
return response_kind, parcel
|
15
15
|
}
|
16
16
|
}
|
17
17
|
subject {
|
@@ -21,7 +21,7 @@ describe Serf::Builder do
|
|
21
21
|
describe '#to_app' do
|
22
22
|
|
23
23
|
it 'builds a callable app' do
|
24
|
-
subject.to_app.
|
24
|
+
expect(subject.to_app).to respond_to(:call)
|
25
25
|
end
|
26
26
|
|
27
27
|
end
|
@@ -32,9 +32,8 @@ describe Serf::Builder do
|
|
32
32
|
|
33
33
|
it 'runs the app' do
|
34
34
|
response = subject.to_app.call request_parcel
|
35
|
-
|
36
|
-
response.
|
37
|
-
response.headers.kind.should == response_kind
|
35
|
+
expect(response.message).to eq(request_parcel.message)
|
36
|
+
expect(response.headers.kind).to eq(response_kind)
|
38
37
|
end
|
39
38
|
|
40
39
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'serf/loader/loader'
|
4
|
+
|
5
|
+
describe Serf::Loader::Loader do
|
6
|
+
let(:root_library_path) {
|
7
|
+
File.join(File.dirname(__FILE__), '../../..')
|
8
|
+
}
|
9
|
+
|
10
|
+
context '#serfup Serf Map' do
|
11
|
+
let(:random_message) {
|
12
|
+
FactoryGirl.create :random_message
|
13
|
+
}
|
14
|
+
subject {
|
15
|
+
Serf::Loader::Loader.new.serfup(
|
16
|
+
globs: [
|
17
|
+
'example/**/*.serf'
|
18
|
+
],
|
19
|
+
serfs: [
|
20
|
+
'subsystem/requests/create_widget'
|
21
|
+
],
|
22
|
+
base_path: root_library_path,
|
23
|
+
env: {
|
24
|
+
success_message: random_message
|
25
|
+
})
|
26
|
+
}
|
27
|
+
|
28
|
+
it 'loads the Serfs into a frozen Serf Map' do
|
29
|
+
expect(subject.frozen?).to be_true
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'loads our only serf into the map' do
|
33
|
+
expect(subject.size).to eq(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'gives us a proper callable serf' do
|
37
|
+
serf = subject['subsystem/requests/create_widget']
|
38
|
+
expect(subject).to_not be_nil
|
39
|
+
|
40
|
+
results = serf.call({})
|
41
|
+
expect(results).to_not be_nil
|
42
|
+
expect(results.headers.kind).to_not eq('serf/events/caught_error')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns nil on not found parcel kind' do
|
46
|
+
expect(subject[nil]).to be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'passes in a good environment' do
|
50
|
+
serf = subject['subsystem/requests/create_widget']
|
51
|
+
results = serf.call({})
|
52
|
+
expect(results.headers.kind).to eq('subsystem/events/mywidget_created')
|
53
|
+
expect(results.message.success_message).to eq(random_message)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context '#serfup Serf Map with missing Serf' do
|
58
|
+
let(:serfup_config) {
|
59
|
+
Hashie::Mash.new(
|
60
|
+
globs: [],
|
61
|
+
serfs: [
|
62
|
+
'subsystem/requests/create_widget'
|
63
|
+
])
|
64
|
+
}
|
65
|
+
|
66
|
+
it 'raises an error' do
|
67
|
+
expect {
|
68
|
+
Serf::Loader::Loader.new.serfup serfup_config
|
69
|
+
}.to raise_error('Missing Serf: subsystem/requests/create_widget')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'serf/loader/registry'
|
4
|
+
|
5
|
+
describe Serf::Loader::Registry do
|
6
|
+
let(:random_message) {
|
7
|
+
FactoryGirl.create :random_message
|
8
|
+
}
|
9
|
+
|
10
|
+
context '#add' do
|
11
|
+
it 'registers a named block, but does not call it' do
|
12
|
+
uncalled_mock = double 'Uncalled Mock'
|
13
|
+
expect(subject.blocks.size).to eq(0)
|
14
|
+
expect(subject.values.size).to eq(0)
|
15
|
+
subject.add 'component_name' do
|
16
|
+
uncalled_mock
|
17
|
+
end
|
18
|
+
expect(subject.blocks.size).to eq(1)
|
19
|
+
expect(subject.values.size).to eq(0)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context '#[]' do
|
24
|
+
it 'evaluates a block on lookup' do
|
25
|
+
expect(subject.blocks.size).to eq(0)
|
26
|
+
expect(subject.values.size).to eq(0)
|
27
|
+
subject.add 'component_name' do
|
28
|
+
random_message
|
29
|
+
end
|
30
|
+
expect(subject['component_name']).to eq(random_message)
|
31
|
+
expect(subject.blocks.size).to eq(0)
|
32
|
+
expect(subject.values.size).to eq(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns memoized block value' do
|
36
|
+
call_once = double 'Callable'
|
37
|
+
call_once.should_receive(:call).once.and_return(random_message)
|
38
|
+
|
39
|
+
# Make the add to the registry
|
40
|
+
expect(subject.blocks.size).to eq(0)
|
41
|
+
expect(subject.values.size).to eq(0)
|
42
|
+
subject.add 'component_name' do
|
43
|
+
call_once.call
|
44
|
+
end
|
45
|
+
|
46
|
+
# First call
|
47
|
+
expect(subject['component_name']).to eq(random_message)
|
48
|
+
expect(subject.blocks.size).to eq(0)
|
49
|
+
expect(subject.values.size).to eq(1)
|
50
|
+
|
51
|
+
# This should be memoized
|
52
|
+
expect(subject['component_name']).to eq(random_message)
|
53
|
+
expect(subject.blocks.size).to eq(0)
|
54
|
+
expect(subject.values.size).to eq(1)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns nil on not found' do
|
58
|
+
expect(subject[random_message]).to be_nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|