surveyor 0.9.1 → 0.9.2

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.1
1
+ 0.9.2
@@ -11,7 +11,7 @@ namespace :surveyor do
11
11
  raise "USAGE: file name required e.g. 'FILE=surveys/kitchen_sink_survey.rb'" if ENV["FILE"].blank?
12
12
  fixture_dir = File.join(RAILS_ROOT, "surveys", "fixtures")
13
13
  mkdir fixture_dir unless File.exists?(fixture_dir)
14
- SurveyParser.parse(File.join(RAILS_ROOT, ENV["FILE"]))
14
+ SurveyParser::Parser.parse(File.join(RAILS_ROOT, ENV["FILE"]))
15
15
  end
16
16
 
17
17
  desc "load survey fixtures"
@@ -1,52 +1,54 @@
1
- class Answer < SurveyParser::Base
2
- # Context, Content, Reference, Display
3
- attr_accessor :id, :parser, :question_id
4
- attr_accessor :text, :short_text, :help_text, :weight, :response_class
5
- attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
6
- attr_accessor :display_order, :is_exclusive, :hide_label, :display_length, :custom_class, :custom_renderer
7
- attr_accessor :validation
1
+ module SurveyParser
2
+ class Answer < SurveyParser::Base
3
+ # Context, Content, Reference, Display
4
+ attr_accessor :id, :parser, :question_id
5
+ attr_accessor :text, :short_text, :help_text, :weight, :response_class
6
+ attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
7
+ attr_accessor :display_order, :is_exclusive, :hide_label, :display_length, :custom_class, :custom_renderer
8
+ attr_accessor :validation
8
9
 
9
- def default_options
10
- { :is_exclusive => false,
11
- :hide_label => false,
12
- :response_class => "answer"
13
- }
14
- end
10
+ def default_options
11
+ { :is_exclusive => false,
12
+ :hide_label => false,
13
+ :response_class => "answer"
14
+ }
15
+ end
15
16
 
16
- def parse_args(args)
17
- case args[0]
18
- when Hash # Hash
19
- text_args(args[0][:text]).merge(args[0])
20
- when String # (String, Hash) or (String, Symbol, Hash)
21
- text_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
22
- when Symbol # (Symbol, Hash) or (Symbol, Symbol, Hash)
23
- symbol_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
24
- else
25
- text_args(nil)
17
+ def parse_args(args)
18
+ case args[0]
19
+ when Hash # Hash
20
+ text_args(args[0][:text]).merge(args[0])
21
+ when String # (String, Hash) or (String, Symbol, Hash)
22
+ text_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
23
+ when Symbol # (Symbol, Hash) or (Symbol, Symbol, Hash)
24
+ symbol_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
25
+ else
26
+ text_args(nil)
27
+ end
26
28
  end
27
- end
28
29
 
29
- def text_args(text = "Answer")
30
- {:text => text.to_s, :short_text => text, :data_export_identifier => Surveyor.to_normalized_string(text)}
31
- end
32
- def hash_from(arg)
33
- arg.is_a?(Symbol) ? {:response_class => arg.to_s} : arg.is_a?(Hash) ? arg : {}
34
- end
35
- def symbol_args(arg)
36
- case arg
37
- when :other
38
- text_args("Other")
39
- when :other_and_string
40
- text_args("Other").merge({:response_class => "string"})
41
- when :none, :omit # is_exclusive erases and disables other checkboxes and input elements
42
- text_args(arg.to_s.humanize).merge({:is_exclusive => true})
43
- when :integer, :date, :time, :datetime, :text, :datetime, :string
44
- text_args(arg.to_s.humanize).merge({:response_class => arg.to_s, :hide_label => true})
30
+ def text_args(text = "Answer")
31
+ {:text => text.to_s, :short_text => text, :data_export_identifier => Surveyor.to_normalized_string(text)}
32
+ end
33
+ def hash_from(arg)
34
+ arg.is_a?(Symbol) ? {:response_class => arg.to_s} : arg.is_a?(Hash) ? arg : {}
35
+ end
36
+ def symbol_args(arg)
37
+ case arg
38
+ when :other
39
+ text_args("Other")
40
+ when :other_and_string
41
+ text_args("Other").merge({:response_class => "string"})
42
+ when :none, :omit # is_exclusive erases and disables other checkboxes and input elements
43
+ text_args(arg.to_s.humanize).merge({:is_exclusive => true})
44
+ when :integer, :date, :time, :datetime, :text, :datetime, :string
45
+ text_args(arg.to_s.humanize).merge({:response_class => arg.to_s, :hide_label => true})
46
+ end
47
+ end
48
+ def to_file
49
+ super
50
+ if self.validation then self.validation.to_file end
45
51
  end
46
- end
47
- def to_file
48
- super
49
- if self.validation then self.validation.to_file end
50
- end
51
52
 
53
+ end
52
54
  end
@@ -1,4 +1,4 @@
1
- class SurveyParser
1
+ module SurveyParser
2
2
  class Base
3
3
 
4
4
  # Class level instance variable, because class variable are shared with subclasses
@@ -22,17 +22,17 @@ class SurveyParser
22
22
  # Instance methods
23
23
  def initialize(obj, args, opts)
24
24
  # inherit the parser from parent (obj)
