breakpointer-surveyor 0.2.0

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 (198) hide show
  1. data/.gitignore +6 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +20 -0
  4. data/Rakefile +57 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/answers_controller.rb +87 -0
  7. data/app/controllers/dependencies_controller.rb +87 -0
  8. data/app/controllers/dependency_conditions_controller.rb +87 -0
  9. data/app/controllers/questions_controller.rb +85 -0
  10. data/app/controllers/sections_controller.rb +87 -0
  11. data/app/controllers/surveying_controller.rb +139 -0
  12. data/app/controllers/surveys_controller.rb +87 -0
  13. data/app/helpers/answers_helper.rb +2 -0
  14. data/app/helpers/application_helper.rb +3 -0
  15. data/app/helpers/questions_helper.rb +2 -0
  16. data/app/helpers/sections_helper.rb +2 -0
  17. data/app/helpers/survey_form_builder.rb +38 -0
  18. data/app/helpers/survey_importer_helper.rb +2 -0
  19. data/app/helpers/surveying_helper.rb +91 -0
  20. data/app/helpers/surveys_helper.rb +2 -0
  21. data/app/models/answer.rb +18 -0
  22. data/app/models/dependency.rb +43 -0
  23. data/app/models/dependency_condition.rb +76 -0
  24. data/app/models/question.rb +44 -0
  25. data/app/models/question_group.rb +5 -0
  26. data/app/models/response.rb +58 -0
  27. data/app/models/response_set.rb +174 -0
  28. data/app/models/survey.rb +54 -0
  29. data/app/models/survey_section.rb +19 -0
  30. data/app/models/user.rb +5 -0
  31. data/app/views/answer_display_types/_any_answer.html.haml +3 -0
  32. data/app/views/answer_display_types/_any_other_and_string.html.haml +5 -0
  33. data/app/views/answer_display_types/_any_string.html.haml +4 -0
  34. data/app/views/answer_display_types/_date.html.haml +3 -0
  35. data/app/views/answer_display_types/_datetime.html.haml +2 -0
  36. data/app/views/answer_display_types/_default.html.haml +1 -0
  37. data/app/views/answer_display_types/_float.html.haml +5 -0
  38. data/app/views/answer_display_types/_grid_any_answer.html.haml +2 -0
  39. data/app/views/answer_display_types/_grid_default.html.haml +2 -0
  40. data/app/views/answer_display_types/_grid_float.html.haml +2 -0
  41. data/app/views/answer_display_types/_grid_integer.html.haml +2 -0
  42. data/app/views/answer_display_types/_grid_one_answer.html.haml +2 -0
  43. data/app/views/answer_display_types/_grid_string.html.haml +2 -0
  44. data/app/views/answer_display_types/_integer.html.haml +6 -0
  45. data/app/views/answer_display_types/_one_answer.html.haml +3 -0
  46. data/app/views/answer_display_types/_one_string.html.haml +6 -0
  47. data/app/views/answer_display_types/_repeater_integer.html.haml +6 -0
  48. data/app/views/answer_display_types/_repeater_string.html.haml +7 -0
  49. data/app/views/answer_display_types/_string.html.haml +7 -0
  50. data/app/views/answer_display_types/_text.html.haml +6 -0
  51. data/app/views/answer_display_types/_time.html.haml +2 -0
  52. data/app/views/layouts/surveys.html.erb +17 -0
  53. data/app/views/question_display_types/_default.html.haml +12 -0
  54. data/app/views/question_display_types/_dropdown.html.haml +12 -0
  55. data/app/views/question_display_types/_grid_default.html.haml +14 -0
  56. data/app/views/question_display_types/_grid_dropdown.html.haml +15 -0
  57. data/app/views/question_display_types/_group_default.html.haml +8 -0
  58. data/app/views/question_display_types/_group_dropdown.html.haml +6 -0
  59. data/app/views/question_display_types/_image.html.haml +2 -0
  60. data/app/views/question_display_types/_inline.html.haml +12 -0
  61. data/app/views/question_display_types/_label.html.haml +4 -0
  62. data/app/views/question_display_types/_repeater_default.html.haml +10 -0
  63. data/app/views/question_display_types/_repeater_dropdown.html.haml +8 -0
  64. data/app/views/question_display_types/_slider.html.haml +17 -0
  65. data/app/views/question_group_display_types/_default.html.haml +13 -0
  66. data/app/views/question_group_display_types/_grid.html.haml +24 -0
  67. data/app/views/question_group_display_types/_repeater.html.haml +20 -0
  68. data/app/views/surveying/edit.html.haml +38 -0
  69. data/app/views/surveying/finish.html.haml +1 -0
  70. data/app/views/surveying/index.html.erb +19 -0
  71. data/app/views/surveying/new.html.haml +17 -0
  72. data/app/views/surveying/show.html.haml +8 -0
  73. data/config/routes.rb +10 -0
  74. data/generators/surveyor/surveyor_generator.rb +38 -0
  75. data/generators/surveyor/templates/README +9 -0
  76. data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_leftright.gif +0 -0
  77. data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_updown.gif +0 -0
  78. data/generators/surveyor/templates/assets/images/222222_11x11_icon_close.gif +0 -0
  79. data/generators/surveyor/templates/assets/images/222222_11x11_icon_doc.gif +0 -0
  80. data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_closed.gif +0 -0
  81. data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_open.gif +0 -0
  82. data/generators/surveyor/templates/assets/images/222222_11x11_icon_minus.gif +0 -0
  83. data/generators/surveyor/templates/assets/images/222222_11x11_icon_plus.gif +0 -0
  84. data/generators/surveyor/templates/assets/images/222222_11x11_icon_resize_se.gif +0 -0
  85. data/generators/surveyor/templates/assets/images/222222_35x9_colorpicker_indicator.gif.gif +0 -0
  86. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_down.gif +0 -0
  87. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_left.gif +0 -0
  88. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_right.gif +0 -0
  89. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_up.gif +0 -0
  90. data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_leftright.gif +0 -0
  91. data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_updown.gif +0 -0
  92. data/generators/surveyor/templates/assets/images/454545_11x11_icon_close.gif +0 -0
  93. data/generators/surveyor/templates/assets/images/454545_11x11_icon_doc.gif +0 -0
  94. data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_closed.gif +0 -0
  95. data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_open.gif +0 -0
  96. data/generators/surveyor/templates/assets/images/454545_11x11_icon_minus.gif +0 -0
  97. data/generators/surveyor/templates/assets/images/454545_11x11_icon_plus.gif +0 -0
  98. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_down.gif +0 -0
  99. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_left.gif +0 -0
  100. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_right.gif +0 -0
  101. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_up.gif +0 -0
  102. data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_leftright.gif +0 -0
  103. data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_updown.gif +0 -0
  104. data/generators/surveyor/templates/assets/images/888888_11x11_icon_close.gif +0 -0
  105. data/generators/surveyor/templates/assets/images/888888_11x11_icon_doc.gif +0 -0
  106. data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_closed.gif +0 -0
  107. data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_open.gif +0 -0
  108. data/generators/surveyor/templates/assets/images/888888_11x11_icon_minus.gif +0 -0
  109. data/generators/surveyor/templates/assets/images/888888_11x11_icon_plus.gif +0 -0
  110. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_down.gif +0 -0
  111. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_left.gif +0 -0
  112. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_right.gif +0 -0
  113. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_up.gif +0 -0
  114. data/generators/surveyor/templates/assets/images/dadada_40x100_textures_02_glass_75.png +0 -0
  115. data/generators/surveyor/templates/assets/images/e6e6e6_40x100_textures_02_glass_75.png +0 -0
  116. data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_01_flat_0.png +0 -0
  117. data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_02_glass_65.png +0 -0
  118. data/generators/surveyor/templates/assets/javascripts/accessibleUISlider.jQuery.js +201 -0
  119. data/generators/surveyor/templates/assets/javascripts/jquery-1.2.6.js +3549 -0
  120. data/generators/surveyor/templates/assets/javascripts/jquery-ui-personalized-1.5.3.js +7616 -0
  121. data/generators/surveyor/templates/assets/javascripts/jquery.form.js +637 -0
  122. data/generators/surveyor/templates/assets/javascripts/surveyor.js +35 -0
  123. data/generators/surveyor/templates/assets/stylesheets/jquery-ui-slider-additions.css +71 -0
  124. data/generators/surveyor/templates/assets/stylesheets/reset.css +46 -0
  125. data/generators/surveyor/templates/assets/stylesheets/sass/surveyor.sass +321 -0
  126. data/generators/surveyor/templates/assets/stylesheets/surveyor.css +245 -0
  127. data/generators/surveyor/templates/assets/stylesheets/ui.theme.css +851 -0
  128. data/generators/surveyor/templates/migrate/create_answers.rb +46 -0
  129. data/generators/surveyor/templates/migrate/create_dependencies.rb +21 -0
  130. data/generators/surveyor/templates/migrate/create_dependency_conditions.rb +29 -0
  131. data/generators/surveyor/templates/migrate/create_question_groups.rb +18 -0
  132. data/generators/surveyor/templates/migrate/create_questions.rb +33 -0
  133. data/generators/surveyor/templates/migrate/create_response_sets.rb +22 -0
  134. data/generators/surveyor/templates/migrate/create_responses.rb +33 -0
  135. data/generators/surveyor/templates/migrate/create_survey_sections.rb +25 -0
  136. data/generators/surveyor/templates/migrate/create_surveys.rb +25 -0
  137. data/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +201 -0
  138. data/init.rb +1 -0
  139. data/install.rb +1 -0
  140. data/lib/tasks/surveyor_tasks.rake +29 -0
  141. data/lib/tiny_code.rb +58 -0
  142. data/lib/user_manager.rb +9 -0
  143. data/lib/xml_formatter.rb +12 -0
  144. data/script/surveyor/answer.rb +84 -0
  145. data/script/surveyor/columnizer.rb +36 -0
  146. data/script/surveyor/dependency.rb +43 -0
  147. data/script/surveyor/dependency_condition.rb +74 -0
  148. data/script/surveyor/dslparse.rb +66 -0
  149. data/script/surveyor/question.rb +76 -0
  150. data/script/surveyor/question_group.rb +33 -0
  151. data/script/surveyor/specs/answer_spec.rb +66 -0
  152. data/script/surveyor/specs/question_dependency_spec.rb +46 -0
  153. data/script/surveyor/specs/question_group_spec.rb +9 -0
  154. data/script/surveyor/specs/question_spec.rb +111 -0
  155. data/script/surveyor/specs/section_spec.rb +58 -0
  156. data/script/surveyor/survey.rb +108 -0
  157. data/script/surveyor/survey_section.rb +153 -0
  158. data/script/surveyor/whr_dsl.tmproj +244 -0
  159. data/spec/controllers/answers_controller_spec.rb +64 -0
  160. data/spec/controllers/dependencies_controller_spec.rb +63 -0
  161. data/spec/controllers/dependency_conditions_controller_spec.rb +64 -0
  162. data/spec/controllers/questions_controller_spec.rb +64 -0
  163. data/spec/controllers/sections_controller_spec.rb +64 -0
  164. data/spec/controllers/surveying_controller_spec.rb +328 -0
  165. data/spec/controllers/surveying_routing_spec.rb +45 -0
  166. data/spec/controllers/surveys_controller_spec.rb +64 -0
  167. data/spec/fixtures/answers.yml +9 -0
  168. data/spec/fixtures/dependencies.yml +7 -0
  169. data/spec/fixtures/dependency_conditions.yml +27 -0
  170. data/spec/fixtures/question_groups.yml +7 -0
  171. data/spec/fixtures/questions.yml +15 -0
  172. data/spec/fixtures/response_sets.yml +13 -0
  173. data/spec/fixtures/responses.yml +9 -0
  174. data/spec/fixtures/survey_sections.yml +11 -0
  175. data/spec/fixtures/surveys.yml +9 -0
  176. data/spec/fixtures/users.yml +7 -0
  177. data/spec/helpers/survey_importer_helper_spec.rb +11 -0
  178. data/spec/helpers/surveying_helper_spec.rb +11 -0
  179. data/spec/models/answer_spec.rb +62 -0
  180. data/spec/models/dependency_condition_spec.rb +347 -0
  181. data/spec/models/dependency_spec.rb +82 -0
  182. data/spec/models/question_group_spec.rb +11 -0
  183. data/spec/models/question_spec.rb +70 -0
  184. data/spec/models/response_set_spec.rb +172 -0
  185. data/spec/models/response_spec.rb +94 -0
  186. data/spec/models/survey_section_spec.rb +34 -0
  187. data/spec/models/survey_spec.rb +72 -0
  188. data/spec/models/user_spec.rb +11 -0
  189. data/spec/rcov.opts +2 -0
  190. data/spec/spec.opts +4 -0
  191. data/spec/spec_helper.rb +72 -0
  192. data/spec/views/app/edit.html.erb_spec.rb +20 -0
  193. data/spec/views/app/index.html.erb_spec.rb +19 -0
  194. data/spec/views/app/new.html.erb_spec.rb +21 -0
  195. data/spec/views/app/show.html.erb_spec.rb +17 -0
  196. data/surveyor.gemspec +258 -0
  197. data/uninstall.rb +1 -0
  198. metadata +286 -0
