smarts_api 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +76 -2
- data/lib/smarts_api/message/evaluate_message.rb +6 -9
- data/lib/smarts_api/version.rb +1 -1
- data/lib/smarts_api.rb +4 -3
- data/spec/smarts_api/message/evaluate_message_spec.rb +20 -36
- data/spec/smarts_api_spec.rb +6 -29
- metadata +3 -3
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,81 @@
|
|
1
1
|
smarts_api
|
2
2
|
==========
|
3
3
|
|
4
|
-
Ruby API for Sparkling Logic SMARTS
|
4
|
+
Ruby API for Sparkling Logic SMARTS™
|
5
5
|
|
6
|
+
## Install
|
7
|
+
```ruby
|
8
|
+
gem install smarts_api #use bundle if working in rails
|
9
|
+
```
|
10
|
+
|
11
|
+
##Usage
|
12
|
+
Create in your ruby app a config/initializers/smarts_api.rb
|
13
|
+
```ruby
|
14
|
+
SMARTS_CONFIG = YAML.load_file(Rails.root.join("config","sparkling_logic.yml"))[Rails.env]
|
15
|
+
SmartsApi.configure do | config |
|
16
|
+
config.base_uri = SMARTS_CONFIG["base_uri"]
|
17
|
+
config.app_id = SMARTS_CONFIG["app_id"]
|
18
|
+
config.access_key = SMARTS_CONFIG["access_key"]
|
19
|
+
config.user_id = SMARTS_CONFIG["user_id"]
|
20
|
+
config.pwd = SMARTS_CONFIG["pwd"]
|
21
|
+
config.workspace_id = SMARTS_CONFIG["workspace_id"]
|
22
|
+
config.project_id = SMARTS_CONFIG["project_id"]
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
And then you'll need a yml config that looks something like
|
27
|
+
```ruby
|
28
|
+
development: &default
|
29
|
+
base_uri: http://customers.sparkological.com/DecisionServer/decision-services/deployments/
|
30
|
+
app_id: #application ID
|
31
|
+
access_key: #SECRET access key
|
32
|
+
user_id: #the user id for the application account that has access to SMARTS
|
33
|
+
pwd: #account password
|
34
|
+
workspace_id: Top/Local #or wherever your workspace is defined.
|
35
|
+
project_id: #Something something project name
|
36
|
+
```
|
37
|
+
|
38
|
+
Finally you can call smarts with
|
39
|
+
```ruby
|
40
|
+
SmartsApi.evaluate("Decide if situation is cool", situation, logger=nil)
|
41
|
+
```
|
42
|
+
|
43
|
+
the evaluate call takes a string parameter identifying the decision to evaluate. the eval_object is any Object, but must respond to the following methods:
|
44
|
+
```ruby
|
45
|
+
class Situation
|
46
|
+
|
47
|
+
def smarts_document
|
48
|
+
#generates a JSON document that matches the expected json format of the SMARTS project
|
49
|
+
[
|
50
|
+
{
|
51
|
+
:time_stamp => DateTime.now
|
52
|
+
:have_money => Money.any?
|
53
|
+
:have_power => Power.significant_amount?
|
54
|
+
}
|
55
|
+
]
|
56
|
+
end
|
57
|
+
|
58
|
+
def process_smarts_response(body)
|
59
|
+
#takes a JSON document as its parameter, and processes it with whatever rules pertain to this class
|
60
|
+
if body["Documents"].first["is_a_cool_situation"]
|
61
|
+
User.notify("Your situation is cool!")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
|
69
|
+
##Credits, Contributors
|
70
|
+
|
71
|
+
Created by [Steve Mitchell](https://github.com/theSteveMitchell)
|
72
|
+
|
73
|
+
Issues and contributions welcome.
|
74
|
+
|
75
|
+
##Disclaimer
|
76
|
+
This project and it's creators, contributors, detractors, fans, haters (who, by definition, are always gonna hate), users, and abusers are in no way associated with Sparkling Logic, the innovator and creator of SMARTS™. We have no connection with Sparkling Logic, and are not responsible for any work they do.
|
77
|
+
|
78
|
+
From http://my.sparklinglogic.com/index.php/what-it-does:
|
79
|
+
|
80
|
+
Sparkling Logic SMARTS™ is a revolutionary decision management product that provides you with an intuitive and interactive environment that dramatically lowers the learning curve to allow you to immediately start capturing and refining your decision logic. You can combine decision logic based on business policies and expertise with decision logic revealed in your historical data- so you can narrow to the most impactful and high-performance business decision. Collaboration is built into SMARTS so all relevant stakeholders can participate in defining and managing automated decisions.
|
6
81
|
|
7
|
-
This project and it's creators, contributors, fans, and haters are in no way associated with Sparkling Logic, the innovator and creator of SMARTS.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class SmartsApi::EvaluateMessage < SmartsApi::Message
|
2
2
|
|
3
|
-
def send(session,
|
4
|
-
body = make_form(request_params(session,
|
3
|
+
def send(session, obj_hash, decision)
|
4
|
+
body = make_form(request_params(session, obj_hash, decision))
|
5
5
|
log "Evaluating"
|
6
6
|
response = Typhoeus::Request.post(uri,
|
7
7
|
:method => method,
|
@@ -20,16 +20,13 @@ class SmartsApi::EvaluateMessage < SmartsApi::Message
|
|
20
20
|
|
21
21
|
raise SmartsApi::Error, "Rules Evaluation failed. Returned JSON is blank."
|
22
22
|
end
|
23
|
-
|
24
|
-
log "Updating issues"
|
25
|
-
member.process_smarts_response body
|
26
23
|
return body
|
27
24
|
end
|
28
25
|
|
29
|
-
def request_params(session,
|
26
|
+
def request_params(session, obj_hash, decision)
|
30
27
|
params = {
|
31
28
|
:appId => SmartsApi::Configuration.app_id,
|
32
|
-
:reqData => request_document(session,
|
29
|
+
:reqData => request_document(session, obj_hash, decision),
|
33
30
|
:reqTime => timestamp,
|
34
31
|
:session => session
|
35
32
|
}
|
@@ -39,9 +36,9 @@ class SmartsApi::EvaluateMessage < SmartsApi::Message
|
|
39
36
|
return params.merge(signature)
|
40
37
|
end
|
41
38
|
|
42
|
-
def request_document(session,
|
39
|
+
def request_document(session, obj_hash, decision)
|
43
40
|
doc = {:OperationId =>1 , :Header => {:SessionId => session, :DecisionId => decision}, :Body => {:Documents => []}}
|
44
|
-
doc[:Body][:Documents] =
|
41
|
+
doc[:Body][:Documents] = obj_hash
|
45
42
|
return doc.to_json
|
46
43
|
end
|
47
44
|
|
data/lib/smarts_api/version.rb
CHANGED
data/lib/smarts_api.rb
CHANGED
@@ -18,15 +18,16 @@ module SmartsApi
|
|
18
18
|
Dir[File.expand_path('../../lib/smarts_api/*.rb', __FILE__)].each {|f| require f}
|
19
19
|
Dir[File.expand_path('../../lib/smarts_api/*/*.rb', __FILE__)].each {|f| require f}
|
20
20
|
|
21
|
-
def self.evaluate(decision,
|
22
|
-
raise SmartsApi::Error.new("Object to be evaluated must define a method 'smarts_document'") unless obj.respond_to?(:smarts_document)
|
21
|
+
def self.evaluate(decision, obj_hash, logger = nil)
|
23
22
|
logger.info "processing request for #{obj.class} id=#{obj.id}{" if logger.respond_to?(:info)
|
24
23
|
|
25
24
|
session = SmartsApi::ConnectMessage.new().send
|
26
25
|
response = SmartsApi::EvaluateMessage.new().
|
27
|
-
send(session,
|
26
|
+
send(session, obj_hash, decision)
|
28
27
|
|
29
28
|
SmartsApi::DisconnectMessage.new().send(session)
|
29
|
+
|
30
|
+
return response
|
30
31
|
end
|
31
32
|
|
32
33
|
end
|
@@ -7,37 +7,31 @@ describe SmartsApi::EvaluateMessage do
|
|
7
7
|
SmartsApi::Configuration.access_key = "sshhhh...Secret!"
|
8
8
|
end
|
9
9
|
|
10
|
-
let(:
|
11
|
-
|
12
|
-
|
13
|
-
def smarts_document
|
14
|
-
"123"
|
15
|
-
end
|
16
|
-
|
17
|
-
def process_smarts_response(body)
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
10
|
+
let(:obj_hash) {
|
11
|
+
{:key => "value!!!?"}
|
21
12
|
}
|
22
13
|
|
23
|
-
|
24
|
-
eval_class.new()
|
25
|
-
}
|
26
|
-
|
27
|
-
it 'should return session ID if successful' do
|
14
|
+
it 'should return request body if successful' do
|
28
15
|
|
29
16
|
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
17
|
|
31
18
|
stub_http_request(:post, "#{SmartsApi::Configuration.base_uri}evaluate")
|
32
19
|
.to_return(:status => 200, :body => body)
|
33
|
-
SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",
|
20
|
+
SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169", obj_hash, "Issues Analysis Decision").should == {"Documents"=>
|
21
|
+
[{"identification"=>
|
22
|
+
{"actor_group"=>"root",
|
23
|
+
"actor_id"=>3,
|
24
|
+
"gender"=>"Male",
|
25
|
+
"birth_date"=>"1984-12-08T06:00:00Z"},
|
26
|
+
"historical_properties"=>[{"weight"=>"150"}]}]}
|
27
|
+
|
34
28
|
|
35
29
|
end
|
36
30
|
|
37
31
|
it 'should throw an error if the connection returns an error' do
|
38
32
|
stub_http_request(:post, "#{SmartsApi::Configuration.base_uri}evaluate")
|
39
33
|
.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",
|
34
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",obj_hash, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
41
35
|
|
42
36
|
end
|
43
37
|
|
@@ -45,7 +39,7 @@ describe SmartsApi::EvaluateMessage do
|
|
45
39
|
|
46
40
|
stub_http_request(:post, "#{SmartsApi::Configuration.base_uri}evaluate")
|
47
41
|
.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",
|
42
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",obj_hash, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
49
43
|
|
50
44
|
end
|
51
45
|
|
@@ -53,7 +47,7 @@ describe SmartsApi::EvaluateMessage do
|
|
53
47
|
|
54
48
|
stub_http_request(:post, "#{SmartsApi::Configuration.base_uri}evaluate")
|
55
49
|
.to_return(:status => 200)
|
56
|
-
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",
|
50
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",obj_hash, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
57
51
|
|
58
52
|
end
|
59
53
|
|
@@ -61,26 +55,16 @@ describe SmartsApi::EvaluateMessage do
|
|
61
55
|
|
62
56
|
stub_http_request(:post, "#{SmartsApi::Configuration.base_uri}evaluate")
|
63
57
|
.to_return(:status => 500)
|
64
|
-
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",
|
58
|
+
expect{SmartsApi::EvaluateMessage.new().send("487d2c44-43fe-44d3-988f-ea462af03169",obj_hash, "Issues Analysis Decision")}.to raise_error(SmartsApi::Error)
|
65
59
|
|
66
60
|
end
|
67
61
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
62
|
+
describe "request document" do
|
63
|
+
it "include the input hash" do
|
64
|
+
SmartsApi::EvaluateMessage.new().request_document("487d2c44-43fe-44d3-988f-ea462af03169", obj_hash, "Issues Analysis Decision").should ==
|
65
|
+
"{\"OperationId\":1,\"Header\":{\"SessionId\":\"487d2c44-43fe-44d3-988f-ea462af03169\",\"DecisionId\":\"Issues Analysis Decision\"},\"Body\":{\"Documents\":{\"key\":\"value!!!?\"}}}"
|
66
|
+
end
|
78
67
|
|
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::Configuration.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
68
|
end
|
85
69
|
|
86
70
|
end
|
data/spec/smarts_api_spec.rb
CHANGED
@@ -10,49 +10,26 @@ describe SmartsApi do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe "expectations on eval object" do
|
13
|
+
it 'should accept any hash as a ' do
|
13
14
|
|
14
|
-
|
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
|
15
|
+
hash = {:hash? => true}
|
38
16
|
|
39
17
|
SmartsApi::ConnectMessage.any_instance.should_receive(:send).and_return("session 334")
|
40
18
|
SmartsApi::EvaluateMessage.any_instance.should_receive(:send)
|
41
19
|
SmartsApi::DisconnectMessage.any_instance.should_receive(:send).with("session 334")
|
42
|
-
SmartsApi.evaluate("string",
|
20
|
+
SmartsApi.evaluate("string", hash)
|
43
21
|
end
|
44
22
|
end
|
45
23
|
|
46
24
|
describe "specifying decision string" do
|
47
25
|
it "should include the decision name and session when sending the evaluate message" do
|
48
26
|
|
49
|
-
|
50
|
-
instance.should_not be_nil
|
27
|
+
hash = {:hash? => true}
|
51
28
|
SmartsApi::ConnectMessage.any_instance.should_receive(:send).and_return("session 3339")
|
52
|
-
SmartsApi::EvaluateMessage.any_instance.should_receive(:send).with("session 3339",
|
29
|
+
SmartsApi::EvaluateMessage.any_instance.should_receive(:send).with("session 3339", hash, "Chosen_decision")
|
53
30
|
SmartsApi::DisconnectMessage.any_instance.should_receive(:send).with("session 3339")
|
54
31
|
|
55
|
-
SmartsApi.evaluate("Chosen_decision",
|
32
|
+
SmartsApi.evaluate("Chosen_decision", hash)
|
56
33
|
end
|
57
34
|
end
|
58
35
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smarts_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: typhoeus
|
@@ -91,7 +91,7 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
-
description: smarts_api-0.0.
|
94
|
+
description: smarts_api-0.0.3
|
95
95
|
email:
|
96
96
|
- theSteveMitchell@gmail.com
|
97
97
|
executables: []
|