decision_table 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .redcar
6
+ vendor/ruby
7
+ bin
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in decision_table.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "decision_table/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "decision_table"
7
+ s.version = DecisionTable::VERSION
8
+ s.authors = ["Chris Nelson"]
9
+ s.email = ["superchrisnelson@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Table driven decision logic in ruby}
12
+ s.description = %q{If you have decision algorithm that can be easily expressed in a table, this gem can help}
13
+
14
+ s.rubyforge_project = "decision_table"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec"
23
+ s.add_development_dependency "rspec-given"
24
+ s.add_runtime_dependency "activesupport"
25
+ end
@@ -0,0 +1,37 @@
1
+ module DecisionTable
2
+ class Rule
3
+
4
+ attr_accessor :criteria, :result
5
+
6
+ def initialize(criteria, result)
7
+ @criteria = criteria
8
+ @result = result
9
+ end
10
+
11
+ def applies?(candidate)
12
+ criteria.all? do |k, v|
13
+ v.blank? || matches?(candidate, k, v)
14
+ end
15
+ end
16
+
17
+ def matches?(candidate, key, value)
18
+ if value.to_s == "true"
19
+ candidate.send(key)
20
+ elsif value.to_s == "false"
21
+ !candidate.send(key)
22
+ else
23
+ candidate.send(key) == value
24
+ end
25
+ end
26
+
27
+ def self.parse(rule_string)
28
+ criteria = {}
29
+ rule_string.split(",").each do |crit|
30
+ k, v = crit.split(":")
31
+ criteria[k] = v
32
+ end
33
+ Rule.new(criteria, true)
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ module DecisionTable
2
+ class Ruleset
3
+ attr_accessor :rules
4
+ def initialize(rules)
5
+ @rules = rules
6
+ end
7
+
8
+ def evaluate(candidate)
9
+ rule = rules.detect { |rule| rule.applies?(candidate) }
10
+ rule.result if rule
11
+ end
12
+
13
+ def self.parse_csv(csv)
14
+ data = FasterCSV.parse(csv)
15
+ keys = data.shift
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module DecisionTable
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,8 @@
1
+ require "active_support/core_ext"
2
+ require "decision_table/version"
3
+ require "decision_table/rule"
4
+ require "decision_table/ruleset"
5
+
6
+ module DecisionTable
7
+ # Your code goes here...
8
+ end
data/spec/rule_spec.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe DecisionTable::Rule do
4
+ Given(:candidate) { double(:candidate, :foo => "bar", :bing => "baz") }
5
+
6
+ describe("applies") do
7
+ context "when all values match" do
8
+ Given(:rule) { DecisionTable::Rule.new({:foo => "bar", :bing => "baz"}, true) }
9
+ Then { rule.applies?(candidate).should be_true}
10
+ end
11
+
12
+ context "when all specified values match" do
13
+ Given(:rule ) { DecisionTable::Rule.new({:foo => "bar", :bing => ""}, true) }
14
+ Then { rule.applies?(candidate).should be_true}
15
+ end
16
+
17
+ context "when values don't match" do
18
+ Given(:rule) { DecisionTable::Rule.new({:foo => "not bar", :bing => "baz"}, true) }
19
+ Then { rule.applies?(candidate).should be_false}
20
+ end
21
+
22
+ end
23
+
24
+ describe("parsing rule") do
25
+ Given(:rule_string) { "foo:bar,bing:baz" }
26
+ When(:rule) { DecisionTable::Rule.parse(rule_string) }
27
+ Then { rule.applies?(candidate).should be_true }
28
+
29
+ context "with boolean rules" do
30
+ Given(:candidate) { double(:candidate, foo: true, bar: false) }
31
+ Given(:non_matching) { double(:candidate, foo: nil, bar: true) }
32
+ Given(:rule) {DecisionTable::Rule.parse("foo:true,bar:false") }
33
+ Then { rule.applies?(candidate).should be_true }
34
+ Then { rule.applies?(non_matching).should be_false }
35
+ end
36
+ end
37
+
38
+ end
data/spec/rules.csv ADDED
@@ -0,0 +1,3 @@
1
+ foo,bar,result
2
+ bork,,false
3
+ bing,baz,true
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ module DecisionTable
4
+ describe Ruleset do
5
+ Given(:candidate) { double(:candidate, foo: "bar", baz: "bing")}
6
+ describe "decide" do
7
+ context "one applicable rule" do
8
+ Given(:ruleset) do
9
+ rule = Rule.new({foo: "bar"}, "result")
10
+ Ruleset.new([rule])
11
+ end
12
+ Then { ruleset.evaluate(candidate).should == "result" }
13
+ end
14
+ context "two applicable rules" do
15
+ Given(:first_rule) { first_rule = Rule.new({baz: "bing"}, "first_result") }
16
+ Given(:second_rule) { first_rule = Rule.new({foo: "bar"}, "second_result") }
17
+ Given(:ruleset) { Ruleset.new [first_rule, second_rule] }
18
+ Then { ruleset.evaluate(candidate).should == "first_result"}
19
+ end
20
+ context "no applicable rules" do
21
+ Given(:rule) { Rule.new({baz: "not bing"}, "first_result") }
22
+ Then { Ruleset.new([rule]).evaluate(candidate).should be_nil }
23
+ end
24
+ end
25
+
26
+ describe "parsing CSV" do
27
+ pending "maybe later"
28
+ # Given(:csv_data) { File.read(File.join(File.dirname(__FILE__), "rules.csv")) }
29
+ # When(:ruleset) { Ruleset.parse_csv(csv_data) }
30
+ # Then { ruleset.rules.size.should == 2}
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rspec/given'
4
+ require 'decision_table' # and any other gems you need
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: decision_table
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Nelson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70177089993400 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70177089993400
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec-given
27
+ requirement: &70177089992480 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70177089992480
36
+ - !ruby/object:Gem::Dependency
37
+ name: activesupport
38
+ requirement: &70177089991940 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70177089991940
47
+ description: If you have decision algorithm that can be easily expressed in a table,
48
+ this gem can help
49
+ email:
50
+ - superchrisnelson@gmail.com
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - .gitignore
56
+ - Gemfile
57
+ - Rakefile
58
+ - decision_table.gemspec
59
+ - lib/decision_table.rb
60
+ - lib/decision_table/rule.rb
61
+ - lib/decision_table/ruleset.rb
62
+ - lib/decision_table/version.rb
63
+ - spec/rule_spec.rb
64
+ - spec/rules.csv
65
+ - spec/ruleset_spec.rb
66
+ - spec/spec_helper.rb
67
+ homepage: ''
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project: decision_table
87
+ rubygems_version: 1.8.17
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Table driven decision logic in ruby
91
+ test_files:
92
+ - spec/rule_spec.rb
93
+ - spec/rules.csv
94
+ - spec/ruleset_spec.rb
95
+ - spec/spec_helper.rb