active_record_survey 0.1.35 → 0.1.36

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e024c72de4b41b4e3937d465726d0110cadbcf83
4
- data.tar.gz: 41352a433cb8b8a6b8f0d8779c7ce8ced446cc4a
3
+ metadata.gz: be07fe6de1d3387ccd71f4c56ea9e33535baf95d
4
+ data.tar.gz: 8a24d9f1c4459a1f2131b28782dbc035ccbace2a
5
5
  SHA512:
6
- metadata.gz: 6f70aea6ac4dd79b3ff9e6b6b97096ca52ea839d6241b39aaef8740ad5ec91d1f9ce18fa7acd5fe5ce7ff5db1657b10586b2effa4fa1a1c7a0f8fca3d89b65a5
7
- data.tar.gz: 77f86f2a2b516981e85cff63cd97bd2fb570cf7014c241894774c6c5a7ff0330fcbcbf226d93b1b02215e40b4b54ffc1c9f26450134c55b46843b93addcfb789
6
+ metadata.gz: 7a533e0173ba238d96430fe78348414cb76249abfd568cc4c6f920d745d920ddc3ea3b12462bb2d4577def1b4d8efefed0ccd2b702c49f9e4c3a822a8f4fa779
7
+ data.tar.gz: 13cd48140d0a0050e487e5a615afa3040b19763268a926db3d93e7758c726f261866f14aa21b3970893508aefadb429e9c47460476c5400fa6c6107ea54aa56d
data/README.md CHANGED
@@ -12,6 +12,10 @@ The goal is to give a simple interface for creating surveys and validating the a
12
12
  Release Notes
13
13
  ============
14
14
 
15
+ **0.1.36**
16
+ - `ActiveRecordSurvey::Node::Answer#build_link` and `ActiveRecordSurvey::Node::Answer#remove_link` moved to `ActiveRecordSurvey::Node` so that questions can directly follow one another without answers
17
+ - Implemented `ActiveRecordSurvey::Node::Question#next_questions` to return all questions that follow either directly or through answers
18
+
15
19
  **0.1.33**
16
20
  - `ActiveRecordSurvey::Node::Answer#sibling_index` method for setting position as well
17
21
 
@@ -3,7 +3,6 @@ module ActiveRecordSurvey
3
3
  module Chained
4
4
  module ClassMethods
5
5
  def self.extended(base)
6
- base.before_destroy :before_destroy_rebuild_node_map, prepend: true # prepend is important! otherwise dependent: :destroy on node<->node_map relation is executed first and no records!
7
6
  end
8
7
  end
9
8
 
@@ -123,21 +122,6 @@ module ActiveRecordSurvey
123
122
  end
124
123
  }
125
124
  end
126
-
127
- private
128
- # Before a node is destroyed, will re-build the node_map links from parent to child if they exist
129
- def before_destroy_rebuild_node_map
130
-
131
- # All the node_maps from this node
132
- self.survey.node_maps.select { |i|
133
- i.node == self
134
- }.each { |node_map|
135
- # Remap all of this nodes children to the parent
136
- node_map.children.each { |child|
137
- node_map.parent.children << child
138
- }
139
- }
140
- end
141
125
  end
142
126
  end
143
127
  end
@@ -50,89 +50,12 @@ module ActiveRecordSurvey
50
50
  return nil
51
51
  end
52
52
 
53
- # Removes the link
54
- def remove_link
55
- # not linked to a question - nothing to remove!
56
- return true if (question = self.next_question).nil?
57
-
58
- count = 0
59
- to_remove = []
60
- self.survey.node_maps.each { |node_map|
61
- if node_map.node == question
62
- if count > 0
63
- to_remove.concat(node_map.self_and_descendants)
64
- else
65
- node_map.parent = nil
66
- end
67
- count = count + 1
68
- end
69
-
70
- if node_map.node == self
71
- node_map.children = []
72
- end
73
- }
74
- self.survey.node_maps.each { |node_map|
75
- if to_remove.include?(node_map)
76
- node_map.parent = nil
77
- node_map.mark_for_destruction
78
- end
79
- }
80
- end
81
-
82
- # Build a link from this node to another node
83
- # Building a link actually needs to throw off a whole new clone of all children nodes
84
53
  def build_link(to_node)
