hssc_surveyor 1.4.1.pre

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.
Files changed (212) hide show
  1. data/.gitignore +28 -0
  2. data/.rspec +1 -0
  3. data/CHANGELOG.md +198 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.rails_version +19 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +186 -0
  8. data/Rakefile +105 -0
  9. data/app/controllers/surveyor_controller.rb +6 -0
  10. data/app/helpers/results_helper.rb +20 -0
  11. data/app/helpers/survey_form_builder.rb +37 -0
  12. data/app/helpers/surveyor_helper.rb +3 -0
  13. data/app/inputs/quiet_input.rb +5 -0
  14. data/app/inputs/surveyor_check_boxes_input.rb +35 -0
  15. data/app/inputs/surveyor_radio_input.rb +18 -0
  16. data/app/models/answer.rb +4 -0
  17. data/app/models/dependency.rb +4 -0
  18. data/app/models/dependency_condition.rb +4 -0
  19. data/app/models/question.rb +4 -0
  20. data/app/models/question_group.rb +5 -0
  21. data/app/models/response.rb +5 -0
  22. data/app/models/response_set.rb +4 -0
  23. data/app/models/survey.rb +4 -0
  24. data/app/models/survey_section.rb +5 -0
  25. data/app/models/survey_section_sweeper.rb +15 -0
  26. data/app/models/survey_translation.rb +5 -0
  27. data/app/models/validation.rb +4 -0
  28. data/app/models/validation_condition.rb +4 -0
  29. data/app/views/layouts/results.html.erb +13 -0
  30. data/app/views/layouts/surveyor_default.html.erb +12 -0
  31. data/app/views/partials/_answer.html.haml +25 -0
  32. data/app/views/partials/_dependents.html.haml +5 -0
  33. data/app/views/partials/_question.html.haml +41 -0
  34. data/app/views/partials/_question_group.html.haml +44 -0
  35. data/app/views/partials/_section.html.haml +12 -0
  36. data/app/views/partials/_section_menu.html.haml +12 -0
  37. data/app/views/surveyor/edit.html.haml +24 -0
  38. data/app/views/surveyor/export.json.rabl +85 -0
  39. data/app/views/surveyor/new.html.haml +24 -0
  40. data/app/views/surveyor/show.html.haml +74 -0
  41. data/app/views/surveyor/show.json.rabl +15 -0
  42. data/ci-exec.sh +56 -0
  43. data/config/routes.rb +8 -0
  44. data/cucumber.yml +10 -0
  45. data/doc/REPRESENTATIONS.md +34 -0
  46. data/doc/api_id_schema.json +7 -0
  47. data/doc/question types.png +0 -0
  48. data/doc/response_set_schema.json +54 -0
  49. data/doc/surveyor question combinations.png +0 -0
  50. data/doc/surveyor reject or delete decision matrix.png +0 -0
  51. data/doc/surveyor_models.png +0 -0
  52. data/doc/surveyor_models2.png +0 -0
  53. data/doc/surveyor_timestamp_schema.json +9 -0
  54. data/features/ajax_submissions.feature +140 -0
  55. data/features/export_to_json.feature +344 -0
  56. data/features/internationalization.feature +121 -0
  57. data/features/no_duplicates.feature +110 -0
  58. data/features/show_survey.feature +71 -0
  59. data/features/step_definitions/parser_steps.rb +145 -0
  60. data/features/step_definitions/surveyor_steps.rb +325 -0
  61. data/features/step_definitions/ui_steps.rb +25 -0
  62. data/features/step_definitions/web_steps.rb +225 -0
  63. data/features/support/REDCapDemoDatabase_DataDictionary.csv +127 -0
  64. data/features/support/database_cleaner.rb +16 -0
  65. data/features/support/env.rb +56 -0
  66. data/features/support/hooks.rb +4 -0
  67. data/features/support/paths.rb +39 -0
  68. data/features/support/redcap_new_headers.csv +1 -0
  69. data/features/support/redcap_siblings.csv +1 -0
  70. data/features/support/redcap_whitespace.csv +1 -0
  71. data/features/support/selectors.rb +39 -0
  72. data/features/support/simultaneous_ajax.rb +101 -0
  73. data/features/support/single_quit_selenium_driver.rb +23 -0
  74. data/features/support/slow_updates.rb +18 -0
  75. data/features/surveyor.feature +895 -0
  76. data/features/surveyor_dependencies.feature +476 -0
  77. data/features/surveyor_parser.feature +504 -0
  78. data/features/z_redcap_parser.feature +62 -0
  79. data/lib/assets/images/surveyor/next.gif +0 -0
  80. data/lib/assets/images/surveyor/prev.gif +0 -0
  81. data/lib/assets/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  82. data/lib/assets/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  83. data/lib/assets/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  84. data/lib/assets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  85. data/lib/assets/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  86. data/lib/assets/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  87. data/lib/assets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  88. data/lib/assets/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  89. data/lib/assets/images/ui-icons_222222_256x240.png +0 -0
  90. data/lib/assets/images/ui-icons_2e83ff_256x240.png +0 -0
  91. data/lib/assets/images/ui-icons_454545_256x240.png +0 -0
  92. data/lib/assets/images/ui-icons_888888_256x240.png +0 -0
  93. data/lib/assets/images/ui-icons_cd0a0a_256x240.png +0 -0
  94. data/lib/assets/javascripts/surveyor/jquery-1.9.0.js +9555 -0
  95. data/lib/assets/javascripts/surveyor/jquery-ui-1.10.0.custom.js +14850 -0
  96. data/lib/assets/javascripts/surveyor/jquery-ui-timepicker-addon.js +1919 -0
  97. data/lib/assets/javascripts/surveyor/jquery.maskedinput.js +338 -0
  98. data/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js +240 -0
  99. data/lib/assets/javascripts/surveyor/jquery.surveyor.js +156 -0
  100. data/lib/assets/stylesheets/surveyor/jquery-ui-1.10.0.custom.css +1174 -0
  101. data/lib/assets/stylesheets/surveyor/jquery-ui-timepicker-addon.css +11 -0
  102. data/lib/assets/stylesheets/surveyor/reset.css +48 -0
  103. data/lib/assets/stylesheets/surveyor/results.css +125 -0
  104. data/lib/assets/stylesheets/surveyor/ui.slider.extras.css +110 -0
  105. data/lib/assets/stylesheets/surveyor.sass +132 -0
  106. data/lib/generators/surveyor/custom_generator.rb +18 -0
  107. data/lib/generators/surveyor/install_generator.rb +102 -0
  108. data/lib/generators/surveyor/templates/app/assets/javascripts/surveyor_all.js +6 -0
  109. data/lib/generators/surveyor/templates/app/assets/stylesheets/surveyor_all.css +9 -0
  110. data/lib/generators/surveyor/templates/app/controllers/surveyor_controller.rb +40 -0
  111. data/lib/generators/surveyor/templates/app/views/layouts/surveyor_custom.html.erb +13 -0
  112. data/lib/generators/surveyor/templates/config/locales/surveyor_en.yml +19 -0
  113. data/lib/generators/surveyor/templates/config/locales/surveyor_es.yml +19 -0
  114. data/lib/generators/surveyor/templates/config/locales/surveyor_he.yml +19 -0
  115. data/lib/generators/surveyor/templates/config/locales/surveyor_ko.yml +19 -0
  116. data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +10 -0
  117. data/lib/generators/surveyor/templates/db/migrate/add_api_ids.rb +14 -0
  118. data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +12 -0
  119. data/lib/generators/surveyor/templates/db/migrate/add_attachment_to_response.rb +5 -0
  120. data/lib/generators/surveyor/templates/db/migrate/add_correct_answer_id_to_questions.rb +10 -0
  121. data/lib/generators/surveyor/templates/db/migrate/add_default_value_to_answers.rb +10 -0
  122. data/lib/generators/surveyor/templates/db/migrate/add_display_order_to_surveys.rb +10 -0
  123. data/lib/generators/surveyor/templates/db/migrate/add_display_type_to_answers.rb +14 -0
  124. data/lib/generators/surveyor/templates/db/migrate/add_index_to_response_sets.rb +10 -0
  125. data/lib/generators/surveyor/templates/db/migrate/add_index_to_surveys.rb +10 -0
  126. data/lib/generators/surveyor/templates/db/migrate/add_input_mask_attributes_to_answer.rb +12 -0
  127. data/lib/generators/surveyor/templates/db/migrate/add_section_id_to_responses.rb +12 -0
  128. data/lib/generators/surveyor/templates/db/migrate/add_unique_index_on_access_code_and_version_in_surveys.rb +10 -0
  129. data/lib/generators/surveyor/templates/db/migrate/add_unique_indicies.rb +18 -0
  130. data/lib/generators/surveyor/templates/db/migrate/add_version_to_surveys.rb +10 -0
  131. data/lib/generators/surveyor/templates/db/migrate/api_ids_must_be_unique.rb +23 -0
  132. data/lib/generators/surveyor/templates/db/migrate/create_answers.rb +38 -0
  133. data/lib/generators/surveyor/templates/db/migrate/create_dependencies.rb +23 -0
  134. data/lib/generators/surveyor/templates/db/migrate/create_dependency_conditions.rb +30 -0
  135. data/lib/generators/surveyor/templates/db/migrate/create_question_groups.rb +28 -0
  136. data/lib/generators/surveyor/templates/db/migrate/create_questions.rb +37 -0
  137. data/lib/generators/surveyor/templates/db/migrate/create_response_sets.rb +23 -0
  138. data/lib/generators/surveyor/templates/db/migrate/create_responses.rb +34 -0
  139. data/lib/generators/surveyor/templates/db/migrate/create_survey_sections.rb +30 -0
  140. data/lib/generators/surveyor/templates/db/migrate/create_survey_translations.rb +19 -0
  141. data/lib/generators/surveyor/templates/db/migrate/create_surveys.rb +32 -0
  142. data/lib/generators/surveyor/templates/db/migrate/create_validation_conditions.rb +33 -0
  143. data/lib/generators/surveyor/templates/db/migrate/create_validations.rb +21 -0
  144. data/lib/generators/surveyor/templates/db/migrate/drop_unique_index_on_access_code_in_surveys.rb +10 -0
  145. data/lib/generators/surveyor/templates/db/migrate/update_blank_api_ids_on_question_group.rb +22 -0
  146. data/lib/generators/surveyor/templates/db/migrate/update_blank_versions_on_surveys.rb +13 -0
  147. data/lib/generators/surveyor/templates/surveys/EXTENDING_SURVEYOR.md +52 -0
  148. data/lib/generators/surveyor/templates/surveys/MODIFYING_SURVEYOR.md +91 -0
  149. data/lib/generators/surveyor/templates/surveys/date_survey.rb +16 -0
  150. data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +284 -0
  151. data/lib/generators/surveyor/templates/surveys/languages.rb +14 -0
  152. data/lib/generators/surveyor/templates/surveys/quiz.rb +11 -0
  153. data/lib/generators/surveyor/templates/surveys/translations/languages.es.yml +18 -0
  154. data/lib/generators/surveyor/templates/surveys/translations/languages.he.yml +18 -0
  155. data/lib/generators/surveyor/templates/surveys/translations/languages.ko.yml +18 -0
  156. data/lib/generators/surveyor/templates/vendor/assets/stylesheets/custom.sass +5 -0
  157. data/lib/surveyor/acts_as_response.rb +17 -0
  158. data/lib/surveyor/common.rb +59 -0
  159. data/lib/surveyor/engine.rb +10 -0
  160. data/lib/surveyor/helpers/asset_pipeline.rb +13 -0
  161. data/lib/surveyor/helpers/formtastic_custom_input.rb +13 -0
  162. data/lib/surveyor/helpers/surveyor_helper_methods.rb +103 -0
  163. data/lib/surveyor/models/answer_methods.rb +86 -0
  164. data/lib/surveyor/models/dependency_condition_methods.rb +72 -0
  165. data/lib/surveyor/models/dependency_methods.rb +60 -0
  166. data/lib/surveyor/models/question_group_methods.rb +61 -0
  167. data/lib/surveyor/models/question_methods.rb +115 -0
  168. data/lib/surveyor/models/response_methods.rb +132 -0
  169. data/lib/surveyor/models/response_set_methods.rb +196 -0
  170. data/lib/surveyor/models/survey_methods.rb +103 -0
  171. data/lib/surveyor/models/survey_section_methods.rb +56 -0
  172. data/lib/surveyor/models/survey_translation_methods.rb +33 -0
  173. data/lib/surveyor/models/validation_condition_methods.rb +56 -0
  174. data/lib/surveyor/models/validation_methods.rb +48 -0
  175. data/lib/surveyor/mustache_context.rb +11 -0
  176. data/lib/surveyor/parser.rb +428 -0
  177. data/lib/surveyor/redcap_parser.rb +289 -0
  178. data/lib/surveyor/surveyor_controller_methods.rb +237 -0
  179. data/lib/surveyor/unparser.rb +147 -0
  180. data/lib/surveyor/version.rb +3 -0
  181. data/lib/surveyor.rb +13 -0
  182. data/lib/tasks/surveyor_tasks.rake +88 -0
  183. data/rails/init.rb +1 -0
  184. data/spec/controllers/surveyor_controller_spec.rb +307 -0
  185. data/spec/factories.rb +161 -0
  186. data/spec/helpers/formtastic_custom_input_spec.rb +15 -0
  187. data/spec/helpers/surveyor_helper_spec.rb +118 -0
  188. data/spec/lib/benchmark_spec.rb +22 -0
  189. data/spec/lib/chinese_survey.rb +14 -0
  190. data/spec/lib/common_spec.rb +34 -0
  191. data/spec/lib/parser_spec.rb +204 -0
  192. data/spec/lib/rake_kitchen_sink.rb +40 -0
  193. data/spec/lib/redcap_parser_spec.rb +75 -0
  194. data/spec/lib/tasks_spec.rake +26 -0
  195. data/spec/lib/unparser_spec.rb +126 -0
  196. data/spec/models/answer_spec.rb +175 -0
  197. data/spec/models/dependency_condition_spec.rb +439 -0
  198. data/spec/models/dependency_spec.rb +101 -0
  199. data/spec/models/question_group_spec.rb +93 -0
  200. data/spec/models/question_spec.rb +207 -0
  201. data/spec/models/response_set_spec.rb +477 -0
  202. data/spec/models/response_spec.rb +218 -0
  203. data/spec/models/survey_section_spec.rb +85 -0
  204. data/spec/models/survey_spec.rb +191 -0
  205. data/spec/models/validation_condition_spec.rb +113 -0
  206. data/spec/models/validation_spec.rb +74 -0
  207. data/spec/rcov.opts +2 -0
  208. data/spec/spec.opts +4 -0
  209. data/spec/spec_helper.rb +56 -0
  210. data/stacktests.sh +65 -0
  211. data/surveyor.gemspec +45 -0
  212. metadata +657 -0