25
- self.parser = (obj.nil? ? nil : obj.class == SurveyParser ? obj : obj.parser)
25
+ self.parser = (obj.nil? ? nil : obj.class == SurveyParser::Parser ? obj : obj.parser)
26
26
  # get a new id from the parser
27
- self.id = parser.nil? ? nil : parser.send("new_#{self.class.name.underscore}_id")
27
+ self.id = parser.nil? ? nil : parser.send("new_#{self.class.name.demodulize.underscore}_id")
28
28
  # set [parent]_id to obj.id, if we have that attribute
29
- self.send("#{obj.class.name.underscore}_id=", obj.nil? ? nil : obj.id) if self.respond_to?("#{obj.class.name.underscore}_id=")
29
+ self.send("#{obj.class.name.demodulize.underscore}_id=", obj.nil? ? nil : obj.id) if self.respond_to?("#{obj.class.name.demodulize.underscore}_id=")
30
30
  # initialize descendant models
31
31
  self.class.children.each{|model| self.send("#{model}=", [])}
32
32
  # combine default options, parsed opts, parsed args, and initialize instance variables
33
33
  self.default_options.merge(parse_opts(opts)).merge(parse_args(args)).each{|k,v| self.send("#{k.to_s}=", v)}
34
34
  # print to the log
35
- print "#{self.class.name.gsub(/[a-z]/, "")[-1,1]}#{self.id} "
35
+ print "#{self.class.name.demodulize.gsub(/[a-z]/, "")[-1,1]}#{self.id} "
36
36
  end
37
37
  def default_options
38
38
  {}
@@ -54,7 +54,7 @@ class SurveyParser
54
54
  (out << nil ).join("\r\n")
55
55
  end
56
56
  def to_file
57
- File.open(self.parser.send("#{self.class.name.underscore.pluralize}_yml"), File::CREAT|File::APPEND|File::WRONLY) {|f| f << to_yml}
57
+ File.open(self.parser.send("#{self.class.name.demodulize.underscore.pluralize}_yml"), File::CREAT|File::APPEND|File::WRONLY) {|f| f << to_yml}
58
58
  self.class.children.each{|model| self.send(model).compact.map(&:to_file)}
59
59
  end
60
60
  end
@@ -1,11 +1,13 @@
1
- class Dependency < SurveyParser::Base
2
- # Context, Conditional, Children
3
- attr_accessor :id, :question_id, :question_group_id, :parser
4
- attr_accessor :rule
5
- has_children :dependency_conditions
1
+ module SurveyParser
2
+ class Dependency < SurveyParser::Base
3
+ # Context, Conditional, Children
4
+ attr_accessor :id, :question_id, :question_group_id, :parser
5
+ attr_accessor :rule
6
+ has_children :dependency_conditions
6
7
 
7
- def parse_opts(opts)
8
- {} # toss the method name and reference identifier by default
9
- end
8
+ def parse_opts(opts)
9
+ {} # toss the method name and reference identifier by default
10
+ end
10
11
 
12
+ end
11
13
  end
@@ -1,38 +1,40 @@
1
- class DependencyCondition < SurveyParser::Base
1
+ module SurveyParser
2
+ class DependencyCondition < SurveyParser::Base
2
3
 
3
- # Context, Conditional, Value
4
- attr_accessor :id, :dependency_id, :rule_key, :parser
5
- attr_accessor :question_id, :operator
6
- attr_accessor :answer_id, :datetime_value, :integer_value, :float_value, :unit, :text_value, :string_value, :response_other
7
- attr_accessor :question_reference, :answer_reference
4
+ # Context, Conditional, Value
5
+ attr_accessor :id, :dependency_id, :rule_key, :parser
6
+ attr_accessor :question_id, :operator
7
+ attr_accessor :answer_id, :datetime_value, :integer_value, :float_value, :unit, :text_value, :string_value, :response_other
8
+ attr_accessor :question_reference, :answer_reference
8
9
 
9
- def default_options
10
- { :operator => "==" }
11
- end
12
- def parse_args(args)
13
- a0, a1, a2 = args
14
- {:question_reference => a0.to_s.gsub("q_", ""), :operator => a1}.merge(a2.is_a?(Hash) ? a2 : {:answer_reference => a2.to_s.gsub("a_", "")})
15
- end
16
- def parse_opts(opts)
17
- {:rule_key => opts[:reference_identifier]}
18
- end
10
+ def default_options
11
+ { :operator => "==" }
12
+ end
13
+ def parse_args(args)
14
+ a0, a1, a2 = args
15
+ {:question_reference => a0.to_s.gsub("q_", ""), :operator => a1}.merge(a2.is_a?(Hash) ? a2 : {:answer_reference => a2.to_s.gsub("a_", "")})
16
+ end
17
+ def parse_opts(opts)
18
+ {:rule_key => opts[:reference_identifier]}
19
+ end
19
20
 
