surveyor 0.14.5 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/README.md +12 -4
  2. data/VERSION +1 -1
  3. data/features/step_definitions/surveyor_steps.rb +64 -4
  4. data/features/surveyor.feature +144 -11
  5. data/lib/surveyor.rb +0 -4
  6. data/lib/surveyor/acts_as_response.rb +13 -29
  7. data/lib/surveyor/common.rb +2 -2
  8. data/lib/surveyor/models/answer_methods.rb +14 -1
  9. data/lib/surveyor/models/dependency_condition_methods.rb +4 -3
  10. data/lib/surveyor/models/question_methods.rb +11 -1
  11. data/lib/surveyor/models/response_methods.rb +2 -1
  12. data/lib/surveyor/models/survey_methods.rb +10 -2
  13. data/lib/surveyor/models/survey_section_methods.rb +11 -1
  14. data/lib/surveyor/models/validation_condition_methods.rb +3 -2
  15. data/lib/surveyor/models/validation_methods.rb +2 -2
  16. data/lib/surveyor/parser.rb +274 -0
  17. data/lib/tasks/surveyor_tasks.rake +25 -25
  18. data/spec/factories.rb +1 -1
  19. data/spec/lib/common_spec.rb +22 -0
  20. data/spec/lib/parser_spec.rb +30 -0
  21. data/spec/models/answer_spec.rb +6 -5
  22. data/spec/models/dependency_condition_spec.rb +7 -6
  23. data/spec/models/question_spec.rb +12 -10
  24. data/spec/models/survey_section_spec.rb +3 -2
  25. data/spec/models/survey_spec.rb +11 -0
  26. data/spec/models/validation_condition_spec.rb +5 -5
  27. data/spec/models/validation_spec.rb +5 -4
  28. data/surveyor.gemspec +7 -23
  29. metadata +10 -26
  30. data/lib/fixtures_extensions.rb +0 -6
  31. data/script/surveyor/answer.rb +0 -54
  32. data/script/surveyor/base.rb +0 -75
  33. data/script/surveyor/dependency.rb +0 -13
  34. data/script/surveyor/dependency_condition.rb +0 -40
  35. data/script/surveyor/parser.rb +0 -223
  36. data/script/surveyor/question.rb +0 -59
  37. data/script/surveyor/question_group.rb +0 -26
  38. data/script/surveyor/specs/answer_spec.rb +0 -29
  39. data/script/surveyor/specs/question_spec.rb +0 -63
  40. data/script/surveyor/specs/spec_helper.rb +0 -7
  41. data/script/surveyor/specs/survey_section_spec.rb +0 -23
  42. data/script/surveyor/specs/validation_condition_spec.rb +0 -20
  43. data/script/surveyor/specs/validation_spec.rb +0 -20
  44. data/script/surveyor/survey.rb +0 -34
  45. data/script/surveyor/survey_section.rb +0 -21
  46. data/script/surveyor/validation.rb +0 -21
  47. data/script/surveyor/validation_condition.rb +0 -21
  48. data/script/surveyor/whr_dsl.tmproj +0 -244
  49. data/spec/lib/surveyor_spec.rb +0 -44
