leap 0.5.6 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/leap/decision.rb +1 -2
- data/lib/leap/deliberation.rb +27 -2
- data/lib/leap/goal_methods_documentation.rb +1 -1
- data/lib/leap/no_solution_error.rb +1 -1
- data/lib/leap/subject.rb +9 -1
- data/lib/leap/version.rb +1 -1
- data/test/helper.rb +18 -3
- data/test/test_leap.rb +36 -1
- metadata +17 -17
data/lib/leap/decision.rb
CHANGED
@@ -32,10 +32,9 @@ module Leap
|
|
32
32
|
#
|
33
33
|
# General you won't call this directly, but rather use the dynamically-created method with this decision's goal as its name on the subject instance.
|
34
34
|
# @see Leap::GoalMethodsDocumentation
|
35
|
-
def make(characteristics, *considerations)
|
35
|
+
def make(characteristics, options, *considerations)
|
36
36
|
Leap.log.decision "Leaping to conclusion", goal
|
37
37
|
Leap.log.decision "Initial characteristics: #{characteristics.inspect}", goal
|
38
|
-
options = considerations.extract_options!
|
39
38
|
committees.reject { |c| characteristics.keys.include? c.name }.reverse.inject(Deliberation.new(characteristics)) do |deliberation, committee|
|
40
39
|
Leap.instrument.committee committee.name do
|
41
40
|
if report = committee.report(deliberation.characteristics, considerations, options)
|
data/lib/leap/deliberation.rb
CHANGED
@@ -19,14 +19,39 @@ module Leap
|
|
19
19
|
def [](characteristic)
|
20
20
|
characteristics[characteristic]
|
21
21
|
end
|
22
|
+
|
23
|
+
# Convenience method to access a certain committee's report within this deliberation.
|
24
|
+
# @param [Symbol] committee
|
25
|
+
def report(committee)
|
26
|
+
reports.find { |r| r.committee.name == committee }
|
27
|
+
end
|
22
28
|
|
23
29
|
# Report which named protocols the deliberation incidentally complied with.
|
30
|
+
# @param [Symbol, optional] committee If provided, Leap will compute this decision's compliance with respect only to this particular conclusion within it. If not provided, compliance will be computed for the entire decision.
|
24
31
|
# @return [Array]
|
25
|
-
def compliance
|
32
|
+
def compliance(committee = nil)
|
33
|
+
(committee ? compliance_from(committee) : general_compliance) || []
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def general_compliance
|
26
39
|
reports.map(&:quorum).map(&:compliance).inject do |memo, c|
|
27
|
-
next c unless memo
|
28
40
|
memo & c
|
29
41
|
end
|
30
42
|
end
|
43
|
+
|
44
|
+
def compliance_from(committee)
|
45
|
+
if report = report(committee)
|
46
|
+
compliance = report.quorum.requirements.inject(nil) do |memo, requirement|
|
47
|
+
if subcompliance = compliance_from(requirement)
|
48
|
+
memo ? memo & subcompliance : subcompliance
|
49
|
+
else
|
50
|
+
memo
|
51
|
+
end
|
52
|
+
end
|
53
|
+
report.quorum.compliance & (compliance || report.quorum.compliance)
|
54
|
+
end
|
55
|
+
end
|
31
56
|
end
|
32
57
|
end
|
@@ -10,7 +10,7 @@ module Leap
|
|
10
10
|
#
|
11
11
|
# @param [optional, Array] considerations An ordered array of additional details, immutable during the course of deliberation, that should be made available to each committee for provision, upon request, to quorums.
|
12
12
|
# @param [optional, Hash] options Additional options
|
13
|
-
# @option comply Force the ensuing deliberation to comply with one or more "protocols" by only respecting quorums that comply with this (these) protocol(s). Protocols can be anything--a Fixnum, a String, whatever, but by tradition a Symbol. If compliance is required with multiple protocols, they should be passed in an Array.
|
13
|
+
# @option comply Force the ensuing deliberation to comply with one or more "protocols" by only respecting quorums that comply with this (these) protocol(s). Protocols can be anything--a Fixnum, a String, whatever, but by tradition a Symbol. If compliance is required with multiple protocols, they should be passed in an Array. If complex compliance is desired, where certain conclusions must comply with specific protocols, use a Hash in the form of <tt>{ :first_protocol => [:a_committee, :another_committee], :second_protocol => :another_committee }</tt>.
|
14
14
|
# @return The value of the newly-decided goal--or, if there is no committee with the same name as the goal, a hash of committee reports
|
15
15
|
# @raise [Leap::NoSolutionError] Leap could not compute the decision's goal on this subject instance given its characteristics and compliance constraint.
|
16
16
|
def method_missing(*args, &blk)
|
@@ -29,7 +29,7 @@ module Leap
|
|
29
29
|
def deliberation_report
|
30
30
|
@deliberation.characteristics.keys.sort_by(&:to_s).map do |characteristic|
|
31
31
|
statement = "#{characteristic}: "
|
32
|
-
if report = @deliberation.
|
32
|
+
if report = @deliberation.report(characteristic)
|
33
33
|
statement << report.quorum.name.humanize.downcase
|
34
34
|
else
|
35
35
|
statement << 'provided as input'
|
data/lib/leap/subject.rb
CHANGED
@@ -51,15 +51,23 @@ module Leap
|
|
51
51
|
Blockenspiel.invoke(blk, decisions[goal])
|
52
52
|
define_method goal do |*considerations|
|
53
53
|
Leap.instrument.decision goal do
|
54
|
+
options = considerations.extract_options!
|
54
55
|
@deliberations ||= {}
|
55
56
|
decision = self.class.decisions[goal]
|
56
57
|
characteristics = send(decision.signature_method)
|
57
|
-
@deliberations[goal] = decision.make(characteristics, *considerations)
|
58
|
+
@deliberations[goal] = decision.make(characteristics, options, *considerations)
|
58
59
|
if decision.mastered? and @deliberations[goal][goal].nil?
|
59
60
|
raise ::Leap::NoSolutionError, :goal => goal, :deliberation => @deliberations[goal]
|
60
61
|
elsif decision.mastered?
|
61
62
|
Leap.log.decision "Success", goal
|
62
63
|
@deliberations[goal][goal]
|
64
|
+
elsif options[:comply].is_a? Hash
|
65
|
+
options[:comply].each do |protocol, committees|
|
66
|
+
[committees].flatten.each do |committee|
|
67
|
+
@deliberations[goal].compliance(committee).include?(protocol) or raise ::Leap::NoSolutionError, :goal => committee, :deliberation => @deliberations[goal]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
Leap.log.decision "Success", goal
|
63
71
|
else
|
64
72
|
Leap.log.decision "Success", goal
|
65
73
|
@deliberations[goal]
|
data/lib/leap/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -120,14 +120,29 @@ class Seamus
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
class Idea
|
123
|
+
class Idea < Struct.new(:gotchas, :caveats)
|
124
|
+
def to_hash() Hash[members.zip(values)].reject {|_,v| v.nil?} end
|
125
|
+
|
124
126
|
include Leap
|
125
|
-
decide :value do
|
127
|
+
decide :value, :with => :to_hash do
|
126
128
|
committee :cost do
|
127
|
-
quorum
|
129
|
+
quorum 'based on estimate of hangups', :needs => :hangups, :complies => :common_sense do |characteristics|
|
130
|
+
characteristics[:hangups]
|
131
|
+
end
|
128
132
|
end
|
129
133
|
committee :benefit do
|
134
|
+
quorum 'based on caveats', :needs => :caveats, :complies => :wisdom do |characteristics|
|
135
|
+
10 - characteristics[:caveats]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
committee :caveats do
|
130
139
|
quorum('default') {1}
|
131
140
|
end
|
141
|
+
committee :hangups do
|
142
|
+
quorum 'based on estimate of gotchas', :needs => :gotchas, :complies => :common_sense do |characteristics|
|
143
|
+
characteristics[:gotchas]
|
144
|
+
end
|
145
|
+
quorum('default') {0}
|
146
|
+
end
|
132
147
|
end
|
133
148
|
end
|
data/test/test_leap.rb
CHANGED
@@ -161,15 +161,50 @@ class TestLeap < Test::Unit::TestCase
|
|
161
161
|
context 'A decision without a master committee' do
|
162
162
|
setup do
|
163
163
|
@idea = Idea.new
|
164
|
+
@bad_idea = Idea.new(100, 10) # gotchas, caveats
|
164
165
|
end
|
165
166
|
|
166
167
|
should 'still compute' do
|
167
168
|
@idea.value
|
168
|
-
assert_equal({:cost => 0, :benefit => 1}, @idea.deliberations[:value].characteristics)
|
169
|
+
assert_equal({:cost => 0, :benefit => 9, :caveats => 1, :hangups => 0}, @idea.deliberations[:value].characteristics)
|
169
170
|
end
|
170
171
|
|
171
172
|
should 'provide easy access to committee reports' do
|
172
173
|
assert_equal 0, @idea.value[:cost]
|
173
174
|
end
|
175
|
+
|
176
|
+
should 'provide compliance specific to a certain conclusion' do
|
177
|
+
# If hangups does not comply with common sense, neither should cost
|
178
|
+
assert_equal [], @idea.deliberations[:value].compliance(:hangups)
|
179
|
+
assert_equal [], @idea.deliberations[:value].compliance(:benefit)
|
180
|
+
assert_equal [], @idea.deliberations[:value].compliance(:cost)
|
181
|
+
|
182
|
+
# If hangups complies with common sense, cost should also
|
183
|
+
assert_equal [:common_sense], @bad_idea.deliberations[:value].compliance(:hangups)
|
184
|
+
assert_equal [:common_sense], @bad_idea.deliberations[:value].compliance(:cost)
|
185
|
+
|
186
|
+
# User input complies with all standards
|
187
|
+
assert_equal [:wisdom], @bad_idea.deliberations[:value].compliance(:benefit)
|
188
|
+
end
|
189
|
+
|
190
|
+
should 'only return compliant values when compliance is requested and endpoint is unknown' do
|
191
|
+
# Nothing complies
|
192
|
+
assert_equal({}, @idea.value(:comply => :common_sense).characteristics)
|
193
|
+
|
194
|
+
# Everything but benefit complies
|
195
|
+
assert_equal({:gotchas => 100, :caveats => 10, :hangups => 100, :cost => 100}, @bad_idea.value(:comply => :common_sense).characteristics)
|
196
|
+
end
|
197
|
+
|
198
|
+
should 'return an error message when known endpoint cannot be achieved' do
|
199
|
+
exception = assert_raise ::Leap::NoSolutionError do
|
200
|
+
@idea.value(:comply => { :common_sense => :benefit })
|
201
|
+
end
|
202
|
+
assert_match(/No solution was found for "benefit"/, exception.message)
|
203
|
+
|
204
|
+
exception = assert_raise ::Leap::NoSolutionError do
|
205
|
+
@bad_idea.value(:comply => { :common_sense => :benefit })
|
206
|
+
end
|
207
|
+
assert_match(/No solution was found for "benefit"/, exception.message)
|
208
|
+
end
|
174
209
|
end
|
175
210
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: leap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -15,7 +15,7 @@ date: 2011-12-15 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: charisma
|
18
|
-
requirement: &
|
18
|
+
requirement: &6662508 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: 0.2.0
|
24
24
|
type: :development
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *6662508
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: shoulda
|
29
|
-
requirement: &
|
29
|
+
requirement: &6662088 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ! '>='
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: '0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *6662088
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: bueller
|
40
|
-
requirement: &
|
40
|
+
requirement: &6661620 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: '0'
|
46
46
|
type: :development
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *6661620
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: blockenspiel
|
51
|
-
requirement: &
|
51
|
+
requirement: &6661068 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ! '>='
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: 0.3.2
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *6661068
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: activesupport
|
62
|
-
requirement: &
|
62
|
+
requirement: &6660456 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ! '>='
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: 2.3.4
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *6660456
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: i18n
|
73
|
-
requirement: &
|
73
|
+
requirement: &6660096 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ! '>='
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: '0'
|
79
79
|
type: :runtime
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *6660096
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: builder
|
84
|
-
requirement: &
|
84
|
+
requirement: &6659700 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,7 +89,7 @@ dependencies:
|
|
89
89
|
version: '0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *6659700
|
93
93
|
description: Leap to conclusions
|
94
94
|
email: andy@rossmeissl.net
|
95
95
|
executables: []
|
@@ -132,7 +132,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
132
|
version: '0'
|
133
133
|
segments:
|
134
134
|
- 0
|
135
|
-
hash:
|
135
|
+
hash: 545920577
|
136
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
137
|
none: false
|
138
138
|
requirements:
|
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
141
|
version: '0'
|
142
142
|
segments:
|
143
143
|
- 0
|
144
|
-
hash:
|
144
|
+
hash: 545920577
|
145
145
|
requirements: []
|
146
146
|
rubyforge_project:
|
147
147
|
rubygems_version: 1.8.11
|