20
- def reconcile_dependencies
21
- # Looking up references to questions and answers for linking the dependency objects
22
- print "Lookup Q ref #{@question_reference}:"
23
- if (ref_question = parser.current_survey.find_question_by_reference(@question_reference))
24
- print " found Q#{ref_question.id} "
25
- @question_id = ref_question.id
26
- print "Lookup A ref #{@answer_reference}"
27
- if (ref_answer = ref_question.find_answer_by_reference(@answer_reference))
28
- print " found A#{ref_answer.id} "
29
- @answer_id = ref_answer.id
21
+ def reconcile_dependencies
22
+ # Looking up references to questions and answers for linking the dependency objects
23
+ print "Lookup Q ref #{@question_reference}:"
24
+ if (ref_question = parser.current_survey.find_question_by_reference(@question_reference))
25
+ print " found Q#{ref_question.id} "
26
+ @question_id = ref_question.id
27
+ print "Lookup A ref #{@answer_reference}"
28
+ if (ref_answer = ref_question.find_answer_by_reference(@answer_reference))
29
+ print " found A#{ref_answer.id} "
30
+ @answer_id = ref_answer.id
31
+ else
32
+ raise "Could not find referenced answer #{@answer_reference}"
33
+ end
30
34
  else
31
- raise "Could not find referenced answer #{@answer_reference}"
35
+ raise "Could not find referenced question #{@question_reference}"
32
36
  end
33
- else
34
- raise "Could not find referenced question #{@question_reference}"
35
37
  end
36
- end
37
38
 
39
+ end
38
40
  end
@@ -0,0 +1,187 @@
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 :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.surveys = []
36
+ self.grid_answers = []
37
+ initialize_counters(@@models)
38
+ initialize_fixtures(@@models.map(&:pluralize), File.join(RAILS_ROOT, "surveys", "fixtures"))
39
+ end
40
+
41
+ # @last_survey_id, @last_survey_section_id, etc.
42
+ def initialize_counters(names)
43
+ names.each{|name| instance_variable_set("@last_#{name}_id", 0)}
44
+ end
45
+
46
+ # @surveys_yml, @survey_sections_yml, etc.
47
+ def initialize_fixtures(names, path)
48
+ names.each {|name| file = instance_variable_set("@#{name}_yml", "#{path}/#{name}.yml"); File.truncate(file, 0) if File.exist?(file) }
49
+ end
50
+
51
+ # This method_missing does all the heavy lifting for the DSL
52
+ def method_missing(missing_method, *args, &block)
53
+ method_name, reference_identifier = missing_method.to_s.split("_", 2)
54
+ opts = {:method_name => method_name, :reference_identifier => reference_identifier}
55
+ case method_name
56
+ when "survey"
57
+ self.current_survey = Survey.new(self, args, opts)
58
+ evaluate_the "survey", &block
59
+
60
+ when "section"
61
+ self.current_survey_section = SurveySection.new(self.current_survey, args, opts.merge({:display_order => current_survey.survey_sections.size + 1}))
62
+ evaluate_the "survey_section", &block
63
+
64
+ when "group", "g", "grid", "repeater"
65
+ self.current_question_group = QuestionGroup.new(self.current_survey_section, args, opts)
66
+ evaluate_the "question_group", &block
67
+
68
+ when "question", "q", "label", "image"
69
+ drop_the &block
70
+ self.current_question = Question.new(self.current_survey_section, args, opts.merge(:question_group_id => current_question_group ? current_question_group.id : nil))
71
+ add_grid_answers if in_a_grid?
72
+
73
+ when "dependency", "d"
74
+ drop_the &block
75
+ self.current_dependency = Dependency.new(self.current_question_group || current_question, args, opts)
76
+
77
+ when "condition", "c"
78
+ drop_the &block
79
+ raise "Error: No current dependency or validation for this condition" if self.current_dependency.nil? && self.current_validation.nil?
80
+ if self.current_dependency.nil?
81
+ self.current_validation.validation_conditions << ValidationCondition.new(self.current_validation, args, opts)
82
+ else
83
+ self.current_dependency.dependency_conditions << DependencyCondition.new(self.current_dependency, args, opts)
84
+ end
85
+
86
+ when "answer", "a"
87
+ drop_the &block
88
+ if in_a_grid?
89
+ self.grid_answers << Answer.new(nil, args, opts.merge(:display_order => grid_answers.size + 1))
90
+ else
91
+ raise "Error: No current question" if self.current_question.nil?
92
+ self.current_answer = Answer.new(self.current_question, args, opts.merge(:display_order => current_question.answers.size + 1))
93
+ end
94
+
95
+ when "validation", "v"
96
+ drop_the &block
97
+ self.current_validation = Validation.new(self.current_answer, args, opts)
98
+
99
+ else
100
+ raise " ERROR: '#{missing_method}' not valid method"
101
+
102
+ end
103
+ end
104
+
105
+ def drop_the(&block)
106
+ raise "Error, I'm dropping the block like it's hot" if block_given?
107
+ end
108
+
109
+ def evaluate_the(model, &block)
110
+ raise "Error: A #{model.humanize} cannot be empty" unless block_given?
111
+ self.instance_eval(&block)
112
+ self.send("clear_current", model)
113
+ end
114
+
115
+ def clear_current(model)
116
+ # puts "clear_current #{model}"
117
+ case model
118
+ when "survey"
119
+ self.current_survey.reconcile_dependencies unless current_survey.nil?
120
+ when "question_group"
121
+ self.grid_answers = []
122
+ clear_current("question")
123
+ when "question"
124
+ @current_dependency = nil
125
+ when "answer"
126
+ @current_validation = nil
127
+ end
128
+ instance_variable_set("@current_#{model}", nil)
129
+ "SurveyParser::#{model.classify}".constantize.send(:children).each{|m| clear_current(m.to_s.singularize)}
130
+ end
131
+
132
+ def current_survey=(s)
133
+ clear_current "survey"
134
+ self.surveys << s
135
+ @current_survey = s
136
+ end
137
+ def current_survey_section=(s)
138
+ clear_current "survey_section"
139
+ self.current_survey.survey_sections << s
140
+ @current_survey_section = s
141
+ end
142
+ def current_question_group=(g)
143
+ clear_current "question_group"
144
+ self.current_survey_section.question_groups << g
145
+ @current_question_group = g
146
+ end
147
+ def current_question=(q)
148
+ clear_current "question"
149
+ self.current_survey_section.questions << q
150
+ @current_question = q
151
+ end
152
+ def current_dependency=(d)
153
+ raise "Error: No question or question group" unless (dependent = self.current_question_group || self.current_question)
154
+ dependent.dependency = d
155
+ @current_dependency = d
156
+ end
157
+ def current_answer=(a)
158
+ raise "Error: No current question" if self.current_question.nil?
159
+ self.current_question.answers << a
160
+ @current_answer = a
161
+ end
162
+ def current_validation=(v)
163
+ clear_current "validation"
164
+ self.current_answer.validation = v
165
+ @current_validation = v
166
+ end
167
+
168
+ def in_a_grid?
169
+ self.current_question_group and self.current_question_group.display_type == "grid"
170
+ end
171
+
172
+ def add_grid_answers
173
+ self.grid_answers.each do |grid_answer|
174
+ my_answer = grid_answer.dup
175
+ my_answer.id = new_answer_id
176
+ my_answer.question_id = self.current_question.id
177
+ my_answer.parser = self
178
+ self.current_answer = my_answer
179
+ end
180
+ end
181
+
182
+ def to_files
183
+ self.surveys.compact.map(&:to_file)
184
+ end
185
+
186
+ end
187
+ end
@@ -1,34 +1,36 @@
1
- class Question < SurveyParser::Base
2
- # Context, Content, Reference, Display, Children
3
- attr_accessor :id, :parser, :survey_section_id, :question_group_id
4
- attr_accessor :text, :short_text, :help_text, :pick
5
- attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identifier
6
- attr_accessor :display_order, :display_type, :is_mandatory, :display_width, :custom_class, :custom_renderer
7
- attr_accessor :dependency
8
- has_children :answers
1
+ module SurveyParser
2
+ class Question < SurveyParser::Base
3
+ # Context, Content, Reference, Display, Children
4
+ attr_accessor :id, :parser, :survey_section_id, :question_group_id
5
+ attr_accessor :text, :short_text, :help_text, :pick
6
+ attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identifier
7
+ attr_accessor :display_order, :display_type, :is_mandatory, :display_width, :custom_class, :custom_renderer
8
+ attr_accessor :dependency
9
+ has_children :answers
9
10
 
