upgrade_surveyor 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +18 -0
  5. data/CHANGELOG.md +253 -0
  6. data/Gemfile +5 -0
  7. data/Gemfile.rails_version +25 -0
  8. data/MIT-LICENSE +20 -0
  9. data/README.md +164 -0
  10. data/Rakefile +65 -0
  11. data/app/controllers/surveyor_controller.rb +5 -0
  12. data/app/helpers/results_helper.rb +20 -0
  13. data/app/helpers/survey_form_builder.rb +37 -0
  14. data/app/helpers/surveyor_helper.rb +3 -0
  15. data/app/inputs/quiet_input.rb +5 -0
  16. data/app/inputs/surveyor_check_boxes_input.rb +35 -0
  17. data/app/inputs/surveyor_radio_input.rb +18 -0
  18. data/app/models/answer.rb +3 -0
  19. data/app/models/dependency.rb +3 -0
  20. data/app/models/dependency_condition.rb +3 -0
  21. data/app/models/permitted_params.rb +102 -0
  22. data/app/models/question.rb +3 -0
  23. data/app/models/question_group.rb +3 -0
  24. data/app/models/response.rb +4 -0
  25. data/app/models/response_set.rb +3 -0
  26. data/app/models/survey.rb +3 -0
  27. data/app/models/survey_section.rb +4 -0
  28. data/app/models/survey_translation.rb +4 -0
  29. data/app/models/validation.rb +3 -0
  30. data/app/models/validation_condition.rb +3 -0
  31. data/app/views/layouts/results.html.erb +13 -0
  32. data/app/views/layouts/surveyor_default.html.erb +12 -0
  33. data/app/views/partials/_answer.html.haml +25 -0
  34. data/app/views/partials/_dependents.html.haml +5 -0
  35. data/app/views/partials/_question.html.haml +28 -0
  36. data/app/views/partials/_question_group.html.haml +44 -0
  37. data/app/views/partials/_section.html.haml +12 -0
  38. data/app/views/partials/_section_menu.html.haml +12 -0
  39. data/app/views/surveyor/edit.html.haml +21 -0
  40. data/app/views/surveyor/export.json.rabl +85 -0
  41. data/app/views/surveyor/new.html.haml +24 -0
  42. data/app/views/surveyor/show.html.haml +74 -0
  43. data/app/views/surveyor/show.json.rabl +15 -0
  44. data/config/routes.rb +8 -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/lib/assets/images/surveyor/next.gif +0 -0
  55. data/lib/assets/images/surveyor/prev.gif +0 -0
  56. data/lib/assets/images/surveyor/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  57. data/lib/assets/images/surveyor/ui-bg_flat_75_ffffff_40x100.png +0 -0
  58. data/lib/assets/images/surveyor/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  59. data/lib/assets/images/surveyor/ui-bg_glass_65_ffffff_1x400.png +0 -0
  60. data/lib/assets/images/surveyor/ui-bg_glass_75_dadada_1x400.png +0 -0
  61. data/lib/assets/images/surveyor/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  62. data/lib/assets/images/surveyor/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  63. data/lib/assets/images/surveyor/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  64. data/lib/assets/images/surveyor/ui-icons_222222_256x240.png +0 -0
  65. data/lib/assets/images/surveyor/ui-icons_2e83ff_256x240.png +0 -0
  66. data/lib/assets/images/surveyor/ui-icons_454545_256x240.png +0 -0
  67. data/lib/assets/images/surveyor/ui-icons_888888_256x240.png +0 -0
  68. data/lib/assets/images/surveyor/ui-icons_cd0a0a_256x240.png +0 -0
  69. data/lib/assets/javascripts/surveyor/jquery-1.9.0.js +9555 -0
  70. data/lib/assets/javascripts/surveyor/jquery-ui-1.10.0.custom.js +14850 -0
  71. data/lib/assets/javascripts/surveyor/jquery-ui-timepicker-addon.js +1919 -0
  72. data/lib/assets/javascripts/surveyor/jquery.maskedinput.js +338 -0
  73. data/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js +240 -0
  74. data/lib/assets/javascripts/surveyor/jquery.surveyor.js +154 -0
  75. data/lib/assets/stylesheets/surveyor/jquery-ui-1.10.0.custom.sass +1380 -0
  76. data/lib/assets/stylesheets/surveyor/jquery-ui-timepicker-addon.css +11 -0
  77. data/lib/assets/stylesheets/surveyor/reset.css +48 -0
  78. data/lib/assets/stylesheets/surveyor/results.css +125 -0
  79. data/lib/assets/stylesheets/surveyor/ui.slider.extras.css +110 -0
  80. data/lib/assets/stylesheets/surveyor.sass +132 -0
  81. data/lib/generators/surveyor/custom_generator.rb +18 -0
  82. data/lib/generators/surveyor/install_generator.rb +98 -0
  83. data/lib/generators/surveyor/templates/app/assets/javascripts/surveyor_all.js +6 -0
  84. data/lib/generators/surveyor/templates/app/assets/stylesheets/surveyor_all.css +9 -0
  85. data/lib/generators/surveyor/templates/app/controllers/surveyor_controller.rb +40 -0
  86. data/lib/generators/surveyor/templates/app/views/layouts/surveyor_custom.html.erb +13 -0
  87. data/lib/generators/surveyor/templates/config/locales/surveyor_en.yml +19 -0
  88. data/lib/generators/surveyor/templates/config/locales/surveyor_es.yml +19 -0
  89. data/lib/generators/surveyor/templates/config/locales/surveyor_he.yml +19 -0
  90. data/lib/generators/surveyor/templates/config/locales/surveyor_ko.yml +19 -0
  91. data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +10 -0
  92. data/lib/generators/surveyor/templates/db/migrate/add_api_ids.rb +14 -0
  93. data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +12 -0
  94. data/lib/generators/surveyor/templates/db/migrate/add_correct_answer_id_to_questions.rb +10 -0
  95. data/lib/generators/surveyor/templates/db/migrate/add_default_value_to_answers.rb +10 -0
  96. data/lib/generators/surveyor/templates/db/migrate/add_display_order_to_surveys.rb +10 -0
  97. data/lib/generators/surveyor/templates/db/migrate/add_display_type_to_answers.rb +14 -0
  98. data/lib/generators/surveyor/templates/db/migrate/add_index_to_response_sets.rb +10 -0
  99. data/lib/generators/surveyor/templates/db/migrate/add_index_to_surveys.rb +10 -0
  100. data/lib/generators/surveyor/templates/db/migrate/add_input_mask_attributes_to_answer.rb +12 -0
  101. data/lib/generators/surveyor/templates/db/migrate/add_section_id_to_responses.rb +12 -0
  102. data/lib/generators/surveyor/templates/db/migrate/add_unique_index_on_access_code_and_version_in_surveys.rb +10 -0
  103. data/lib/generators/surveyor/templates/db/migrate/add_unique_indicies.rb +18 -0
  104. data/lib/generators/surveyor/templates/db/migrate/add_version_to_surveys.rb +10 -0
  105. data/lib/generators/surveyor/templates/db/migrate/api_ids_must_be_unique.rb +23 -0
  106. data/lib/generators/surveyor/templates/db/migrate/create_answers.rb +38 -0
  107. data/lib/generators/surveyor/templates/db/migrate/create_dependencies.rb +23 -0
  108. data/lib/generators/surveyor/templates/db/migrate/create_dependency_conditions.rb +30 -0
  109. data/lib/generators/surveyor/templates/db/migrate/create_question_groups.rb +28 -0
  110. data/lib/generators/surveyor/templates/db/migrate/create_questions.rb +37 -0
  111. data/lib/generators/surveyor/templates/db/migrate/create_response_sets.rb +23 -0
  112. data/lib/generators/surveyor/templates/db/migrate/create_responses.rb +34 -0
  113. data/lib/generators/surveyor/templates/db/migrate/create_survey_sections.rb +30 -0
  114. data/lib/generators/surveyor/templates/db/migrate/create_survey_translations.rb +19 -0
  115. data/lib/generators/surveyor/templates/db/migrate/create_surveys.rb +32 -0
  116. data/lib/generators/surveyor/templates/db/migrate/create_validation_conditions.rb +33 -0
  117. data/lib/generators/surveyor/templates/db/migrate/create_validations.rb +21 -0
  118. data/lib/generators/surveyor/templates/db/migrate/drop_unique_index_on_access_code_in_surveys.rb +10 -0
  119. data/lib/generators/surveyor/templates/db/migrate/update_blank_api_ids_on_question_group.rb +22 -0
  120. data/lib/generators/surveyor/templates/db/migrate/update_blank_versions_on_surveys.rb +13 -0
  121. data/lib/generators/surveyor/templates/surveys/EXTENDING_SURVEYOR.md +52 -0
  122. data/lib/generators/surveyor/templates/surveys/MODIFYING_SURVEYOR.md +91 -0
  123. data/lib/generators/surveyor/templates/surveys/date_survey.rb +16 -0
  124. data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +280 -0
  125. data/lib/generators/surveyor/templates/surveys/languages.rb +14 -0
  126. data/lib/generators/surveyor/templates/surveys/quiz.rb +11 -0
  127. data/lib/generators/surveyor/templates/surveys/translations/languages.es.yml +18 -0
  128. data/lib/generators/surveyor/templates/surveys/translations/languages.he.yml +18 -0
  129. data/lib/generators/surveyor/templates/surveys/translations/languages.ko.yml +18 -0
  130. data/lib/generators/surveyor/templates/vendor/assets/stylesheets/custom.sass +5 -0
  131. data/lib/surveyor/acts_as_response.rb +19 -0
  132. data/lib/surveyor/common.rb +59 -0
  133. data/lib/surveyor/engine.rb +15 -0
  134. data/lib/surveyor/helpers/formtastic_custom_input.rb +13 -0
  135. data/lib/surveyor/helpers/surveyor_helper_methods.rb +86 -0
  136. data/lib/surveyor/models/answer_methods.rb +76 -0
  137. data/lib/surveyor/models/dependency_condition_methods.rb +65 -0
  138. data/lib/surveyor/models/dependency_methods.rb +57 -0
  139. data/lib/surveyor/models/question_group_methods.rb +62 -0
  140. data/lib/surveyor/models/question_methods.rb +103 -0
  141. data/lib/surveyor/models/response_methods.rb +125 -0
  142. data/lib/surveyor/models/response_set_methods.rb +187 -0
  143. data/lib/surveyor/models/survey_methods.rb +95 -0
  144. data/lib/surveyor/models/survey_section_methods.rb +48 -0
  145. data/lib/surveyor/models/survey_translation_methods.rb +28 -0
  146. data/lib/surveyor/models/validation_condition_methods.rb +42 -0
  147. data/lib/surveyor/models/validation_methods.rb +41 -0
  148. data/lib/surveyor/mustache_context.rb +13 -0
  149. data/lib/surveyor/parser.rb +427 -0
  150. data/lib/surveyor/redcap_parser.rb +288 -0
  151. data/lib/surveyor/surveyor_controller_methods.rb +237 -0
  152. data/lib/surveyor/unparser.rb +161 -0
  153. data/lib/surveyor/version.rb +3 -0
  154. data/lib/surveyor.rb +13 -0
  155. data/lib/tasks/surveyor_tasks.rake +88 -0
  156. data/rails/init.rb +1 -0
  157. data/spec/controllers/surveyor_controller_spec.rb +304 -0
  158. data/spec/factories.rb +166 -0
  159. data/spec/features/ajax_spec.rb +205 -0
  160. data/spec/features/api_spec.rb +157 -0
  161. data/spec/features/duplicate_prevention_spec.rb +50 -0
  162. data/spec/features/translations_spec.rb +116 -0
  163. data/spec/features/ui_spec.rb +466 -0
  164. data/spec/fixtures/REDCapDemoDatabase_DataDictionary.csv +127 -0
  165. data/spec/fixtures/chinese_survey.rb +14 -0
  166. data/spec/fixtures/everything.rb +215 -0
  167. data/spec/fixtures/favorites-ish.rb +22 -0
  168. data/spec/fixtures/favorites.rb +22 -0
  169. data/spec/fixtures/feelings.rb +38 -0
  170. data/spec/fixtures/lifestyle.rb +55 -0
  171. data/spec/fixtures/numbers.rb +21 -0
  172. data/spec/fixtures/redcap_new_headers.csv +1 -0
  173. data/spec/fixtures/redcap_siblings.csv +1 -0
  174. data/spec/fixtures/redcap_whitespace.csv +1 -0
  175. data/spec/helpers/formtastic_custom_input_spec.rb +15 -0
  176. data/spec/helpers/surveyor_helper_spec.rb +114 -0
  177. data/spec/lib/common_spec.rb +37 -0
  178. data/spec/lib/parser_spec.rb +393 -0
  179. data/spec/lib/rake_kitchen_sink.rb +40 -0
  180. data/spec/lib/redcap_parser_spec.rb +129 -0
  181. data/spec/lib/tasks_spec.rake +26 -0
  182. data/spec/lib/unparser_spec.rb +126 -0
  183. data/spec/models/answer_spec.rb +144 -0
  184. data/spec/models/dependency_condition_spec.rb +428 -0
  185. data/spec/models/dependency_spec.rb +90 -0
  186. data/spec/models/question_group_spec.rb +66 -0
  187. data/spec/models/question_spec.rb +176 -0
  188. data/spec/models/response_set_spec.rb +447 -0
  189. data/spec/models/response_spec.rb +205 -0
  190. data/spec/models/survey_section_spec.rb +58 -0
  191. data/spec/models/survey_spec.rb +155 -0
  192. data/spec/models/validation_condition_spec.rb +98 -0
  193. data/spec/models/validation_spec.rb +64 -0
  194. data/spec/rcov.opts +2 -0
  195. data/spec/spec.opts +4 -0
  196. data/spec/spec_helper.rb +99 -0
  197. data/spec/support/shared.rb +5 -0
  198. data/spec/support/surveyor_api_helpers.rb +15 -0
  199. data/spec/support/surveyor_ui_helpers.rb +108 -0
  200. data/spec/support/wait_for_ajax.rb +11 -0
  201. data/surveyor.gemspec +40 -0
  202. data/switch.sh +53 -0
  203. metadata +510 -0
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'rake'
3
+
4
+ describe Surveyor::Parser do
5
+ before do
6
+ @rake = Rake::Application.new
7
+ Rake.application = @rake
8
+ Rake.application.rake_require "lib/tasks/surveyor_tasks"
9
+ Rake::Task.define_task(:environment)
10
+ end
11
+ it "should return properly parse the kitchen sink survey" do
12
+ ENV["FILE"]="surveys/kitchen_sink_survey.rb"
13
+ @rake["surveyor"].invoke
14
+
15
+ Survey.count.should == 1
16
+ SurveySection.count.should == 2
17
+ Question.count.should == 44
18
+ Answer.count.should == 241
19
+ Dependency.count.should == 6
20
+ DependencyCondition.count.should == 9
21
+ QuestionGroup.count.should == 6
22
+
23
+ Survey.all.map(&:destroy)
24
+ end
25
+ it "should return properly parse a UTF8 survey" do
26
+ ENV["FILE"]="../spec/fixtures/chinese_survey.rb"
27
+ @rake["surveyor"].invoke
28
+
29
+ Survey.count.should == 1
30
+ SurveySection.count.should == 1
31
+ Question.count.should == 3
32
+ Answer.count.should == 15
33
+ Dependency.count.should == 0
34
+ DependencyCondition.count.should == 0
35
+ QuestionGroup.count.should == 1
36
+
37
+ Survey.all.map(&:destroy)
38
+ end
39
+
40
+ end
@@ -0,0 +1,129 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Surveyor::RedcapParser do
4
+ let(:parser){ Surveyor::RedcapParser.new }
5
+ it "returns a survey object" do
6
+ x = %("Variable / Field Name","Form Name","Field Units","Section Header","Field Type","Field Label","Choices OR Calculations","Field Note","Text Validation Type","Text Validation Min","Text Validation Max",Identifier?,"Branching Logic (Show field only if...)","Required Field?"\nstudy_id,demographics,,,text,"Study ID",,,,,,,,)
7
+ parser.parse(x, "redcaptest").is_a?(Survey).should be_true
8
+ end
9
+ context "parses" do
10
+ it "basic questions from REDCap" do
11
+ file = "REDCapDemoDatabase_DataDictionary.csv"
12
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
13
+ expect(Survey.count).to eq(1)
14
+ expect(Question.count).to eq(143)
15
+ expect(Answer.count).to eq(233)
16
+ expect(Dependency.count).to eq(2)
17
+ expect(DependencyCondition.count).to eq(3)
18
+ dependencies = [{rule: "A", question_reference_identifier: "given_birth"},
19
+ {rule: "A and B", question_reference_identifier: "num_children"}]
20
+ dependencies.each{|attrs| (expect(Dependency.where(rule: attrs[:rule]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
21
+ dependency_conditions_a = [{rule_key: "A", operator: "==", question_reference_identifier: "sex", answer_reference_identifier: "0"}]
22
+ dependency_conditions_ab = [{rule_key: "A", operator: "==", question_reference_identifier: "sex", answer_reference_identifier: "0"},
23
+ {rule_key: "B", operator: "==", question_reference_identifier: "given_birth", answer_reference_identifier: "1"}]
24
+ dependency_conditions_a.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.answer.reference_identifier).to eq(attrs[:answer_reference_identifier])) if attrs[:answer_reference_identifier] }
25
+ dependency_conditions_a.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
26
+ dependency_conditions_a.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.operator).to eq(attrs[:operator])) if attrs[:operator] }
27
+ dependency_conditions_ab.each{|attrs| (expect(Dependency.where(rule: "A and B").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.answer.reference_identifier).to eq(attrs[:answer_reference_identifier])) if attrs[:answer_reference_identifier] }
28
+ dependency_conditions_ab.each{|attrs| (expect(Dependency.where(rule: "A and B").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
29
+ dependency_conditions_ab.each{|attrs| (expect(Dependency.where(rule: "A and B").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.operator).to eq(attrs[:operator])) if attrs[:operator] }
30
+ end
31
+ it "question level dependencies from REDCap" do
32
+ file = "redcap_siblings.csv"
33
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
34
+ expect(Dependency.count).to eq(1)
35
+ expect(DependencyCondition.count).to eq(1)
36
+ dependencies = [{rule: "A", question_reference_identifier: "sib1yob"}]
37
+ dependencies.each{|attrs| (expect(Dependency.where(rule: attrs[:rule]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
38
+ dependency_conditions = [{rule_key: "A", operator: ">", question_reference_identifier: "sibs"}]
39
+ dependency_conditions.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
40
+ dependency_conditions.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.operator).to eq(attrs[:operator])) if attrs[:operator] }
41
+ end
42
+ it "different headers from REDCap" do
43
+ file = "redcap_new_headers.csv"
44
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
45
+ expect(Survey.count).to eq(1)
46
+ expect(Question.count).to eq(1)
47
+ expect(Answer.count).to eq(2)
48
+ end
49
+ it "different whitespace from REDCap" do
50
+ file = "redcap_whitespace.csv"
51
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
52
+ expect(Survey.count).to eq(1)
53
+ expect(Question.count).to eq(2)
54
+ expect(Answer.count).to eq(7)
55
+ answers = [{reference_identifier: "1", text: "Lexapro"},
56
+ {reference_identifier: "2", text: "Celexa"},
57
+ {reference_identifier: "3", text: "Prozac"},
58
+ {reference_identifier: "4", text: "Paxil"},
59
+ {reference_identifier: "5", text: "Zoloft"},
60
+ {reference_identifier: "0", text: "No"},
61
+ {reference_identifier: "1", text: "Yes"}]
62
+ answers.each{|attrs| (expect(Answer.where(text: attrs[:text]).first.reference_identifier).to eq(attrs[:reference_identifier]))}
63
+ end
64
+ end
65
+ context "helper methods" do
66
+ it "requires specific columns" do
67
+ # with standard fields
68
+ x = %w(field_units choices_or_calculations text_validation_type variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
69
+ parser.missing_columns(x).should be_blank
70
+ # without field_units
71
+ y = %w(choices_or_calculations text_validation_type variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
72
+ parser.missing_columns(y).should be_blank
73
+ # choices_or_calculations => choices_calculations_or_slider_labels
74
+ z = %w(field_units choices_calculations_or_slider_labels text_validation_type variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
75
+ parser.missing_columns(z).should be_blank
76
+ # text_validation_type => text_validation_type_or_show_slider_number
77
+ a = %w(field_units choices_or_calculations text_validation_type_or_show_slider_number variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
78
+ parser.missing_columns(a).should be_blank
79
+ end
80
+ it "decomposes dependency rules" do
81
+ # basic
82
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q12]="1"').should == {:rule => "A", :components => ['[f1_q12]="1"']}
83
+ # spacing
84
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q9] = "1"').should == {:rule => "A", :components => ['[f1_q9] = "1"']}
85
+ # and
86
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[pre_q88]="1" and [pre_q90]="1"').should == {:rule => "A and B", :components => ['[pre_q88]="1"', '[pre_q90]="1"']}
87
+ # or
88
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[second_q111]="1" or [second_q111]="3"').should == {:rule => "A or B", :components => ['[second_q111]="1"', '[second_q111]="3"']}
89
+ # or and
90
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[second_q100]="1" or [second_q100]="3" and [second_q101]="1"').should == {:rule => "A or B and C", :components => ['[second_q100]="1"', '[second_q100]="3"', '[second_q101]="1"']}
91
+ # and or
92
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[second_q4]="1" and [second_q11]="1" or [second_q11]="98"').should == {:rule => "A and B or C", :components => ['[second_q4]="1"', '[second_q11]="1"', '[second_q11]="98"']}
93
+ # or or or
94
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[pre_q74]="1" or [pre_q74]="2" or [pre_q74]="4" or [pre_q74]="5"').should == {:rule => "A or B or C or D", :components => ['[pre_q74]="1"', '[pre_q74]="2"', '[pre_q74]="4"', '[pre_q74]="5"']}
95
+ # and with different operator
96
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q15] >= 21 and [f1_q28] ="1"').should == {:rule => "A and B", :components => ['[f1_q15] >= 21', '[f1_q28] ="1"']}
97
+ end
98
+ it "decomposes nested dependency rules" do
99
+ # external parenthesis
100
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('([pre_q74]="1" or [pre_q74]="2" or [pre_q74]="4" or [pre_q74]="5") and [pre_q76]="2"').should == {:rule => "(A or B or C or D) and E", :components => ['[pre_q74]="1"', '[pre_q74]="2"', '[pre_q74]="4"', '[pre_q74]="5"', '[pre_q76]="2"']}
101
+ # internal parenthesis
102
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q10(4)]="1"').should == {:rule => "A", :components => ['[f1_q10(4)]="1"']}
103
+ # internal and external parenthesis
104
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('([f1_q7(11)] = "1" or [initial_52] = "1") and [pre_q76]="2"').should == {:rule => "(A or B) and C", :components => ['[f1_q7(11)] = "1"', '[initial_52] = "1"', '[pre_q76]="2"']}
105
+ end
106
+ it "decomposes shortcut dependency rules" do
107
+ # 'or' on the right of the operator
108
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_108] = "1" or "2"').should == {:rule => "A or B", :components => ['[initial_108] = "1"', '[initial_108] = "2"']}
109
+ # multiple 'or' on the right
110
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_52] = "1" or "2" or "3"').should == {:rule => "A or B or C", :components => ['[initial_52] = "1"', '[initial_52] = "2"', '[initial_52] = "3"']}
111
+ # commas on the right
112
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_189] = "1, 2, 3"').should == {:rule => "(A and B and C)", :components => ['[initial_189] = "1"', '[initial_189] = "2"', '[initial_189] = "3"']}
113
+ # multiple internal parenthesis on the left
114
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_119(1)(2)(3)(4)(5)] = "1"').should == {:rule => "(A and B and C and D and E)", :components => ['[initial_119(1)] = "1"', '[initial_119(2)] = "1"', '[initial_119(3)] = "1"', '[initial_119(4)] = "1"', '[initial_119(5)] = "1"']}
115
+ end
116
+ it "decomposes components" do
117
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component('[initial_52] = "1"').should == {:question_reference => 'initial_52', :operator => '==', :answer_reference => '1'}
118
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component('[initial_119(2)] = "1"').should == {:question_reference => 'initial_119', :operator => '==', :answer_reference => '2'}
119
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component('[f1_q15] >= 21').should == {:question_reference => 'f1_q15', :operator => '>=', :integer_value => '21'}
120
+ # basic, blanks
121
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[f1_q15]=''").should == {:question_reference => 'f1_q15', :operator => '==', :answer_reference => ''}
122
+ # basic, negatives
123
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[f1_q15]='-2'").should == {:question_reference => 'f1_q15', :operator => '==', :answer_reference => '-2'}
124
+ # internal parenthesis
125
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[hiprep_heat2(97)] = '1'").should == {:question_reference => 'hiprep_heat2', :operator => '==', :answer_reference => '97'}
126
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[hi_event1_type] <> ''").should == {:question_reference => 'hi_event1_type', :operator => '!=', :answer_reference => ''}
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "rake"
3
+
4
+ describe "app rake tasks" do
5
+ before(:all) do # do this only once before all tests
6
+ @rake = Rake::Application.new
7
+ Rake.application = @rake
8
+ Rake.application.rake_require "lib/tasks/surveyor_tasks"
9
+ Rake::Task.define_task(:environment)
10
+ end
11
+ after do # after every test
12
+ @rake[@task_name].reenable if @task_name
13
+ end
14
+
15
+ it "should have 'environment' as a prereq" do
16
+ @task_name = "surveyor:parse"
17
+ @rake[@task_name].prerequisites.should include("environment")
18
+ end
19
+ it "should should trace" do
20
+ ENV["FILE"]="surveys/kitchen_sink_survey.rb"
21
+ @task_name = "surveyor:parse"
22
+ @rake.options.trace = true
23
+ Surveyor::Parser.should_receive(:parse).with(File.read(File.join(Rails.root, ENV["FILE"])), {:trace => true})
24
+ @rake[@task_name].invoke
25
+ end
26
+ end
@@ -0,0 +1,126 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Surveyor::Unparser do
4
+ before(:each) do
5
+ @survey = Survey.new(:title => "Simple survey", :description => "very simple")
6
+ @section = @survey.sections.build(:title => "Simple section")
7
+ end
8
+
9
+ it "should unparse a basic survey, section, and question" do
10
+ q1 = @section.questions.build(:text => "What is your favorite color?", :reference_identifier => 1, :pick => :one)
11
+ a11 = q1.answers.build(:text => "red", :response_class => "answer", :reference_identifier => 1, :question => q1)
12
+ a12 = q1.answers.build(:text => "green", :response_class => "answer", :reference_identifier => 2, :question => q1)
13
+ a13 = q1.answers.build(:text => "blue", :response_class => "answer", :reference_identifier => 3, :question => q1)
14
+ a14 = q1.answers.build(:text => "Other", :response_class => "string", :reference_identifier => 4, :question => q1)
15
+ a15 = q1.answers.build(:text => "Omit", :reference_identifier => 5, :question => q1, :is_exclusive => true)
16
+ q2 = @section.questions.build(:text => "What is your name?", :reference_identifier => 2, :pick => :none)
17
+ a21 = q2.answers.build(:response_class => "string", :reference_identifier => 1, :question => q2)
18
+ Surveyor::Unparser.unparse(@survey).should ==
19
+ <<-dsl
20
+ survey "Simple survey", :description=>"very simple" do
21
+ section "Simple section" do
22
+
23
+ q_1 "What is your favorite color?", :pick=>"one"
24
+ a_1 "red"
25
+ a_2 "green"
26
+ a_3 "blue"
27
+ a_4 :other, :string
28
+ a_5 :omit
29
+
30
+ q_2 "What is your name?"
31
+ a_1 :string
32
+ end
33
+ end
34
+ dsl
35
+ end
36
+
37
+ it "should unparse groups" do
38
+ q3 = @section.questions.build(:text => "Happy?")
39
+ a31 = q3.answers.build(:text => "Yes", :question => q3)
40
+ a32 = q3.answers.build(:text => "Maybe", :question => q3)
41
+ a33 = q3.answers.build(:text => "No", :question => q3)
42
+
43
+ q4 = @section.questions.build(:text => "Energized?")
44
+ a41 = q4.answers.build(:text => "Yes", :question => q4)
45
+ a42 = q4.answers.build(:text => "Maybe", :question => q4)
46
+ a43 = q4.answers.build(:text => "No", :question => q4)
47
+
48
+ g1 = q3.build_question_group(:text => "How are you feeling?", :display_type => "grid")
49
+ q4.question_group = g1
50
+ g1.questions = [q3, q4]
51
+
52
+ q5 = @section.questions.build(:text => "Model")
53
+ a51 = q5.answers.build(:response_class => "string", :question => q3)
54
+
55
+ g2 = q5.build_question_group(:text => "Tell us about the cars you own", :display_type => "repeater")
56
+ g2.questions = [q5]
57
+
58
+ Surveyor::Unparser.unparse(@survey).should ==
59
+ <<-dsl
60
+ survey "Simple survey", :description=>"very simple" do
61
+ section "Simple section" do
62
+
63
+ grid "How are you feeling?" do
64
+ a "Yes"
65
+ a "Maybe"
66
+ a "No"
67
+ q "Happy?"
68
+ q "Energized?"
69
+ end
70
+
71
+ repeater "Tell us about the cars you own" do
72
+ q "Model"
73
+ a :string
74
+ end
75
+ end
76
+ end
77
+ dsl
78
+ end
79
+
80
+ it "should unparse a basic survey, section, and question" do
81
+ q6 = @section.questions.build(:text => "What... is your name? (e.g. It is 'Arthur', King of the Britons)", :reference_identifier => "montypython3")
82
+ a61 = q6.answers.build(:response_class => "string", :reference_identifier => 1, :question => q6)
83
+
84
+ q7 = @section.questions.build(:text => "What... is your quest? (e.g. To seek the Holy Grail)", :display_type => "label")
85
+ d1 = q7.build_dependency(:rule => "A", :question => q7)
86
+ dc1 = d1.dependency_conditions.build(:dependency => d1, :question => q6, :answer => a61, :operator => "==", :string_value => "It is 'Arthur', King of the Britons", :rule_key => "A")
87
+
88
+ q8 = @section.questions.build(:text => "How many pets do you own?")
89
+ a81 = q8.answers.build(:response_class => "integer", :question => q8)
90
+ v1 = a81.validations.build(:rule => "A", :answer => a81)
91
+ vc1 = v1.validation_conditions.build(:operator => ">=", :integer_value => 0, :validation => v1, :rule_key => "A")
92
+
93
+ q9 = @section.questions.build(:text => "Pick your favorite date AND time", :custom_renderer => "/partials/custom_question")
94
+ a91 = q9.answers.build(:response_class => "datetime", :question => q9)
95
+
96
+ q10 = @section.questions.build(:text => "What time do you usually take a lunch break?", :reference_identifier => "time_lunch")
97
+ a101 = q10.answers.build(:response_class => "time", :reference_identifier => 1, :question => q10)
98
+
99
+ Surveyor::Unparser.unparse(@survey).should ==
100
+ <<-dsl
101
+ survey "Simple survey", :description=>"very simple" do
102
+ section "Simple section" do
103
+
104
+ q_montypython3 "What... is your name? (e.g. It is 'Arthur', King of the Britons)"
105
+ a_1 :string
106
+
107
+ label "What... is your quest? (e.g. To seek the Holy Grail)"
108
+ dependency :rule=>"A"
109
+ condition_A :q_montypython3, "==", {:string_value=>"It is 'Arthur', King of the Britons", :answer_reference=>"1"}
110
+
111
+ q "How many pets do you own?"
112
+ a :integer
113
+ validation :rule=>"A"
114
+ condition_A ">=", :integer_value=>0
115
+
116
+ q "Pick your favorite date AND time", :custom_renderer=>"/partials/custom_question"
117
+ a :datetime
118
+
119
+ q_time_lunch "What time do you usually take a lunch break?"
120
+ a_1 :time
121
+ end
122
+ end
123
+ dsl
124
+ end
125
+ end
126
+
@@ -0,0 +1,144 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe Answer do
5
+ let(:answer){ FactoryGirl.create(:answer) }
6
+
7
+ context "when creating" do
8
+ it { answer.should be_valid }
9
+ it "deletes validation when deleted" do
10
+ v_id = FactoryGirl.create(:validation, :answer => answer).id
11
+ answer.destroy
12
+ Validation.find_by_id(v_id).should be_nil
13
+ end
14
+ end
15
+
16
+ context "with mustache text substitution" do
17
+ require 'mustache'
18
+ let(:mustache_context){ Class.new(::Mustache){ def site; "Northwestern"; end; def foo; "bar"; end } }
19
+ it "subsitutes Mustache context variables" do
20
+ answer.text = "You are in {{site}}"
21
+ answer.in_context(answer.text, mustache_context).should == "You are in Northwestern"
22
+ answer.text_for(nil, mustache_context).should == "You are in Northwestern"
23
+
24
+ answer.help_text = "{{site}} is your site"
25
+ answer.in_context(answer.help_text, mustache_context).should == "Northwestern is your site"
26
+ answer.help_text_for(mustache_context).should == "Northwestern is your site"
27
+
28
+ answer.default_value = "{{site}}"
29
+ answer.in_context(answer.default_value, mustache_context).should == "Northwestern"
30
+ answer.default_value_for(mustache_context).should == "Northwestern"
31
+ end
32
+ end
33
+
34
+ context "with translations" do
35
+ require 'yaml'
36
+ let(:survey){ FactoryGirl.create(:survey) }
37
+ let(:survey_section){ FactoryGirl.create(:survey_section) }
38
+ let(:survey_translation){
39
+ FactoryGirl.create(:survey_translation, :locale => :es, :translation => {
40
+ :questions => {
41
+ :name => {
42
+ :answers => {
43
+ :name => {
44
+ :help_text => "Mi nombre es..."
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }.to_yaml)
50
+ }
51
+ let(:question){ FactoryGirl.create(:question, :reference_identifier => "name") }
52
+ before do
53
+ answer.reference_identifier = "name"
54
+ answer.help_text = "My name is..."
55
+ answer.text = nil
56
+ answer.question = question
57
+ question.survey_section = survey_section
58
+ survey_section.survey = survey
59
+ survey.translations << survey_translation
60
+ end
61
+ it "returns its own translation" do
62
+ answer.translation(:es)[:help_text].should == "Mi nombre es..."
63
+ end
64
+ it "returns translations in views" do
65
+ answer.help_text_for(nil, :es).should == "Mi nombre es..."
66
+ end
67
+ it "returns its own default values" do
68
+ answer.translation(:de).should == {"text" => nil, "help_text" => "My name is...", "default_value" => nil}
69
+ end
70
+ it "returns default values in views" do
71
+ answer.help_text_for(nil, :de).should == "My name is..."
72
+ end
73
+ end
74
+
75
+ context "handling strings" do
76
+ it "#split preserves strings" do
77
+ answer.split(answer.text).should == "My favorite color is clear"
78
+ end
79
+ it "#split(:pre) preserves strings" do
80
+ answer.split(answer.text, :pre).should == "My favorite color is clear"
81
+ end
82
+ it "#split(:post) preserves strings" do
83
+ answer.split(answer.text, :post).should == ""
84
+ end
85
+ it "#split splits strings" do
86
+ answer.text = "before|after|extra"
87
+ answer.split(answer.text).should == "before|after|extra"
88
+ end
89
+ it "#split(:pre) splits strings" do
90
+ answer.text = "before|after|extra"
91
+ answer.split(answer.text, :pre).should == "before"
92
+ end
93
+ it "#split(:post) splits strings" do
94
+ answer.text = "before|after|extra"
95
+ answer.split(answer.text, :post).should == "after|extra"
96
+ end
97
+ end
98
+
99
+ context "for views" do
100
+ it "#text_for with #display_type == image" do
101
+ answer.text = "rails.png"
102
+ answer.display_type = :image
103
+ answer.text_for.should =~ /<img alt="Rails" src="\/(images|assets)\/rails\.png" \/>/
104
+ end
105
+ it "#text_for with #display_type == hidden_label" do
106
+ answer.text = "Red"
107
+ answer.text_for.should == "Red"
108
+ answer.display_type = "hidden_label"
109
+ answer.text_for.should == ""
110
+ end
111
+ it "#default_value_for"
112
+ it "#help_text_for"
113
+ it "reports DOM ready #css_class from #custom_class" do
114
+ answer.custom_class = "foo bar"
115
+ answer.css_class.should == "foo bar"
116
+ end
117
+ it "reports DOM ready #css_class from #custom_class and #is_exclusive" do
118
+ answer.custom_class = "foo bar"
119
+ answer.is_exclusive = true
120
+ answer.css_class.should == "exclusive foo bar"
121
+ end
122
+ it "#text_for preserves strings" do
123
+ answer.text_for.should == "My favorite color is clear"
124
+ end
125
+ it "#text_for(:pre) preserves strings" do
126
+ answer.text_for(:pre).should == "My favorite color is clear"
127
+ end
128
+ it "#text_for(:post) preserves strings" do
129
+ answer.text_for(:post).should == ""
130
+ end
131
+ it "#text_for splits strings" do
132
+ answer.text = "before|after|extra"
133
+ answer.text_for.should == "before|after|extra"
134
+ end
135
+ it "#text_for(:pre) splits strings" do
136
+ answer.text = "before|after|extra"
137
+ answer.text_for(:pre).should == "before"
138
+ end
139
+ it "#text_for(:post) splits strings" do
140
+ answer.text = "before|after|extra"
141
+ answer.text_for(:post).should == "after|extra"
142
+ end
143
+ end
144
+ end