active_record_survey 0.1.43 → 0.1.44
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.
- checksums.yaml +4 -4
- data/lib/active_record_survey/node/answer/chained.rb +39 -8
- data/lib/active_record_survey/node/answer.rb +31 -2
- data/lib/active_record_survey/node/question.rb +52 -0
- data/lib/active_record_survey/node.rb +21 -0
- data/lib/active_record_survey/version.rb +1 -1
- data/spec/active_record_survey/node/question_spec.rb +109 -0
- data/spec/active_record_survey/survey_spec.rb +1 -1
- 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: f946ba156789de15394c69e91b562a102b046b57
|
4
|
+
data.tar.gz: f10f2b482a0522dff5028172205e69c56762b072
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 043b935b0cb4a714811685febc81d6d67c7bac689dca3916f11749e292da71c7fbe7c946a01710353cf7eeb9dc980d653ef7668755207a26329ec06e3e0528dc
|
7
|
+
data.tar.gz: 00d73a743e0874b61d6387f3f1590ba69788161d06068875923e8440bca76342e8e70039a0911f0bdd3801e5fd559768d7c5f021e4ccbe8f267474386fa67df4
|
@@ -7,6 +7,7 @@ module ActiveRecordSurvey
|
|
7
7
|
end
|
8
8
|
|
9
9
|
module InstanceMethods
|
10
|
+
|
10
11
|
# Gets index relative to other chained answers
|
11
12
|
def sibling_index
|
12
13
|
if node_map = self.survey.node_maps.select { |i|
|
@@ -18,6 +19,23 @@ module ActiveRecordSurvey
|
|
18
19
|
return 0
|
19
20
|
end
|
20
21
|
|
22
|
+
# Chain nodes are different
|
23
|
+
# They must also see if this answer linked to subsequent answers, and re-build the link
|
24
|
+
def remove_answer(question_node)
|
25
|
+
self.survey = question_node.survey
|
26
|
+
|
27
|
+
# The node from answer from the parent question
|
28
|
+
self.survey.node_maps.reverse.select { |i|
|
29
|
+
i.node == self && !i.marked_for_destruction?
|
30
|
+
}.each { |answer_node_map|
|
31
|
+
answer_node_map.children.each { |child|
|
32
|
+
answer_node_map.parent.children << child
|
33
|
+
}
|
34
|
+
|
35
|
+
answer_node_map.send((answer_node_map.new_record?)? :destroy : :mark_for_destruction )
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
21
39
|
# Chain nodes are different - they must find the final answer node added and add to it
|
22
40
|
# They must also see if the final answer node then points somewhere else - and fix the links on that
|
23
41
|
def build_answer(question_node)
|
@@ -25,6 +43,14 @@ module ActiveRecordSurvey
|
|
25
43
|
|
26
44
|
question_node_maps = self.survey.node_maps.select { |i| i.node == question_node && !i.marked_for_destruction? }
|
27
45
|
|
46
|
+
answer_node_maps = self.survey.node_maps.select { |i|
|
47
|
+
i.node == self && i.parent.nil?
|
48
|
+
}.collect { |i|
|
49
|
+
i.survey = self.survey
|
50
|
+
|
51
|
+
i
|
52
|
+
}
|
53
|
+
|
28
54
|
# No node_maps exist yet from this question
|
29
55
|
if question_node_maps.length === 0
|
30
56
|
# Build our first node-map
|
@@ -36,18 +62,23 @@ module ActiveRecordSurvey
|
|
36
62
|
# Each instance of this question needs the answer hung from it
|
37
63
|
self.survey.node_maps.select { |i|
|
38
64
|
i.node == last_answer_in_chain
|
39
|
-
}.
|
40
|
-
|
41
|
-
|
42
|
-
|
65
|
+
}.each_with_index { |node_map, index|
|
66
|
+
if answer_node_maps[index]
|
67
|
+
new_node_map = answer_node_maps[index]
|
68
|
+
else
|
69
|
+
new_node_map = self.survey.node_maps.build(:node => self, :survey => self.survey)
|
70
|
+
end
|
43
71
|
|
44
|
-
|
72
|
+
# Hack - should fix this - why does self.survey.node_maps still think... yea somethigns not referenced right
|
73
|
+
#curr_children = self.survey.node_maps.select { |j|
|
74
|
+
# node_map.children.include?(j) && j != new_node_map
|
75
|
+
#}
|
45
76
|
|
46
77
|
node_map.children << new_node_map
|
47
78
|
|
48
|
-
curr_children.each { |c|
|
49
|
-
|
50
|
-
}
|
79
|
+
#curr_children.each { |c|
|
80
|
+
# new_node_map.children << c
|
81
|
+
#}
|
51
82
|
}
|
52
83
|
|
53
84
|
true
|
@@ -140,12 +140,35 @@ module ActiveRecordSurvey
|
|
140
140
|
end
|
141
141
|
|
142
142
|
private
|
143
|
+
# By default - answers build off the original question node
|
144
|
+
#
|
145
|
+
# This allows us to easily override the answer removal behaviour for different answer types
|
146
|
+
def remove_answer(question_node)
|
147
|
+
#self.survey = question_node.survey
|
148
|
+
|
149
|
+
# The node from answer from the parent question
|
150
|
+
self.survey.node_maps.select { |i|
|
151
|
+
!i.marked_for_destruction? &&
|
152
|
+
i.node == self && i.parent && i.parent.node === question_node
|
153
|
+
}.each { |answer_node_map|
|
154
|
+
answer_node_map.send((answer_node_map.new_record?)? :destroy : :mark_for_destruction )
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
143
158
|
# By default - answers build off the original question node
|
144
159
|
#
|
145
160
|
# This allows us to easily override the answer building behaviour for different answer types
|
146
161
|
def build_answer(question_node)
|
147
162
|
self.survey = question_node.survey
|
148
163
|
|
164
|
+
answer_node_maps = self.survey.node_maps.select { |i|
|
165
|
+
i.node == self && i.parent.nil?
|
166
|
+
}.collect { |i|
|
167
|
+
i.survey = self.survey
|
168
|
+
|
169
|
+
i
|
170
|
+
}
|
171
|
+
|
149
172
|
question_node_maps = self.survey.node_maps.select { |i| i.node == question_node && !i.marked_for_destruction? }
|
150
173
|
|
151
174
|
# No node_maps exist yet from this question
|
@@ -155,8 +178,14 @@ module ActiveRecordSurvey
|
|
155
178
|
end
|
156
179
|
|
157
180
|
# Each instance of this question needs the answer hung from it
|
158
|
-
question_node_maps.
|
159
|
-
|
181
|
+
question_node_maps.each_with_index { |question_node_map, index|
|
182
|
+
if answer_node_maps[index]
|
183
|
+
new_node_map = answer_node_maps[index]
|
184
|
+
else
|
185
|
+
new_node_map = self.survey.node_maps.build(:node => self, :survey => self.survey)
|
186
|
+
end
|
187
|
+
|
188
|
+
question_node_map.children << new_node_map
|
160
189
|
}
|
161
190
|
|
162
191
|
true
|
@@ -7,6 +7,55 @@ module ActiveRecordSurvey
|
|
7
7
|
}.include?(false)
|
8
8
|
end
|
9
9
|
|
10
|
+
# Updates the answers of this question to a different type
|
11
|
+
def update_question_type(klass)
|
12
|
+
if self.next_questions.length > 0
|
13
|
+
raise RuntimeError.new "No questions can follow when changing the question type"
|
14
|
+
end
|
15
|
+
|
16
|
+
nm = self.survey.node_maps
|
17
|
+
|
18
|
+
self.answers.collect { |answer|
|
19
|
+
nm.select { |i|
|
20
|
+
i.node == answer
|
21
|
+
}
|
22
|
+
}.flatten.uniq.collect { |answer_node_map|
|
23
|
+
answer_node_map.move_to_root
|
24
|
+
answer_node_map.survey = self.survey
|
25
|
+
|
26
|
+
answer_node_map
|
27
|
+
}.collect { |answer_node_map|
|
28
|
+
answer_node_map.node.type = klass.to_s
|
29
|
+
answer_node_map.node = answer_node_map.node.becomes(klass)
|
30
|
+
answer_node_map.node.survey = self.survey
|
31
|
+
answer_node_map.node.save
|
32
|
+
|
33
|
+
self.build_answer(answer_node_map.node)
|
34
|
+
|
35
|
+
answer_node_map
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Removes an answer
|
40
|
+
def remove_answer(answer_node)
|
41
|
+
# A survey must either be passed or already present in self.node_maps
|
42
|
+
if self.survey.nil?
|
43
|
+
raise ArgumentError.new "A survey must be passed if ActiveRecordSurvey::Node::Question is not yet added to a survey"
|
44
|
+
end
|
45
|
+
|
46
|
+
if !answer_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
|
47
|
+
raise ArgumentError.new "::ActiveRecordSurvey::Node::Answer not passed"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Cannot mix answer types
|
51
|
+
# Check if not match existing - throw error
|
52
|
+
if !self.answers.include?(answer_node)
|
53
|
+
raise ArgumentError.new "Answer not linked to question"
|
54
|
+
end
|
55
|
+
|
56
|
+
answer_node.send(:remove_answer, self)
|
57
|
+
end
|
58
|
+
|
10
59
|
# Build an answer off this node
|
11
60
|
def build_answer(answer_node)
|
12
61
|
# A survey must either be passed or already present in self.node_maps
|
@@ -34,6 +83,9 @@ module ActiveRecordSurvey
|
|
34
83
|
# Is a question
|
35
84
|
j.parent == answer_node_map.parent && j.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
|
36
85
|
}.each { |j|
|
86
|
+
answer_node_map.survey = self.survey
|
87
|
+
j.survey = self.survey
|
88
|
+
|
37
89
|
answer_node_map.children << j
|
38
90
|
}
|
39
91
|
}
|
@@ -10,6 +10,26 @@ module ActiveRecordSurvey
|
|
10
10
|
|
11
11
|
# All the answer nodes that follow from this node
|
12
12
|
def answers
|
13
|
+
#=begin
|
14
|
+
next_answer_nodes = lambda { |node, survey, list|
|
15
|
+
survey.node_maps.select { |node_map|
|
16
|
+
!node_map.parent.nil? && node_map.parent.node == node && node_map.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer) && !node_map.marked_for_destruction?
|
17
|
+
}.select { |i|
|
18
|
+
!list.include?(i.node)
|
19
|
+
}.collect { |i|
|
20
|
+
i.survey = self.survey
|
21
|
+
i.node.survey = self.survey
|
22
|
+
|
23
|
+
list << i.node
|
24
|
+
|
25
|
+
next_answer_nodes.call(i.node, survey, list)
|
26
|
+
}.flatten.uniq
|
27
|
+
|
28
|
+
list
|
29
|
+
}
|
30
|
+
next_answer_nodes.call(self, self.survey, []).flatten.uniq
|
31
|
+
#=end
|
32
|
+
=begin
|
13
33
|
self.survey.node_maps.select { |i|
|
14
34
|
i.node == self
|
15
35
|
}.collect { |i|
|
@@ -25,6 +45,7 @@ module ActiveRecordSurvey
|
|
25
45
|
i.survey = self.survey # ensure that the survey being referenced by the answers is the original survey - needed for keeping consistent node_maps between build_link and remove_link
|
26
46
|
[i] + i.answers
|
27
47
|
}.flatten.uniq
|
48
|
+
=end
|
28
49
|
end
|
29
50
|
|
30
51
|
# The instance_node recorded for the passed instance for this node
|
@@ -51,6 +51,115 @@ describe ActiveRecordSurvey::Node::Question, :question_spec => true do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
describe "#remove_answer" do
|
55
|
+
before(:each) do
|
56
|
+
@survey = ActiveRecordSurvey::Survey.new()
|
57
|
+
|
58
|
+
@q1 = ActiveRecordSurvey::Node::Question.new(:text => "Q1", :survey => @survey)
|
59
|
+
@q1_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 A1")
|
60
|
+
@q1_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 A2")
|
61
|
+
@q1.build_answer(@q1_a1)
|
62
|
+
@q1.build_answer(@q1_a2)
|
63
|
+
|
64
|
+
@q2 = ActiveRecordSurvey::Node::Question.new(:text => "Q2", :survey => @survey)
|
65
|
+
@q2_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q2 A1")
|
66
|
+
@q2_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q2 A2")
|
67
|
+
@q2.build_answer(@q2_a1)
|
68
|
+
@q2.build_answer(@q2_a2)
|
69
|
+
|
70
|
+
@q3 = ActiveRecordSurvey::Node::Question.new(:text => "Q3", :survey => @survey)
|
71
|
+
@q3_a1 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Q3 A1")
|
72
|
+
@q3_a2 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Q3 A1")
|
73
|
+
@q3.build_answer(@q3_a1)
|
74
|
+
@q3.build_answer(@q3_a2)
|
75
|
+
|
76
|
+
@survey.save
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should remove the answer for regular answers' do
|
80
|
+
expect(@q1.answers.length).to eq(2)
|
81
|
+
|
82
|
+
@q1.remove_answer(@q1_a1)
|
83
|
+
|
84
|
+
expect(@q1.answers.length).to eq(1)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should remove the answer for boolean answers' do
|
88
|
+
expect(@q3.answers.length).to eq(2)
|
89
|
+
|
90
|
+
@q3.remove_answer(@q3_a1)
|
91
|
+
|
92
|
+
@survey.save
|
93
|
+
@survey.reload
|
94
|
+
|
95
|
+
expect(@q3.answers.length).to eq(1)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should remove the answer for boolean answers, and keep full question links' do
|
99
|
+
@q3_a2.build_link(@q2)
|
100
|
+
|
101
|
+
@survey.save
|
102
|
+
@survey.reload
|
103
|
+
|
104
|
+
expect(@q3.answers.length).to eq(2)
|
105
|
+
expect(@q3.next_questions.length).to eq(1)
|
106
|
+
|
107
|
+
@q3.remove_answer(@q3_a1)
|
108
|
+
|
109
|
+
@survey.save
|
110
|
+
@survey.reload
|
111
|
+
|
112
|
+
expect(@q3.answers.length).to eq(1)
|
113
|
+
expect(@q3.next_questions.length).to eq(1)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#update_question_type" do
|
118
|
+
before(:each) do
|
119
|
+
@survey = ActiveRecordSurvey::Survey.new()
|
120
|
+
|
121
|
+
@q1 = ActiveRecordSurvey::Node::Question.new(:text => "Q1", :survey => @survey)
|
122
|
+
@q1_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 A1")
|
123
|
+
@q1_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 A2")
|
124
|
+
@q1.build_answer(@q1_a1)
|
125
|
+
@q1.build_answer(@q1_a2)
|
126
|
+
|
127
|
+
@q2 = ActiveRecordSurvey::Node::Question.new(:text => "Q2", :survey => @survey)
|
128
|
+
@q2_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q2 A1")
|
129
|
+
@q2.build_answer(@q2_a1)
|
130
|
+
|
131
|
+
@q3 = ActiveRecordSurvey::Node::Question.new(:text => "Q3", :survey => @survey)
|
132
|
+
@q3_a1 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Q3 A1")
|
133
|
+
@q3_a2 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Q3 A2")
|
134
|
+
@q3.build_answer(@q3_a1)
|
135
|
+
@q3.build_answer(@q3_a2)
|
136
|
+
|
137
|
+
@survey.save
|
138
|
+
end
|
139
|
+
it 'should raise exception linked to another question' do
|
140
|
+
@q1_a1.build_link(@q2)
|
141
|
+
@survey.save
|
142
|
+
|
143
|
+
expect{@q1.update_question_type(ActiveRecordSurvey::Node::Answer::Boolean)}.to raise_error(RuntimeError)
|
144
|
+
end
|
145
|
+
it 'should change ActiveRecordSurvey::Node::Answer to ActiveRecordSurvey::Node::Answer::Boolean' do
|
146
|
+
@q1.update_question_type(ActiveRecordSurvey::Node::Answer::Boolean)
|
147
|
+
expect(@survey.as_map(:no_ids => true)).to eq([{"text"=>"Q1", :type=>"ActiveRecordSurvey::Node::Question", :children=>[{"text"=>"Q1 A1", :type=>"ActiveRecordSurvey::Node::Answer::Boolean", :children=>[{"text"=>"Q1 A2", :type=>"ActiveRecordSurvey::Node::Answer::Boolean", :children=>[]}]}]}, {"text"=>"Q2", :type=>"ActiveRecordSurvey::Node::Question", :children=>[{"text"=>"Q2 A1", :type=>"ActiveRecordSurvey::Node::Answer", :children=>[]}]}, {"text"=>"Q3", :type=>"ActiveRecordSurvey::Node::Question", :children=>[{"text"=>"Q3 A1", :type=>"ActiveRecordSurvey::Node::Answer::Boolean", :children=>[{"text"=>"Q3 A2", :type=>"ActiveRecordSurvey::Node::Answer::Boolean", :children=>[]}]}]}])
|
148
|
+
expect(@q1.answers.length).to eq(2)
|
149
|
+
@q1.answers.each { |answer|
|
150
|
+
expect(answer.class).to eq(ActiveRecordSurvey::Node::Answer::Boolean)
|
151
|
+
}
|
152
|
+
end
|
153
|
+
it 'should change ActiveRecordSurvey::Node::Answer::Boolean to ActiveRecordSurvey::Node::Answer' do
|
154
|
+
@q3.update_question_type(ActiveRecordSurvey::Node::Answer)
|
155
|
+
expect(@survey.as_map(:no_ids => true)).to eq([{"text"=>"Q1", :type=>"ActiveRecordSurvey::Node::Question", :children=>[{"text"=>"Q1 A1", :type=>"ActiveRecordSurvey::Node::Answer", :children=>[]}, {"text"=>"Q1 A2", :type=>"ActiveRecordSurvey::Node::Answer", :children=>[]}]}, {"text"=>"Q2", :type=>"ActiveRecordSurvey::Node::Question", :children=>[{"text"=>"Q2 A1", :type=>"ActiveRecordSurvey::Node::Answer", :children=>[]}]}, {"text"=>"Q3", :type=>"ActiveRecordSurvey::Node::Question", :children=>[{"text"=>"Q3 A1", :type=>"ActiveRecordSurvey::Node::Answer", :children=>[]}, {"text"=>"Q3 A2", :type=>"ActiveRecordSurvey::Node::Answer", :children=>[]}]}])
|
156
|
+
expect(@q3.answers.length).to eq(2)
|
157
|
+
@q3.answers.each { |answer|
|
158
|
+
expect(answer.class).to eq(ActiveRecordSurvey::Node::Answer)
|
159
|
+
}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
54
163
|
describe "#remove_link" do
|
55
164
|
it 'should remove the link between the question and child questions or answers child questions' do
|
56
165
|
@survey = ActiveRecordSurvey::Survey.new()
|
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.44
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Butch Marshall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|