10
- def default_options
11
- { :pick => :none,
12
- :display_type => :default,
13
- :is_mandatory => true,
14
- :display_order => self.id
15
- }
16
- end
17
- def parse_opts(opts)
18
- (name = opts.delete(:method_name)) =~ /label|image/ ? opts.merge(:display_type => name) : opts
19
- end
20
- def parse_args(args)
21
- text = args[0] || "Question"
22
- {:text => text, :short_text => text, :data_export_identifier => Surveyor.to_normalized_string(text)}.merge(args[1] || {})
23
- end
11
+ def default_options
12
+ { :pick => :none,
13
+ :display_type => :default,
14
+ :is_mandatory => true,
15
+ :display_order => self.id
16
+ }
17
+ end
18
+ def parse_opts(opts)
19
+ (name = opts.delete(:method_name)) =~ /label|image/ ? opts.merge(:display_type => name) : opts
20
+ end
21
+ def parse_args(args)
22
+ text = args[0] || "Question"
23
+ {:text => text, :short_text => text, :data_export_identifier => Surveyor.to_normalized_string(text)}.merge(args[1] || {})
24
+ end
24
25
 
25
- def find_answer_by_reference(ref_id)
26
- self.answers.detect{|a| a.reference_identifier == ref_id}
27
- end
26
+ def find_answer_by_reference(ref_id)
27
+ self.answers.detect{|a| a.reference_identifier == ref_id}
28
+ end
28
29
 
29
- def to_file
30
- super
31
- if self.dependency then self.dependency.to_file end
32
- end
30
+ def to_file
31
+ super
32
+ if self.dependency then self.dependency.to_file end
33
+ end
33
34
 
35
+ end
34
36
  end
@@ -1,24 +1,26 @@
1
- class QuestionGroup < SurveyParser::Base
2
- # Context, Content, Display, Children
3
- attr_accessor :id, :parser
4
- attr_accessor :text, :help_text
5
- attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
6
- attr_accessor :display_type, :custom_class, :custom_renderer
7
- attr_accessor :dependency
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
8
9
 
9
- def default_options
10
- {:display_type => "default"}
11
- end
12
- def parse_args(args)
13
- {:text => args[0] || "Question Group"}.merge(args[1] || {})
14
- end
15
- def parse_opts(opts)
16
- (name = opts.delete(:method_name)) =~ /grid|repeater/ ? opts.merge(:display_type => name) : opts
17
- end
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
18
19
 
19
- def to_file
20
- super
21
- if self.dependency then self.dependency.to_file end
22
- end
20
+ def to_file
21
+ super
22
+ if self.dependency then self.dependency.to_file end
23
+ end
23
24
 