85
- # build_link only accepts a to_node that inherits from Question
86
- if !to_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
87
- raise ArgumentError.new "to_node must inherit from ::ActiveRecordSurvey::Node::Question"
88
- end
89
-
90
54
  if self.question.nil?
91
55
  raise ArgumentError.new "A question is required before calling #build_link"
92
56
  end
93
57
 
94
- if self.survey.nil?
95
- raise ArgumentError.new "A survey is required before calling #build_link"
96
- end
97
-
98
- from_node_maps = self.survey.node_maps.select { |i| i.node == self && !i.marked_for_destruction? }
99
-
100
- # Answer has already got a question - throw error
101
- if from_node_maps.select { |i|
102
- i.children.length === 0
103
- }.length === 0
104
- raise RuntimeError.new "This answer has already been linked"
105
- end
106
-
107
- # Because we need something to clone - filter this further below
108
- to_node_maps = self.survey.node_maps.select { |i| i.node == to_node && !i.marked_for_destruction? }
109
-
110
- if to_node_maps.first.nil?
111
- to_node_maps << self.survey.node_maps.build(:survey => self.survey, :node => to_node)
112
- end
113
-
114
- # Ensure we can through each possible path of getting to this answer
115
- to_node_map = to_node_maps.first
116
- to_node_map.survey = self.survey # required due to voodoo - we want to use the same survey with the same object_id
117
-
118
- # We only want node maps that aren't linked somewhere
119
- to_node_maps = to_node_maps.select { |i| i.parent.nil? }
120
- while to_node_maps.length < from_node_maps.length do
121
- to_node_maps.push(to_node_map.recursive_clone)
122
- end
123
-
124
- # Link unused node_maps to the new parents
125
- from_node_maps.each_with_index { |from_node_map, index|
126
- from_node_map.children << to_node_maps[index]
127
- }
128
-
129
- # Ensure no infinite loops were created
130
- from_node_maps.each { |node_map|
131
- # There is a path from Q -> A that is a loop
132
- if node_map.has_infinite_loop?
133
- raise RuntimeError.new "Infinite loop detected"
134
- end
135
- }
58
+ super(to_node)
136
59
  end
137
60
 
138
61
  # Gets index in sibling relationship
@@ -25,5 +25,26 @@ module ActiveRecordSurvey
25
25
  # Answers actually define how they're built off the parent node
26
26
  answer_node.send(:build_answer, self)
27
27
  end
28
+
29
+ # Returns the questions that follows this question (either directly or via its answers)
30
+ def next_questions
31
+ list = []
32
+
33
+ if question_node_map = self.survey.node_maps.select { |i|
34
+ i.node == self && !i.marked_for_destruction?
35
+ }.first
36
+ question_node_map.children.each { |child|
37
+ if !child.node.nil? && !child.marked_for_destruction?
38
+ if child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
39
+ list << child.node
40
+ elsif child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
41
+ list << child.node.next_question
42
+ end
43
+ end
44
+ }
45
+ end
46
+
47
+ list.compact.uniq
48
+ end
28
49
  end
29
50
  end
@@ -6,6 +6,8 @@ module ActiveRecordSurvey
6
6
  has_many :node_validations, :class_name => "ActiveRecordSurvey::NodeValidation", :foreign_key => :active_record_survey_node_id, autosave: true, dependent: :destroy
7
7
  has_many :instance_nodes, :class_name => "ActiveRecordSurvey::InstanceNode", :foreign_key => :active_record_survey_node_id
8
8
 
9
+ before_destroy :before_destroy_rebuild_node_map, prepend: true # prepend is important! otherwise dependent: :destroy on node<->node_map relation is executed first and no records!
10
+
9
11
  # All the answer nodes that follow from this node
10
12
  def answers