@@ -1,223 +0,0 @@
1
- require 'activesupport' # for pluralize, humanize in ActiveSupport::CoreExtensions::String::Inflections
2
- module SurveyParser
3
- class Parser
4
- @@models = %w(survey survey_section question_group question answer dependency dependency_condition validation validation_condition)
5
-
6
- # Require base and all models
7
- (%w(base) + @@models).each{|m| require File.dirname(__FILE__) + "/#{m}"}
8
-
9
- # Attributes
10
- attr_accessor :salt, :surveys, :grid_answers
11
- @@models.each{|m| attr_accessor "#{m.pluralize}_yml".to_sym } # for fixtures
12
- (@@models - %w(dependency_condition validation_condition)).each {|m| attr_accessor "current_#{m}".to_sym} # for current_model caches
13
-
14
- # Class methods
15
- def self.parse(file_name)
16
- self.define_counter_methods(@@models)
17
- puts "\n--- Parsing '#{file_name}' ---"
18
- parser = SurveyParser::Parser.new
19
- parser.instance_eval(File.read(file_name))
20
- parser.to_files
21
- puts "--- End of parsing ---\n\n"
22
- end
23
-
24
- # new_survey_id, new_survey_section_id, etc.
25
- def self.define_counter_methods(names)
26
- names.each do |name|
27
- define_method("new_#{name}_id") do
28
- instance_variable_set("@last_#{name}_id", instance_variable_get("@last_#{name}_id") + 1)
29
- end
30
- end
31
- end
32
-
33
- # Instance methods
34
- def initialize
35
- self.salt = Time.now.strftime("%Y%m%d%H%M%S")
36
- self.surveys = []
37
- self.grid_answers = []
38
- initialize_counters(@@models)
39
- initialize_fixtures(@@models.map(&:pluralize), File.join(RAILS_ROOT, "surveys", "fixtures"))
40
- end
41
-
42
- # @last_survey_id, @last_survey_section_id, etc.
43
- def initialize_counters(names)
44
- names.each{|name| instance_variable_set("@last_#{name}_id", 0)}
45
- end
46
-
47
- # @surveys_yml, @survey_sections_yml, etc.
48
- def initialize_fixtures(names, path)
49
- names.each {|name| file = instance_variable_set("@#{name}_yml", "#{path}/#{name}.yml"); File.truncate(file, 0) if File.exist?(file) }
50
- end
51
-
52
- # This method_missing does all the heavy lifting for the DSL
53
- def method_missing(missing_method, *args, &block)
54
- method_name, reference_identifier = missing_method.to_s.split("_", 2)
55
- opts = {:method_name => method_name, :reference_identifier => reference_identifier}
56
- case method_name
57
- when "survey"
58
- self.current_survey = Survey.new(self, args, opts)
59
- evaluate_the "survey", &block
60
-
61
- when "section"
62
- self.current_survey_section = SurveySection.new(self.current_survey, args, opts.merge({:display_order => current_survey.survey_sections.size + 1}))
63
- evaluate_the "survey_section", &block
64
-
65
- when "group", "g", "grid", "repeater"
66
- self.current_question_group = QuestionGroup.new(self.current_survey_section, args, opts)
67
- evaluate_the "question_group", &block
68
-
69
- when "question", "q", "label", "image"
70
- drop_the &block
71
- self.current_question = Question.new(self.current_survey_section, args, opts.merge(:question_group_id => current_question_group ? current_question_group.id : nil))
72
- add_grid_answers if in_a_grid?
73
-
74
- when "dependency", "d"
75
- drop_the &block
76
- self.current_dependency = Dependency.new(self.current_question_group || current_question, args, opts)
77
-
78
- when "condition", "c"
79
- drop_the &block
80
- raise "Error: No current dependency or validation for this condition" if self.current_dependency.nil? && self.current_validation.nil?
81
- if self.current_dependency.nil?
82
- self.current_validation.validation_conditions << ValidationCondition.new(self.current_validation, args, opts)
83
- else
84
- self.current_dependency.dependency_conditions << DependencyCondition.new(self.current_dependency, args, opts)
85
- end
86
-
87
- when "answer", "a"
88
- drop_the &block
89
- if in_a_grid?
90
- self.grid_answers << Answer.new(nil, args, opts.merge(:display_order => grid_answers.size + 1))
91
- else
92
- raise "Error: No current question" if self.current_question.nil?
93
- self.current_answer = Answer.new(self.current_question, args, opts.merge(:display_order => current_question.answers.size + 1))
94
- end
95
-
96
- when "correct"
97
- drop_the &block
98
- raise "Error: No current question" if self.current_question.nil?
99
- self.current_correct_answer = self.current_question.find_current_answers(args)
100
-
101
- when "validation", "v"
102
- drop_the &block
103
- self.current_validation = Validation.new(self.current_answer, args, opts)
104
-
105
-
106
- # explicitly define a dependency condition
107
- # (not really necessary as is default)
108
- when "dependencycondition", "dcondition", "dc"
109
- drop_the &block
110
- raise "Error: No current dependency for this condition" if self.current_dependency.nil?
111
- self.current_dependency.dependency_conditions << DependencyCondition.new(self.current_dependency, args, opts)
112
-
113
- # explicitly define a validation condition
114
- # (is necessary if want dependency AND validation on
115
- # same question as dependency existance would try to
116
- # make the condition a dependency condition.)
117
- when "validationcondition", "vcondition", "vc"
118
- drop_the &block
119
- raise "Error: No current validation for this condition" if self.current_validation.nil?
120
- self.current_validation.validation_conditions << ValidationCondition.new(self.current_validation, args, opts)
121
-
122
-
123
-
124
- else
125
- raise " ERROR: '#{missing_method}' not valid method"
126
-
127
- end
128
- end
129
-
130
- def drop_the(&block)
131
- raise "Error, I'm dropping the block like it's hot" if block_given?
132
- end
133
-
134
- def evaluate_the(model, &block)
135
- raise "Error: A #{model.humanize} cannot be empty" unless block_given?
136
- self.instance_eval(&block)
137
- self.send("clear_current", model)
138
- end
139
-
140
- def clear_current(model)
141
- # puts "clear_current #{model}"
142
- case model
143
- when "survey"
144
- self.current_survey.reconcile_dependencies unless current_survey.nil?
145
- when "question_group"
146
- self.grid_answers = []
147
- clear_current("question")
148
- when "question"
149
- @current_dependency = nil
150
- when "answer"
151
- @current_validation = nil
152
- end
153
- instance_variable_set("@current_#{model}", nil)
154
- "SurveyParser::#{model.classify}".constantize.send(:children).each{|m| clear_current(m.to_s.singularize)}
155
- end
156
-
157
- def current_survey=(s)
158
- clear_current "survey"
159
- self.surveys << s
160
- @current_survey = s
161
- end
162
-
163
- def current_survey_section=(s)
164
- clear_current "survey_section"
165
- self.current_survey.survey_sections << s
166
- @current_survey_section = s
167
- end
168
-
169
- def current_question_group=(g)
170
- clear_current "question_group"
171
- self.current_survey_section.question_groups << g
172
- @current_question_group = g
173
- end
174
-
175
- def current_question=(q)
176
- clear_current "question"
177
- self.current_survey_section.questions << q
178
- @current_question = q
179
- end
180
-
181
- def current_dependency=(d)
182
- raise "Error: No question or question group" unless (dependent = self.current_question_group || self.current_question)
183
- dependent.dependency = d
184
- @current_dependency = d
185
- end
186
-
187
- def current_answer=(a)
188
- raise "Error: No current question" if self.current_question.nil?
189
- self.current_question.answers << a
190
- @current_answer = a
191
- end
192
-
193
- def current_correct_answer=(a)
194
- raise "Error: No current question" if self.current_question.nil?
195
- self.current_question.correct_answer = a
196
- end
197
-
198
- def current_validation=(v)
199
- clear_current "validation"
200
- self.current_answer.validation = v
201
- @current_validation = v
202
- end
203
-
204
- def in_a_grid?
205
- self.current_question_group and self.current_question_group.display_type == "grid"
206
- end
207
-
208
- def add_grid_answers
209
- self.grid_answers.each do |grid_answer|
210
- my_answer = grid_answer.dup
211
- my_answer.id = new_answer_id
212
- my_answer.question_id = self.current_question.id
213
- my_answer.parser = self
214
- self.current_answer = my_answer
215
- end
216
- end
217
-
218
- def to_files
219
- self.surveys.compact.map(&:to_file)
220
- end
221
-
222
- end
223
- end
@@ -1,59 +0,0 @@
1
- module SurveyParser
2
- class Question < SurveyParser::Base
3
- ANSWER_ID = /\s*\w+_/ unless defined?(ANSWER_ID)
4
-
5
- # Context, Content, Reference, Display, Children
6
- attr_accessor :id, :parser, :survey_section_id, :question_group_id, :correct_answer_id
7
- attr_accessor :text, :short_text, :help_text, :pick, :answer_id
8
- attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identifier
9
- attr_accessor :display_order, :display_type, :is_mandatory, :display_width, :custom_class, :custom_renderer
10
- attr_accessor :dependency
11
- has_children :answers
12
-
13
- def default_options
14
- { :pick => :none,
15
- :display_type => :default,
16
- :is_mandatory => true,
17
- :display_order => self.id
18
- }
19
- end
20
-
21
- def parse_opts(opts)
22
- (name = opts.delete(:method_name)) =~ /label|image/ ? opts.merge(:display_type => name) : opts
23
- end
24
-
25
- def parse_args(args)
26
- text = args[0] || "Question"
27
- {:text => text, :short_text => text, :data_export_identifier => Surveyor::Common.to_normalized_string(text)}.merge(args[1] || {})
28
- end
29
-
30
- def correct_answer=(a)
31
- self.answer_id = a.id
32
- end
33
-
34
- def find_answer_by_reference(ref_id)
35
- self.answers.detect{|a| a.reference_identifier == ref_id}
36
- end
37
-
38
- # currently, only one correct answer is allowed
39
- def find_current_answers(args)
40
- ref_ids = args[0][:answer]
41
- ids = ref_ids.to_s.split(ANSWER_ID).compact
42
- self.answers.select{|a| ids.include?(a.reference_identifier)}.first
43
- end
44
-
45
- # so we can build the correct yaml structure
46
- def property_name_map(property)
47
- names = {
48
- "answer" => "correct_answer"
49
- }
50
- return names.has_key?(property) ? names[property] : property
51
- end
52
-
53
- def to_file
54
- super
55
- if self.dependency then self.dependency.to_file end
56
- end
57
-
58
- end
59
- end
@@ -1,26 +0,0 @@
1
- module SurveyParser
2
- class QuestionGroup < SurveyParser::Base
3
- # Context, Content, Display, Children
4
- attr_accessor :id, :parser
5
- attr_accessor :text, :help_text
6
- attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
7
- attr_accessor :display_type, :custom_class, :custom_renderer
8
- attr_accessor :dependency
9
-
10
- def default_options
11
- {:display_type => "default"}
12
- end
13
- def parse_args(args)
14
- {:text => args[0] || "Question Group"}.merge(args[1] || {})
15
- end
16
- def parse_opts(opts)
17
- (name = opts.delete(:method_name)) =~ /grid|repeater/ ? opts.merge(:display_type => name) : opts
18
- end
19
-
20
- def to_file
21
- super
22
- if self.dependency then self.dependency.to_file end
23
- end
24
-
25
- end
26
- end
@@ -1,29 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'answer'
3
-
4
- describe SurveyParser::Answer, " when first created" do
5
-
6
- before(:each) do
7
- question = mock("Question", :id => 2, :parser => mock("SurveyParser::Parser", :new_answer_id => 1))
8
- question.stub!(:class => SurveyParser::Question)
9
- options = {:help_text => "Never or rarely ever", :reference_identifier => "b3a_1"}
10
- @ans = SurveyParser::Answer.new(question, ["No / Rarely"], options)
11
- end
12
-
13
- it "should set inititalized variables to those passed in" do
14
- @ans.id.should == 1
15
- @ans.question_id.should == 2
16
- @ans.reference_identifier.should == "b3a_1"
17
- @ans.text.should == "No / Rarely"
18
- @ans.help_text.should == "Never or rarely ever"
19
- end
20
-
21
- it "should output current state to yml" do
22
- @ans.should.respond_to?(:to_yml)
23
- end
24
-
25
- it "should create a normalized code automatically when initalized" do
26
- @ans.data_export_identifier.should eql("no_rarely")
27
- end
28
-
29
- end
@@ -1,63 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'question'
3
-
4
- describe SurveyParser::Question, " when first created" do
5
- before do
6
- section = mock("SurveyParser::SurveySection", :id => 2, :parser => mock("SurveyParser::Parser", :new_question_id => 1))
7
- section.stub!(:class => SurveyParser::SurveySection)
8
- args = {:help_text => "Please give a rough estimate", :reference_identifier => "B3"}
9
- options = {}
10
- @ques = SurveyParser::Question.new(section, ["In the past 12 months how many times have you been to a doctor?", args], options)
11
- end
12
-
13
- it "should set initialization parameters properly" do
14
- @ques.id.should == 1
15
- @ques.reference_identifier.should == "B3"
16
- @ques.survey_section_id.should == 2
17
- @ques.help_text.should == "Please give a rough estimate"
18
-
19
- #Checking the defaults
20
- @ques.pick.should == :none
21
- @ques.display_type.should == :default
22
- @ques.is_mandatory.should == true
23
- end
24
-
25
- it "should output current state to yml" do
26
- @ques.should.respond_to?(:to_yml)
27
- end
28
-
29
- it "should create a normalized code automatically when initalized" do
30
- @ques.data_export_identifier.should eql("many_times_you_been_doctor")
31
- end
32
-
33
- # We don't change titles via the DSL
34
- # it "should update the normalized code if the title is changed" do
35
- # @ques.data_export_identifier.should == "many_times_you_been_doctor"
36
- # @ques.text = "Sometimes or All the time?"
37
- # @ques.data_export_identifier.should == "sometimes_all_time"
38
- # end
39
-
40
- end
41
-
42
- describe SurveyParser::Question, "when it contains data" do
43
- before(:each) do
44
- section = mock("SurveyParser::SurveySection", :id => 2, :parser => mock("SurveyParser::Parser", :new_question_id => 1))
45
- args = {:help_text => "Please give a rough estimate", :reference_identifier => "B3"}
46
- options = {}
47
- @ques = SurveyParser::Question.new(section, ["In the past 12 months how many times have you been to a doctor?", args], options)
48
- @ques.answers << mock("SurveyParser::Answer", :reference_identifier => "1", :text => "foo")
49
- @ques.answers << mock("SurveyParser::Answer", :reference_identifier => "2", :text => "foo")
50
- @ques.answers << mock("SurveyParser::Answer", :reference_identifier => "3", :text => "foo")
51
- end
52
-
53
- it "should have added the test answers correctly" do
54
- @ques.answers.length.should eql(3)
55
- end
56
-
57
- it "should find an answer by reference" do
58
- a_to_find = @ques.find_answer_by_reference("2")
59
- a_to_find.should_not be_nil
60
- a_to_find.reference_identifier.should eql("2")
61
- end
62
-
63
- end
@@ -1,7 +0,0 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
2
- require File.expand_path(File.dirname(__FILE__) + "/../../../lib/surveyor")
3
- require File.expand_path(File.dirname(__FILE__) + "/../parser")
4
- require File.expand_path(File.dirname(__FILE__) + "/../base")
5
-
6
- Spec::Runner.configure do |config|
7
- end
@@ -1,23 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'survey_section'
3
-
4
- describe SurveyParser::SurveySection, "when first created" do
5
-
6
- before(:each) do
7
- @section = SurveyParser::SurveySection.new(mock("SurveyParser::Survey", :id => 2, :parser => mock("SurveyParser::Parser", :new_survey_section_id => 1)), ["Demographics"], {})
8
- end
9
-
10
- it "should generate a data export identifier" do
11
- @section.data_export_identifier.should == "demographics"
12
- end
13
-
14
- it "should find a question by reference" do
15
- @section.questions << mock("SurveyParser::Question", :reference_identifier => "1", :text => "foo")
16
- @section.questions << mock("SurveyParser::Question", :reference_identifier => "2", :text => "foo")
17
- @section.questions << mock("SurveyParser::Question", :reference_identifier => "3", :text => "foo")
18
-
19
- q = @section.find_question_by_reference("2")
20
- q.should_not be_nil
21
- q.reference_identifier.should == "2"
22
- end
23
- end
@@ -1,20 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'validation_condition'
3
-
4
- describe SurveyParser::ValidationCondition, " when first created" do
5
- before do
6
- validation = mock("SurveyParser::Validation", :id => 29, :parser => mock("SurveyParser::Parser", :new_validation_condition_id => 21))
7
- validation.stub!(:class => SurveyParser::Validation)
8
- args = [">=", {:integer_value => 0}]
9
- options = {}
10
- @validation_condition = SurveyParser::ValidationCondition.new(validation, args, options)
11
- end
12
-
13
- it "should set initialization parameters properly" do
14
- @validation_condition.id.should == 21
15
- @validation_condition.validation_id.should == 29
16
- @validation_condition.integer_value.should == 0
17
- @validation_condition.operator.should == ">="
18
- end
19
-
20
- end