25
+ end
24
26
  end
@@ -1,13 +1,13 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'answer'
3
3
 
4
- describe Answer, " when first created" do
4
+ describe SurveyParser::Answer, " when first created" do
5
5
 
6
6
  before(:each) do
7
- question = mock("Question", :id => 2, :parser => mock("Parser", :new_answer_id => 1))
8
- question.stub!(:class => Question)
7
+ question = mock("Question", :id => 2, :parser => mock("SurveyParser::Parser", :new_answer_id => 1))
8
+ question.stub!(:class => SurveyParser::Question)
9
9
  options = {:help_text => "Never or rarely ever", :reference_identifier => "b3a_1"}
10
- @ans = Answer.new(question, ["No / Rarely"], options)
10
+ @ans = SurveyParser::Answer.new(question, ["No / Rarely"], options)
11
11
  end
12
12
 
13
13
  it "should set inititalized variables to those passed in" do
@@ -1,13 +1,13 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'question'
3
3
 
4
- describe Question, " when first created" do
4
+ describe SurveyParser::Question, " when first created" do
5
5
  before do
6
- section = mock("SurveySection", :id => 2, :parser => mock("Parser", :new_question_id => 1))
7
- section.stub!(:class => SurveySection)
6
+ section = mock("SurveyParser::SurveySection", :id => 2, :parser => mock("SurveyParser::Parser", :new_question_id => 1))
7
+ section.stub!(:class => SurveyParser::SurveySection)
8
8
  args = {:help_text => "Please give a rough estimate", :reference_identifier => "B3"}
9
9
  options = {}
10
- @ques = Question.new(section, ["In the past 12 months how many times have you been to a doctor?", args], options)
10
+ @ques = SurveyParser::Question.new(section, ["In the past 12 months how many times have you been to a doctor?", args], options)
11
11
  end
12
12
 
13
13
  it "should set initialization parameters properly" do
@@ -39,15 +39,15 @@ describe Question, " when first created" do
39
39
 
40
40
  end
41
41
 
42
- describe Question, "when it contains data" do
42
+ describe SurveyParser::Question, "when it contains data" do
43
43
  before(:each) do
44
- section = mock("SurveySection", :id => 2, :parser => mock("Parser", :new_question_id => 1))
44
+ section = mock("SurveyParser::SurveySection", :id => 2, :parser => mock("SurveyParser::Parser", :new_question_id => 1))
45
45
  args = {:help_text => "Please give a rough estimate", :reference_identifier => "B3"}
46
46
  options = {}
47
- @ques = Question.new(section, ["In the past 12 months how many times have you been to a doctor?", args], options)
48
- @ques.answers << mock("Answer", :reference_identifier => "1", :text => "foo")
49
- @ques.answers << mock("Answer", :reference_identifier => "2", :text => "foo")
50
- @ques.answers << mock("Answer", :reference_identifier => "3", :text => "foo")
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
51
  end
52
52
 
53
53
  it "should have added the test answers correctly" do
@@ -1,5 +1,6 @@
1
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
2
2
  require File.expand_path(File.dirname(__FILE__) + "/../../../lib/surveyor")
3
+ require File.expand_path(File.dirname(__FILE__) + "/../parser")
3
4
  require File.expand_path(File.dirname(__FILE__) + "/../base")
4
5
 
5
6
  Spec::Runner.configure do |config|
@@ -1,10 +1,10 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'survey_section'
3
3
 
4
- describe SurveySection, "when first created" do
4
+ describe SurveyParser::SurveySection, "when first created" do
5
5
 
6
6
  before(:each) do
7
- @section = SurveySection.new(mock("Survey", :id => 2, :parser => mock("Parser", :new_survey_section_id => 1)), ["Demographics"], {})
7
+ @section = SurveyParser::SurveySection.new(mock("SurveyParser::Survey", :id => 2, :parser => mock("SurveyParser::Parser", :new_survey_section_id => 1)), ["Demographics"], {})
8
8
  end
9
9
 
10
10
  it "should generate a data export identifier" do
@@ -12,9 +12,9 @@ describe SurveySection, "when first created" do
12
12
  end
13
13
 
14
14
  it "should find a question by reference" do
15
- @section.questions << mock("Question", :reference_identifier => "1", :text => "foo")
16
- @section.questions << mock("Question", :reference_identifier => "2", :text => "foo")
17
- @section.questions << mock("Question", :reference_identifier => "3", :text => "foo")
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
18
 
19
19
  q = @section.find_question_by_reference("2")
20
20
  q.should_not be_nil
@@ -1,13 +1,13 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'validation_condition'
3
3
 
4
- describe ValidationCondition, " when first created" do
4
+ describe SurveyParser::ValidationCondition, " when first created" do
5
5
  before do
6
- validation = mock("Validation", :id => 29, :parser => mock("Parser", :new_validation_condition_id => 21))
7
- validation.stub!(:class => Validation)
6
+ validation = mock("SurveyParser::Validation", :id => 29, :parser => mock("SurveyParser::Parser", :new_validation_condition_id => 21))
7
+ validation.stub!(:class => SurveyParser::Validation)
8
8
  args = [">=", {:integer_value => 0}]
9
9
  options = {}
