smarts_api 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +46 -0
- data/LICENSE +22 -0
- data/README.md +7 -0
- data/Rakefile +2 -0
- data/lib/smarts_api/error.rb +3 -0
- data/lib/smarts_api/message/connect_message.rb +45 -0
- data/lib/smarts_api/message/disconnect_message.rb +39 -0
- data/lib/smarts_api/message/evaluate_message.rb +51 -0
- data/lib/smarts_api/message.rb +81 -0
- data/lib/smarts_api/version.rb +5 -0
- data/lib/smarts_api.rb +17 -0
- data/smarts_api.gemspec +24 -0
- data/spec/smarts_api/message/connect_message_spec.rb +54 -0
- data/spec/smarts_api/message/disconnect_message_spec.rb +49 -0
- data/spec/smarts_api/message/evaluate_message_spec.rb +86 -0
- data/spec/smarts_api/message_spec.rb +80 -0
- data/spec/smarts_api_spec.rb +58 -0
- data/spec/spec_helper.rb +3 -0
- metadata +151 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
smarts_api (0.0.1)
|
5
|
+
active_support
|
6
|
+
typhoeus
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
active_support (3.0.0)
|
12
|
+
activesupport (= 3.0.0)
|
13
|
+
activesupport (3.0.0)
|
14
|
+
addressable (2.3.5)
|
15
|
+
crack (0.4.1)
|
16
|
+
safe_yaml (~> 0.9.0)
|
17
|
+
diff-lcs (1.2.4)
|
18
|
+
ethon (0.6.1)
|
19
|
+
ffi (>= 1.3.0)
|
20
|
+
mime-types (~> 1.18)
|
21
|
+
ffi (1.9.0)
|
22
|
+
mime-types (1.25)
|
23
|
+
rspec (2.14.1)
|
24
|
+
rspec-core (~> 2.14.0)
|
25
|
+
rspec-expectations (~> 2.14.0)
|
26
|
+
rspec-mocks (~> 2.14.0)
|
27
|
+
rspec-core (2.14.5)
|
28
|
+
rspec-expectations (2.14.2)
|
29
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
30
|
+
rspec-mocks (2.14.3)
|
31
|
+
safe_yaml (0.9.5)
|
32
|
+
timecop (0.6.3)
|
33
|
+
typhoeus (0.6.5)
|
34
|
+
ethon (~> 0.6.1)
|
35
|
+
webmock (1.13.0)
|
36
|
+
addressable (>= 2.2.7)
|
37
|
+
crack (>= 0.3.2)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
rspec (~> 2.14.1)
|
44
|
+
smarts_api!
|
45
|
+
timecop
|
46
|
+
webmock
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Steve Mitchell
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
class SmartsApi::ConnectMessage < SmartsApi::Message
|
2
|
+
|
3
|
+
def send
|
4
|
+
logger.info "Connecting to #{uri}" if logger.respond_to?(:info)
|
5
|
+
response = Typhoeus::Request.post(uri,
|
6
|
+
:method => method,
|
7
|
+
:headers => {:Accept => "text/json"},
|
8
|
+
:body => make_form(request_params)
|
9
|
+
)
|
10
|
+
raise SmartsApi::Error, "Service connection failed. Recieved empty reply" if response.nil? || response.body.blank?
|
11
|
+
reply = JSON.parse(response.body)
|
12
|
+
|
13
|
+
raise SmartsApi::Error, "Connection failed. Received malformed response." unless reply["Header"] && reply["Header"]["SessionId"]
|
14
|
+
|
15
|
+
session = reply["Header"]["SessionId"]
|
16
|
+
raise SmartsApi::Error, "Connection failed. Did not receive session ID" if session == "00000000-0000-0000-0000-000000000000"
|
17
|
+
|
18
|
+
return session
|
19
|
+
end
|
20
|
+
|
21
|
+
def request_document
|
22
|
+
{:OperationId =>1 , :Header => {:DeploymentId => project_id}}.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
def request_params
|
26
|
+
params = {
|
27
|
+
:appId => app_id,
|
28
|
+
:pwd => pwd,
|
29
|
+
:reqData => request_document,
|
30
|
+
:reqTime => self.timestamp,
|
31
|
+
:userId => user_id,
|
32
|
+
:workspaceId => workspace_id
|
33
|
+
}
|
34
|
+
signature = {
|
35
|
+
:sign => sign_request(params)
|
36
|
+
}
|
37
|
+
return params.merge(signature)
|
38
|
+
end
|
39
|
+
|
40
|
+
def uri
|
41
|
+
"#{base_uri}connect"
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class SmartsApi::DisconnectMessage < SmartsApi::Message
|
2
|
+
|
3
|
+
|
4
|
+
def send(session)
|
5
|
+
body = make_form(request_params(session))
|
6
|
+
logger.info "Disconnecting" if logger.respond_to?(:info)
|
7
|
+
response = Typhoeus::Request.post(uri,
|
8
|
+
:method => method,
|
9
|
+
:headers => {:Accept => "text/json"},
|
10
|
+
:body => body
|
11
|
+
)
|
12
|
+
raise SmartsApi::Error, "Service connection failed. Recieved empty reply" if response.nil? || response.body.blank?
|
13
|
+
reply = JSON.parse(response.body)
|
14
|
+
|
15
|
+
raise SmartsApi::Error, "Connection failed. Received malformed response." unless reply["Header"] && reply["Header"]["SessionId"]
|
16
|
+
|
17
|
+
session = reply["Header"]["SessionId"]
|
18
|
+
raise SmartsApi::Error, "Connection failed. Did not receive session ID" if session == "00000000-0000-0000-0000-000000000000"
|
19
|
+
return session
|
20
|
+
end
|
21
|
+
|
22
|
+
def request_params(session)
|
23
|
+
params = {
|
24
|
+
:appId => app_id,
|
25
|
+
:reqTime => timestamp,
|
26
|
+
:session => session
|
27
|
+
}
|
28
|
+
signature = {
|
29
|
+
:sign => sign_request(params)
|
30
|
+
}
|
31
|
+
return params.merge(signature)
|
32
|
+
end
|
33
|
+
|
34
|
+
def uri
|
35
|
+
"#{base_uri}disconnect"
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class SmartsApi::EvaluateMessage < SmartsApi::Message
|
2
|
+
|
3
|
+
def send(session, member, decision)
|
4
|
+
body = make_form(request_params(session, member, decision))
|
5
|
+
logger.info "Evaluating" if logger.respond_to?(:info)
|
6
|
+
response = Typhoeus::Request.post(uri,
|
7
|
+
:method => method,
|
8
|
+
:headers => {:Accept => "text/json"},
|
9
|
+
:body => body
|
10
|
+
)
|
11
|
+
raise SmartsApi::Error, "Rules Evaluation failed failed. Recieved empty reply" if response.nil? || response.body.blank?
|
12
|
+
reply = JSON.parse(response.body)
|
13
|
+
|
14
|
+
raise SmartsApi::Error, "Rules Evaluation failed failed. Received malformed response." unless reply["Header"] && ["Body"]
|
15
|
+
|
16
|
+
body = reply["Body"]
|
17
|
+
|
18
|
+
if body.blank?
|
19
|
+
logger.info "Rules Engine Evaluation failed. \n\n #{body} \n\n #{response.body}" if logger.respond_to?(:info)
|
20
|
+
|
21
|
+
raise SmartsApi::Error, "Rules Evaluation failed. Returned JSON is blank."
|
22
|
+
end
|
23
|
+
|
24
|
+
logger.info "Updating issues" if logger.respond_to?(:info)
|
25
|
+
member.process_smarts_response body
|
26
|
+
return body
|
27
|
+
end
|
28
|
+
|
29
|
+
def request_params(session, member, decision)
|
30
|
+
params = {
|
31
|
+
:appId => app_id,
|
32
|
+
:reqData => request_document(session, member, decision),
|
33
|
+
:reqTime => timestamp,
|
34
|
+
:session => session
|
35
|
+
}
|
36
|
+
signature = {
|
37
|
+
:sign => sign_request(params)
|
38
|
+
}
|
39
|
+
return params.merge(signature)
|
40
|
+
end
|
41
|
+
|
42
|
+
def request_document(session, member, decision)
|
43
|
+
doc = {:OperationId =>1 , :Header => {:SessionId => session, :DecisionId => decision}, :Body => {:Documents => []}}
|
44
|
+
doc[:Body][:Documents] = member.smarts_document
|
45
|
+
return doc.to_json
|
46
|
+
end
|
47
|
+
|
48
|
+
def uri
|
49
|
+
"#{base_uri}evaluate"
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'typhoeus'
|
2
|
+
require 'json'
|
3
|
+
require 'active_support/core_ext/class'
|
4
|
+
require 'active_support/core_ext/array'
|
5
|
+
include ERB::Util
|
6
|
+
require 'openssl'
|
7
|
+
require 'base64'
|
8
|
+
|
9
|
+
class SmartsApi::Message
|
10
|
+
attr_reader :logger
|
11
|
+
cattr_accessor :user_id, :pwd, :app_id, :workspace_id, :access_key, :base_uri, :project_id
|
12
|
+
|
13
|
+
|
14
|
+
def initialize(logger=nil)
|
15
|
+
@logger = logger
|
16
|
+
end
|
17
|
+
|
18
|
+
def method
|
19
|
+
:post
|
20
|
+
end
|
21
|
+
|
22
|
+
def uri
|
23
|
+
base_uri
|
24
|
+
end
|
25
|
+
|
26
|
+
def sign_request(params)
|
27
|
+
#Below you will find the reverse-engineered ruby implementation of Sparkling Logic's security signing algorithm.
|
28
|
+
#this was translated from a javascript library on their documentation site, then
|
29
|
+
|
30
|
+
#The params object include the following parameters, in this order: AppId, pwd, reqData, reqTime, userID, and workspaceID.
|
31
|
+
#naming of the parameters is significant, and case-sensitive.
|
32
|
+
|
33
|
+
#combine the parameters into a long encoded string (again, order of elements is critical)
|
34
|
+
encoded_parts = []
|
35
|
+
http = URI.parse(uri)
|
36
|
+
encoded_parts[0] = method.to_s.upcase
|
37
|
+
encoded_parts[1] = http.host
|
38
|
+
encoded_parts[2] = http.request_uri
|
39
|
+
encoded_parts[3] = encode_hash(params)
|
40
|
+
|
41
|
+
encoded = encoded_parts.join("\n") #Join parts with newline character
|
42
|
+
|
43
|
+
#5 Digest the encode string with SHA256, using the pre-shared AccessKey as the digest key.
|
44
|
+
digest = OpenSSL::Digest::Digest.new('sha256')
|
45
|
+
hash = OpenSSL::HMAC.hexdigest(digest, access_key, encoded)
|
46
|
+
|
47
|
+
#6 OpenSSL::Digest correctly translates the Hash to a string of bytes. Sparkling Logic's algorithm ...unexpectedle converts the hex value to the corresponding ascii code.
|
48
|
+
#So we need to iterate each pair in our byte string and convert to ascii. this is a little ugly, but necessary
|
49
|
+
#7 AND THEN we encode that string to base64. Not sure why, exactly...
|
50
|
+
signature = Base64.encode64(hex_string_to_ascii(hash))
|
51
|
+
#8 re-URL_encode the string and remove line-endings. Again, for absolutely no logical reason. I think the javascript version did this automatically.
|
52
|
+
signature = url_encode(signature)
|
53
|
+
signature = signature.gsub("%0A", "" )
|
54
|
+
return signature
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def hex_string_to_ascii hex_str
|
60
|
+
#we need to iterate our hex-string and convert each pair to a hex-number. Then evaluate that as ascii code and replace with the corresponding ascii character.
|
61
|
+
ascii_str = ''
|
62
|
+
hex_str.split('').in_groups_of(2){|c| ascii_str << (c[0]+c[1]).hex.chr }
|
63
|
+
ascii_str
|
64
|
+
end
|
65
|
+
|
66
|
+
def timestamp
|
67
|
+
Time.now.utc.iso8601.to_s # => "2012-06-21T18:15:09Z"
|
68
|
+
end
|
69
|
+
|
70
|
+
def encode_hash(hash)
|
71
|
+
new = []
|
72
|
+
hash.each do |k,v|
|
73
|
+
new << k.to_s+"="+url_encode(v)
|
74
|
+
end
|
75
|
+
return new.join("&")
|
76
|
+
end
|
77
|
+
|
78
|
+
def make_form(request_params)
|
79
|
+
request_params.map{|k,v| "#{k}=#{v}"}.join("&")
|
80
|
+
end
|
81
|
+
end
|
data/lib/smarts_api.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
module SmartsApi
|
3
|
+
Dir[File.expand_path('../../lib/smarts_api/*.rb', __FILE__)].each {|f| require f}
|
4
|
+
Dir[File.expand_path('../../lib/smarts_api/*/*.rb', __FILE__)].each {|f| require f}
|
5
|
+
|
6
|
+
def self.evaluate(decision, obj, logger = nil)
|
7
|
+
raise SmartsApi::Error.new("Object to be evaluated must define a method 'smarts_document'") unless obj.respond_to?(:smarts_document)
|
8
|
+
logger.info "processing request for #{obj}" if logger.respond_to?(:info)
|
9
|
+
|
10
|
+
session = SmartsApi::ConnectMessage.new(logger).send
|
11
|
+
response = SmartsApi::EvaluateMessage.new(logger).
|
12
|
+
send(session, obj, decision)
|
13
|
+
|
14
|
+
#SmartsApi::DisconnectMessage.new(logger).disconnect(session)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/smarts_api.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/smarts_api/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Steve Mitchell"]
|
6
|
+
gem.email = ["theSteveMitchell@gmail.com"]
|
7
|
+
gem.description = "smarts_api-#{SmartsApi::Version::STRING}"
|
8
|
+
gem.summary = "api gem for Sparkling Logic's SMARTS business logic platform"
|
9
|
+
gem.homepage = "http://github.com/theSteveMitchell/smarts_api"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "smarts_api"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = SmartsApi::Version::STRING
|
17
|
+
|
18
|
+
gem.add_dependency('typhoeus')
|
19
|
+
gem.add_dependency('activesupport')
|
20
|
+
|
21
|
+
gem.add_development_dependency('rspec', '~> 2.14.1')
|
22
|
+
gem.add_development_dependency('webmock')
|
23
|
+
gem.add_development_dependency('timecop')
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmartsApi::ConnectMessage do
|
4
|
+
before (:all) do
|
5
|
+
SmartsApi::Message.base_uri = "http://smarts.dev.thismashine.com/"
|
6
|
+
SmartsApi::Message.access_key = "sshhhh...Secret!"
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should return session ID if successful' do
|
10
|
+
|
11
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}connect")
|
12
|
+
.to_return(:status => 200, :body => "{\"Header\":{\"SessionId\":\"487d2c44-43fe-44d3-988f-ea462af03169\"},\"Body\":null,\"ErrorInfo\":null,\"Metrics\":null,\"Success\":true,\"OperationException\":null}")
|
13
|
+
|
14
|
+
|
15
|
+
SmartsApi::ConnectMessage.new().send.should == "487d2c44-43fe-44d3-988f-ea462af03169"
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should throw an error if the connection returns an error' do
|
20
|
+
|
21
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}connect")
|
22
|
+
.to_return(:status => 200, :body => "{\"OperationId\":0,\"Header\":{\"SessionId\":\"00000000-0000-0000-0000-000000000000\",\"TransactionTime\":\"2012-06-22T21:02:16.642625Z\",\"Workspace\":null,\"DeploymentId\":null,\"DecisionId\":null},\"Body\":null,\"ErrorInfo\":{\"ErrorCode\":\"ServerException\",\"ErrorMessage\":\"Exception during connection\",\"Details\":[\"Invalid API access\"]},\"Metrics\":null,\"Success\":false,\"OperationException\":{\"IsRestException\":true,\"ErrorType\":\"DocApiAccessDeniedException\",\"CompleteStackTrace\":\"Type: DocApiAccessDeniedException\\r\\nMessage: Invalid API access\\r\\nStack Trace:\\r\\n at Splog.Rest.Base.DocRestHttpHandler.VerifyHmacSignature(String method, IEnumerable`1 keys, String signature, String[] paramaters)\\r\\n at Splog.Rest.Decisions.DocRestDecisionService.Connect(String appId, String reqTime, String userId, String pwd, String workspaceId, String reqData, String sign)\\r\\n\\r\\n\",\"ExtraInfo\":null,\"Message\":\"[DecisionServer] Exception connecting to the decision server for session 72950db0-9639-477b-b824-b82ad5122b56\",\"Data\":{}}}")
|
23
|
+
|
24
|
+
expect{SmartsApi::ConnectMessage.new().send}.to raise_error(SmartsApi::Error)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should throw an error if the returned sessionID is empty' do
|
29
|
+
|
30
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}connect")
|
31
|
+
.to_return(:status => 200, :body => "{\"OperationId\":0,\"Header\":{\"SessionId\":\"00000000-0000-0000-0000-000000000000\",\"TransactionTime\":\"2012-06-22T21:02:16.642625Z\",\"Workspace\":null,\"DeploymentId\":null,\"DecisionId\":null},\"Body\":null,\"ErrorInfo\":{\"ErrorCode\":\"ServerException\",\"ErrorMessage\":\"Exception during connection\",\"Details\":[\"Invalid API access\"]},\"Metrics\":null,\"Success\":false,\"OperationException\":{\"IsRestException\":true,\"ErrorType\":\"DocApiAccessDeniedException\",\"CompleteStackTrace\":\"Type: DocApiAccessDeniedException\\r\\nMessage: Invalid API access\\r\\nStack Trace:\\r\\n at Splog.Rest.Base.DocRestHttpHandler.VerifyHmacSignature(String method, IEnumerable`1 keys, String signature, String[] paramaters)\\r\\n at Splog.Rest.Decisions.DocRestDecisionService.Connect(String appId, String reqTime, String userId, String pwd, String workspaceId, String reqData, String sign)\\r\\n\\r\\n\",\"ExtraInfo\":null,\"Message\":\"[DecisionServer] Exception connecting to the decision server for session 72950db0-9639-477b-b824-b82ad5122b56\",\"Data\":{}}}")
|
32
|
+
|
33
|
+
expect{SmartsApi::ConnectMessage.new().send}.to raise_error(SmartsApi::Error)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should throw an error if no body is returned' do
|
38
|
+
|
39
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}connect")
|
40
|
+
.to_return(:status => 200)
|
41
|
+
expect{SmartsApi::ConnectMessage.new().send}.to raise_error(SmartsApi::Error)
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should throw an error if status code is bad' do
|
46
|
+
|
47
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}connect")
|
48
|
+
.to_return(:status => 500)
|
49
|
+
expect{SmartsApi::ConnectMessage.new().send}.to raise_error(SmartsApi::Error)
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe SmartsApi::DisconnectMessage do
|
5
|
+
it 'should return session ID if successful' do
|
6
|
+
|
7
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}disconnect")
|
8
|
+
.to_return(:status => 200, :body => "{\"Header\":{\"SessionId\":\"487d2c44-43fe-44d3-988f-ea462af03169\"},\"Body\":null,\"ErrorInfo\":null,\"Metrics\":null,\"Success\":true,\"OperationException\":null}")
|
9
|
+
|
10
|
+
|
11
|
+
SmartsApi::DisconnectMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169").should == "487d2c44-43fe-44d3-988f-ea462af03169"
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should throw an error if the connection returns an error' do
|
16
|
+
|
17
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}disconnect")
|
18
|
+
.to_return(:status => 200, :body => "{\"OperationId\":0,\"Header\":{\"SessionId\":\"00000000-0000-0000-0000-000000000000\",\"TransactionTime\":\"2012-06-22T21:02:16.642625Z\",\"Workspace\":null,\"DeploymentId\":null,\"DecisionId\":null},\"Body\":null,\"ErrorInfo\":{\"ErrorCode\":\"ServerException\",\"ErrorMessage\":\"Exception during connection\",\"Details\":[\"Invalid API access\"]},\"Metrics\":null,\"Success\":false,\"OperationException\":{\"IsRestException\":true,\"ErrorType\":\"DocApiAccessDeniedException\",\"CompleteStackTrace\":\"Type: DocApiAccessDeniedException\\r\\nMessage: Invalid API access\\r\\nStack Trace:\\r\\n at Splog.Rest.Base.DocRestHttpHandler.VerifyHmacSignature(String method, IEnumerable`1 keys, String signature, String[] paramaters)\\r\\n at Splog.Rest.Decisions.DocRestDecisionService.Connect(String appId, String reqTime, String userId, String pwd, String workspaceId, String reqData, String sign)\\r\\n\\r\\n\",\"ExtraInfo\":null,\"Message\":\"[DecisionServer] Exception connecting to the decision server for session 72950db0-9639-477b-b824-b82ad5122b56\",\"Data\":{}}}")
|
19
|
+
|
20
|
+
expect{SmartsApi::DisconnectMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169")}.to raise_error(SmartsApi::Error)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should throw an error if the returned sessionID is empty returns an error' do
|
25
|
+
|
26
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}disconnect")
|
27
|
+
.to_return(:status => 200, :body => "{\"OperationId\":0,\"Header\":{\"SessionId\":\"00000000-0000-0000-0000-000000000000\",\"TransactionTime\":\"2012-06-22T21:02:16.642625Z\",\"Workspace\":null,\"DeploymentId\":null,\"DecisionId\":null},\"Body\":null,\"ErrorInfo\":{\"ErrorCode\":\"ServerException\",\"ErrorMessage\":\"Exception during connection\",\"Details\":[\"Invalid API access\"]},\"Metrics\":null,\"Success\":false,\"OperationException\":{\"IsRestException\":true,\"ErrorType\":\"DocApiAccessDeniedException\",\"CompleteStackTrace\":\"Type: DocApiAccessDeniedException\\r\\nMessage: Invalid API access\\r\\nStack Trace:\\r\\n at Splog.Rest.Base.DocRestHttpHandler.VerifyHmacSignature(String method, IEnumerable`1 keys, String signature, String[] paramaters)\\r\\n at Splog.Rest.Decisions.DocRestDecisionService.Connect(String appId, String reqTime, String userId, String pwd, String workspaceId, String reqData, String sign)\\r\\n\\r\\n\",\"ExtraInfo\":null,\"Message\":\"[DecisionServer] Exception connecting to the decision server for session 72950db0-9639-477b-b824-b82ad5122b56\",\"Data\":{}}}")
|
28
|
+
|
29
|
+
expect{SmartsApi::DisconnectMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169")}.to raise_error(SmartsApi::Error)
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should throw an error if no body is returned' do
|
34
|
+
|
35
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}disconnect")
|
36
|
+
.to_return(:status => 200)
|
37
|
+
expect{SmartsApi::DisconnectMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169")}.to raise_error(SmartsApi::Error)
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should throw an error if status code is bad' do
|
42
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}disconnect")
|
43
|
+
.to_return(:status => 500)
|
44
|
+
expect{SmartsApi::DisconnectMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169")}.to raise_error(SmartsApi::Error)
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmartsApi::EvaluateMessage do
|
4
|
+
|
5
|
+
before (:all) do
|
6
|
+
SmartsApi::Message.base_uri = "http://smarts.dev.thismashine.com/"
|
7
|
+
SmartsApi::Message.access_key = "sshhhh...Secret!"
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:eval_class) {
|
11
|
+
Class.new() do
|
12
|
+
|
13
|
+
def smarts_document
|
14
|
+
"123"
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_smarts_response(body)
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
}
|
22
|
+
|
23
|
+
let(:eval_object) {
|
24
|
+
eval_class.new()
|
25
|
+
}
|
26
|
+
|
27
|
+
it 'should return session ID if successful' do
|
28
|
+
|
29
|
+
body = "{\"OperationId\":1,\"Header\":{\"SessionId\":\"e3e2b012-e9b6-45e7-a96a-a009ebf0a07a\"},\"Body\":{\"Documents\":[{\"identification\":{\"actor_group\":\"root\",\"actor_id\":3,\"gender\":\"Male\",\"birth_date\":\"1984-12-08T06:00:00Z\"},\"historical_properties\":[{\"weight\":\"150\"}]}]},\"ErrorInfo\":null,\"Metrics\":null,\"Success\":true,\"OperationException\":null}"
|
30
|
+
|
31
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}evaluate")
|
32
|
+
.to_return(:status => 200, :body => body)
|
33
|
+
SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169", eval_object, "Issues Analysis Decision").should == JSON.parse(body)["Body"]
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should throw an error if the connection returns an error' do
|
38
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}evaluate")
|
39
|
+
.to_return(:status => 200, :body => "{\"OperationId\":0,\"Header\":{\"SessionId\":\"00000000-0000-0000-0000-000000000000\",\"TransactionTime\":\"2012-06-22T21:02:16.642625Z\",\"Workspace\":null,\"DeploymentId\":null,\"DecisionId\":null},\"Body\":null,\"ErrorInfo\":{\"ErrorCode\":\"ServerException\",\"ErrorMessage\":\"Exception during connection\",\"Details\":[\"Invalid API access\"]},\"Metrics\":null,\"Success\":false,\"OperationException\":{\"IsRestException\":true,\"ErrorType\":\"DocApiAccessDeniedException\",\"CompleteStackTrace\":\"Type: DocApiAccessDeniedException\\r\\nMessage: Invalid API access\\r\\nStack Trace:\\r\\n at Splog.Rest.Base.DocRestHttpHandler.VerifyHmacSignature(String method, IEnumerable`1 keys, String signature, String[] paramaters)\\r\\n at Splog.Rest.Decisions.DocRestDecisionService.Connect(String appId, String reqTime, String userId, String pwd, String workspaceId, String reqData, String sign)\\r\\n\\r\\n\",\"ExtraInfo\":null,\"Message\":\"[DecisionServer] Exception connecting to the decision server for session 72950db0-9639-477b-b824-b82ad5122b56\",\"Data\":{}}}")
|
40
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",eval_object, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should throw an error if the returned sessionID is empty returns an error' do
|
45
|
+
|
46
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}evaluate")
|
47
|
+
.to_return(:status => 200, :body => "{\"OperationId\":0,\"Header\":{\"SessionId\":\"00000000-0000-0000-0000-000000000000\",\"TransactionTime\":\"2012-06-22T21:02:16.642625Z\",\"Workspace\":null,\"DeploymentId\":null,\"DecisionId\":null},\"Body\":null,\"ErrorInfo\":{\"ErrorCode\":\"ServerException\",\"ErrorMessage\":\"Exception during connection\",\"Details\":[\"Invalid API access\"]},\"Metrics\":null,\"Success\":false,\"OperationException\":{\"IsRestException\":true,\"ErrorType\":\"DocApiAccessDeniedException\",\"CompleteStackTrace\":\"Type: DocApiAccessDeniedException\\r\\nMessage: Invalid API access\\r\\nStack Trace:\\r\\n at Splog.Rest.Base.DocRestHttpHandler.VerifyHmacSignature(String method, IEnumerable`1 keys, String signature, String[] paramaters)\\r\\n at Splog.Rest.Decisions.DocRestDecisionService.Connect(String appId, String reqTime, String userId, String pwd, String workspaceId, String reqData, String sign)\\r\\n\\r\\n\",\"ExtraInfo\":null,\"Message\":\"[DecisionServer] Exception connecting to the decision server for session 72950db0-9639-477b-b824-b82ad5122b56\",\"Data\":{}}}")
|
48
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",eval_object, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should throw an error if no body is returned' do
|
53
|
+
|
54
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}evaluate")
|
55
|
+
.to_return(:status => 200)
|
56
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",eval_object, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should throw an error if status code is bad' do
|
61
|
+
|
62
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}evaluate")
|
63
|
+
.to_return(:status => 500)
|
64
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",eval_object, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should call the document method on the member object' do
|
69
|
+
eval_object.should_receive(:smarts_document)
|
70
|
+
body = "{\"OperationId\":1,\"Header\":{\"SessionId\":\"e3e2b012-e9b6-45e7-a96a-a009ebf0a07a\"},\"Body\":{\"Documents\":[{\"identification\":{\"actor_group\":\"root\",\"actor_id\":3,\"gender\":\"Male\",\"birth_date\":\"1984-12-08T06:00:00Z\"},\"historical_properties\":[{\"weight\":\"150\"}]}]},\"ErrorInfo\":null,\"Metrics\":null,\"Success\":true,\"OperationException\":null}"
|
71
|
+
|
72
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}evaluate")
|
73
|
+
.to_return(:status => 200, :body => body)
|
74
|
+
SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169", eval_object, "Issues Analysis Decision").should == JSON.parse(body)["Body"]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should pass the returned message body to the evaluated object for processing" do
|
78
|
+
|
79
|
+
body = "{\"OperationId\":1,\"Header\":{\"SessionId\":\"e3e2b012-e9b6-45e7-a96a-a009ebf0a07a\"},\"Body\":{\"Documents\":[{\"identification\":{\"actor_group\":\"root\",\"actor_id\":3,\"gender\":\"Male\",\"birth_date\":\"1984-12-08T06:00:00Z\"},\"historical_properties\":[{\"weight\":\"150\"}]}]},\"ErrorInfo\":null,\"Metrics\":null,\"Success\":true,\"OperationException\":null}"
|
80
|
+
eval_object.should_receive(:process_smarts_response).with(JSON.parse(body)["Body"])
|
81
|
+
stub_http_request(:post, "#{SmartsApi::Message.base_uri}evaluate")
|
82
|
+
.to_return(:status => 200, :body => body)
|
83
|
+
SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169", eval_object, "Issues Analysis Decision").should == JSON.parse(body)["Body"]
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmartsApi::Message do
|
4
|
+
|
5
|
+
before (:all) do
|
6
|
+
SmartsApi::Message.base_uri = "http://www.versign.com/request/doSomething.aspc"
|
7
|
+
SmartsApi::Message.access_key = "secretKey"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'initializer' do
|
11
|
+
it "should keep the logger for logging purposes" do
|
12
|
+
logger = Logger.new(STDOUT)
|
13
|
+
message = SmartsApi::Message.new(logger)
|
14
|
+
|
15
|
+
message.logger.should == logger
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'timestamp' do
|
21
|
+
it "should be formatted correctly" do
|
22
|
+
Timecop.freeze(Time.utc(2012, 6, 21, 12, 34, 56))
|
23
|
+
SmartsApi::Message.new().timestamp.should == "2012-06-21T12:34:56Z"
|
24
|
+
Timecop.return
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'hash encoding' do
|
30
|
+
it 'should convert a hash into a url_encoded string' do
|
31
|
+
hash = {:a => "123", :b => "aber=/3sd8:&++\\", :c => "hellpo"}
|
32
|
+
|
33
|
+
SmartsApi::Message.new().encode_hash(hash).should == "a=123&b=aber%3D%2F3sd8%3A%26%2B%2B%5C&c=hellpo"
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'ascii conversion' do
|
40
|
+
it "should convert a hex string to ascii in the way the service expects" do
|
41
|
+
#even if it's wrong...'
|
42
|
+
|
43
|
+
SmartsApi::Message.new().hex_string_to_ascii("3D").should == "="
|
44
|
+
SmartsApi::Message.new().hex_string_to_ascii("0B").should == "\v"
|
45
|
+
SmartsApi::Message.new().hex_string_to_ascii("52").should == "R"
|
46
|
+
|
47
|
+
hex = "52410baf20302e9e2c31b5ecea597348aa3df3067c58cf35cb5bd94273dc1de0"
|
48
|
+
SmartsApi::Message.new().hex_string_to_ascii(hex)
|
49
|
+
.should == "RA\v\xAF 0.\x9E,1\xB5\xEC\xEAYsH\xAA=\xF3\x06|X\xCF5\xCB[\xD9Bs\xDC\x1D\xE0"
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
#Notes on signing: The signing algorithm for Sparkling Logic is very brittle and depends on ALL of the
|
56
|
+
#values in sparkling_logic.yml, as well as timestamp. The below tests will fail if any of those settings change.
|
57
|
+
#so if the signature does not match the expected, and one of those settings did change, we can update the expected sig.
|
58
|
+
describe 'signing' do
|
59
|
+
it "should create a correct signature when no params supplied" do
|
60
|
+
Timecop.freeze(Time.utc(2012, 6, 21, 12, 34, 56))
|
61
|
+
|
62
|
+
SmartsApi::Message.new().sign_request({})
|
63
|
+
.should == "dOqhdTRLwMSUBSO7HZDRTsD63fVVA%2FKnffCn3DuaRnE%3D"
|
64
|
+
Timecop.return
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should create a correct signature when params supplied" do
|
68
|
+
Timecop.freeze(Time.utc(2012, 6, 21, 12, 34, 56))
|
69
|
+
params = {:param1 => "nothing", :param2 => "nothing More"}
|
70
|
+
|
71
|
+
SmartsApi::Message.new().sign_request(params)
|
72
|
+
.should == "EIvlfFrm7FpotCVp6MIt76P6bz%2BUKWbVaO7pAIclyd8%3D"
|
73
|
+
Timecop.return
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmartsApi do
|
4
|
+
|
5
|
+
describe "evaluate" do
|
6
|
+
|
7
|
+
before (:all) do
|
8
|
+
SmartsApi::Message.base_uri = "http://smarts.dev.thismashine.com/"
|
9
|
+
SmartsApi::Message.access_key = "sshhhh...Secret!"
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "expectations on eval object" do
|
13
|
+
|
14
|
+
it 'should raise error and not call connect if obj is nil' do
|
15
|
+
expect{SmartsApi.evaluate(
|
16
|
+
"string", nil
|
17
|
+
)}.to raise_error(SmartsApi::Error, "Object to be evaluated must define a method 'smarts_document'")
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should raise error and not call connect if obj does not define the document method' do
|
21
|
+
RegularClass = Class.new() {}
|
22
|
+
instance = RegularClass.new
|
23
|
+
instance.should_not be_nil
|
24
|
+
expect{SmartsApi.evaluate(
|
25
|
+
"string", instance
|
26
|
+
)}.to raise_error(SmartsApi::Error, "Object to be evaluated must define a method 'smarts_document'")
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should accept any object that defines the document method' do
|
30
|
+
EvalClass= Class.new() do
|
31
|
+
def smarts_document
|
32
|
+
"EvalClass.Instance 1"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
instance = EvalClass.new
|
37
|
+
instance.should_not be_nil
|
38
|
+
|
39
|
+
SmartsApi::ConnectMessage.any_instance.should_receive(:send).and_return("session 334")
|
40
|
+
SmartsApi::EvaluateMessage.any_instance.should_receive(:send)
|
41
|
+
SmartsApi.evaluate("string", instance)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "specifying decision string" do
|
46
|
+
it "should include the decision name and session when sending the evaluate message" do
|
47
|
+
|
48
|
+
instance = EvalClass.new
|
49
|
+
instance.should_not be_nil
|
50
|
+
SmartsApi::ConnectMessage.any_instance.should_receive(:send).and_return("session 3339")
|
51
|
+
SmartsApi::EvaluateMessage.any_instance.should_receive(:send).with("session 3339", instance, "Chosen_decision")
|
52
|
+
SmartsApi.evaluate("Chosen_decision", instance)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smarts_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Steve Mitchell
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: typhoeus
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.14.1
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.14.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: webmock
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: timecop
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: smarts_api-0.0.1
|
95
|
+
email:
|
96
|
+
- theSteveMitchell@gmail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- Gemfile
|
103
|
+
- Gemfile.lock
|
104
|
+
- LICENSE
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- lib/smarts_api.rb
|
108
|
+
- lib/smarts_api/error.rb
|
109
|
+
- lib/smarts_api/message.rb
|
110
|
+
- lib/smarts_api/message/connect_message.rb
|
111
|
+
- lib/smarts_api/message/disconnect_message.rb
|
112
|
+
- lib/smarts_api/message/evaluate_message.rb
|
113
|
+
- lib/smarts_api/version.rb
|
114
|
+
- smarts_api.gemspec
|
115
|
+
- spec/smarts_api/message/connect_message_spec.rb
|
116
|
+
- spec/smarts_api/message/disconnect_message_spec.rb
|
117
|
+
- spec/smarts_api/message/evaluate_message_spec.rb
|
118
|
+
- spec/smarts_api/message_spec.rb
|
119
|
+
- spec/smarts_api_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
homepage: http://github.com/theSteveMitchell/smarts_api
|
122
|
+
licenses: []
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ! '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 1.8.24
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: api gem for Sparkling Logic's SMARTS business logic platform
|
145
|
+
test_files:
|
146
|
+
- spec/smarts_api/message/connect_message_spec.rb
|
147
|
+
- spec/smarts_api/message/disconnect_message_spec.rb
|
148
|
+
- spec/smarts_api/message/evaluate_message_spec.rb
|
149
|
+
- spec/smarts_api/message_spec.rb
|
150
|
+
- spec/smarts_api_spec.rb
|
151
|
+
- spec/spec_helper.rb
|