alephant-broker 0.1.0 → 0.1.1
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 +4 -4
- data/alephant-broker.gemspec +1 -0
- data/lib/alephant/broker/call_environment.rb +12 -6
- data/lib/alephant/broker/models/request/post_request.rb +9 -5
- data/lib/alephant/broker/models/request_handler.rb +17 -7
- data/lib/alephant/broker/models/response.rb +0 -1
- data/lib/alephant/broker/models/response/asset_response.rb +58 -5
- data/lib/alephant/broker/models/response_factory.rb +8 -2
- data/lib/alephant/broker/version.rb +1 -1
- data/spec/asset_response_spec.rb +45 -43
- data/spec/batch_response_spec.rb +20 -18
- data/spec/rack_spec.rb +28 -17
- data/spec/spec_helper.rb +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b93740e5628e1841d3f296c5675304678cc0be7
|
4
|
+
data.tar.gz: 9412546f75f2f95a77c3b2cbfa3b53e98a296f9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34c3356dc0bab54c046bf2d8c269a07ea08c60ebfa9077d9f3eadd46a3df6fb48e1dd01d0bab710022607228629f98b6a4b91448153ed125cc38340e7a6e3626
|
7
|
+
data.tar.gz: 9414facbf42866a0eba6e903ec71ba365f0f342c183edb13a8710125c9fba411b08067a6493551bd1fb8223c64f3a5ef58722404fcf796c7faed88fae2ed56bd
|
data/alephant-broker.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module Alephant
|
2
4
|
module Broker
|
3
5
|
class CallEnvironment
|
@@ -9,23 +11,27 @@ module Alephant
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def method
|
12
|
-
|
14
|
+
settings['REQUEST_METHOD']
|
13
15
|
end
|
14
16
|
|
15
17
|
def post?
|
16
|
-
|
18
|
+
settings['REQUEST_METHOD'] == 'POST'
|
17
19
|
end
|
18
20
|
|
19
21
|
def get?
|
20
|
-
|
22
|
+
settings['REQUEST_METHOD'] == 'GET'
|
21
23
|
end
|
22
24
|
|
23
25
|
def query
|
24
|
-
|
26
|
+
settings['QUERY_STRING']
|
25
27
|
end
|
26
28
|
|
27
29
|
def path
|
28
|
-
|
30
|
+
settings['PATH_INFO']
|
31
|
+
end
|
32
|
+
|
33
|
+
def request_type
|
34
|
+
path.split('/')[1]
|
29
35
|
end
|
30
36
|
|
31
37
|
def data
|
@@ -35,7 +41,7 @@ module Alephant
|
|
35
41
|
private
|
36
42
|
|
37
43
|
def rack_input
|
38
|
-
(
|
44
|
+
(settings['rack.input'].read).tap { settings['rack.input'].rewind } # http://rack.rubyforge.org/doc/SPEC.html
|
39
45
|
end
|
40
46
|
|
41
47
|
def parse(json)
|
@@ -3,16 +3,16 @@ require 'alephant/broker/models/request'
|
|
3
3
|
module Alephant
|
4
4
|
module Broker
|
5
5
|
class PostRequest < Request
|
6
|
-
attr_reader :type, :component_id, :options, :content_type
|
6
|
+
attr_reader :type, :renderer_id, :component_id, :options, :content_type
|
7
7
|
|
8
8
|
def initialize
|
9
|
-
@
|
9
|
+
@renderer_id = batch_id
|
10
10
|
@content_type = 'application/json'
|
11
11
|
super(:batch)
|
12
12
|
end
|
13
13
|
|
14
14
|
def components
|
15
|
-
@requested_components ||= components_for
|
15
|
+
@requested_components ||= components_for env.path
|
16
16
|
end
|
17
17
|
|
18
18
|
def set_component(id, options)
|
@@ -22,6 +22,10 @@ module Alephant
|
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
|
+
def env
|
26
|
+
@env ||= RequestStore.store[:env]
|
27
|
+
end
|
28
|
+
|
25
29
|
def components_for(path)
|
26
30
|
request_parts = path.split('/')
|
27
31
|
|
@@ -33,11 +37,11 @@ module Alephant
|
|
33
37
|
end
|
34
38
|
|
35
39
|
def batch_id
|
36
|
-
|
40
|
+
env.data['batch_id']
|
37
41
|
end
|
38
42
|
|
39
43
|
def batched
|
40
|
-
|
44
|
+
env.data['components'].reduce({ :components => [] }) do |obj, component|
|
41
45
|
obj.tap { |o| o[:components].push(component) }
|
42
46
|
end
|
43
47
|
end
|
@@ -7,24 +7,30 @@ module Alephant
|
|
7
7
|
include Logger
|
8
8
|
|
9
9
|
def initialize(config)
|
10
|
-
@
|
11
|
-
@request = RequestFactory.process(request_type)
|
12
|
-
@response_factory = ResponseFactory.new(config)
|
10
|
+
@config = config
|
13
11
|
end
|
14
12
|
|
15
13
|
def process
|
16
14
|
begin
|
17
|
-
|
15
|
+
response_factory.response_from(request)
|
18
16
|
rescue Exception => e
|
19
17
|
logger.info("Broker.requestHandler.process: Exception raised (#{e.message})")
|
20
|
-
|
18
|
+
response_factory.response(500)
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
22
|
private
|
25
23
|
|
24
|
+
def request
|
25
|
+
@request ||= RequestFactory.process(request_type)
|
26
|
+
end
|
27
|
+
|
28
|
+
def response_factory
|
29
|
+
@response_factory ||= ResponseFactory.new(@config)
|
30
|
+
end
|
31
|
+
|
26
32
|
def request_type
|
27
|
-
case
|
33
|
+
case env.request_type
|
28
34
|
when 'components'
|
29
35
|
component_type
|
30
36
|
when 'status'
|
@@ -35,13 +41,17 @@ module Alephant
|
|
35
41
|
end
|
36
42
|
|
37
43
|
def component_type
|
38
|
-
case
|
44
|
+
case env.method
|
39
45
|
when 'POST'
|
40
46
|
:component_batch
|
41
47
|
when 'GET'
|
42
48
|
:component
|
43
49
|
end
|
44
50
|
end
|
51
|
+
|
52
|
+
def env
|
53
|
+
@env ||= RequestStore.store[:env]
|
54
|
+
end
|
45
55
|
end
|
46
56
|
end
|
47
57
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'crimp'
|
1
2
|
require 'alephant/cache'
|
2
3
|
require 'alephant/lookup'
|
3
4
|
require 'alephant/broker/errors/invalid_cache_key'
|
5
|
+
require 'alephant/sequencer'
|
4
6
|
|
5
7
|
module Alephant
|
6
8
|
module Broker
|
@@ -11,15 +13,14 @@ module Alephant
|
|
11
13
|
|
12
14
|
def initialize(request, config)
|
13
15
|
@request = request
|
14
|
-
@
|
15
|
-
@cache = Cache.new(config[:bucket_id], config[:path])
|
16
|
+
@config = config
|
16
17
|
super()
|
17
18
|
end
|
18
19
|
|
19
20
|
def setup
|
20
21
|
begin
|
21
22
|
self.content_type = request.content_type
|
22
|
-
self.content =
|
23
|
+
self.content = cache.get(s3_path)
|
23
24
|
rescue AWS::S3::Errors::NoSuchKey, InvalidCacheKey => e
|
24
25
|
set_error_for(e, 404)
|
25
26
|
rescue Exception => e
|
@@ -29,14 +30,66 @@ module Alephant
|
|
29
30
|
|
30
31
|
private
|
31
32
|
|
33
|
+
def cache
|
34
|
+
@cache ||= Alephant::Cache.new(config[:bucket_id], config[:path])
|
35
|
+
end
|
36
|
+
|
32
37
|
def set_error_for(exception, status)
|
33
38
|
logger.info("Broker.assetResponse.set_error_for: #{status} exception raised (#{exception.message})")
|
34
39
|
self.status = status
|
35
40
|
self.content = exception.message
|
36
41
|
end
|
37
42
|
|
38
|
-
def
|
39
|
-
|
43
|
+
def s3_path
|
44
|
+
lookup.read(id, request.options, version).tap { |cache_id| raise InvalidCacheKey if cache_id.nil? }
|
45
|
+
end
|
46
|
+
|
47
|
+
def lookup
|
48
|
+
@lookup ||= Alephant::Lookup.create(config[:lookup_table_name])
|
49
|
+
end
|
50
|
+
|
51
|
+
def asset?
|
52
|
+
request.type == :asset
|
53
|
+
end
|
54
|
+
|
55
|
+
def key
|
56
|
+
asset? ? component_key : renderer_key
|
57
|
+
end
|
58
|
+
|
59
|
+
def component_key
|
60
|
+
"#{component_id}/#{opts_hash}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def renderer_key
|
64
|
+
"#{renderer_id}/#{opts_hash}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def id
|
68
|
+
asset? ? component_id : renderer_id
|
69
|
+
end
|
70
|
+
|
71
|
+
def component_id
|
72
|
+
request.component_id
|
73
|
+
end
|
74
|
+
|
75
|
+
def renderer_id
|
76
|
+
request.renderer_id
|
77
|
+
end
|
78
|
+
|
79
|
+
def opts_hash
|
80
|
+
@opts_hash ||= Crimp.signature(request.options)
|
81
|
+
end
|
82
|
+
|
83
|
+
def version
|
84
|
+
@version ||= sequencer.get_last_seen
|
85
|
+
end
|
86
|
+
|
87
|
+
def sequencer
|
88
|
+
@sequencer ||= Alephant::Sequencer.create(config[:sequencer_table_name], key)
|
89
|
+
end
|
90
|
+
|
91
|
+
def config
|
92
|
+
@config
|
40
93
|
end
|
41
94
|
end
|
42
95
|
end
|
@@ -13,9 +13,9 @@ module Alephant
|
|
13
13
|
def response_from(request)
|
14
14
|
case request.type
|
15
15
|
when :asset
|
16
|
-
AssetResponse.new(request,
|
16
|
+
AssetResponse.new(request, config)
|
17
17
|
when :batch
|
18
|
-
BatchResponse.new(request,
|
18
|
+
BatchResponse.new(request, config).process
|
19
19
|
when :status
|
20
20
|
response(200)
|
21
21
|
when :notfound
|
@@ -25,6 +25,12 @@ module Alephant
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
private
|
29
|
+
|
30
|
+
def config
|
31
|
+
@config
|
32
|
+
end
|
33
|
+
|
28
34
|
def response(status)
|
29
35
|
Response.new(status)
|
30
36
|
end
|
data/spec/asset_response_spec.rb
CHANGED
@@ -1,73 +1,75 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Alephant::Broker::AssetResponse do
|
4
|
+
subject { Alephant::Broker::AssetResponse }
|
5
|
+
|
4
6
|
describe "#initialize(request, config)" do
|
5
7
|
let(:location) { 'test_location' }
|
8
|
+
|
6
9
|
let(:config) {{
|
7
10
|
:lookup_table_name => 'test_table',
|
8
11
|
:bucket_id => 'test_bucket',
|
9
12
|
:path => 'test_path'
|
10
13
|
}}
|
14
|
+
|
11
15
|
let(:request) { double(
|
12
16
|
"Alephant::Broker::Request",
|
13
17
|
:component_id => 'test',
|
14
18
|
:content_type => 'text/html',
|
19
|
+
:type => :asset,
|
15
20
|
:options => { :variant => 'test_variant' }
|
16
21
|
)
|
17
22
|
}
|
18
23
|
|
19
24
|
before do
|
20
|
-
|
21
|
-
Alephant::Lookup.stub(:create).and_return(@lookup_table)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "Should return the content from a successful cache lookup" do
|
25
|
-
allow(@lookup_table)
|
26
|
-
.to receive(:read)
|
27
|
-
.with(request.options)
|
28
|
-
.and_return(location)
|
29
|
-
|
30
|
-
Alephant::Cache
|
31
|
-
.any_instance
|
32
|
-
.stub(:initialize)
|
33
|
-
|
34
|
-
Alephant::Cache
|
25
|
+
subject
|
35
26
|
.any_instance
|
36
|
-
.stub(:
|
37
|
-
.
|
38
|
-
.and_return('Test cache content')
|
39
|
-
|
40
|
-
instance = Alephant::Broker::AssetResponse.new(request, config)
|
41
|
-
|
42
|
-
expect(instance.content).to eq('Test cache content')
|
43
|
-
expect(instance.status).to eq(200)
|
27
|
+
.stub(:s3_path)
|
28
|
+
.and_return(:foo)
|
44
29
|
end
|
45
30
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
31
|
+
context "successful" do
|
32
|
+
before(:each) do
|
33
|
+
subject
|
34
|
+
.any_instance
|
35
|
+
.stub(:cache)
|
36
|
+
.and_return(double(:get => 'Test'))
|
37
|
+
end
|
51
38
|
|
52
|
-
|
53
|
-
.
|
54
|
-
.stub(:initialize)
|
39
|
+
it "Should return the content from a successful cache lookup" do
|
40
|
+
instance = subject.new(request, config)
|
55
41
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
expect(instance.status).to eq(404)
|
42
|
+
expect(instance.content).to eq('Test')
|
43
|
+
expect(instance.status).to eq(200)
|
44
|
+
end
|
60
45
|
end
|
61
46
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
47
|
+
context "client failure" do
|
48
|
+
before(:each) do
|
49
|
+
subject
|
50
|
+
.any_instance
|
51
|
+
.stub(:cache)
|
52
|
+
.and_raise(Alephant::Broker::InvalidCacheKey)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return a 404 if lookup can't find a valid location" do
|
56
|
+
instance = subject.new(request, config)
|
57
|
+
expect(instance.status).to eq(404)
|
58
|
+
end
|
59
|
+
end
|
69
60
|
|
70
|
-
|
61
|
+
context "server failure" do
|
62
|
+
before(:each) do
|
63
|
+
subject
|
64
|
+
.any_instance
|
65
|
+
.stub(:cache)
|
66
|
+
.and_raise(Exception)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should return a 500 for any other exceptions" do
|
70
|
+
instance = subject.new(request, config)
|
71
|
+
expect(instance.status).to eq(500)
|
72
|
+
end
|
71
73
|
end
|
72
74
|
end
|
73
75
|
end
|
data/spec/batch_response_spec.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Alephant::Broker::BatchResponse do
|
4
|
+
subject { Alephant::Broker::BatchResponse }
|
5
|
+
|
4
6
|
let (:config) {{
|
5
7
|
:lookup_table_name => 'test_table',
|
6
8
|
:bucket_id => 'test_bucket',
|
@@ -15,6 +17,7 @@ describe Alephant::Broker::BatchResponse do
|
|
15
17
|
:content_type => 'application/json',
|
16
18
|
:set_component => nil,
|
17
19
|
:component_id => nil,
|
20
|
+
:renderer_id => nil,
|
18
21
|
:components => {
|
19
22
|
:batch_id => :baz,
|
20
23
|
:components => [
|
@@ -25,31 +28,20 @@ describe Alephant::Broker::BatchResponse do
|
|
25
28
|
}
|
26
29
|
|
27
30
|
before do
|
28
|
-
|
29
|
-
|
30
|
-
Alephant::Lookup
|
31
|
-
.stub(:create)
|
32
|
-
.and_return(@lookup_table)
|
33
|
-
|
34
|
-
Alephant::Cache
|
31
|
+
Alephant::Broker::AssetResponse
|
35
32
|
.any_instance
|
36
33
|
.stub(:initialize)
|
37
|
-
|
38
|
-
Alephant::Cache
|
39
|
-
.any_instance
|
40
|
-
.stub(:get)
|
41
|
-
.and_return('Test response')
|
42
34
|
end
|
43
35
|
|
44
36
|
describe "#process" do
|
45
37
|
context "if a component is unrecognised" do
|
46
38
|
before(:each) do
|
47
|
-
Alephant::
|
39
|
+
Alephant::Broker::AssetResponse
|
48
40
|
.any_instance
|
49
|
-
.stub(:
|
50
|
-
.
|
41
|
+
.stub(:status)
|
42
|
+
.and_return(404)
|
51
43
|
|
52
|
-
instance =
|
44
|
+
instance = subject.new(post_request, config)
|
53
45
|
json = JSON.parse(instance.process.content)
|
54
46
|
@bad_component = json.fetch('components')[1]
|
55
47
|
end
|
@@ -65,7 +57,17 @@ describe Alephant::Broker::BatchResponse do
|
|
65
57
|
|
66
58
|
context "if a component is recognised" do
|
67
59
|
before(:each) do
|
68
|
-
|
60
|
+
Alephant::Broker::AssetResponse
|
61
|
+
.any_instance
|
62
|
+
.stub(:status)
|
63
|
+
.and_return(200)
|
64
|
+
|
65
|
+
Alephant::Broker::AssetResponse
|
66
|
+
.any_instance
|
67
|
+
.stub(:content)
|
68
|
+
.and_return('Test')
|
69
|
+
|
70
|
+
@instance = subject.new(post_request, config)
|
69
71
|
@content = @instance.process.content
|
70
72
|
@json = JSON.parse(@content)
|
71
73
|
end
|
@@ -77,7 +79,7 @@ describe Alephant::Broker::BatchResponse do
|
|
77
79
|
end
|
78
80
|
|
79
81
|
it "set @content to be JSON string containing retrieved components" do
|
80
|
-
compiled_json = '{"batch_id":"baz","components":[{"component":"foo1","options":{"variant":"bar1"},"status":200,"body":"Test
|
82
|
+
compiled_json = '{"batch_id":"baz","components":[{"component":"foo1","options":{"variant":"bar1"},"status":200,"body":"Test"},{"component":"foo2","options":{"variant":"bar2"},"status":200,"body":"Test"}]}'
|
81
83
|
expect(@content).to eq(compiled_json)
|
82
84
|
end
|
83
85
|
end
|
data/spec/rack_spec.rb
CHANGED
@@ -12,11 +12,19 @@ describe 'Broker Rack Application' do
|
|
12
12
|
before do
|
13
13
|
RequestStore.store[:env] = nil
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
Alephant::
|
15
|
+
Alephant::Broker::AssetResponse
|
16
|
+
.any_instance
|
17
|
+
.stub(:initialize)
|
18
|
+
|
19
|
+
Alephant::Broker::AssetResponse
|
20
|
+
.any_instance
|
21
|
+
.stub(:status)
|
22
|
+
.and_return(200)
|
23
|
+
|
24
|
+
Alephant::Broker::AssetResponse
|
25
|
+
.any_instance
|
26
|
+
.stub(:content)
|
27
|
+
.and_return('Test')
|
20
28
|
end
|
21
29
|
|
22
30
|
def app
|
@@ -40,41 +48,44 @@ describe 'Broker Rack Application' do
|
|
40
48
|
end
|
41
49
|
|
42
50
|
it "Test asset data is returned" do
|
43
|
-
allow(@lookup_table).to receive(:read).and_return('some_location')
|
44
|
-
|
45
51
|
get '/components/test_component'
|
52
|
+
|
46
53
|
expect(last_response).to be_ok
|
47
|
-
expect(last_response.body).to eq('Test
|
54
|
+
expect(last_response.body).to eq('Test')
|
48
55
|
end
|
49
56
|
|
50
57
|
it "Tests query string parameters are passed correctly to lookup" do
|
51
|
-
variant = {:variant => 'test_variant'}
|
52
|
-
allow(@lookup_table).to receive(:read).with(variant).and_return('some_location')
|
53
|
-
|
54
58
|
get '/components/test_component?variant=test_variant'
|
59
|
+
|
55
60
|
expect(last_response).to be_ok
|
56
|
-
expect(last_response.body).to eq('Test
|
61
|
+
expect(last_response.body).to eq('Test')
|
57
62
|
end
|
58
63
|
|
59
64
|
it "Tests 404 when lookup doesn't return a valid location" do
|
60
|
-
|
65
|
+
Alephant::Broker::AssetResponse
|
66
|
+
.any_instance
|
67
|
+
.stub(:status)
|
68
|
+
.and_return(404)
|
61
69
|
|
62
70
|
get '/components/test_component'
|
71
|
+
|
63
72
|
expect(last_response.status).to eq(404)
|
64
73
|
end
|
65
74
|
|
66
75
|
it "Tests 500 when exception is raised in application" do
|
67
|
-
|
76
|
+
Alephant::Broker::AssetResponse
|
77
|
+
.any_instance
|
78
|
+
.stub(:status)
|
79
|
+
.and_return(500)
|
68
80
|
|
69
81
|
get '/components/test_component'
|
82
|
+
|
70
83
|
expect(last_response.status).to eq(500)
|
71
84
|
end
|
72
85
|
|
73
86
|
it "Test batch asset data is returned" do
|
74
|
-
allow(@lookup_table).to receive(:read).and_return('some_location')
|
75
|
-
|
76
87
|
json = '{"batch_id":"baz","components":[{"component":"ni_council_results_table"},{"component":"ni_council_results_table"}]}'
|
77
|
-
compiled_json = '{"batch_id":"baz","components":[{"component":"ni_council_results_table","status":200,"body":"Test
|
88
|
+
compiled_json = '{"batch_id":"baz","components":[{"component":"ni_council_results_table","status":200,"body":"Test"},{"component":"ni_council_results_table","status":200,"body":"Test"}]}'
|
78
89
|
|
79
90
|
post '/components/batch', json, "CONTENT_TYPE" => "application/json"
|
80
91
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alephant-broker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Jack
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -206,6 +206,20 @@ dependencies:
|
|
206
206
|
version: '0'
|
207
207
|
prerelease: false
|
208
208
|
type: :runtime
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: alephant-sequencer
|
211
|
+
version_requirements: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - '>='
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
requirement: !ruby/object:Gem::Requirement
|
217
|
+
requirements:
|
218
|
+
- - '>='
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: '0'
|
221
|
+
prerelease: false
|
222
|
+
type: :runtime
|
209
223
|
description: Brokers requests for alephant components
|
210
224
|
email:
|
211
225
|
- stevenmajack@gmail.com
|