10
- @validation_condition = ValidationCondition.new(validation, args, options)
10
+ @validation_condition = SurveyParser::ValidationCondition.new(validation, args, options)
11
11
  end
12
12
 
13
13
  it "should set initialization parameters properly" do
@@ -1,13 +1,13 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'validation'
3
3
 
4
- describe Validation, " when first created" do
4
+ describe SurveyParser::Validation, " when first created" do
5
5
  before do
6
- answer = mock("Answer", :id => 2, :parser => mock("Parser", :new_validation_id => 1))
7
- answer.stub!(:class => Answer)
6
+ answer = mock("SurveyParser::Answer", :id => 2, :parser => mock("SurveyParser::Parser", :new_validation_id => 1))
7
+ answer.stub!(:class => SurveyParser::Answer)
8
8
  args = [{:rule => "C", :message => "Please select a number between 0 and 120"}]
9
9
  options = {}
10
- @validation = Validation.new(answer, args, options)
10
+ @validation = SurveyParser::Validation.new(answer, args, options)
11
11
  end
12
12
 
13
13
  it "should set initialization parameters properly" do
@@ -1,32 +1,34 @@
1
- class Survey < SurveyParser::Base
2
- # Context, Content, Reference, Expiry, Display
3
- attr_accessor :id, :parser
4
- attr_accessor :title, :description
5
- attr_accessor :access_code, :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
6
- attr_accessor :active_at, :inactive_at
7
- attr_accessor :css_url, :custom_class
8
- has_children :survey_sections
1
+ module SurveyParser
2
+ class Survey < SurveyParser::Base
3
+ # Context, Content, Reference, Expiry, Display
4
+ attr_accessor :id, :parser
5
+ attr_accessor :title, :description
6
+ attr_accessor :access_code, :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
7
+ attr_accessor :active_at, :inactive_at
8
+ attr_accessor :css_url, :custom_class
9
+ has_children :survey_sections
9
10
 
10
- def parse_args(args)
11
- title = args[0]
12
- {:title => title, :access_code => Surveyor.to_normalized_string(title)}.merge(args[1] || {})
13
- end
11
+ def parse_args(args)
12
+ title = args[0]
13
+ {:title => title, :access_code => Surveyor.to_normalized_string(title)}.merge(args[1] || {})
14
+ end
14
15
 
15
- def find_question_by_reference(ref_id)
16
- found = nil
17
- survey_sections.detect{|s| found = s.find_question_by_reference(ref_id)}
18
- return found
19
- end
16
+ def find_question_by_reference(ref_id)
17
+ found = nil
18
+ survey_sections.detect{|s| found = s.find_question_by_reference(ref_id)}
19
+ return found
20
+ end
20
21
 
21
- def reconcile_dependencies
22
- survey_sections.each do |section|
23
- section.questions.each do |question|
24
- question.dependency.dependency_conditions.each { |con| con.reconcile_dependencies} unless question.dependency.nil?
25
- end
26
- section.question_groups.each do |group|
27
- group.dependency.dependency_conditions.each { |con| con.reconcile_dependencies} unless group.dependency.nil?
28
- end
29
- end
30
- end
22
+ def reconcile_dependencies
23
+ survey_sections.each do |section|
24
+ section.questions.each do |question|
25
+ question.dependency.dependency_conditions.each { |con| con.reconcile_dependencies} unless question.dependency.nil?
26
+ end
27
+ section.question_groups.each do |group|
28
+ group.dependency.dependency_conditions.each { |con| con.reconcile_dependencies} unless group.dependency.nil?
29
+ end
30
+ end
31
+ end
31
32
 
33
+ end
32
34
  end
@@ -1,19 +1,21 @@
1
- class SurveySection < SurveyParser::Base
2
- # Context, Content, Display, Reference, Children, Placeholders
3
- attr_accessor :id, :parser, :survey_id
4
- attr_accessor :title, :description
5
- attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
6
- attr_accessor :display_order, :custom_class
7
- has_children :question_groups, :questions
1
+ module SurveyParser
2
+ class SurveySection < SurveyParser::Base
3
+ # Context, Content, Display, Reference, Children, Placeholders
4
+ attr_accessor :id, :parser, :survey_id
5
+ attr_accessor :title, :description
6
+ attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
7
+ attr_accessor :display_order, :custom_class
8
+ has_children :question_groups, :questions
8
9
 
9
- def parse_args(args)
10
- title = args[0]
11
- {:title => title, :data_export_identifier => Surveyor.to_normalized_string(title)}.merge(args[1] || {})
12
- end
10
+ def parse_args(args)
11
+ title = args[0]
12
+ {:title => title, :data_export_identifier => Surveyor.to_normalized_string(title)}.merge(args[1] || {})
13
+ end
13
14
 
14
- # Used to find questions for dependency linking
15
- def find_question_by_reference(ref_id)
16
- self.questions.detect{|q| q.reference_identifier == ref_id}
17
- end
15
+ # Used to find questions for dependency linking
16
+ def find_question_by_reference(ref_id)
17
+ self.questions.detect{|q| q.reference_identifier == ref_id}
18
+ end
18
19
 
20
+ end
19
21
  end
@@ -1,19 +1,21 @@
1
- class Validation < SurveyParser::Base
1
+ module SurveyParser
2
+ class Validation < SurveyParser::Base
2
3
 