@@ -0,0 +1,428 @@
1
+ %w(survey survey_translation survey_section question_group question dependency dependency_condition answer validation validation_condition).each {|model| require model }
2
+
3
+ require 'yaml'
4
+
5
+ module Surveyor
6
+ class ParserError < StandardError; end
7
+ class Parser
8
+ class << self; attr_accessor :options, :log end
9
+
10
+ # Attributes
11
+ attr_accessor :context
12
+
13
+ # Class methods
14
+ def self.parse_file(filename, options={})
15
+ self.parse(File.read(filename),{:filename => filename}.merge(options))
16
+ end
17
+ def self.parse(str, options={})
18
+ self.ensure_attrs
19
+ self.options = options
20
+ self.log[:source] = str
21
+ Surveyor::Parser.rake_trace "\n"
22
+ Surveyor::Parser.new.parse(str)
23
+ Surveyor::Parser.rake_trace "\n"
24
+ end
25
+ def self.ensure_attrs
26
+ self.options ||= {}
27
+ self.log ||= {}
28
+ self.log[:indent] ||= 0
29
+ self.log[:source] ||= ""
30
+ end
31
+ def self.rake_trace(str, indent_increment=0)
32
+ self.ensure_attrs
33
+ unless str.blank?
34
+ puts "#{' ' * self.log[:indent]}#{str}" if self.options[:trace] == true
35
+ end
36
+ self.log[:indent] += indent_increment
37
+ end
38
+ # from https://github.com/rails/rails/blob/master/actionpack/lib/action_view/template/error.rb#L81
39
+ def self.source_extract(line)
40
+ source_code = self.log[:source].split("\n")
41
+ radius = 3
42
+ start_on_line = [ line - radius - 1, 0 ].max
43
+ end_on_line = [ line + radius - 1, source_code.length].min
44
+
45
+ return unless source_code = source_code[start_on_line..end_on_line]
46
+ line_counter = start_on_line
47
+ source_code.sum do |line|
48
+ line_counter += 1
49
+ "#{line_counter}: #{line}\n"
50
+ end
51
+ end
52
+ def self.raise_error(str, skip_trace = false)
53
+ self.ensure_attrs
54
+ line = caller[1].split('/').last.split(':')[1].to_i
55
+
56
+ raise Surveyor::ParserError, "#{str}\n" if skip_trace
57
+ raise Surveyor::ParserError, "#{self.source_extract(line)}\nline \##{line}: #{str}\n"
58
+ end
59
+
60
+ # Instance methods
61
+ def initialize
62
+ self.context = {}
63
+ end
64
+ def parse(str)
65
+ instance_eval(str)
66
+ return context[:survey]
67
+ end
68
+ # This method_missing does all the heavy lifting for the DSL
69
+ def method_missing(missing_method, *args, &block)
70
+ method_name, reference_identifier = missing_method.to_s.split("_", 2)
71
+ type = full(method_name)
72
+ Surveyor::Parser.raise_error( "\"#{type}\" is not a surveyor method." )if !%w(survey survey_translation survey_section question_group question dependency dependency_condition answer validation validation_condition).include?(type)
73
+
74
+ Surveyor::Parser.rake_trace(reference_identifier.blank? ? "#{type} #{args.map(&:inspect).join ', '}" : "#{type}_#{reference_identifier} #{args.map(&:inspect).join ', '}",
75
+ block_models.include?(type) ? 2 : 0)
76
+
77
+ # check for blocks
78
+ Surveyor::Parser.raise_error "A #{type.humanize.downcase} should take a block" if block_models.include?(type) && !block_given?
79
+ Surveyor::Parser.raise_error "A #{type.humanize.downcase} doesn't take a block" if !block_models.include?(type) && block_given?
80
+
81
+ # parse and build
82
+ type.classify.constantize.new.extend("SurveyorParser#{type.classify}Methods".constantize).parse_and_build(context, args, method_name, reference_identifier)
83
+
84
+ # evaluate and clear context for block models
85
+ if block_models.include?(type)
86
+ self.instance_eval(&block)
87
+ if type == 'survey'
88
+ resolve_dependency_condition_references
89
+ resolve_question_correct_answers
90
+ report_lost_and_duplicate_references
91
+ report_missing_default_locale
92
+ Surveyor::Parser.rake_trace("", -2)
93
+ if context[:survey].save
94
+ Surveyor::Parser.rake_trace "Survey saved."
95
+ else
96
+ Surveyor::Parser.raise_error "Survey not saved: #{context[:survey].errors.full_messages.join(", ")}"
97
+ end
98
+ else
99
+ Surveyor::Parser.rake_trace("", -2)
100
+ context[type.to_sym].clear(context)
101
+ end
102
+ end
103
+ end
104
+
105
+ # Private methods
106
+ private
107
+
108
+ def full(method_name)
109
+ case method_name.to_s
110
+ when /^translations$/; "survey_translation"
111
+ when /^section$/; "survey_section"
112
+ when /^g$|^grid$|^group$|^repeater$/; "question_group"
113
+ when /^q$|^label$|^image$/; "question"
114
+ when /^a$/; "answer"
115
+ when /^d$/; "dependency"
116
+ when /^c(ondition)?$/; context[:validation] ? "validation_condition" : "dependency_condition"
117
+ when /^v$/; "validation"
118
+ when /^dc(ondition)?$/; "dependency_condition"
119
+ when /^vc(ondition)?$/; "validation_condition"
120
+ else method_name
121
+ end
122
+ end
123
+ def block_models
124
+ %w(survey survey_section question_group)
125
+ end
126
+ def report_missing_default_locale
127
+ if !self.context[:survey].translations.empty? && self.context[:survey].translations.select{|t|YAML::load(t.translation)=={}}.empty?
128
+ Surveyor::Parser.raise_error("No default locale specified for translations.",true)
129
+ end
130
+ end
131
+ def report_lost_and_duplicate_references
132
+ Surveyor::Parser.raise_error("Bad references: #{self.context[:bad_references].join("; ")}", true) unless self.context[:bad_references].empty?
133
+ Surveyor::Parser.raise_error("Duplicate references: #{self.context[:duplicate_references].join("; ")}", true) unless self.context[:duplicate_references].empty?
134
+ end
135
+ def resolve_question_correct_answers
136
+ self.context[:questions_with_correct_answers].each do |question_reference_idenitifer, correct_answer_reference|
137
+ # Looking up references for quiz answers
138
+ if self.context[:answer_references][question_reference_idenitifer] &&
139
+ (a = self.context[:answer_references][question_reference_idenitifer][correct_answer_reference]) &&
140
+ a.save
141
+ self.context[:question_references][question_reference_idenitifer].correct_answer_id = a.id
142
+ else
143
+ self.context[:bad_references].push "q_#{question_reference_idenitifer}.correct => a_#{correct_answer_reference}"
144
+ end
145
+ end
146
+ end
147
+ def resolve_dependency_condition_references
148
+ self.context[:dependency_conditions].each do |dc|
149
+ # Looking up references to questions and answers for linking the dependency objects
150
+ self.context[:bad_references].push "q_#{dc.question_reference}" unless (dc.question = self.context[:question_references][dc.question_reference])
151
+ self.context[:answer_references][dc.question_reference] ||= {}
152
+ self.context[:bad_references].push "q_#{dc.question_reference}, a_#{dc.answer_reference}" if !dc.answer_reference.blank? and (dc.answer = self.context[:answer_references][dc.question_reference][dc.answer_reference]).nil?
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ # Surveyor models with extra parsing methods
159
+
160
+ # Survey model
161
+ module SurveyorParserSurveyMethods
162
+ def parse_and_build(context, args, original_method, reference_identifier)
163
+ # clear context
164
+ clear(context)
165
+
166
+ # build and set context
167
+ title = args[0]
168
+ args[1] ||= {}
169
+ context[:default_mandatory] = args[1].delete(:default_mandatory) || false
170
+ self.attributes = ({
171
+ :title => title,
172
+ :reference_identifier => reference_identifier }.merge(args[1]))
173
+ context[:survey] = self
174
+ end
175
+ def clear(context)
176
+ context.delete_if{|k,v| true}
177
+ context.merge!({
178
+ :question_references => {},
179
+ :answer_references => {},
180
+ :bad_references => [],
181
+ :duplicate_references => [],
182
+ :dependency_conditions => [],
183
+ :questions_with_correct_answers => {},
184
+ :default_mandatory => false
185
+ })
186
+ end
187
+ end
188
+
189
+ # SurveySection model
190
+ module SurveyorParserSurveyTranslationMethods
191
+ def parse_and_build(context, args, original_method, reference_identifier)
192
+ dir = Surveyor::Parser.options[:filename].nil? ? Dir.pwd : File.dirname(Surveyor::Parser.options[:filename])
193
+ # build, no change in context
194
+ args[0].each do |k,v|
195
+ case v
196
+ when Hash
197
+ trans = YAML::dump(v)
198
+ when String
199
+ trans = File.read(File.join(dir,v))
200
+ when :default
201
+ trans = YAML::dump({})
202
+ end
203
+ context[:survey].translations << self.class.new(:locale => k.to_s, :translation => trans)
204
+ end
205
+ end
206
+ end
207
+
208
+ # SurveySection model
209
+ module SurveyorParserSurveySectionMethods
210
+ def parse_and_build(context, args, original_method, reference_identifier)
211
+ # clear context
212
+ clear(context)
213
+
214
+ # build and set context
215
+ title = args[0]
216
+ self.attributes = ({
217
+ :title => title,
218
+ :reference_identifier => reference_identifier,
219
+ :display_order => context[:survey].sections.size }.merge(args[1] || {}))
220
+ context[:survey].sections << context[:survey_section] = self
221
+ end
222
+ def clear(context)
223
+ [ :survey_section,
224
+ :question_group,
225
+ :grid_answers,
226
+ :question,
227
+ :dependency,
228
+ :dependency_condition,
229
+ :answer,
230
+ :validation,
231
+ :validation_condition ].each{|k| context.delete k}
232
+ end
233
+ end
234
+
235
+ # QuestionGroup model
236
+ module SurveyorParserQuestionGroupMethods
237
+ def parse_and_build(context, args, original_method, reference_identifier)
238
+ # clear context
239
+ clear(context)
240
+
241
+ # build and set context
242
+ self.attributes = ({
243
+ :text => args[0] || "Question Group",
244
+ :reference_identifier => reference_identifier,
245
+ :display_type => (original_method =~ /grid|repeater/ ? original_method : "default")}.merge(args[1] || {}))
246
+ context[:question_group] = self
247
+ end
248
+ def clear(context)
249
+ [ :question_group,
250
+ :grid_answers,
251
+ :question,
252
+ :dependency,
253
+ :dependency_condition,
254
+ :answer,
255
+ :validation,
256
+ :validation_condition ].each{|k| context.delete k}
257
+ context[:grid_answers] = []
258
+ end
259
+ end
260
+
261
+ # Question model
262
+ module SurveyorParserQuestionMethods
263
+ def parse_and_build(context, args, original_method, reference_identifier)
264
+ # clear context
265
+ [ :question,
266
+ :dependency,
267
+ :dependency_condition,
268
+ :answer,
269
+ :validation,
270
+ :validation_condition ].each{|k| context.delete k}
271
+
272
+ # build and set context
273
+ text = args[0] || "Question"
274
+ hash_args = args[1] || {}
275
+ correct = hash_args.delete :correct
276
+ self.attributes = ({
277
+ :question_group => context[:question_group],
278
+ :reference_identifier => reference_identifier,
279
+ :is_mandatory => context[:default_mandatory],
280
+ :text => text,
281
+ :display_type => (original_method =~ /label|image/ ? original_method : "default"),
282
+ :display_order => context[:survey_section].questions.size }.merge(hash_args))
283
+ context[:survey_section].questions << context[:question] = self
284
+
285
+ # keep reference for correct answers
286
+ context[:questions_with_correct_answers][self.reference_identifier] = correct unless self.reference_identifier.blank? or correct.blank?
287
+
288
+ # keep reference for dependencies
289
+ unless self.reference_identifier.blank?
290
+ context[:duplicate_references].push "q_#{self.reference_identifier}" if context[:question_references].has_key?(self.reference_identifier)
291
+ context[:question_references][self.reference_identifier] = context[:question]
292
+ end
293
+
294
+ # add grid answers
295
+ if context[:question_group] && context[:question_group].display_type == "grid"
296
+ (context[:grid_answers] || []).each do |grid_answer|
297
+ a = context[:question].answers.build(grid_answer.attributes.reject{|k,v| %w(id api_id created_at updated_at).include?(k)})
298
+ context[:answer_references][self.reference_identifier] ||= {} unless self.reference_identifier.blank?
299
+ context[:answer_references][self.reference_identifier][grid_answer.reference_identifier] = a unless self.reference_identifier.blank? or grid_answer.reference_identifier.blank?
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ # Dependency model
306
+ module SurveyorParserDependencyMethods
307
+ def parse_and_build(context, args, original_method, reference_identifier)
308
+ # clear context
309
+ [ :dependency,
310
+ :dependency_condition ].each{|k| context.delete k}
311
+
312
+ # build and set context
313
+ self.attributes = (args[0] || {})
314
+ if context[:question]
315
+ context[:dependency] = context[:question].dependency = self
316
+ elsif context[:question_group]
317
+ context[:dependency] = context[:question_group].dependency = self
318
+ end
319
+ end
320
+ end
321
+
322
+ # DependencyCondition model
323
+ module SurveyorParserDependencyConditionMethods
324
+ DependencyCondition.instance_eval do
325
+ attr_accessor :question_reference, :answer_reference
326
+ attr_accessible :question_reference, :answer_reference
327
+ end
328
+ def parse_and_build(context, args, original_method, reference_identifier)
329
+ # clear context
330
+ context.delete :dependency_condition
331
+
332
+ # build and set context
333
+ a0, a1, a2 = args
334
+ self.attributes = ({
335
+ :operator => a1 || "==",
336
+ :question_reference => a0.to_s.gsub(/^q_|^question_/, ""),
337
+ :rule_key => reference_identifier
338
+ }.merge( a2.is_a?(Hash) ? a2 : { :answer_reference => a2.to_s.gsub(/^a_|^answer_/, "") }))
339
+ context[:dependency].dependency_conditions << context[:dependency_condition] = self
340
+ context[:dependency_conditions] << self
341
+ end
342
+ end
343
+
344
+ # Answer model
345
+ module SurveyorParserAnswerMethods
346
+ def parse_and_build(context, args, original_method, reference_identifier)
347
+ # clear context
348
+ [ :answer,
349
+ :validation,
350
+ :validation_condition ].each{|k| context.delete k}
351
+ attrs = { :reference_identifier => reference_identifier }.merge(parse_args(args))
352
+
353
+ # add answers to grid
354
+ if context[:question_group] && context[:question_group].display_type == "grid"
355
+ self.attributes = ({:display_order => context[:grid_answers].size}.merge(attrs))
356
+ context[:grid_answers] << context[:answer] = self
357
+ else
358
+ self.attributes = ({:display_order => context[:question].answers.size}.merge(attrs))
359
+ context[:question].answers << context[:answer] = self
360
+ # keep reference for dependencies
361
+ unless context[:question].reference_identifier.blank? or self.reference_identifier.blank?
362
+ context[:answer_references][context[:question].reference_identifier] ||= {}
363
+ context[:duplicate_references].push "q_#{context[:question].reference_identifier}, a_#{self.reference_identifier}" if context[:answer_references][context[:question].reference_identifier].has_key?(self.reference_identifier)
364
+ context[:answer_references][context[:question].reference_identifier][self.reference_identifier] = context[:answer]
365
+ end
366
+ end
367
+ end
368
+ def parse_args(args)
369
+ case args[0]
370
+ when Hash # Hash
371
+ text_args(args[0][:text]).merge(args[0])
372
+ when String # (String, Hash) or (String, Symbol, Hash)
373
+ text_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
374
+ when Symbol # (Symbol, Hash) or (Symbol, Symbol, Hash)
375
+ symbol_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
376
+ else
377
+ text_args(nil)
378
+ end
379
+ end
380
+ def text_args(text = "Answer")
381
+ {:text => text.to_s}
382
+ end
383
+ def hash_from(arg)
384
+ arg.is_a?(Symbol) ? {:response_class => arg.to_s} : arg.is_a?(Hash) ? arg : {}
385
+ end
386
+ def symbol_args(arg)
387
+ case arg
388
+ when :other
389
+ text_args("Other")
390
+ when :other_and_string
391
+ text_args("Other").merge({:response_class => "string"})
392
+ when :none, :omit # is_exclusive erases and disables other checkboxes and input elements
393
+ text_args(arg.to_s.humanize).merge({:is_exclusive => true})
394
+ when :integer, :float, :date, :time, :datetime, :text, :datetime, :string, :file
395
+ text_args(arg.to_s.humanize).merge({:response_class => arg.to_s, :display_type => "hidden_label"})
396
+ end
397
+ end
398
+ end
399
+
400
+ # Validation model
401
+ module SurveyorParserValidationMethods
402
+ def parse_and_build(context, args, original_method, reference_identifier)
403
+ # clear context
404
+ [ :validation,
405
+ :validation_condition ].each{|k| context.delete k}
406
+
407
+ context.delete_if{|k,v| %w(validation validation_condition).map(&:to_sym).include? k}
408
+
409
+ # build and set context
410
+ self.attributes = ({:rule => "A"}.merge(args[0] || {}))
411
+ context[:answer].validations << context[:validation] = self
412
+ end
413
+ end
414
+
415
+ # ValidationCondition model
416
+ module SurveyorParserValidationConditionMethods
417
+ def parse_and_build(context, args, original_method, reference_identifier)
418
+ # clear context
419
+ context.delete :validation_condition
420
+
421
+ # build and set context
422
+ a0, a1 = args
423
+ self.attributes = ({
424
+ :operator => a0 || "==",
425
+ :rule_key => reference_identifier}.merge(a1 || {}))
426
+ context[:validation].validation_conditions << context[:validation_condition] = self
427
+ end
428
+ end