surveyor 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
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