3
- # Context, Conditional, Children
4
- attr_accessor :id, :answer_id, :parser
5
- attr_accessor :rule, :message
6
- has_children :validation_conditions
4
+ # Context, Conditional, Children
5
+ attr_accessor :id, :answer_id, :parser
6
+ attr_accessor :rule, :message
7
+ has_children :validation_conditions
7
8
 
8
9
 
9
- def default_options
10
- {:rule => "A"}
11
- end
12
- def parse_args(args)
13
- args[0] || {}
14
- end
15
- def parse_opts(opts)
16
- {} # toss the method name and reference identifier by default
17
- end
10
+ def default_options
11
+ {:rule => "A"}
12
+ end
13
+ def parse_args(args)
14
+ args[0] || {}
15
+ end
16
+ def parse_opts(opts)
17
+ {} # toss the method name and reference identifier by default
18
+ end
18
19
 
20
+ end
19
21
  end
@@ -1,19 +1,21 @@
1
- class ValidationCondition < SurveyParser::Base
2
- # Context, Conditional, Value, Reference
3
- attr_accessor :id, :validation_id, :rule_key, :parser
4
- attr_accessor :operator
5
- attr_accessor :question_id, :answer_id, :datetime_value, :integer_value, :float_value, :unit, :text_value, :string_value, :response_other, :regexp
6
- attr_accessor :question_reference, :answer_reference
1
+ module SurveyParser
2
+ class ValidationCondition < SurveyParser::Base
3
+ # Context, Conditional, Value, Reference
4
+ attr_accessor :id, :validation_id, :rule_key, :parser
5
+ attr_accessor :operator
6
+ attr_accessor :question_id, :answer_id, :datetime_value, :integer_value, :float_value, :unit, :text_value, :string_value, :response_other, :regexp
7
+ attr_accessor :question_reference, :answer_reference
7
8
 
8
- def default_options
9
- { :operator => "==" }
10
- end
11
- def parse_args(args)
12
- a0, a1 = args
13
- {:operator => a0}.merge(a1 || {})
14
- end
15
- def parse_opts(opts)
16
- {:rule_key => opts[:reference_identifier]}
17
- end
9
+ def default_options
10
+ { :operator => "==" }
11
+ end
12
+ def parse_args(args)
13
+ a0, a1 = args
14
+ {:operator => a0}.merge(a1 || {})
15
+ end
16
+ def parse_opts(opts)
17
+ {:rule_key => opts[:reference_identifier]}
18
+ end
18
19
 
20
+ end
19
21
  end
data/spec/factories.rb CHANGED
@@ -98,7 +98,7 @@ end
98
98
  Factory.define :response_set do |r|
99
99
  r.user_id {}
100
100
  r.association :survey # r.survey_id {}
101
- r.access_code {ResponseSet.make_tiny_code}
101
+ r.access_code {Surveyor.make_tiny_code}
102
102
  r.started_at {Time.now}
103
103
  r.completed_at {}
104
104
  end
data/surveyor.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{surveyor}
8
- s.version = "0.9.1"
8
+ s.version = "0.9.2"
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"]
@@ -137,6 +137,7 @@ Gem::Specification.new do |s|
137
137
  "script/surveyor/base.rb",
138
138
  "script/surveyor/dependency.rb",
139
139
  "script/surveyor/dependency_condition.rb",
140
+ "script/surveyor/parser.rb",
140
141
  "script/surveyor/question.rb",
141
142
  "script/surveyor/question_group.rb",
142
143
  "script/surveyor/specs/answer_spec.rb",
@@ -146,7 +147,6 @@ Gem::Specification.new do |s|
146
147
  "script/surveyor/specs/validation_condition_spec.rb",
147
148
  "script/surveyor/specs/validation_spec.rb",
148
149
  "script/surveyor/survey.rb",
149
- "script/surveyor/survey_parser.rb",
150
150
  "script/surveyor/survey_section.rb",
151
151
  "script/surveyor/validation.rb",
152
152
  "script/surveyor/validation_condition.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.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Chamberlain
@@ -154,6 +154,7 @@ files:
154
154
  - script/surveyor/base.rb
155
155
  - script/surveyor/dependency.rb
156
156
  - script/surveyor/dependency_condition.rb
157
+ - script/surveyor/parser.rb
157
158
  - script/surveyor/question.rb
158
159
  - script/surveyor/question_group.rb
159
160
  - script/surveyor/specs/answer_spec.rb
@@ -163,7 +164,6 @@ files:
163
164
  - script/surveyor/specs/validation_condition_spec.rb
164
165
  - script/surveyor/specs/validation_spec.rb
165
166
  - script/surveyor/survey.rb
166
- - script/surveyor/survey_parser.rb
167
167
  - script/surveyor/survey_section.rb
168
168
  - script/surveyor/validation.rb
169
169
  - script/surveyor/validation_condition.rb
