surveyor 0.9.5 → 0.9.6

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.5
1
+ 0.9.6
@@ -21,7 +21,11 @@ class Response < ActiveRecord::Base
21
21
  true
22
22
  end
23
23
 
24
- def to_s
24
+ def correct?
25
+ question.correct_answer_id.nil? or self.answer.response_class != "answer" or (question.correct_answer_id.to_i == answer_id.to_i)
26
+ end
27
+
28
+ def to_s # used in dependency_explanation_helper
25
29
  if self.answer.response_class == "answer" and self.answer_id
26
30
  return self.answer.text
27
31
  else
@@ -89,8 +89,33 @@ class ResponseSet < ActiveRecord::Base
89
89
  self.completed_at = Time.now
90
90
  end
91
91
 
92
- def has_not_answered_question?(question)
93
- self.responses.find_all_by_question_id(question.id).empty?
92
+ def correct?
93
+ responses.all?(&:correct?)
94
+ end
95
+ def correctness_hash
96
+ { :questions => @survey.sections_with_questions.map(&:questions).flatten.compact.size,
97
+ :responses => responses.compact.size,
98
+ :correct => responses.find_all(&:correct?).compact.size
99
+ }
100
+ end
101
+ def mandatory_questions_complete?
102
+ progress_hash[:triggered_mandatory] == progress_hash[:triggered_mandatory_completed]
103
+ end
104
+ def progress_hash
105
+ qs = @survey.sections_with_questions.map(&:questions).flatten
106
+ ds = dependencies(qs.map(&:id))
107
+ triggered = qs - ds.select{|d| !d.is_met?(self)}.map(&:question)
108
+ { :questions => qs.compact.size,
109
+ :triggered => triggered.compact.size,
110
+ :triggered_mandatory => triggered.select{|q| q.mandatory?}.compact.size,
111
+ :triggered_mandatory_completed => triggered.select{|q| q.mandatory? and is_answered?(q)}.compact.size
112
+ }
113
+ end
114
+ def is_answered?(question)
115
+ !is_unanswered?(question)
116
+ end
117
+ def is_unanswered?(question)
118
+ self.responses.detect{|r| r.question_id == question.id}.nil?
94
119
  end
95
120
 
96
121
  # Returns the number of response groups (count of group responses enterted) for this question group
@@ -99,7 +124,7 @@ class ResponseSet < ActiveRecord::Base
99
124
  end
100
125
 
101
126
  def unanswered_dependencies
102
- dependencies.select{|d| d.is_met?(self) and self.has_not_answered_question?(d.question)}.map(&:question)
127
+ dependencies.select{|d| d.is_met?(self) and self.is_unanswered?(d.question)}.map(&:question)
103
128
  end
104
129
 
105
130
  def all_dependencies
@@ -109,11 +134,12 @@ class ResponseSet < ActiveRecord::Base
109
134
 
110
135
  protected
111
136
 
112
- def dependencies
113
- question_ids = Question.find_all_by_survey_section_id(current_section_id).map(&:id)
137
+ def dependencies(question_ids = nil)
138
+ question_ids ||= Question.find_all_by_survey_section_id(current_section_id).map(&:id)
114
139
  depdendecy_ids = DependencyCondition.all(:conditions => {:question_id => question_ids}).map(&:dependency_id)
115
140
  Dependency.find(depdendecy_ids, :include => :dependency_conditions)
116
141
  end
142
+
117
143
  end
118
144
 
119
145
  # responses
@@ -29,7 +29,7 @@ class SurveyorGenerator < Rails::Generator::Base
29
29
  "create_response_sets", "create_responses",
30
30
  "create_dependencies", "create_dependency_conditions",
31
31
  "create_validations", "create_validation_conditions",
32
- "add_display_order_to_surveys"].each_with_index do |model, i|
32
+ "add_display_order_to_surveys", "add_correct_answer_id_to_questions"].each_with_index do |model, i|
33
33
  unless (prev_migrations = Dir.glob("db/migrate/[0-9]*_*.rb").grep(/[0-9]+_#{model}.rb$/)).empty?
34
34
  prev_migration_timestamp = prev_migrations[0].match(/([0-9]+)_#{model}.rb$/)[1]
35
35
  end
@@ -0,0 +1,9 @@
1
+ class AddCorrectAnswerIdToQuestions < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :questions, :correct_answer_id, :integer
4
+ end
5
+
6
+ def self.down
7
+ remove_column :questions, :correct_answer_id
8
+ end
9
+ end
data/spec/factories.rb CHANGED
@@ -1,42 +1,43 @@
1
1
  # http://github.com/thoughtbot/factory_girl/tree/master
2
2
 
3
3
  Factory.define :survey do |s|
4
- s.title {"Simple survey"}
5
- s.description {"A simple survey for testing"}
6
- s.access_code {"simple_survey"}
7
- s.active_at {Time.now}
8
- s.inactive_at {}
9
- s.css_url {}
4
+ s.title {"Simple survey"}
5
+ s.description {"A simple survey for testing"}
6
+ s.access_code {"simple_survey"}
7
+ s.active_at {Time.now}
8
+ s.inactive_at {}
9
+ s.css_url {}
10
10
  end
11
11
 
12
12
  Factory.sequence(:survey_section_display_order){|n| n }
13
13
 
14
14
  Factory.define :survey_section do |s|
15
15
  s.association :survey # s.survey_id {}
16
- s.title {"Demographics"}
17
- s.description {"Asking you about your personal data"}
18
- s.display_order {Factory.next :survey_section_display_order}
19
- s.reference_identifier {"demographics"}
20
- s.data_export_identifier {"demographics"}
16
+ s.title {"Demographics"}
17
+ s.description {"Asking you about your personal data"}
18
+ s.display_order {Factory.next :survey_section_display_order}
19
+ s.reference_identifier {"demographics"}
20
+ s.data_export_identifier {"demographics"}
21
21
  end
22
22
 
23
23
  Factory.sequence(:question_display_order){|n| n }
24
24
 
25
25
  Factory.define :question do |q|
26
26
  q.association :survey_section # s.survey_section_id {}
27
- q.question_group_id {}
28
- q.text {"What is your favorite color?"}
29
- q.short_text {"favorite_color"}
30
- q.help_text {"just write it in the box"}
31
- q.pick {:none}
27
+ q.question_group_id {}
28
+ q.text {"What is your favorite color?"}
29
+ q.short_text {"favorite_color"}
30
+ q.help_text {"just write it in the box"}
31
+ q.pick {:none}
32
32
  q.reference_identifier {|me| "q_#{me.object_id}"}
33
33
  q.data_export_identifier {}
34
34
  q.common_namespace {}
35
35
  q.common_identifier {}
36
- q.display_order {Factory.next :question_display_order}
37
- q.display_type {} # nil is default
38
- q.is_mandatory {false}
39
- q.display_width {}
36
+ q.display_order {Factory.next :question_display_order}
37
+ q.display_type {} # nil is default
38
+ q.is_mandatory {false}
39
+ q.display_width {}
40
+ q.correct_answer_id {nil}
40
41
  end
41
42
 
42
43
  Factory.define :question_group do |g|
@@ -55,19 +56,19 @@ Factory.sequence(:answer_display_order){|n| n }
55
56
 
56
57
  Factory.define :answer do |a|
57
58
  a.association :question # a.question_id {}
58
- a.text {"My favorite color is clear"}
59
- a.short_text {"clear"}
60
- a.help_text {"Clear is the absense of color"}
61
- a.weight {}
62
- a.response_class {"String"}
63
- a.reference_identifier {}
64
- a.data_export_identifier {}
59
+ a.text {"My favorite color is clear"}
60
+ a.short_text {"clear"}
61
+ a.help_text {"Clear is the absense of color"}
62
+ a.weight {}
63
+ a.response_class {"String"}
64
+ a.reference_identifier {}
65
+ a.data_export_identifier {}
65
66
  a.common_namespace {}
66
- a.common_identifier {}
67
- a.display_order {Factory.next :answer_display_order}
68
- a.is_exclusive {}
69
- a.hide_label {}
70
- a.display_length {}
67
+ a.common_identifier {}
68
+ a.display_order {Factory.next :answer_display_order}
69
+ a.is_exclusive {}
70
+ a.hide_label {}
71
+ a.display_length {}
71
72
  a.custom_class {}
72
73
  a.custom_renderer {}
73
74
  end
@@ -76,12 +77,12 @@ Factory.define :dependency do |d|
76
77
  # the dependent question
77
78
  d.association :question # d.question_id {}
78
79
  d.question_group_id {}
79
- d.rule {"A and B"}
80
+ d.rule {"A"}
80
81
  end
81
82
 
82
83
  Factory.define :dependency_condition do |d|
83
84
  d.association :dependency # d.dependency_id {}
84
- d.rule_key {"1"}
85
+ d.rule_key {"A"}
85
86
  # the conditional question
86
87
  d.question_id {}
87
88
  d.operator {"=="}
@@ -96,25 +97,25 @@ Factory.define :dependency_condition do |d|
96
97
  end
97
98
 
98
99
  Factory.define :response_set do |r|
99
- r.user_id {}
100
+ r.user_id {}
100
101
  r.association :survey # r.survey_id {}
101
- r.access_code {Surveyor.make_tiny_code}
102
- r.started_at {Time.now}
103
- r.completed_at {}
102
+ r.access_code {Surveyor.make_tiny_code}
103
+ r.started_at {Time.now}
104
+ r.completed_at {}
104
105
  end
105
106
 
106
107
  Factory.define :response do |r|
107
108
  r.association :response_set # r.response_set_id {}
108
- r.question_id {}
109
- r.answer_id {}
110
- r.datetime_value {}
111
- r.integer_value {}
112
- r.float_value {}
113
- r.unit {}
114
- r.text_value {}
115
- r.string_value {}
116
- r.response_other {}
117
- r.response_group {}
109
+ r.question_id {}
110
+ r.answer_id {}
111
+ r.datetime_value {}
112
+ r.integer_value {}
113
+ r.float_value {}
114
+ r.unit {}
115
+ r.text_value {}
116
+ r.string_value {}
117
+ r.response_other {}
118
+ r.response_group {}
118
119
  end
119
120
 
120
121
  Factory.define :validation do |v|
@@ -1,46 +1,24 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
- describe ResponseSet, "class methods" do
4
- before(:each) do
5
- @response_set = Factory(:response_set, :access_code => "PDQ")
6
- end
7
- it "should find a response set by response_set.access_code or return false" do
8
- ResponseSet.find_by_access_code("PDQ").should == @response_set
9
- ResponseSet.find_by_access_code("Different").should be_nil
10
- end
11
- end
12
- describe ResponseSet, "with responses" do
3
+ describe ResponseSet do
13
4
  before(:each) do
14
5
  @response_set = Factory(:response_set)
15
6
  end
16
-
17
- it "can tell you its responses" do
18
- 3.times{ |x| @response_set.responses.build }
19
- @response_set.responses.should have(3).items
7
+ it "should have a unique code with length 10 that identifies the survey" do
8
+ @response_set.access_code.should_not be_nil
9
+ @response_set.access_code.length.should == 10
20
10
  end
21
-
22
11
  it "is completable" do
23
12
  @response_set.completed_at.should be_nil
24
13
  @response_set.complete!
25
14
  @response_set.completed_at.should_not be_nil
26
15
  @response_set.completed_at.is_a?(Time).should be_true
27
16
  end
28
-
29
17
  it "does not allow completion through mass assignment" do
30
18
  @response_set.completed_at.should be_nil
31
19
  @response_set.update_attributes(:completed_at => Time.now)
32
20
  @response_set.completed_at.should be_nil
33
21
  end
34
-
35
- end
36
- describe ResponseSet, "Creating new set for user" do
37
- before(:each) do
38
- @response_set = Factory(:response_set)
39
- end
40
- it "should have a unique code with length 10 that identifies the survey" do
41
- @response_set.access_code.should_not be_nil
42
- @response_set.access_code.length.should == 10
43
- end
44
22
  end
45
23
  describe ResponseSet, "Updating the response set" do
46
24
  before(:each) do
@@ -135,4 +113,99 @@ describe ResponseSet, "with dependencies" do
135
113
  @response_set.all_dependencies[:show].should == ["question_#{@what_flavor.id}", "question_#{@what_bakery.id}"]
136
114
  end
137
115
 
116
+ end
117
+ describe ResponseSet, "as a quiz" do
118
+ before(:each) do
119
+ @survey = Factory(:survey)
120
+ @section = Factory(:survey_section, :survey => @survey)
121
+ @response_set = Factory(:response_set, :survey => @survey)
122
+ end
123
+ def generate_responses(count, quiz = nil, correct = nil)
124
+ count.times do |i|
125
+ q = Factory(:question, :survey_section => @section)
126
+ a = Factory(:answer, :question => q, :response_class => "answer")
127
+ x = Factory(:answer, :question => q, :response_class => "answer")
128
+ q.correct_answer_id = (quiz == "quiz" ? a.id : nil)
129
+ @response_set.responses << Factory(:response, :question => q, :answer => (correct == "correct" ? a : x))
130
+ end
131
+ end
132
+
133
+ it "should report correctness if it is a quiz" do
134
+ generate_responses(3, "quiz", "correct")
135
+ @response_set.correct?.should be_true
136
+ @response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 3}
137
+ end
138
+ it "should report incorrectness if it is a quiz" do
139
+ generate_responses(3, "quiz", "incorrect")
140
+ @response_set.correct?.should be_false
141
+ @response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 0}
142
+ end
143
+ it "should report correct if it isn't a quiz" do
144
+ generate_responses(3, "non-quiz")
145
+ @response_set.correct?.should be_true
146
+ @response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 3}
147
+ end
148
+ end
149
+ describe ResponseSet, "with mandatory questions" do
150
+ before(:each) do
151
+ @survey = Factory(:survey)
152
+ @section = Factory(:survey_section, :survey => @survey)
153
+ @response_set = Factory(:response_set, :survey => @survey)
154
+ end
155
+ def generate_responses(count, mandatory = nil, responded = nil)
156
+ count.times do |i|
157
+ q = Factory(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
158
+ a = Factory(:answer, :question => q, :response_class => "answer")
159
+ if responded == "responded"
160
+ @response_set.responses << Factory(:response, :question => q, :answer => a)
161
+ end
162
+ end
163
+ end
164
+ it "should report progress without mandatory questions" do
165
+ generate_responses(3)
166
+ @response_set.mandatory_questions_complete?.should be_true
167
+ @response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 0, :triggered_mandatory_completed => 0}
168
+ end
169
+ it "should report progress with mandatory questions" do
170
+ generate_responses(3, "mandatory", "responded")
171
+ @response_set.mandatory_questions_complete?.should be_true
172
+ @response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 3, :triggered_mandatory_completed => 3}
173
+ end
174
+ it "should report progress with mandatory questions" do
175
+ generate_responses(3, "mandatory", "not-responded")
176
+ @response_set.mandatory_questions_complete?.should be_false
177
+ @response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 3, :triggered_mandatory_completed => 0}
178
+ end
179
+ end
180
+ describe ResponseSet, "with mandatory, dependent questions" do
181
+ before(:each) do
182
+ @survey = Factory(:survey)
183
+ @section = Factory(:survey_section, :survey => @survey)
184
+ @response_set = Factory(:response_set, :survey => @survey)
185
+ end
186
+ def generate_responses(count, mandatory = nil, dependent = nil, triggered = nil)
187
+ dq = Factory(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
188
+ da = Factory(:answer, :question => dq, :response_class => "answer")
189
+ dx = Factory(:answer, :question => dq, :response_class => "answer")
190
+ count.times do |i|
191
+ q = Factory(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
192
+ a = Factory(:answer, :question => q, :response_class => "answer")
193
+ if dependent = "dependent"
194
+ d = Factory(:dependency, :question => q)
195
+ dc = Factory(:dependency_condition, :dependency => d, :question_id => dq.id, :answer_id => da.id)
196
+ end
197
+ @response_set.responses << Factory(:response, :question => dq, :answer => (triggered == "triggered" ? da : dx))
198
+ @response_set.responses << Factory(:response, :question => q, :answer => a)
199
+ end
200
+ end
201
+ it "should report progress without mandatory questions" do
202
+ generate_responses(3, "mandatory", "dependent")
203
+ @response_set.mandatory_questions_complete?.should be_true
204
+ @response_set.progress_hash.should == {:questions => 4, :triggered => 1, :triggered_mandatory => 1, :triggered_mandatory_completed => 1}
205
+ end
206
+ it "should report progress with mandatory questions" do
207
+ generate_responses(3, "mandatory", "dependent", "triggered")
208
+ @response_set.mandatory_questions_complete?.should be_true
209
+ @response_set.progress_hash.should == {:questions => 4, :triggered => 4, :triggered_mandatory => 4, :triggered_mandatory_completed => 4}
210
+ end
138
211
  end
@@ -2,7 +2,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe Response, "when saving a response" do
4
4
  before(:each) do
5
- @response = Response.new(:question_id => 314, :response_set_id => 159, :answer_id => 1)
5
+ # @response = Response.new(:question_id => 314, :response_set_id => 159, :answer_id => 1)
6
+ @response = Factory(:response, :question => Factory(:question), :answer => Factory(:answer))
6
7
  end
7
8
 
8
9
  it "should be valid" do
@@ -17,6 +18,22 @@ describe Response, "when saving a response" do
17
18
  @response.should have(1).error_on(:question_id)
18
19
  end
19
20
 
21
+ it "should be correct if the question has no correct_answer_id" do
22
+ @response.question.correct_answer_id.should be_nil
23
+ @response.correct?.should be_true
24
+ end
25
+ it "should be correct if the answer's response class != answer" do
26
+ @response.answer.response_class.should_not == "answer"
27
+ @response.correct?.should be_true
28
+ end
29
+ it "should be (in)correct if answer_id is (not) equal to question's correct_answer_id" do
30
+ @answer = Factory(:answer, :response_class => "answer")
31
+ @question = Factory(:question, :correct_answer_id => @answer.id)
32
+ @response = Factory(:response, :question => @question, :answer => @answer)
33
+ @response.correct?.should be_true
34
+ @response.answer_id = 143
35
+ @response.correct?.should be_false
36
+ end
20
37
  describe "returns the response as the type requested" do
21
38
 
22
39
  it "returns 'string'" do
data/surveyor.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{surveyor}
8
- s.version = "0.9.5"
8
+ s.version = "0.9.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brian Chamberlain", "Mark Yoon"]
12
- s.date = %q{2009-11-12}
12
+ s.date = %q{2009-11-13}
13
13
  s.email = %q{yoon@northwestern.edu}
14
14
  s.extra_rdoc_files = [
15
15
  "README.md"
@@ -109,6 +109,7 @@ Gem::Specification.new do |s|
109
109
  "generators/surveyor/templates/assets/stylesheets/ui.theme.css",
110
110
  "generators/surveyor/templates/initializers/haml.rb",
111
111
  "generators/surveyor/templates/initializers/surveyor.rb",
112
+ "generators/surveyor/templates/migrate/add_correct_answer_id_to_questions.rb",
112
113
  "generators/surveyor/templates/migrate/add_display_order_to_surveys.rb",
113
114
  "generators/surveyor/templates/migrate/create_answers.rb",
114
115
  "generators/surveyor/templates/migrate/create_dependencies.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: surveyor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Chamberlain
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-11-12 00:00:00 -06:00
13
+ date: 2009-11-13 00:00:00 -06:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -126,6 +126,7 @@ files:
126
126
  - generators/surveyor/templates/assets/stylesheets/ui.theme.css
127
127
  - generators/surveyor/templates/initializers/haml.rb
128
128
  - generators/surveyor/templates/initializers/surveyor.rb
129
+ - generators/surveyor/templates/migrate/add_correct_answer_id_to_questions.rb
129
130
  - generators/surveyor/templates/migrate/add_display_order_to_surveys.rb
130
131
  - generators/surveyor/templates/migrate/create_answers.rb
131
132
  - generators/surveyor/templates/migrate/create_dependencies.rb