11
13
  self.survey.node_maps.select { |i|
@@ -113,5 +115,102 @@ module ActiveRecordSurvey
113
115
  # If recursion reports back to have at least one valid path to root
114
116
  paths.include?(true)
115
117
  end
118
+
119
+ # Removes the node_map link
120
+ def remove_link
121
+ # not linked to a question - nothing to remove!
122
+ return true if (question = self.next_question).nil?
123
+
124
+ count = 0
125
+ to_remove = []
126
+ self.survey.node_maps.each { |node_map|
127
+ if node_map.node == question
128
+ if count > 0
129
+ to_remove.concat(node_map.self_and_descendants)
130
+ else
131
+ node_map.parent = nil
132
+ end
133
+ count = count + 1
134
+ end
135
+
136
+ if node_map.node == self
137
+ node_map.children = []
138
+ end
139
+ }
140
+ self.survey.node_maps.each { |node_map|
141
+ if to_remove.include?(node_map)
142
+ node_map.parent = nil
143
+ node_map.mark_for_destruction
144
+ end
145
+ }
146
+ end
147
+
148
+ # Build a link from this node to another node
149
+ # Building a link actually needs to throw off a whole new clone of all children nodes
150
+ def build_link(to_node)
151
+ # build_link only accepts a to_node that inherits from Question
152
+ if !to_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
153
+ raise ArgumentError.new "to_node must inherit from ::ActiveRecordSurvey::Node::Question"
154
+ end
155
+
156
+ if self.survey.nil?
157
+ raise ArgumentError.new "A survey is required before calling #build_link"
158
+ end
159
+
160
+ from_node_maps = self.survey.node_maps.select { |i| i.node == self && !i.marked_for_destruction? }
161
+
162
+ # Answer has already got a question - throw error
163
+ if from_node_maps.select { |i|
164
+ i.children.length === 0
165
+ }.length === 0
166
+ raise RuntimeError.new "This node has already been linked"
167
+ end
168
+
169
+ # Because we need something to clone - filter this further below
170
+ to_node_maps = self.survey.node_maps.select { |i| i.node == to_node && !i.marked_for_destruction? }
171
+
172
+ if to_node_maps.first.nil?
173
+ to_node_maps << self.survey.node_maps.build(:survey => self.survey, :node => to_node)
174
+ end
175
+
176
+ # Ensure we can through each possible path of getting to this answer
177
+ to_node_map = to_node_maps.first
178
+ to_node_map.survey = self.survey # required due to voodoo - we want to use the same survey with the same object_id
179
+
180
+ # We only want node maps that aren't linked somewhere
181
+ to_node_maps = to_node_maps.select { |i| i.parent.nil? }
182
+ while to_node_maps.length < from_node_maps.length do
183
+ to_node_maps.push(to_node_map.recursive_clone)
184
+ end
185
+
186
+ # Link unused node_maps to the new parents
187
+ from_node_maps.each_with_index { |from_node_map, index|
188
+ from_node_map.children << to_node_maps[index]
189
+ }
190
+
191
+ # Ensure no infinite loops were created
192
+ from_node_maps.each { |node_map|
193
+ # There is a path from Q -> A that is a loop
194
+ if node_map.has_infinite_loop?
195
+ raise RuntimeError.new "Infinite loop detected"
196
+ end
197
+ }
198
+ end
199
+
200
+ private
201
+ # Before a node is destroyed, will re-build the node_map links from parent to child if they exist
202
+ def before_destroy_rebuild_node_map
203
+ # All the node_maps from this node
204
+ self.survey.node_maps.select { |i|
205
+ i.node == self
206
+ }.each { |node_map|
207
+ # Remap all of this nodes children to the parent
208
+ node_map.children.each { |child|
209
+ node_map.parent.children << child
210
+ }
211
+ }
212
+
213
+ true
214
+ end
116
215
  end
117
216
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordSurvey
2
- VERSION = "0.1.35"
2
+ VERSION = "0.1.36"
3
3
  end
@@ -1,6 +1,88 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveRecordSurvey::Node::Question, :question_spec => true do
4
+ describe "#next_questions" do
5
+ it "should return an array of all questions following a question, whether they have answers or not" do
6
+ @survey = ActiveRecordSurvey::Survey.new()
7
+
8
+ @q1 = ActiveRecordSurvey::Node::Question.new(:text => "Question #1", :survey => @survey)
9
+ @q1_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 Answer #1")
10
+ @q1_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 Answer #2")
11
+ @q1_a3 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 Answer #3")
12
+ @q1_a4 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 Answer #4")
13
+ @q1.build_answer(@q1_a1)
14
+ @q1.build_answer(@q1_a2)
15
+ @q1.build_answer(@q1_a3)
16
+ @q1.build_answer(@q1_a4)
17
+
18
+ @q2 = ActiveRecordSurvey::Node::Question.new(:text => "Question #2", :survey => @survey)
19
+ @q2_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q2 Answer #1")
20
+ @q2_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q2 Answer #2")
21
+ @q2.build_answer(@q2_a1)
22
+ @q2.build_answer(@q2_a2)
23
+
24
+ @q3 = ActiveRecordSurvey::Node::Question.new(:text => "Question #3", :survey => @survey)
25
+ @q3_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q3 Answer #1")
26
+ @q3_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q3 Answer #2")
27
+ @q3.build_answer(@q3_a1)
28
+ @q3.build_answer(@q3_a2)
29
+
30
+ @q4 = ActiveRecordSurvey::Node::Question.new(:text => "Question #4", :survey => @survey)
31
+ @q4_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q4 Answer #1")
32
+ @q4_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q4 Answer #2")
33
+ @q4.build_answer(@q4_a1)
34
+ @q4.build_answer(@q4_a2)
35
+
36
+ @q5 = ActiveRecordSurvey::Node::Question.new(:text => "Question #5", :survey => @survey)
37
+
38
+ @q6 = ActiveRecordSurvey::Node::Question.new(:text => "Question #6", :survey => @survey)
39
+ @q6_a1 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Q6 Answer #1")
40
+ @q6_a2 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "Q6 Answer #2")
41
+ @q6.build_answer(@q6_a1)
42
+ @q6.build_answer(@q6_a2)
43
+
44
+ @q7 = ActiveRecordSurvey::Node::Question.new(:text => "Question #7", :survey => @survey)
45
+
46
+ # Link up Q1
47
+ @q1_a1.build_link(@q2)
48
+ @q1_a2.build_link(@q3)
49
+ @q1_a3.build_link(@q4)
50
+
51
+ # Link up Q2
52
+ @q2_a1.build_link(@q4)
53
+ @q2_a2.build_link(@q3)
54
+
55
+ # Link up Q3
56
+ @q3_a1.build_link(@q4)
57
+ @q3_a2.build_link(@q4)
58
+
59
+ # Link up Q1A4 -> Q5
60
+ @q1_a4.build_link(@q5)
61
+
62
+ # Link up Q5 -> Q6
63
+ @q5.build_link(@q6)
64
+
65
+ # Link up Q6 -> Q7
66
+ @q6_a2.build_link(@q7)
67
+
68
+ @survey.save
69
+
70
+ q1_next_questions = @q1.next_questions
71
+ q2_next_questions = @q2.next_questions
72
+ q3_next_questions = @q3.next_questions
73
+ q4_next_questions = @q4.next_questions
74
+ q5_next_questions = @q5.next_questions
75
+ q6_next_questions = @q6.next_questions
76
+
77
+ expect(q1_next_questions.length).to eq(4)
78
+ expect(q2_next_questions.length).to eq(2)
79
+ expect(q3_next_questions.length).to eq(1)
80
+ expect(q4_next_questions.length).to eq(0)
81
+ expect(q5_next_questions.length).to eq(1)
82
+ expect(q6_next_questions.length).to eq(1)
83
+ end
84
+ end
85
+
4
86
  describe "#build_answer" do
5
87
  before(:each) do
6
88
  @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.35
4
+ version: 0.1.36
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-03-26 00:00:00.000000000 Z
11
+ date: 2016-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord