rufus-decision 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +5 -0
- data/{README.txt → README.rdoc} +13 -1
- data/Rakefile +1 -0
- data/TODO.txt +8 -3
- data/demo/README.txt +12 -0
- data/demo/public/{index.html → decision.html} +4 -5
- data/demo/public/js/ruote-sheets.js +1 -1
- data/demo/start.rb +49 -50
- data/examples/journalists.rb +37 -0
- data/examples/readme_example.rb +4 -8
- data/examples/reimbursement.csv +12 -0
- data/lib/rufus/decision/participant.rb +96 -0
- data/lib/rufus/decision/table.rb +0 -2
- data/lib/rufus/decision/version.rb +1 -1
- data/rufus-decision.gemspec +20 -14
- data/test/{test_base.rb → base.rb} +2 -1
- data/test/{decision_0_test.rb → dt_0_basic.rb} +3 -5
- data/test/{decision_1_test.rb → dt_1_vertical.rb} +3 -6
- data/test/{decision_2_test.rb → dt_2_google.rb} +3 -5
- data/test/{decision_3_test.rb → dt_3_bounded.rb} +3 -5
- data/test/{eval_test.rb → dt_4_eval.rb} +4 -5
- data/test/{transpose_test.rb → dt_5_transpose.rb} +4 -5
- data/test/ruote/base.rb +36 -0
- data/test/ruote/rt_0_basic.rb +44 -0
- data/test/ruote/test.rb +9 -0
- data/test/test.rb +2 -2
- metadata +19 -13
- data/demo/public/js/fluo-json.js +0 -186
data/CHANGELOG.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
@@ -14,7 +14,7 @@ http://jmettraux.wordpress.com/2009/04/25/rufus-decision-11-ruby-decision-tables
|
|
14
14
|
|
15
15
|
== usage
|
16
16
|
|
17
|
-
More info at http://rufus.rubyforge.org/rufus-decision/
|
17
|
+
More info at http://rufus.rubyforge.org/rufus-decision/Rufus/Decision/Table.html but here is a recap.
|
18
18
|
|
19
19
|
An example where a few rules determine which salesperson should interact with a customer with given characteristics.
|
20
20
|
|
@@ -98,6 +98,18 @@ In this example, the CSV table is the direction CSV representation of the Google
|
|
98
98
|
WARNING though : use at your own risk. CSV loaded from untrusted locations may contain harmful code. The rufus-decision gem has an abstract tree checker integrated, it will check all the CSVs that contain calls in Ruby and raise a security error when possibly harmful code is spotted. Bullet vs Armor. Be warned.
|
99
99
|
|
100
100
|
|
101
|
+
== web demo
|
102
|
+
|
103
|
+
There is a small demo of an input table + a decision table. You can run it by doing :
|
104
|
+
|
105
|
+
gem install sinatra
|
106
|
+
git clone git://github.com/jmettraux/rufus-decision.git
|
107
|
+
cd rufus-decision
|
108
|
+
ruby demo/start.rb
|
109
|
+
|
110
|
+
and then point your browser to http://localost:4567/
|
111
|
+
|
112
|
+
|
101
113
|
== uninstalling it
|
102
114
|
|
103
115
|
gem uninstall rufus-decision
|
data/Rakefile
CHANGED
@@ -39,6 +39,7 @@ CSV based Ruby decision tables
|
|
39
39
|
gem.add_dependency 'rufus-treechecker'
|
40
40
|
gem.add_development_dependency 'yard'
|
41
41
|
gem.add_development_dependency 'jeweler'
|
42
|
+
#gem.add_development_dependency 'ruote', '>= 2.1.7'
|
42
43
|
|
43
44
|
# gemspec spec : http://www.rubygems.org/read/chapter/20
|
44
45
|
end
|
data/TODO.txt
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
|
2
|
+
[o] move demo to sinatra
|
3
|
+
[o] nuke fluo-json in demo
|
2
4
|
[x] transform(h, options), :accumulate option ? NO
|
5
|
+
[o] something about demo in README
|
6
|
+
[o] demo/README.txt
|
7
|
+
[o] ruote participant
|
3
8
|
|
4
|
-
|
5
|
-
[ ] non csv string representation ?
|
9
|
+
[ ] non csv string representation ? JSON ?
|
6
10
|
[ ] dsl ?
|
7
|
-
|
11
|
+
|
12
|
+
[ ] rufus-jig for GETting the table (304 ftw)
|
8
13
|
|
data/demo/README.txt
ADDED
@@ -61,7 +61,6 @@
|
|
61
61
|
}
|
62
62
|
</style>
|
63
63
|
|
64
|
-
<script src="js/fluo-json.js"></script>
|
65
64
|
<script src="js/ruote-sheets.js"></script>
|
66
65
|
<script src="js/request.js"></script>
|
67
66
|
</head>
|
@@ -123,12 +122,12 @@
|
|
123
122
|
|
124
123
|
var data =
|
125
124
|
'[' +
|
126
|
-
|
127
|
-
|
125
|
+
JSON.stringify(RuoteSheets.toArray('sheet_in')) + ',' +
|
126
|
+
JSON.stringify(RuoteSheets.toArray('sheet_decision')) +
|
128
127
|
']';
|
129
128
|
|
130
|
-
var result = httpPost('/
|
131
|
-
result =
|
129
|
+
var result = httpPost('/decide', data);
|
130
|
+
result = JSON.parse(result);
|
132
131
|
|
133
132
|
RuoteSheets.render('sheet_out', result);
|
134
133
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
|
2
|
+
* Copyright (c) 2009-2010, John Mettraux, jmettraux@gmail.com
|
3
3
|
*
|
4
4
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
* of this software and associated documentation files (the "Software"), to deal
|
data/demo/start.rb
CHANGED
@@ -13,66 +13,65 @@
|
|
13
13
|
# if necessary)
|
14
14
|
#
|
15
15
|
|
16
|
-
$:.unshift('lib')
|
16
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
17
17
|
|
18
18
|
require 'rubygems'
|
19
|
-
require 'rack'
|
20
19
|
require 'json'
|
20
|
+
require 'sinatra'
|
21
21
|
require 'rufus/decision'
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
23
|
+
#class App
|
24
|
+
# def initialize
|
25
|
+
# @rfapp = Rack::File.new(File.dirname(__FILE__) + '/public')
|
26
|
+
# end
|
27
|
+
# def call (env)
|
28
|
+
# return decide(env) if env['PATH_INFO'] == '/decision'
|
29
|
+
# env['PATH_INFO'] = '/index.html' if env['PATH_INFO'] == '/'
|
30
|
+
# @rfapp.call(env)
|
31
|
+
# end
|
32
|
+
# protected
|
33
|
+
# def in_to_h (keys, values)
|
34
|
+
# keys.inject({}) { |h, k| h[k] = values.shift; h }
|
35
|
+
# end
|
36
|
+
# def decide (env)
|
37
|
+
# json = env['rack.input'].read
|
38
|
+
# json = JSON.parse(json)
|
39
|
+
# dt = Rufus::Decision::Table.new(json.last)
|
40
|
+
# input = Rufus::Decision.transpose(json.first)
|
41
|
+
# # from array of arrays to array of hashes
|
42
|
+
# output = input.inject([]) { |a, hash| a << dt.transform(hash); a }
|
43
|
+
# output = Rufus::Decision.transpose(output)
|
44
|
+
# # from array of hashes to array of arrays
|
45
|
+
# [ 200, {}, output.to_json ]
|
46
|
+
# end
|
47
|
+
#end
|
48
|
+
|
49
|
+
use Rack::CommonLogger
|
50
|
+
use Rack::ShowExceptions
|
51
|
+
|
52
|
+
set :public, File.expand_path(File.join(File.dirname(__FILE__), 'public'))
|
53
|
+
#set :views, File.expand_path(File.join(File.dirname(__FILE__), 'views'))
|
54
|
+
|
55
|
+
get '/' do
|
56
|
+
|
57
|
+
redirect '/decision.html'
|
59
58
|
end
|
60
59
|
|
61
|
-
|
60
|
+
post '/decide' do
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
json = env['rack.input'].read
|
63
|
+
json = JSON.parse(json)
|
64
|
+
|
65
|
+
dt = Rufus::Decision::Table.new(json.last)
|
66
|
+
input = Rufus::Decision.transpose(json.first)
|
67
|
+
# from array of arrays to array of hashes
|
67
68
|
|
68
|
-
|
69
|
+
output = input.inject([]) { |a, hash| a << dt.transform(hash); a }
|
70
|
+
output = Rufus::Decision.transpose(output)
|
71
|
+
# from array of hashes to array of arrays
|
69
72
|
|
70
|
-
|
73
|
+
response.headers['Content-Type'] = 'application/json'
|
71
74
|
|
72
|
-
|
73
|
-
trap(:INT) do
|
74
|
-
puts ".. [#{Time.now}] stopped."
|
75
|
-
server.stop
|
76
|
-
end
|
75
|
+
output.to_json
|
77
76
|
end
|
78
77
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rufus/decision' # sudo gem install rufus-decision
|
4
|
+
|
5
|
+
table = %{
|
6
|
+
in:topic,in:region,out:team_member
|
7
|
+
sports,europe,Alice
|
8
|
+
sports,,Bob
|
9
|
+
finance,america,Charly
|
10
|
+
finance,europe,Donald
|
11
|
+
finance,,Ernest
|
12
|
+
politics,asia,Fujio
|
13
|
+
politics,america,Gilbert
|
14
|
+
politics,,Henry
|
15
|
+
,,Zach
|
16
|
+
}
|
17
|
+
|
18
|
+
#Rufus::Decision.csv_to_a(table).transpose.each do |row|
|
19
|
+
# puts row.join(', ')
|
20
|
+
#end
|
21
|
+
table = %{
|
22
|
+
in:topic,sports,sports,finance,finance,finance,politics,politics,politics,
|
23
|
+
in:region,europe,,america,europe,,asia,america,,
|
24
|
+
out:team_member,Alice,Bob,Charly,Donald,Ernest,Fujio,Gilbert,Henry,Zach
|
25
|
+
}
|
26
|
+
|
27
|
+
table = Rufus::Decision::Table.new(table)
|
28
|
+
|
29
|
+
p table.run('topic' => 'politics', 'region' => 'america')
|
30
|
+
# => {"region"=>"america", "topic"=>"politics", "team_member"=>"Gilbert"}
|
31
|
+
|
32
|
+
p table.run('topic' => 'sports', 'region' => 'antarctic')
|
33
|
+
# => {"region"=>"antarctic", "topic"=>"sports", "team_member"=>"Bob"}
|
34
|
+
|
35
|
+
p table.run('topic' => 'culture', 'region' => 'america')
|
36
|
+
# => {"region"=>"america", "topic"=>"culture", "team_member"=>"Zach"}
|
37
|
+
|
data/examples/readme_example.rb
CHANGED
@@ -2,10 +2,7 @@
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'rufus/decision'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
TABLE = DecisionTable.new("""
|
5
|
+
TABLE = Rufus::Decision::Table.new(%{
|
9
6
|
in:age,in:trait,out:salesperson
|
10
7
|
|
11
8
|
18..35,,adeslky
|
@@ -17,11 +14,10 @@ in:age,in:trait,out:salesperson
|
|
17
14
|
25..35,rich,kerfelden
|
18
15
|
,cheerful,swanson
|
19
16
|
,maniac,korolev
|
20
|
-
|
17
|
+
})
|
21
18
|
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# convenience), returns the name of the first
|
19
|
+
# Given a customer (a Hash instance directly, for
|
20
|
+
# convenience), returns the name of the first
|
25
21
|
# corresponding salesman.
|
26
22
|
#
|
27
23
|
def determine_salesperson (customer)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
in:deductible met ?,in:type of visit,in:participating physician ?,out:reimbursement
|
2
|
+
yes,doctor office,yes,90%
|
3
|
+
yes,doctor office,no,50%
|
4
|
+
yes,hospital visit,yes,n/a
|
5
|
+
yes,hospital visit,no,80%
|
6
|
+
yes,lab visit,yes,n/a
|
7
|
+
yes,lab visit,no,70%
|
8
|
+
no,doctor office,no,0%
|
9
|
+
no,hospital visit,yes,n/a
|
10
|
+
no,hospital visit,no,0%
|
11
|
+
no,lab visit,yes,n/a
|
12
|
+
no,lab visit,no,0%
|
@@ -0,0 +1,96 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007-2010, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
require 'rufus/decision'
|
26
|
+
require 'ruote/participant'
|
27
|
+
|
28
|
+
|
29
|
+
module Rufus::Decision
|
30
|
+
|
31
|
+
#
|
32
|
+
# Decision participants were named 'CSV participants' prior to ruote 2.1.
|
33
|
+
#
|
34
|
+
# Make sure you have the gem "rufus-decision" installed in order to
|
35
|
+
# use this decision participant.
|
36
|
+
#
|
37
|
+
# In this example, a participant named 'decide_team_member' is bound in the
|
38
|
+
# ruote engine and, depending on the value of the workitem fields 'topic'
|
39
|
+
# and region, sets the value of the field named 'team_member' :
|
40
|
+
#
|
41
|
+
# require 'rufus/decision/participant'
|
42
|
+
#
|
43
|
+
# engine.register_participant(
|
44
|
+
# :decide_team_member
|
45
|
+
# Rufus::Decision::Participant, :table => %{
|
46
|
+
# in:topic,in:region,out:team_member
|
47
|
+
# sports,europe,Alice
|
48
|
+
# sports,,Bob
|
49
|
+
# finance,america,Charly
|
50
|
+
# finance,europe,Donald
|
51
|
+
# finance,,Ernest
|
52
|
+
# politics,asia,Fujio
|
53
|
+
# politics,america,Gilbert
|
54
|
+
# politics,,Henry
|
55
|
+
# ,,Zach
|
56
|
+
# })
|
57
|
+
#
|
58
|
+
# pdef = Ruote.process_definition :name => 'dec-test', :revision => '1' do
|
59
|
+
# sequence do
|
60
|
+
# decide_team_member
|
61
|
+
# participant :ref => '${team_member}'
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# A process instance about the election results in Venezuela :
|
66
|
+
#
|
67
|
+
# engine.launch(
|
68
|
+
# pdef,
|
69
|
+
# 'topic' => 'politics',
|
70
|
+
# 'region' => 'america',
|
71
|
+
# 'line' => 'election results in Venezuela')
|
72
|
+
#
|
73
|
+
# would thus get routed to Gilbert.
|
74
|
+
#
|
75
|
+
class Participant
|
76
|
+
include Ruote::LocalParticipant
|
77
|
+
|
78
|
+
def initialize (opts={})
|
79
|
+
|
80
|
+
@options = opts
|
81
|
+
end
|
82
|
+
|
83
|
+
def consume (workitem)
|
84
|
+
|
85
|
+
table = @options['table']
|
86
|
+
raise(ArgumentError.new("'table' option is missing")) unless table
|
87
|
+
|
88
|
+
table = Rufus::Decision::Table.new(table)
|
89
|
+
|
90
|
+
workitem.fields = table.run(workitem.fields)
|
91
|
+
|
92
|
+
reply_to_engine(workitem)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
data/lib/rufus/decision/table.rb
CHANGED
data/rufus-decision.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rufus-decision}
|
8
|
-
s.version = "1.3.
|
8
|
+
s.version = "1.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["John Mettraux"]
|
12
|
-
s.date = %q{2010-02-
|
12
|
+
s.date = %q{2010-02-16}
|
13
13
|
s.default_executable = %q{rufus_decide}
|
14
14
|
s.description = %q{
|
15
15
|
CSV based Ruby decision tables
|
@@ -18,43 +18,49 @@ CSV based Ruby decision tables
|
|
18
18
|
s.executables = ["rufus_decide"]
|
19
19
|
s.extra_rdoc_files = [
|
20
20
|
"LICENSE.txt",
|
21
|
-
"README.
|
21
|
+
"README.rdoc"
|
22
22
|
]
|
23
23
|
s.files = [
|
24
24
|
"CHANGELOG.txt",
|
25
25
|
"CREDITS.txt",
|
26
26
|
"LICENSE.txt",
|
27
|
-
"README.
|
27
|
+
"README.rdoc",
|
28
28
|
"Rakefile",
|
29
29
|
"TODO.txt",
|
30
30
|
"bin/rufus_decide",
|
31
|
+
"demo/README.txt",
|
32
|
+
"demo/public/decision.html",
|
31
33
|
"demo/public/decision.js",
|
32
34
|
"demo/public/images/arrow.png",
|
33
35
|
"demo/public/images/ruse_head_bg.png",
|
34
36
|
"demo/public/in.js",
|
35
|
-
"demo/public/index.html",
|
36
|
-
"demo/public/js/fluo-json.js",
|
37
37
|
"demo/public/js/request.js",
|
38
38
|
"demo/public/js/ruote-sheets.js",
|
39
39
|
"demo/start.rb",
|
40
|
+
"examples/journalists.rb",
|
40
41
|
"examples/readme_example.rb",
|
42
|
+
"examples/reimbursement.csv",
|
41
43
|
"lib/rufus-decision.rb",
|
42
44
|
"lib/rufus/decision.rb",
|
43
45
|
"lib/rufus/decision/hashes.rb",
|
46
|
+
"lib/rufus/decision/participant.rb",
|
44
47
|
"lib/rufus/decision/table.rb",
|
45
48
|
"lib/rufus/decision/version.rb",
|
46
49
|
"rufus-decision.gemspec",
|
47
|
-
"test/
|
48
|
-
"test/
|
49
|
-
"test/
|
50
|
-
"test/
|
51
|
-
"test/
|
50
|
+
"test/base.rb",
|
51
|
+
"test/dt_0_basic.rb",
|
52
|
+
"test/dt_1_vertical.rb",
|
53
|
+
"test/dt_2_google.rb",
|
54
|
+
"test/dt_3_bounded.rb",
|
55
|
+
"test/dt_4_eval.rb",
|
56
|
+
"test/dt_5_transpose.rb",
|
52
57
|
"test/goal.csv",
|
53
58
|
"test/input.csv",
|
59
|
+
"test/ruote/base.rb",
|
60
|
+
"test/ruote/rt_0_basic.rb",
|
61
|
+
"test/ruote/test.rb",
|
54
62
|
"test/table.csv",
|
55
|
-
"test/test.rb"
|
56
|
-
"test/test_base.rb",
|
57
|
-
"test/transpose_test.rb"
|
63
|
+
"test/test.rb"
|
58
64
|
]
|
59
65
|
s.homepage = %q{http://github.com/jmettraux/rufus-decision/}
|
60
66
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -1,16 +1,14 @@
|
|
1
1
|
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# testing rufus-decision
|
4
4
|
#
|
5
5
|
# Sun Oct 29 15:41:44 JST 2006
|
6
6
|
#
|
7
7
|
|
8
|
-
require '
|
8
|
+
require File.join(File.dirname(__FILE__), 'base.rb')
|
9
9
|
|
10
|
-
require File.join(File.dirname(__FILE__), 'test_base.rb')
|
11
10
|
|
12
|
-
|
13
|
-
class Decision0Test < Test::Unit::TestCase
|
11
|
+
class Dt0Test < Test::Unit::TestCase
|
14
12
|
include DecisionTestMixin
|
15
13
|
|
16
14
|
CSV0 = %{
|
@@ -1,16 +1,14 @@
|
|
1
1
|
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# testing rufus-deciision
|
4
4
|
#
|
5
5
|
# Sun Oct 29 15:41:44 JST 2006
|
6
6
|
#
|
7
7
|
|
8
|
-
require '
|
8
|
+
require File.join(File.dirname(__FILE__), 'base.rb')
|
9
9
|
|
10
|
-
require File.join(File.dirname(__FILE__), 'test_base.rb')
|
11
10
|
|
12
|
-
|
13
|
-
class Decision1Test < Test::Unit::TestCase
|
11
|
+
class Dt1Test < Test::Unit::TestCase
|
14
12
|
include DecisionTestMixin
|
15
13
|
|
16
14
|
CSV1 = %{
|
@@ -96,6 +94,5 @@ out:team_member,Alice,Bob,Charly,Donald,Ernest,Fujio,Gilbert,Henry,Zach
|
|
96
94
|
h = { 'topic' => 'politics', 'region' => 'america' }
|
97
95
|
do_test(table, h, { 'team_member' => 'Gilbert' }, false)
|
98
96
|
end
|
99
|
-
|
100
97
|
end
|
101
98
|
|
@@ -1,16 +1,14 @@
|
|
1
1
|
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# testing rufus-decision
|
4
4
|
#
|
5
5
|
# Sun Oct 29 15:41:44 JST 2006
|
6
6
|
#
|
7
7
|
|
8
|
-
require '
|
8
|
+
require File.join(File.dirname(__FILE__), 'base.rb')
|
9
9
|
|
10
|
-
require File.join(File.dirname(__FILE__), 'test_base.rb')
|
11
10
|
|
12
|
-
|
13
|
-
class Decision2Test < Test::Unit::TestCase
|
11
|
+
class Dt2Test < Test::Unit::TestCase
|
14
12
|
include DecisionTestMixin
|
15
13
|
|
16
14
|
CSV3D = "http://spreadsheets.google.com/pub?key=pCkopoeZwCNsMWOVeDjR1TQ&output=csv&gid=0"
|
@@ -1,16 +1,14 @@
|
|
1
1
|
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# testing rufus-decision
|
4
4
|
#
|
5
5
|
# Mon Sep 7 13:42:09 JST 2009
|
6
6
|
#
|
7
7
|
|
8
|
-
require '
|
8
|
+
require File.join(File.dirname(__FILE__), 'base.rb')
|
9
9
|
|
10
|
-
require File.join(File.dirname(__FILE__), 'test_base.rb')
|
11
10
|
|
12
|
-
|
13
|
-
class Decision3Test < Test::Unit::TestCase
|
11
|
+
class Dt3Test < Test::Unit::TestCase
|
14
12
|
include DecisionTestMixin
|
15
13
|
|
16
14
|
CSV14 = %{
|
@@ -1,18 +1,16 @@
|
|
1
1
|
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# testing rufus-decision
|
4
4
|
#
|
5
5
|
# Mon Oct 9 22:19:44 JST 2006
|
6
6
|
#
|
7
7
|
|
8
|
-
require '
|
9
|
-
|
10
|
-
require File.dirname(__FILE__) + '/test_base.rb'
|
8
|
+
require File.join(File.dirname(__FILE__), 'base.rb')
|
11
9
|
|
12
10
|
require 'rufus/decision/hashes'
|
13
11
|
|
14
12
|
|
15
|
-
class
|
13
|
+
class Dt4Test < Test::Unit::TestCase
|
16
14
|
|
17
15
|
def test_0
|
18
16
|
|
@@ -26,3 +24,4 @@ class EvalTest < Test::Unit::TestCase
|
|
26
24
|
assert_equal 72, eh['r:36+36']
|
27
25
|
end
|
28
26
|
end
|
27
|
+
|
@@ -1,16 +1,14 @@
|
|
1
1
|
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# testing rufus-decision
|
4
4
|
#
|
5
5
|
# Thu Apr 23 15:18:15 JST 2009
|
6
6
|
#
|
7
7
|
|
8
|
-
require '
|
8
|
+
require File.join(File.dirname(__FILE__), 'base.rb')
|
9
9
|
|
10
|
-
require File.dirname(__FILE__) + '/test_base.rb'
|
11
10
|
|
12
|
-
|
13
|
-
class MiscTest < Test::Unit::TestCase
|
11
|
+
class Dt5Test < Test::Unit::TestCase
|
14
12
|
|
15
13
|
def test_transpose_empty_array
|
16
14
|
|
@@ -62,3 +60,4 @@ class MiscTest < Test::Unit::TestCase
|
|
62
60
|
)
|
63
61
|
end
|
64
62
|
end
|
63
|
+
|
data/test/ruote/base.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# testing rufus-decision (ruote participant)
|
4
|
+
#
|
5
|
+
# Tue Feb 16 14:37:13 JST 2010
|
6
|
+
#
|
7
|
+
|
8
|
+
$:.unshift(
|
9
|
+
File.expand_path(File.join(File.dirname(__FILE__), %w[ .. .. lib ])))
|
10
|
+
$:.unshift(
|
11
|
+
File.expand_path(File.join(File.dirname(__FILE__), %w[ .. .. .. .. ruote lib ])))
|
12
|
+
|
13
|
+
require 'test/unit'
|
14
|
+
require 'rubygems'
|
15
|
+
require 'ruote'
|
16
|
+
require 'rufus/decision'
|
17
|
+
|
18
|
+
|
19
|
+
module RuoteBase
|
20
|
+
|
21
|
+
def setup
|
22
|
+
|
23
|
+
@engine =
|
24
|
+
Ruote::Engine.new(
|
25
|
+
Ruote::Worker.new(
|
26
|
+
Ruote::HashStorage.new(
|
27
|
+
's_logger' => %w[ ruote/log/test_logger Ruote::TestLogger ])))
|
28
|
+
end
|
29
|
+
|
30
|
+
def teardown
|
31
|
+
|
32
|
+
@engine.shutdown
|
33
|
+
@engine.context.storage.purge!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# testing rufus-decision (ruote participant)
|
4
|
+
#
|
5
|
+
# Tue Feb 16 14:54:55 JST 2010
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), 'base')
|
9
|
+
|
10
|
+
require 'rufus/decision/participant'
|
11
|
+
|
12
|
+
class Rt0Test < Test::Unit::TestCase
|
13
|
+
include RuoteBase
|
14
|
+
|
15
|
+
def test_basic
|
16
|
+
|
17
|
+
@engine.register_participant(
|
18
|
+
:decision,
|
19
|
+
Rufus::Decision::Participant, :table => %{
|
20
|
+
in:topic,in:region,out:team_member
|
21
|
+
sports,europe,Alice
|
22
|
+
sports,,Bob
|
23
|
+
finance,america,Charly
|
24
|
+
finance,europe,Donald
|
25
|
+
finance,,Ernest
|
26
|
+
politics,asia,Fujio
|
27
|
+
politics,america,Gilbert
|
28
|
+
politics,,Henry
|
29
|
+
,,Zach
|
30
|
+
})
|
31
|
+
|
32
|
+
pdef = Ruote.process_definition :name => 'dec-test', :revision => '1' do
|
33
|
+
decision
|
34
|
+
end
|
35
|
+
|
36
|
+
wfid = @engine.launch(pdef, 'topic' => 'politics', 'region' => 'america')
|
37
|
+
r = @engine.wait_for(wfid)
|
38
|
+
|
39
|
+
assert_equal(
|
40
|
+
{"topic"=>"politics", "region"=>"america", "team_member"=>"Gilbert"},
|
41
|
+
r['workitem']['fields'])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
data/test/ruote/test.rb
ADDED
data/test/test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rufus-decision
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Mettraux
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-16 00:00:00 +09:00
|
13
13
|
default_executable: rufus_decide
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -61,42 +61,48 @@ extensions: []
|
|
61
61
|
|
62
62
|
extra_rdoc_files:
|
63
63
|
- LICENSE.txt
|
64
|
-
- README.
|
64
|
+
- README.rdoc
|
65
65
|
files:
|
66
66
|
- CHANGELOG.txt
|
67
67
|
- CREDITS.txt
|
68
68
|
- LICENSE.txt
|
69
|
-
- README.
|
69
|
+
- README.rdoc
|
70
70
|
- Rakefile
|
71
71
|
- TODO.txt
|
72
72
|
- bin/rufus_decide
|
73
|
+
- demo/README.txt
|
74
|
+
- demo/public/decision.html
|
73
75
|
- demo/public/decision.js
|
74
76
|
- demo/public/images/arrow.png
|
75
77
|
- demo/public/images/ruse_head_bg.png
|
76
78
|
- demo/public/in.js
|
77
|
-
- demo/public/index.html
|
78
|
-
- demo/public/js/fluo-json.js
|
79
79
|
- demo/public/js/request.js
|
80
80
|
- demo/public/js/ruote-sheets.js
|
81
81
|
- demo/start.rb
|
82
|
+
- examples/journalists.rb
|
82
83
|
- examples/readme_example.rb
|
84
|
+
- examples/reimbursement.csv
|
83
85
|
- lib/rufus-decision.rb
|
84
86
|
- lib/rufus/decision.rb
|
85
87
|
- lib/rufus/decision/hashes.rb
|
88
|
+
- lib/rufus/decision/participant.rb
|
86
89
|
- lib/rufus/decision/table.rb
|
87
90
|
- lib/rufus/decision/version.rb
|
88
91
|
- rufus-decision.gemspec
|
89
|
-
- test/
|
90
|
-
- test/
|
91
|
-
- test/
|
92
|
-
- test/
|
93
|
-
- test/
|
92
|
+
- test/base.rb
|
93
|
+
- test/dt_0_basic.rb
|
94
|
+
- test/dt_1_vertical.rb
|
95
|
+
- test/dt_2_google.rb
|
96
|
+
- test/dt_3_bounded.rb
|
97
|
+
- test/dt_4_eval.rb
|
98
|
+
- test/dt_5_transpose.rb
|
94
99
|
- test/goal.csv
|
95
100
|
- test/input.csv
|
101
|
+
- test/ruote/base.rb
|
102
|
+
- test/ruote/rt_0_basic.rb
|
103
|
+
- test/ruote/test.rb
|
96
104
|
- test/table.csv
|
97
105
|
- test/test.rb
|
98
|
-
- test/test_base.rb
|
99
|
-
- test/transpose_test.rb
|
100
106
|
has_rdoc: true
|
101
107
|
homepage: http://github.com/jmettraux/rufus-decision/
|
102
108
|
licenses: []
|
data/demo/public/js/fluo-json.js
DELETED
@@ -1,186 +0,0 @@
|
|
1
|
-
// Copyright (C) 2008 Google Inc.
|
2
|
-
//
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
// you may not use this file except in compliance with the License.
|
5
|
-
// You may obtain a copy of the License at
|
6
|
-
//
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
//
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
// See the License for the specific language governing permissions and
|
13
|
-
// limitations under the License.
|
14
|
-
|
15
|
-
// ruote 'source' :
|
16
|
-
// http://github.com/jmettraux/ruote-fluo/tree/master/public/js/fluo-json.js
|
17
|
-
|
18
|
-
/**
|
19
|
-
* @param {string} json per RFC 4627
|
20
|
-
* @return {Object|Array}
|
21
|
-
* @author Mike Samuel <mikesamuel@gmail.com>
|
22
|
-
*/
|
23
|
-
//var jsonParse = (function () {
|
24
|
-
var fluoFromJson = (function () {
|
25
|
-
var number
|
26
|
-
= '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)';
|
27
|
-
var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]'
|
28
|
-
+ '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))';
|
29
|
-
var string = '(?:\"' + oneChar + '*\")';
|
30
|
-
|
31
|
-
// Will match a value in a well-formed JSON file.
|
32
|
-
// If the input is not well-formed, may match strangely, but not in an unsafe
|
33
|
-
// way.
|
34
|
-
// Since this only matches value tokens, it does not match whitespace, colons,
|
35
|
-
// or commas.
|
36
|
-
var jsonToken = new RegExp(
|
37
|
-
'(?:false|true|null|[\\{\\}\\[\\]]'
|
38
|
-
+ '|' + number
|
39
|
-
+ '|' + string
|
40
|
-
+ ')', 'g');
|
41
|
-
|
42
|
-
// Matches escape sequences in a string literal
|
43
|
-
var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g');
|
44
|
-
|
45
|
-
// Decodes escape sequences in object literals
|
46
|
-
var escapes = {
|
47
|
-
'"': '"',
|
48
|
-
'/': '/',
|
49
|
-
'\\': '\\',
|
50
|
-
'b': '\b',
|
51
|
-
'f': '\f',
|
52
|
-
'n': '\n',
|
53
|
-
'r': '\r',
|
54
|
-
't': '\t'
|
55
|
-
};
|
56
|
-
function unescapeOne(_, ch, hex) {
|
57
|
-
return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16));
|
58
|
-
}
|
59
|
-
|
60
|
-
// A non-falsy value that coerces to the empty string when used as a key.
|
61
|
-
var EMPTY_STRING = new String('');
|
62
|
-
var SLASH = '\\';
|
63
|
-
|
64
|
-
// Constructor to use based on an open token.
|
65
|
-
var firstTokenCtors = { '{': Object, '[': Array };
|
66
|
-
|
67
|
-
return function (json) {
|
68
|
-
// Split into tokens
|
69
|
-
var toks = json.match(jsonToken);
|
70
|
-
// Construct the object to return
|
71
|
-
var result;
|
72
|
-
var tok = toks[0];
|
73
|
-
if ('{' === tok) {
|
74
|
-
result = {};
|
75
|
-
} else if ('[' === tok) {
|
76
|
-
result = [];
|
77
|
-
} else {
|
78
|
-
throw new Error(tok);
|
79
|
-
}
|
80
|
-
|
81
|
-
// If undefined, the key in an object key/value record to use for the next
|
82
|
-
// value parsed.
|
83
|
-
var key;
|
84
|
-
// Loop over remaining tokens maintaining a stack of uncompleted objects and
|
85
|
-
// arrays.
|
86
|
-
var stack = [result];
|
87
|
-
for (var i = 1, n = toks.length; i < n; ++i) {
|
88
|
-
tok = toks[i];
|
89
|
-
|
90
|
-
var cont;
|
91
|
-
switch (tok.charCodeAt(0)) {
|
92
|
-
default: // sign or digit
|
93
|
-
cont = stack[0];
|
94
|
-
cont[key || cont.length] = +(tok);
|
95
|
-
key = void 0;
|
96
|
-
break;
|
97
|
-
case 0x22: // '"'
|
98
|
-
tok = tok.substring(1, tok.length - 1);
|
99
|
-
if (tok.indexOf(SLASH) !== -1) {
|
100
|
-
tok = tok.replace(escapeSequence, unescapeOne);
|
101
|
-
}
|
102
|
-
cont = stack[0];
|
103
|
-
if (!key) {
|
104
|
-
if (cont instanceof Array) {
|
105
|
-
key = cont.length;
|
106
|
-
} else {
|
107
|
-
key = tok || EMPTY_STRING; // Use as key for next value seen.
|
108
|
-
break;
|
109
|
-
}
|
110
|
-
}
|
111
|
-
cont[key] = tok;
|
112
|
-
key = void 0;
|
113
|
-
break;
|
114
|
-
case 0x5b: // '['
|
115
|
-
cont = stack[0];
|
116
|
-
stack.unshift(cont[key || cont.length] = []);
|
117
|
-
key = void 0;
|
118
|
-
break;
|
119
|
-
case 0x5d: // ']'
|
120
|
-
stack.shift();
|
121
|
-
break;
|
122
|
-
case 0x66: // 'f'
|
123
|
-
cont = stack[0];
|
124
|
-
cont[key || cont.length] = false;
|
125
|
-
key = void 0;
|
126
|
-
break;
|
127
|
-
case 0x6e: // 'n'
|
128
|
-
cont = stack[0];
|
129
|
-
cont[key || cont.length] = null;
|
130
|
-
key = void 0;
|
131
|
-
break;
|
132
|
-
case 0x74: // 't'
|
133
|
-
cont = stack[0];
|
134
|
-
cont[key || cont.length] = true;
|
135
|
-
key = void 0;
|
136
|
-
break;
|
137
|
-
case 0x7b: // '{'
|
138
|
-
cont = stack[0];
|
139
|
-
stack.unshift(cont[key || cont.length] = {});
|
140
|
-
key = void 0;
|
141
|
-
break;
|
142
|
-
case 0x7d: // '}'
|
143
|
-
stack.shift();
|
144
|
-
break;
|
145
|
-
}
|
146
|
-
}
|
147
|
-
// Fail if we've got an uncompleted object.
|
148
|
-
if (stack.length) { throw new Error(); }
|
149
|
-
return result;
|
150
|
-
};
|
151
|
-
})();
|
152
|
-
|
153
|
-
|
154
|
-
//
|
155
|
-
// the following code is ruote-fluo code, under the BSD license.
|
156
|
-
//
|
157
|
-
function fluoToJson (o, quotes) {
|
158
|
-
if (quotes != false) quotes = true;
|
159
|
-
if (o == null) return 'null';
|
160
|
-
var t = (typeof o);
|
161
|
-
if (t == 'undefined') return 'null' // really ?
|
162
|
-
if (t == 'number') return o;
|
163
|
-
if (t == 'string') {
|
164
|
-
//return quotes ? '"' + o + '"' : o;
|
165
|
-
if ( ! quotes) return o;
|
166
|
-
return '"' +
|
167
|
-
o
|
168
|
-
.replace(/"/g, '\\"')
|
169
|
-
.replace(/\r/g, '')
|
170
|
-
.replace(/\n/g, '\\n') +
|
171
|
-
'"';
|
172
|
-
// this global replace works with safari (webkit) and ffox
|
173
|
-
}
|
174
|
-
if (o.constructor.toString().indexOf(' Array()') == 8) {
|
175
|
-
var a = [];
|
176
|
-
for (var i = 0; i < o.length; i++) a.push(fluoToJson(o[i]));
|
177
|
-
return '[' + a.join(', ') + ']';
|
178
|
-
}
|
179
|
-
if (t == 'object') {
|
180
|
-
var a = [];
|
181
|
-
for (var key in o) a.push(fluoToJson(key) + ': ' + fluoToJson(o[key]));
|
182
|
-
return '{' + a.join(', ') + '}';
|
183
|
-
}
|
184
|
-
return o.toString();
|
185
|
-
}
|
186
|
-
|