@@ -0,0 +1,33 @@
1
+ class QuestionGroup
2
+
3
+ # Context, Content, Display
4
+ attr_accessor :id, :section_id, :section, :parser
5
+ attr_accessor :text, :help_text
6
+ attr_accessor :display_type
7
+
8
+ # id, section and text required
9
+ def initialize(section, args, options)
10
+ self.parser = section.parser
11
+ self.id = parser.new_question_group_id
12
+ self.text = args[0]
13
+ self.default_options().merge(options).merge(args[1] || {}).each{|key,value| self.instance_variable_set("@#{key}", value)}
14
+ end
15
+
16
+ def default_options()
17
+ {:display_type => "default"}
18
+ end
19
+
20
+ def to_yml
21
+ out =[ %(#{@id}:) ]
22
+ out << %( id: #{@id})
23
+ out << %( text: "#{@text}")
24
+ out << %( help_text: "#{@help_text}")
25
+ out << %( display_type: "#{@display_type}")
26
+ (out << nil ).join("\r\n")
27
+ end
28
+
29
+ def to_file
30
+ File.open(self.parser.question_groups_yml, File::CREAT|File::APPEND|File::WRONLY){ |f| f << to_yml }
31
+ end
32
+
33
+ end
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/../answer'
2
+
3
+ describe Answer, " when first created" do
4
+
5
+ TEST_ID = 1
6
+ TEST_CONTEXT_ID = "b3a_1"
7
+ TEST_QUESTION_ID = "2"
8
+ TEST_TEXT = "No / Rarely"
9
+ TEST_OPTIONS = {:help_text => "Never or rarely ever"}
10
+
11
+ before do
12
+ @ans = Answer.new(TEST_ID, TEST_QUESTION_ID, TEST_CONTEXT_ID, TEST_TEXT, TEST_OPTIONS)
13
+ end
14
+
15
+ it "should set inititalized variables to those passed in" do
16
+ @ans.id.should == TEST_ID
17
+ @ans.question_id.should == TEST_QUESTION_ID
18
+ @ans.context_id.should == TEST_CONTEXT_ID
19
+ @ans.text.should == TEST_TEXT
20
+ @ans.help_text.should == TEST_OPTIONS[:help_text]
21
+ end
22
+
23
+ it "should output current state to yml" do
24
+ @ans.should.respond_to?(:to_yml)
25
+ end
26
+
27
+ it "should create a normalized code from the answer text" do
28
+ # The answer object should take the title of the text and convert
29
+ # it to a code that is more appropirate for a database entry
30
+
31
+ # Taking a few answers from the survey for testing
32
+ str = []
33
+ str[0] = "This? is a in - t3rrible-@nswer of! (question) on"
34
+ str[1] = "Private insurance/ HMO/ PPO"
35
+ str[2] = "VA"
36
+ str[3] = "PMS (Premenstrual syndrome)/ PMDD (Premenstrual Dysphoric Disorder)"
37
+ str[4] = "Have never been employed outside the home"
38
+ str[5] = "Professional"
39
+ str[6] = "Not working because of temporary disability, but expect to return to a job"
40
+
41
+ # What the results should look like
42
+ r_str = []
43
+ r_str[0] = "this_t3rrible_nswer"
44
+ r_str[1] = "private_insurance_hmo_ppo"
45
+ r_str[2] = "va"
46
+ r_str[3] = "pms_pmdd"
47
+ r_str[4] = "never_been_employed_outside_home"
48
+ r_str[5] = "professional"
49
+ r_str[6] = "temporary_disability_expect_return_job"
50
+
51
+ count = 0
52
+ str.each do |s|
53
+
54
+ code = Answer.to_normalized_code(s)
55
+ code.should eql(r_str[count])
56
+ count += 1
57
+
58
+ end
59
+
60
+ end
61
+
62
+ it "should create a normalized code automatically when initalized" do
63
+ @ans.code.should eql("no_rarely")
64
+ end
65
+
66
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/../question_dependency'
2
+
3
+ describe QuestionDependency, " when first created" do
4
+
5
+ ID = 1
6
+ QUESTION_ID = 2
7
+ DEPENDENT_QUESTION_ID = 3
8
+ DEPENDENT_GROUP_ID = nil
9
+ DEPENDENCY_TYPE_1 = {:dependency_type => :response_count, :conditional => :one_or_more }
10
+ DEPENDENCY_TYPE_2 = {:dependency_type => :response_answer, :conditional => :selected, :answer_id => 1}
11
+ DEPENDENCY_TYPE_3 = {:dependency_type => :response_value, :condition => :not_zero}
12
+
13
+ before do
14
+ @dependent_1 = QuestionDependency.new(ID, QUESTION_ID, DEPENDENT_QUESTION_ID, DEPENDENT_GROUP_ID, DEPENDENCY_TYPE_1)
15
+ @dependent_2 = QuestionDependency.new(ID, QUESTION_ID, DEPENDENT_QUESTION_ID, DEPENDENT_GROUP_ID, DEPENDENCY_TYPE_2)
16
+ @dependent_3 = QuestionDependency.new(ID, QUESTION_ID, DEPENDENT_QUESTION_ID, DEPENDENT_GROUP_ID, DEPENDENCY_TYPE_3)
17
+
18
+ end
19
+
20
+ it "should set initialization paramerters properly" do
21
+ # Checking both type1 and type2 dependencies
22
+ @dependent_1.id.should == ID
23
+ @dependent_1.question_id.should == QUESTION_ID
24
+ @dependent_1.dependent_question_id.should == DEPENDENT_QUESTION_ID
25
+ @dependent_1.dependency_type.should == DEPENDENCY_TYPE_1[:dependency_type]
26
+ @dependent_1.conditional.should == DEPENDENCY_TYPE_1[:conditional]
27
+
28
+ @dependent_2.id.should == ID
29
+ @dependent_2.question_id.should == QUESTION_ID
30
+ @dependent_2.dependent_question_id.should == DEPENDENT_QUESTION_ID
31
+ @dependent_2.dependency_type.should == DEPENDENCY_TYPE_2[:dependency_type]
32
+ @dependent_2.conditional.should == DEPENDENCY_TYPE_2[:conditional]
33
+ @dependent_2.answer_id.should == DEPENDENCY_TYPE_2[:answer_id]
34
+
35
+ @dependent_3.id.should == ID
36
+ @dependent_3.question_id.should == QUESTION_ID
37
+ @dependent_3.dependent_question_id.should == DEPENDENT_QUESTION_ID
38
+ @dependent_3.dependency_type.should == DEPENDENCY_TYPE_3[:dependency_type]
39
+ @dependent_3.conditional.should == DEPENDENCY_TYPE_3[:conditional]
40
+ end
41
+
42
+ it "should output current state to yml" do
43
+ @ans.should.respond_to?(:to_yml)
44
+ end
45
+
46
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/../question_group'
2
+
3
+ describe QuestionGroup, " when first created" do
4
+
5
+ it "should do stuff" do
6
+ pending
7
+ end
8
+
9
+ end
@@ -0,0 +1,111 @@
1
+ require File.dirname(__FILE__) + '/../question'
2
+
3
+ describe Question, " when first created" do
4
+ TEST_ID = 1
5
+ TEST_CONTEXT_ID = "B3"
6
+ TEST_SECTION_ID = 2
7
+ TEST_TEXT = "In the past 12 months how many times have you been to a doctor?"
8
+ TEST_HELP_TEXT = "Please give a rough estimate"
9
+ TEST_OPTIONS = {:help_text => TEST_HELP_TEXT }
10
+ TEST_CODE = "many_times_you_been_doctor"
11
+
12
+ before do
13
+ @ques = Question.new(TEST_ID, TEST_SECTION_ID, TEST_CONTEXT_ID, TEST_TEXT, TEST_OPTIONS)
14
+ end
15
+
16
+ it "should set initialization parameters properly" do
17
+ @ques.id.should == TEST_ID
18
+ @ques.context_id.should == TEST_CONTEXT_ID
19
+ @ques.section_id.should == TEST_SECTION_ID
20
+ @ques.code.should == TEST_CODE
21
+ @ques.options[:help_text].should == TEST_HELP_TEXT
22
+
23
+ #Checking the defaults
24
+ @ques.options[:has_omit?].should == true
25
+ @ques.options[:has_other?].should == false
26
+ @ques.options[:answer_format].should == :medium_text
27
+ end
28
+
29
+ it "should output current state to yml" do
30
+ @ques.should.respond_to?(:to_yml)
31
+ end
32
+
33
+ it "should create a normalized code from the answer text" do
34
+ # The question object should take the title of the text and convert
35
+ # it to a code that is more appropirate for a database entry
36
+
37
+ # Taking a few questions from the survey for testing
38
+ str = []
39
+ str[0] = "How long has it been since you last visited a doctor for a routine checkup (routine being not for a particular reason)?"
40
+ str[1] = "Do you take medications as directed?"
41
+ str[2] = "Do you every leak urine (or) water when you didn't want to?" #checking for () and ' removal
42
+ str[3] = "Do your biological family members (not adopted) have a \"history\" of any of the following?"
43
+ str[4] = "Your health:"
44
+ str[5] = "In general, you would say your health is:"
45
+
46
+ # What the results should look like
47
+ r_str = []
48
+ r_str[0] = "visited_doctor_for_routine_checkup"
49
+ r_str[1] = "you_take_medications_as_directed"
50
+ r_str[2] = "urine_water_you_didnt_want"
51
+ r_str[3] = "family_members_history_any_following"
52
+ r_str[4] = "your_health"
53
+ r_str[5] = "you_would_say_your_health"
54
+
55
+ count = 0
56
+ str.each do |s|
57
+
58
+ code = Question.to_normalized_code(s)
59
+ code.should eql(r_str[count])
60
+ count += 1
61
+
62
+ end
63
+
64
+ end
65
+
66
+ it "should create a normalized code automatically when initalized" do
67
+ @ques.code.should eql(TEST_CODE)
68
+ end
69
+
70
+ it "should update the normalized code if the title is changed" do
71
+ @ques.code.should eql(TEST_CODE)
72
+ @ques.text = "Sometimes or All the time?"
73
+ @ques.code.should eql("sometimes_all_time")
74
+ end
75
+
76
+ end
77
+
78
+ describe Question, " when it contains data" do
79
+
80
+ before do # Mocking up some answers
81
+ @question = Question.new(1,TEST_SECTION_ID,TEST_CONTEXT_ID,TEST_TEXT,TEST_OPTIONS)
82
+ ma1 = mock("answer")
83
+ ma1.stub!(:context_id).and_return("1")
84
+ @question.add_answer(ma1)
85
+
86
+ ma2 = mock("answer")
87
+ ma2.stub!(:context_id).and_return("2")
88
+ @question.add_answer(ma2)
89
+
90
+ ma3 = mock("answer")
91
+ ma3.stub!(:context_id).and_return("3")
92
+ @question.add_answer(ma3)
93
+
94
+ end
95
+
96
+ it "should have added the test answers correctly" do
97
+ @question.answers.length.should eql(3)
98
+ end
99
+
100
+ it "should have a question text" do
101
+ @question.text.should eql(TEST_TEXT)
102
+ end
103
+
104
+ it "should find an answer by context_id" do
105
+ pending # yoon: commented out during dsl refactoring
106
+ a_to_find = @question.find_answer_by_context_id("2")
107
+ a_to_find.should_not eql(nil)
108
+ a_to_find.context_id.should eql("2")
109
+ end
110
+
111
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/../section'
2
+
3
+ describe Section, " when first created" do
4
+
5
+ TEST_TITLE = "Demographics"
6
+ TEST_SECTION = :B
7
+
8
+ before do
9
+ @section = Section.new(1,TEST_SECTION,TEST_TITLE)
10
+ end
11
+
12
+ it "should accept questions" do
13
+ mock_question = mock("question")
14
+ @section.questions.size.should eql(0)
15
+ @section.add_question(mock_question)
16
+ @section.questions.size.should eql(1)
17
+ end
18
+
19
+ it "should output current state to code" do
20
+ @section.should.respond_to?(:to_code)
21
+ end
22
+
23
+ end
24
+
25
+ describe Section, " when it contains data" do
26
+
27
+ before do # Mocking up some questions
28
+ @section = Section.new(1,TEST_SECTION,TEST_TITLE)
29
+ mq1 = mock("question")
30
+ mq1.stub!(:context_id).and_return("B1")
31
+ @section.add_question(mq1)
32
+
33
+ mq2 = mock("question")
34
+ mq2.stub!(:context_id).and_return("B2")
35
+ @section.add_question(mq2)
36
+
37
+ mq3 = mock("question")
38
+ mq3.stub!(:context_id).and_return("B3")
39
+ @section.add_question(mq3)
40
+
41
+ end
42
+
43
+ it "should have added the test questions correctly" do
44
+ @section.questions.length.should eql(3)
45
+ end
46
+
47
+ it "should have a title" do
48
+ @section.title.should eql(TEST_TITLE)
49
+ end
50
+
51
+ it "should find a question by context_id" do
52
+ pending # yoon: commented out during dsl refactoring
53
+ q_to_find = @section.find_question_by_context_id("B2")
54
+ q_to_find.should_not eql(nil)
55
+ q_to_find.context_id.should eql("B2")
56
+ end
57
+
58
+ end
@@ -0,0 +1,108 @@
1
+ require File.dirname(__FILE__) + '/survey_section'
2
+
3
+ class Survey
4
+ include Columnizer
5
+ # Content, Reference, Expiry, Children
6
+ attr_accessor :id, :parser
7
+ attr_accessor :title, :description
8
+ attr_accessor :access_code
9
+ attr_accessor :active_at, :inactive_at
10
+ attr_accessor :survey_sections
11
+
12
+ @@current_survey = nil
13
+
14
+ def self.current_survey
15
+ @@current_survey
16
+ end
17
+
18
+ def self.current_survey=(value)
19
+ @@current_survey = value
20
+ puts "Assigning current survey #{@@current_survey.title}"
21
+ end
22
+
23
+ # id, parser, and title required
24
+ def initialize(id, parser, title, options = {})
25
+ self.id = id
26
+ self.parser = parser
27
+ self.title = title
28
+ self.survey_sections = []
29
+ self.access_code = Columnizer.to_normalized_column(title)
30
+ # self.default_options(title).merge(options).each{|key,value| self.instance_variable_set("@#{key}", value)}
31
+ Survey.current_survey = self
32
+ end
33
+
34
+ # def default_options(title)
35
+ # {}
36
+ # end
37
+
38
+ # This method_missing magic does all the heavy lifting for the DSL
39
+ def method_missing(missing_method, *args, &block)
40
+ m_name = missing_method.to_s
41
+ if (section_match = m_name.match(/(\Asection)_?(.*)/))
42
+ build_survey_section(section_match[3].to_s, *args, &block) # Parse "section" method, create new section in this survey
43
+ else
44
+ puts " ERROR: '#{m_name}' not valid method_missing name"
45
+ end
46
+ end
47
+
48
+ def build_survey_section(reference_identifier, title, &block)
49
+ puts " Section: #{title}"
50
+ if block_given?
51
+ new_survey_section = SurveySection.new(new_survey_section_id, self, title, {:display_order => self.survey_sections.size + 1, :reference_identifier => reference_identifier})
52
+ new_survey_section.instance_eval(&block)
53
+ add_survey_section(new_survey_section)
54
+ puts " Section added"
55
+ else
56
+ puts " ERROR: A section cannot be empty!"
57
+ end
58
+ end
59
+
60
+ def new_survey_section_id
61
+ self.parser.new_survey_section_id
62
+ end
63
+
64
+ def add_survey_section(survey_section)
65
+ self.survey_sections << survey_section
66
+ end
67
+
68
+ # Used to find questions for dependency linking
69
+ def find_question_by_reference(ref_id)
70
+ question = nil
71
+ count = 0
72
+ while question.nil? and count < self.survey_sections.size
73
+ question = self.survey_sections[count].find_question_by_reference(ref_id)
74
+ count += 1
75
+ end
76
+ question
77
+ end
78
+
79
+
80
+ def reconcile_dependencies
81
+
82
+ @survey_sections.each do |section|
83
+ section.questions.each do |question|
84
+ question.dependency.dependency_conditions.each { |con| con.reconcile_dependencies} unless question.dependency.nil?
85
+
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ def to_yml
92
+ out =[ %(survey_#{@id}:) ]
93
+ out << %( id: #{@id})
94
+ out << %( title: "#{@title}")
95
+ out << %( description: "#{@description}")
96
+ out << %( access_code: #{@access_code})
97
+ out << %( active_at: #{@active_at})
98
+ out << %( inactive_at: #{@inactive_at})
99
+ (out << nil ).join("\r\n")
100
+ end
101
+
102
+ def to_file
103
+ "survey -#{self.title}- written to file..."
104
+ File.open(self.parser.surveys_yml, File::CREAT|File::APPEND|File::WRONLY) {|f| f << to_yml}
105
+ self.survey_sections.compact.map(&:to_file)
106
+ end
107
+
108
+ end
@@ -0,0 +1,153 @@
1
+ require File.dirname(__FILE__) + '/question_group'
2
+ require File.dirname(__FILE__) + '/question'
3
+ require File.dirname(__FILE__) + '/answer'
4
+ require File.dirname(__FILE__) + '/dependency'
5
+ require File.dirname(__FILE__) + '/dependency_condition'
6
+ require File.dirname(__FILE__) + '/columnizer'
7
+ require 'activesupport'
8
+ #require 'activesupport/lib/active_support/core_ext/string/inflections'
9
+
10
+ class SurveySection
11
+ include Columnizer
12
+
13
+ # Context, Content, Display, Reference, Children, Placeholders
14
+ attr_accessor :id, :survey_id, :parser
15
+ attr_accessor :title, :description
16
+ attr_accessor :display_order
17
+ attr_accessor :reference_identifier, :data_export_identifier
18
+ attr_accessor :question_groups, :questions, :grid_answers
19
+ attr_accessor :current_question_group, :current_question, :current_dependency
20
+
21
+
22
+ # id, survey, and title required
23
+ def initialize(id, survey, title, options = {})
24
+ self.id = id
25
+ self.survey_id = survey.id
26
+ self.parser = survey.parser
27
+ self.title = title.strip
28
+ self.questions = []
29
+ self.question_groups = []
30
+ self.grid_answers = []
31
+ self.current_question_group = nil
32
+ self.current_question = nil
33
+ self.current_dependency = nil
34
+ self.default_options(title).merge(options).each{|key,value| self.instance_variable_set("@#{key}", value)}
35
+ end
36
+
37
+ def default_options(title)
38
+ { :data_export_identifier => Columnizer.to_normalized_column(title)
39
+ }
40
+ end
41
+
42
+ # This method_missing magic does all the heavy lifting for the DSL
43
+ def method_missing(missing_method, *args, &block)
44
+ method_name, reference_identifier = missing_method.to_s.split("_")
45
+
46
+ case method_name
47
+
48
+ when "group", "g", "grid", "repeater"
49
+ puts " Group: #{reference_identifier}"
50
+ raise "Error: A question group cannot be empty" unless block_given?
51
+
52
+ options = {:reference_identifier => reference_identifier, :display_type => (method_name =~ /grid|repeater/)? method_name : nil }
53
+ self.question_groups << (self.current_question_group = QuestionGroup.new(self, args, options))
54
+ self.instance_eval(&block)
55
+ clear_current_question_group
56
+
57
+ when "question", "q", "label", "image"
58
+ puts " Question: #{reference_identifier}"
59
+ raise "Error: I'm dropping the block like it's hot" if block_given?
60
+
61
+ clear_current_question
62
+ options = {:reference_identifier => reference_identifier, :question_group_id => (current_question_group ? current_question_group.id : nil)}
63
+ options.merge!({:display_type => "label"}) if method_name == "label"
64
+ options.merge!({:display_type => "image"}) if method_name == "image"
65
+ self.questions << (self.current_question = Question.new(self, args, options))
66
+ add_grid_answers if self.current_question_group and self.current_question_group.display_type == "grid"
67
+
68
+ when "dependency", "d"
69
+ puts " Dependency: #{reference_identifier}"
70
+ raise "Error: I'm dropping the block like it's hot" if block_given?
71
+ raise "Error: " unless self.current_question
72
+
73
+ options = {:reference_identifier => reference_identifier}
74
+ self.current_question.dependency = (self.current_dependency = Dependency.new(current_question, args, options))
75
+
76
+ when "condition", "c"
77
+ puts " Condition: #{reference_identifier}"
78
+ raise "Error, I'm dropping the block like it's hot" if block_given?
79
+ raise "Error: No current dependency" unless self.current_dependency
80
+
81
+ options = {:reference_identifier => reference_identifier}
82
+ self.current_dependency.add_dependency_condition DependencyCondition.new(self, args, options)
83
+
84
+ when "answer", "a"
85
+ puts " Answer: #{reference_identifier}"
86
+ raise "Error, I'm dropping the block like it's hot" if block_given?
87
+
88
+ if self.current_question_group and self.current_question_group.display_type == "grid"
89
+ options = {:reference_identifier => reference_identifier, :display_order => self.grid_answers.size + 1}
90
+ self.grid_answers << Answer.new(nil, args, options)
91
+ else
92
+ raise "Error: No current question" unless self.current_question
93
+ options = {:reference_identifier => reference_identifier, :display_order => self.current_question.answers.size + 1}
94
+ self.current_question.answers << Answer.new(self.current_question, args, options)
95
+ end
96
+
97
+ else
98
+ raise " ERROR: '#{m_name}' not valid method_missing name"
99
+ end
100
+ end
101
+
102
+ def clear_current_question_group
103
+ self.current_question_group = nil
104
+ self.grid_answers = []
105
+ self.current_question = nil
106
+ end
107
+
108
+ def clear_current_question
109
+ self.current_question = nil
110
+ self.current_dependency = nil
111
+ end
112
+
113
+ def add_grid_answers
114
+ self.grid_answers.each do |grid_answer|
115
+ my_answer = grid_answer.dup
116
+ my_answer.id = self.parser.new_answer_id
117
+ my_answer.question_id = self.current_question.id
118
+ my_answer.parser = self.parser
119
+ self.current_question.answers << my_answer
120
+ end
121
+ end
122
+
123
+ # Used to find questions for dependency linking
124
+ def find_question_by_reference(ref_id)
125
+ question = nil
126
+ count = 0
127
+ while question.nil? and count < questions.size
128
+ question = self.questions[count] if self.questions[count].reference_identifier == ref_id
129
+ count +=1
130
+ end
131
+ question
132
+ end
133
+
134
+
135
+ def to_yml
136
+ out =[ %(#{@data_export_identifier}_#{@id}:) ]
137
+ out << %( id: #{@id})
138
+ out << %( survey_id: #{@survey_id})
139
+ out << %( title: "#{@title}")
140
+ out << %( description: "#{@description}")
141
+ out << %( display_order: #{display_order})
142
+ out << %( reference_identifier: #{@reference_identifier})
143
+ out << %( data_export_identifier: "#{@data_export_identifier}")
144
+ (out << nil ).join("\r\n")
145
+ end
146
+
147
+ def to_file
148
+ File.open(self.parser.survey_sections_yml, File::CREAT|File::APPEND|File::WRONLY) {|f| f << to_yml}
149
+ self.question_groups.compact.map(&:to_file)
150
+ self.questions.compact.map(&:to_file)
151
+ end
152
+
153
+ end