@@ -1,186 +0,0 @@
1
- require 'activesupport' # for pluralize, humanize in ActiveSupport::CoreExtensions::String::Inflections
2
-
3
- class SurveyParser
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 :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.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.surveys = []
36
- self.grid_answers = []
37
- initialize_counters(@@models)
38
- initialize_fixtures(@@models.map(&:pluralize), File.join(RAILS_ROOT, "surveys", "fixtures"))
39
- end
40
-
41
- # @last_survey_id, @last_survey_section_id, etc.
42
- def initialize_counters(names)
43
- names.each{|name| instance_variable_set("@last_#{name}_id", 0)}
44
- end
45
-
46
- # @surveys_yml, @survey_sections_yml, etc.
47
- def initialize_fixtures(names, path)
48
- names.each {|name| file = instance_variable_set("@#{name}_yml", "#{path}/#{name}.yml"); File.truncate(file, 0) if File.exist?(file) }
49
- end
50
-
51
- # This method_missing does all the heavy lifting for the DSL
52
- def method_missing(missing_method, *args, &block)
53
- method_name, reference_identifier = missing_method.to_s.split("_", 2)
54
- opts = {:method_name => method_name, :reference_identifier => reference_identifier}
55
- case method_name
56
- when "survey"
57
- self.current_survey = Survey.new(self, args, opts)
58
- evaluate_the "survey", &block
59
-
60
- when "section"
61
- self.current_survey_section = SurveySection.new(self.current_survey, args, opts.merge({:display_order => current_survey.survey_sections.size + 1}))
62
- evaluate_the "survey_section", &block
63
-
64
- when "group", "g", "grid", "repeater"
65
- self.current_question_group = QuestionGroup.new(self.current_survey_section, args, opts)
66
- evaluate_the "question_group", &block
67
-
68
- when "question", "q", "label", "image"
69
- drop_the &block
70
- self.current_question = Question.new(self.current_survey_section, args, opts.merge(:question_group_id => current_question_group ? current_question_group.id : nil))
71
- add_grid_answers if in_a_grid?
72
-
73
- when "dependency", "d"
74
- drop_the &block
75
- self.current_dependency = Dependency.new(self.current_question_group || current_question, args, opts)
76
-
77
- when "condition", "c"
78
- drop_the &block
79
- raise "Error: No current dependency or validation for this condition" if self.current_dependency.nil? && self.current_validation.nil?
80
- if self.current_dependency.nil?
81
- self.current_validation.validation_conditions << ValidationCondition.new(self.current_validation, args, opts)
82
- else
83
- self.current_dependency.dependency_conditions << DependencyCondition.new(self.current_dependency, args, opts)
84
- end
85
-
86
- when "answer", "a"
87
- drop_the &block
88
- if in_a_grid?
89
- self.grid_answers << Answer.new(nil, args, opts.merge(:display_order => grid_answers.size + 1))
90
- else
91
- raise "Error: No current question" if self.current_question.nil?
92
- self.current_answer = Answer.new(self.current_question, args, opts.merge(:display_order => current_question.answers.size + 1))
93
- end
94
-
95
- when "validation", "v"
96
- drop_the &block
97
- self.current_validation = Validation.new(self.current_answer, args, opts)
98
-
99
- else
100
- raise " ERROR: '#{missing_method}' not valid method"
101
-
102
- end
103
- end
104
-
105
- def drop_the(&block)
106
- raise "Error, I'm dropping the block like it's hot" if block_given?
107
- end
108
-
109
- def evaluate_the(model, &block)
110
- raise "Error: A #{model.humanize} cannot be empty" unless block_given?
111
- self.instance_eval(&block)
112
- self.send("clear_current", model)
113
- end
114
-
115
- def clear_current(model)
116
- # puts "clear_current #{model}"
117
- case model
118
- when "survey"
119
- self.current_survey.reconcile_dependencies unless current_survey.nil?
120
- when "question_group"
121
- self.grid_answers = []
122
- clear_current("question")
123
- when "question"
124
- @current_dependency = nil
125
- when "answer"
126
- @current_validation = nil
127
- end
128
- instance_variable_set("@current_#{model}", nil)
129
- model.classify.constantize.send(:children).each{|m| clear_current(m.to_s.singularize)}
130
- end
131
-
132
- def current_survey=(s)
133
- clear_current "survey"
134
- self.surveys << s
135
- @current_survey = s
136
- end
137
- def current_survey_section=(s)
138
- clear_current "survey_section"
139
- self.current_survey.survey_sections << s
140
- @current_survey_section = s
141
- end
142
- def current_question_group=(g)
143
- clear_current "question_group"
144
- self.current_survey_section.question_groups << g
145
- @current_question_group = g
146
- end
147
- def current_question=(q)
148
- clear_current "question"
149
- self.current_survey_section.questions << q
150
- @current_question = q
151
- end
152
- def current_dependency=(d)
153
- raise "Error: No question or question group" unless (dependent = self.current_question_group || self.current_question)
154
- dependent.dependency = d
155
- @current_dependency = d
156
- end
157
- def current_answer=(a)
158
- raise "Error: No current question" if self.current_question.nil?
159
- self.current_question.answers << a
160
- @current_answer = a
161
- end
162
- def current_validation=(v)
163
- clear_current "validation"
164
- self.current_answer.validation = v
165
- @current_validation = v
166
- end
167
-
168
- def in_a_grid?
169
- self.current_question_group and self.current_question_group.display_type == "grid"
170
- end
171
-
172
- def add_grid_answers
173
- self.grid_answers.each do |grid_answer|
174
- my_answer = grid_answer.dup
175
- my_answer.id = new_answer_id
176
- my_answer.question_id = self.current_question.id
177
- my_answer.parser = self
178
- self.current_answer = my_answer
179
- end
180
- end
181
-
182
- def to_files
183
- self.surveys.compact.map(&:to_file)
184
- end
185
-
186
- end