active_record_survey 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/active_record_survey/instance_node.rb +8 -2
- data/lib/active_record_survey/node/answer/boolean.rb +8 -0
- data/lib/active_record_survey/node/answer.rb +8 -0
- data/lib/active_record_survey/node.rb +38 -2
- data/lib/active_record_survey/node_map.rb +11 -0
- data/lib/active_record_survey/node_validation/maximum_answer.rb +22 -3
- data/lib/active_record_survey/node_validation/minimum_answer.rb +22 -3
- data/lib/active_record_survey/node_validation.rb +5 -1
- data/lib/active_record_survey/version.rb +1 -1
- data/spec/active_record_survey/node/answer/boolean_spec.rb +113 -13
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc0440e0c23ed5d966185f62fe83619c7d50fa01
|
4
|
+
data.tar.gz: b0e93efb11a6994878ce6c3d5d948043525125a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81b0ea583a5d440eddb185547a584dcf471d8f1618a4f8a0e80406882d7a866c5391851e9eb962f28a90f6308bd3c2aba0c30891b700e28a9737acf19fc04f1e
|
7
|
+
data.tar.gz: 64b747965c5c7bcefe1753f4518f5f4dcbf5279339c459ed1c60a64d854854f77f88ba12410cbd76bb8fd02da05d671fdf1098405405c82384fe19d750eefad8
|
@@ -15,12 +15,18 @@ module ActiveRecordSurvey
|
|
15
15
|
# Two instance_nodes on the same node for this instance
|
16
16
|
if self.instance.instance_nodes.select { |i|
|
17
17
|
# Two votes share a parent (this means a question has two answers for this instance)
|
18
|
-
(i.node.node_maps.collect { |j|
|
18
|
+
(i.node.node_maps.collect { |j|
|
19
|
+
j.parent
|
20
|
+
} & self.node.node_maps.collect { |j|
|
21
|
+
j.parent
|
22
|
+
}).length > 0
|
19
23
|
}.length > 1
|
20
24
|
instance_node.errors[:base] << "DUPLICATE_PATH"
|
21
25
|
end
|
22
26
|
|
23
|
-
|
27
|
+
if !self.node.validate_instance_node(self)
|
28
|
+
instance_node.errors[:base] << "INVALID"
|
29
|
+
end
|
24
30
|
end
|
25
31
|
end
|
26
32
|
end
|
@@ -7,5 +7,13 @@ module ActiveRecordSurvey
|
|
7
7
|
super &&
|
8
8
|
!instance_node.value.to_s.match(/^[0|1]$/).nil?
|
9
9
|
end
|
10
|
+
|
11
|
+
# Boolean answers are considered answered if they have a value of "1"
|
12
|
+
def is_answered_for_instance?(instance)
|
13
|
+
if instance_node = self.instance_node_for_instance(instance)
|
14
|
+
# Instance node is answered "1"
|
15
|
+
(instance_node.value.to_i === 1)
|
16
|
+
end
|
17
|
+
end
|
10
18
|
end
|
11
19
|
end
|
@@ -1,4 +1,12 @@
|
|
1
1
|
module ActiveRecordSurvey
|
2
2
|
class Node::Answer < Node
|
3
|
+
# Answer nodes are valid if their questions are valid!
|
4
|
+
# Validate this node against an instance
|
5
|
+
def validate_node(instance)
|
6
|
+
# Ensure each parent node to this node (the goal here is to hit a question node) is valid
|
7
|
+
!self.node_maps.collect { |node_map|
|
8
|
+
node_map.parent.node.validate_node(instance)
|
9
|
+
}.include?(false)
|
10
|
+
end
|
3
11
|
end
|
4
12
|
end
|
@@ -2,12 +2,48 @@ module ActiveRecordSurvey
|
|
2
2
|
class Node < ::ActiveRecord::Base
|
3
3
|
self.table_name = "active_record_survey_nodes"
|
4
4
|
has_many :node_maps, :class_name => "ActiveRecordSurvey::NodeMap", :foreign_key => :active_record_survey_node_id
|
5
|
-
has_many :node_validations, :class_name => "ActiveRecordSurvey::NodeValidation", :foreign_key => :active_record_survey_node_id
|
5
|
+
has_many :node_validations, :class_name => "ActiveRecordSurvey::NodeValidation", :foreign_key => :active_record_survey_node_id, autosave: true
|
6
|
+
has_many :instance_nodes, :class_name => "ActiveRecordSurvey::InstanceNode", :foreign_key => :active_record_survey_node_id
|
6
7
|
|
7
|
-
#
|
8
|
+
# The instance_node recorded for the passed instance for this node
|
9
|
+
def instance_node_for_instance(instance)
|
10
|
+
instance.instance_nodes.select { |instance_node|
|
11
|
+
(instance_node.node === self)
|
12
|
+
}.first
|
13
|
+
end
|
14
|
+
|
15
|
+
# Whether this node has an answer recorded the instance
|
16
|
+
def has_instance_node_for_instance?(instance)
|
17
|
+
!self.instance_node_for_instance(instance).nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
# Whether considered answered for instance
|
21
|
+
#
|
22
|
+
# Is answered is a little different than has_answer
|
23
|
+
# Is answered is answer type specific, as what constitutes "answered" changes depending on
|
24
|
+
# the question type asked (e.g. boolean is answered if "1")
|
25
|
+
#
|
26
|
+
# Each specific answer type should override this method if they have special criteria for answered
|
27
|
+
#
|
28
|
+
# default - if instance node exists, answered
|
29
|
+
def is_answered_for_instance?(instance)
|
30
|
+
self.has_instance_node_for_instance?(instance)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Run all validations applied to this node
|
8
34
|
def validate_instance_node(instance_node)
|
35
|
+
# UGH - so bsaically this validation doesn't know about the non-saved validation..
|
36
|
+
#puts "Valdating #{self.id} - #{self.text} - total validations are - #{self.node_validations(true).length}"
|
9
37
|
!self.node_validations.collect { |node_validation|
|
10
38
|
node_validation.validate_instance_node(instance_node, self)
|
39
|
+
}.include?(false) &&
|
40
|
+
!self.node_maps.collect { |node_map|
|
41
|
+
if node_map.parent
|
42
|
+
node_map.parent.node.validate_instance_node(instance_node)
|
43
|
+
# Hit top node
|
44
|
+
else
|
45
|
+
true
|
46
|
+
end
|
11
47
|
}.include?(false)
|
12
48
|
end
|
13
49
|
|
@@ -22,5 +22,16 @@ module ActiveRecordSurvey
|
|
22
22
|
}
|
23
23
|
}
|
24
24
|
end
|
25
|
+
|
26
|
+
# Gets all the child nodes until one is not an ancestor of klass
|
27
|
+
def children_until_node_not_ancestor_of(klass)
|
28
|
+
if !self.node.class.ancestors.include?(klass)
|
29
|
+
return []
|
30
|
+
end
|
31
|
+
|
32
|
+
[self] + self.children.collect { |i|
|
33
|
+
i.children_until_node_not_ancestor_of(klass)
|
34
|
+
}
|
35
|
+
end
|
25
36
|
end
|
26
37
|
end
|
@@ -2,9 +2,28 @@ module ActiveRecordSurvey
|
|
2
2
|
# Ensure the a maximum number of answers are made
|
3
3
|
class NodeValidation::MaximumAnswer < NodeValidation
|
4
4
|
# Validate the instance_node to ensure a maximum number of answers are made
|
5
|
-
def validate_instance_node(instance_node,
|
6
|
-
|
7
|
-
|
5
|
+
def validate_instance_node(instance_node, question_node = nil)
|
6
|
+
#puts "-------------------------------------------"
|
7
|
+
#puts "runnin min answer validation"
|
8
|
+
|
9
|
+
# Only makes sense for questions to have minimum answers
|
10
|
+
if !question_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
|
11
|
+
return false
|
12
|
+
end
|
13
|
+
|
14
|
+
instance = instance_node.instance
|
15
|
+
|
16
|
+
# Go through the node_map of this node
|
17
|
+
total_answered = question_node.node_maps.collect { |question_node_map|
|
18
|
+
# Get all children until a childs node isn't an answer
|
19
|
+
question_node_map.children.collect { |i|
|
20
|
+
i.children_until_node_not_ancestor_of(::ActiveRecordSurvey::Node::Answer)
|
21
|
+
}.flatten.collect { |i|
|
22
|
+
i.node.is_answered_for_instance?(instance)
|
23
|
+
}
|
24
|
+
}.flatten.select { |i| i }.count
|
25
|
+
|
26
|
+
total_answered <= self.value.to_i
|
8
27
|
end
|
9
28
|
end
|
10
29
|
end
|
@@ -2,9 +2,28 @@ module ActiveRecordSurvey
|
|
2
2
|
# Ensure the a minimum number of answers are made
|
3
3
|
class NodeValidation::MinimumAnswer < NodeValidation
|
4
4
|
# Validate the instance_node to ensure a minimum number of answers are made
|
5
|
-
def validate_instance_node(instance_node,
|
6
|
-
|
7
|
-
|
5
|
+
def validate_instance_node(instance_node, question_node = nil)
|
6
|
+
#puts "-------------------------------------------"
|
7
|
+
#puts "runnin min answer validation"
|
8
|
+
|
9
|
+
# Only makes sense for questions to have minimum answers
|
10
|
+
if !question_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
|
11
|
+
return false
|
12
|
+
end
|
13
|
+
|
14
|
+
instance = instance_node.instance
|
15
|
+
|
16
|
+
# Go through the node_map of this node
|
17
|
+
total_answered = question_node.node_maps.collect { |question_node_map|
|
18
|
+
# Get all children until a childs node isn't an answer
|
19
|
+
question_node_map.children.collect { |i|
|
20
|
+
i.children_until_node_not_ancestor_of(::ActiveRecordSurvey::Node::Answer)
|
21
|
+
}.flatten.collect { |i|
|
22
|
+
i.node.is_answered_for_instance?(instance)
|
23
|
+
}
|
24
|
+
}.flatten.select { |i| i }.count
|
25
|
+
|
26
|
+
total_answered >= self.value.to_i
|
8
27
|
end
|
9
28
|
end
|
10
29
|
end
|
@@ -5,8 +5,12 @@ module ActiveRecordSurvey
|
|
5
5
|
belongs_to :node, :class_name => "ActiveRecordSurvey::Node", :foreign_key => :active_record_survey_node_id
|
6
6
|
|
7
7
|
# By default everything is valid! WOOO!
|
8
|
-
def validate_instance_node(instance_node
|
8
|
+
def validate_instance_node(instance_node)
|
9
9
|
true
|
10
10
|
end
|
11
|
+
|
12
|
+
def validate_node(instance_node, node)
|
13
|
+
#code
|
14
|
+
end
|
11
15
|
end
|
12
16
|
end
|
@@ -1,18 +1,31 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe ActiveRecordSurvey::Node::Answer::Boolean do
|
3
|
+
describe ActiveRecordSurvey::Node::Answer::Boolean, :focus => true do
|
4
4
|
describe 'a boolean survey is' do
|
5
5
|
before(:all) do
|
6
6
|
@survey = ActiveRecordSurvey::Survey.new
|
7
7
|
|
8
|
-
@q1 = ActiveRecordSurvey::Node::Question.new(:text => "Please select
|
8
|
+
@q1 = ActiveRecordSurvey::Node::Question.new(:text => "Please select two")
|
9
9
|
@q1_a1 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Dog")
|
10
10
|
@q1_a2 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Cat")
|
11
11
|
@q1_a3 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Mouse")
|
12
|
+
@q1_a4 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Tiger")
|
13
|
+
@q1_a5 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Bear")
|
12
14
|
|
13
15
|
nodes = @survey.build_question(@q1, [@q1_a1])
|
14
16
|
nodes = @survey.build_question(@q1_a2, [], nodes[1])
|
15
17
|
nodes = @survey.build_question(@q1_a3, [], nodes[0])
|
18
|
+
nodes = @survey.build_question(@q1_a4, [], nodes[0])
|
19
|
+
nodes = @survey.build_question(@q1_a5, [], nodes[0])
|
20
|
+
|
21
|
+
@q1.node_validations << ActiveRecordSurvey::NodeValidation::MinimumAnswer.new(
|
22
|
+
:node => @q1,
|
23
|
+
:value => 1 # min 1 of the 3 answers must be "answered"
|
24
|
+
)
|
25
|
+
@q1.node_validations << ActiveRecordSurvey::NodeValidation::MaximumAnswer.new(
|
26
|
+
:node => @q1,
|
27
|
+
:value => 3 # max 2 of the 3 answers must be "answered"
|
28
|
+
)
|
16
29
|
|
17
30
|
@survey.save
|
18
31
|
end
|
@@ -37,6 +50,11 @@ describe ActiveRecordSurvey::Node::Answer::Boolean do
|
|
37
50
|
:node => @q1_a1,
|
38
51
|
:value => 0
|
39
52
|
)
|
53
|
+
instance.instance_nodes.build(
|
54
|
+
:instance => instance,
|
55
|
+
:node => @q1_a2,
|
56
|
+
:value => 1
|
57
|
+
)
|
40
58
|
instance.save
|
41
59
|
|
42
60
|
expect(instance.valid?).to be(true)
|
@@ -94,40 +112,122 @@ describe ActiveRecordSurvey::Node::Answer::Boolean do
|
|
94
112
|
describe ActiveRecordSurvey::NodeValidation::MinimumAnswer do
|
95
113
|
describe 'valid when' do
|
96
114
|
it 'has a value greater than the minimum' do
|
97
|
-
@q1.node_validations << ActiveRecordSurvey::NodeValidation::MinimumAnswer.new(
|
98
|
-
:node => @q1,
|
99
|
-
:value => 2 # 2 of the 3 answers must be "answered"
|
100
|
-
)
|
101
115
|
instance = ActiveRecordSurvey::Instance.new(:survey => @survey)
|
102
116
|
instance.instance_nodes.build(
|
103
117
|
:instance => instance,
|
104
118
|
:node => @q1_a1,
|
105
|
-
:value =>
|
119
|
+
:value => 1,
|
120
|
+
)
|
121
|
+
instance.instance_nodes.build(
|
122
|
+
:instance => instance,
|
123
|
+
:node => @q1_a2,
|
124
|
+
:value => 0,
|
125
|
+
)
|
126
|
+
instance.instance_nodes.build(
|
127
|
+
:instance => instance,
|
128
|
+
:node => @q1_a3,
|
129
|
+
:value => 1,
|
106
130
|
)
|
107
131
|
instance.save
|
108
132
|
|
109
|
-
|
133
|
+
expect(instance.valid?).to be(true)
|
110
134
|
end
|
111
135
|
end
|
112
|
-
|
136
|
+
|
113
137
|
describe 'invalid when' do
|
114
138
|
it 'has a value less than the minimum' do
|
115
|
-
|
139
|
+
instance = ActiveRecordSurvey::Instance.new(:survey => @survey)
|
140
|
+
instance.instance_nodes.build(
|
141
|
+
:instance => instance,
|
116
142
|
:node => @q1_a1,
|
117
|
-
:value =>
|
143
|
+
:value => 0,
|
118
144
|
)
|
145
|
+
instance.instance_nodes.build(
|
146
|
+
:instance => instance,
|
147
|
+
:node => @q1_a2,
|
148
|
+
:value => 0,
|
149
|
+
)
|
150
|
+
instance.instance_nodes.build(
|
151
|
+
:instance => instance,
|
152
|
+
:node => @q1_a3,
|
153
|
+
:value => 0,
|
154
|
+
)
|
155
|
+
instance.save
|
156
|
+
|
157
|
+
expect(instance.valid?).to be(false)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
describe ActiveRecordSurvey::NodeValidation::MaximumAnswer do
|
164
|
+
describe 'valid when' do
|
165
|
+
it 'has a value less than the maximum' do
|
119
166
|
instance = ActiveRecordSurvey::Instance.new(:survey => @survey)
|
120
167
|
instance.instance_nodes.build(
|
121
168
|
:instance => instance,
|
122
169
|
:node => @q1_a1,
|
123
|
-
:value =>
|
170
|
+
:value => 1,
|
171
|
+
)
|
172
|
+
instance.instance_nodes.build(
|
173
|
+
:instance => instance,
|
174
|
+
:node => @q1_a2,
|
175
|
+
:value => 0,
|
176
|
+
)
|
177
|
+
instance.instance_nodes.build(
|
178
|
+
:instance => instance,
|
179
|
+
:node => @q1_a3,
|
180
|
+
:value => 1,
|
181
|
+
)
|
182
|
+
instance.instance_nodes.build(
|
183
|
+
:instance => instance,
|
184
|
+
:node => @q1_a4,
|
185
|
+
:value => 1,
|
186
|
+
)
|
187
|
+
instance.instance_nodes.build(
|
188
|
+
:instance => instance,
|
189
|
+
:node => @q1_a5,
|
190
|
+
:value => 0,
|
124
191
|
)
|
125
192
|
instance.save
|
193
|
+
|
194
|
+
expect(instance.valid?).to be(true)
|
195
|
+
end
|
196
|
+
end
|
126
197
|
|
198
|
+
describe 'invalid when' do
|
199
|
+
it 'has a value greater than the maximum' do
|
200
|
+
instance = ActiveRecordSurvey::Instance.new(:survey => @survey)
|
201
|
+
instance.instance_nodes.build(
|
202
|
+
:instance => instance,
|
203
|
+
:node => @q1_a1,
|
204
|
+
:value => 1,
|
205
|
+
)
|
206
|
+
instance.instance_nodes.build(
|
207
|
+
:instance => instance,
|
208
|
+
:node => @q1_a2,
|
209
|
+
:value => 1,
|
210
|
+
)
|
211
|
+
instance.instance_nodes.build(
|
212
|
+
:instance => instance,
|
213
|
+
:node => @q1_a3,
|
214
|
+
:value => 1,
|
215
|
+
)
|
216
|
+
instance.instance_nodes.build(
|
217
|
+
:instance => instance,
|
218
|
+
:node => @q1_a4,
|
219
|
+
:value => 1,
|
220
|
+
)
|
221
|
+
instance.instance_nodes.build(
|
222
|
+
:instance => instance,
|
223
|
+
:node => @q1_a5,
|
224
|
+
:value => 1,
|
225
|
+
)
|
226
|
+
instance.save
|
227
|
+
|
127
228
|
expect(instance.valid?).to be(false)
|
128
229
|
end
|
129
230
|
end
|
130
|
-
=end
|
131
231
|
end
|
132
232
|
end
|
133
233
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_survey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Butch Marshall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|