surveyor 0.22.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +1 -0
  3. data/CHANGELOG.md +83 -0
  4. data/Gemfile.rails_version +7 -1
  5. data/README.md +114 -16
  6. data/Rakefile +15 -9
  7. data/app/inputs/quiet_input.rb +5 -0
  8. data/app/inputs/surveyor_check_boxes_input.rb +35 -0
  9. data/app/inputs/surveyor_radio_input.rb +18 -0
  10. data/app/views/partials/_answer.html.haml +4 -4
  11. data/app/views/partials/_question.html.haml +7 -7
  12. data/app/views/partials/_question_group.html.haml +9 -8
  13. data/app/views/surveyor/export.json.rabl +28 -25
  14. data/app/views/surveyor/new.html.haml +8 -5
  15. data/app/views/surveyor/show.json.rabl +3 -2
  16. data/ci-exec.sh +13 -7
  17. data/cucumber.yml +3 -3
  18. data/doc/REPRESENTATIONS.md +34 -0
  19. data/doc/api_id_schema.json +7 -0
  20. data/doc/response_set_schema.json +54 -0
  21. data/doc/surveyor question combinations.png +0 -0
  22. data/doc/surveyor_timestamp_schema.json +9 -0
  23. data/features/ajax_submissions.feature +140 -0
  24. data/features/export_to_json.feature +182 -34
  25. data/features/no_duplicates.feature +110 -0
  26. data/features/show_survey.feature +1 -1
  27. data/features/step_definitions/parser_steps.rb +25 -2
  28. data/features/step_definitions/surveyor_steps.rb +145 -20
  29. data/features/step_definitions/ui_steps.rb +3 -0
  30. data/features/support/database_cleaner.rb +16 -0
  31. data/features/support/env.rb +21 -17
  32. data/features/support/simultaneous_ajax.rb +101 -0
  33. data/features/support/single_quit_selenium_driver.rb +23 -0
  34. data/features/support/slow_updates.rb +18 -0
  35. data/features/surveyor.feature +174 -44
  36. data/features/surveyor_dependencies.feature +80 -39
  37. data/features/surveyor_parser.feature +114 -20
  38. data/features/z_redcap_parser.feature +0 -1
  39. data/lib/{generators/surveyor/templates/public → assets}/images/surveyor/next.gif +0 -0
  40. data/lib/{generators/surveyor/templates/public → assets}/images/surveyor/prev.gif +0 -0
  41. data/lib/{generators/surveyor/templates/public/stylesheets/surveyor → assets/images}/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  42. data/lib/{generators/surveyor/templates/public/stylesheets/surveyor → assets/images}/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  43. data/lib/{generators/surveyor/templates/public/stylesheets/surveyor → assets/images}/ui-bg_glass_65_ffffff_1x400.png +0 -0
  44. data/lib/{generators/surveyor/templates/public/stylesheets/surveyor → assets/images}/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  45. data/lib/assets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  46. data/lib/{generators/surveyor/templates/public/stylesheets/surveyor → assets/images}/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  47. data/lib/{generators/surveyor/templates/public/stylesheets/surveyor → assets/images}/ui-icons_ef8c08_256x240.png +0 -0
  48. data/lib/{generators/surveyor/templates/public/stylesheets/surveyor → assets/images}/ui-icons_ffffff_256x240.png +0 -0
  49. data/lib/{generators/surveyor/templates/public → assets}/javascripts/surveyor/jquery-ui-timepicker-addon.js +23 -23
  50. data/lib/{generators/surveyor/templates/public → assets}/javascripts/surveyor/jquery-ui.js +125 -125
  51. data/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js +240 -0
  52. data/lib/{generators/surveyor/templates/public → assets}/javascripts/surveyor/jquery.surveyor.js +52 -57
  53. data/lib/{generators/surveyor/templates/public → assets}/javascripts/surveyor/jquery.tools.min.js +7 -7
  54. data/lib/{generators/surveyor/templates/public → assets}/stylesheets/surveyor/dateinput.css +13 -13
  55. data/lib/{generators/surveyor/templates/public → assets}/stylesheets/surveyor/jquery-ui-timepicker-addon.css +0 -0
  56. data/lib/{generators/surveyor/templates/public → assets}/stylesheets/surveyor/jquery-ui.custom.css +17 -17
  57. data/lib/{generators/surveyor/templates/public → assets}/stylesheets/surveyor/reset.css +1 -1
  58. data/lib/{generators/surveyor/templates/public → assets}/stylesheets/surveyor/results.css +0 -0
  59. data/lib/assets/stylesheets/surveyor/ui.slider.extras.css +110 -0
  60. data/lib/{generators/surveyor/templates/public/stylesheets/sass → assets/stylesheets}/surveyor.sass +15 -7
  61. data/lib/generators/surveyor/custom_generator.rb +3 -2
  62. data/lib/generators/surveyor/install_generator.rb +59 -17
  63. data/lib/generators/surveyor/templates/app/assets/javascripts/surveyor_all.js +5 -0
  64. data/lib/generators/surveyor/templates/app/assets/stylesheets/surveyor_all.css +9 -0
  65. data/lib/generators/surveyor/templates/app/controllers/surveyor_controller.rb +2 -1
  66. data/lib/generators/surveyor/templates/app/views/layouts/surveyor_custom.html.erb +1 -0
  67. data/lib/generators/surveyor/templates/config/locales/surveyor_es.yml +1 -0
  68. data/lib/generators/surveyor/templates/config/locales/surveyor_he.yml +1 -0
  69. data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +1 -0
  70. data/lib/generators/surveyor/templates/db/migrate/add_api_ids.rb +1 -0
  71. data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +1 -0
  72. data/lib/generators/surveyor/templates/db/migrate/add_correct_answer_id_to_questions.rb +1 -0
  73. data/lib/generators/surveyor/templates/db/migrate/add_default_value_to_answers.rb +1 -0
  74. data/lib/generators/surveyor/templates/db/migrate/add_display_order_to_surveys.rb +1 -0
  75. data/lib/generators/surveyor/templates/db/migrate/add_display_type_to_answers.rb +1 -0
  76. data/lib/generators/surveyor/templates/db/migrate/add_index_to_response_sets.rb +1 -0
  77. data/lib/generators/surveyor/templates/db/migrate/add_index_to_surveys.rb +1 -0
  78. data/lib/generators/surveyor/templates/db/migrate/add_section_id_to_responses.rb +1 -0
  79. data/lib/generators/surveyor/templates/db/migrate/add_unique_index_on_access_code_and_version_in_surveys.rb +10 -0
  80. data/lib/generators/surveyor/templates/db/migrate/add_unique_indicies.rb +3 -2
  81. data/lib/generators/surveyor/templates/db/migrate/add_version_to_surveys.rb +10 -0
  82. data/lib/generators/surveyor/templates/db/migrate/api_ids_must_be_unique.rb +23 -0
  83. data/lib/generators/surveyor/templates/db/migrate/create_answers.rb +6 -5
  84. data/lib/generators/surveyor/templates/db/migrate/create_dependencies.rb +2 -1
  85. data/lib/generators/surveyor/templates/db/migrate/create_dependency_conditions.rb +2 -1
  86. data/lib/generators/surveyor/templates/db/migrate/create_question_groups.rb +5 -4
  87. data/lib/generators/surveyor/templates/db/migrate/create_questions.rb +4 -3
  88. data/lib/generators/surveyor/templates/db/migrate/create_response_sets.rb +1 -0
  89. data/lib/generators/surveyor/templates/db/migrate/create_responses.rb +10 -9
  90. data/lib/generators/surveyor/templates/db/migrate/create_survey_sections.rb +5 -4
  91. data/lib/generators/surveyor/templates/db/migrate/create_surveys.rb +4 -3
  92. data/lib/generators/surveyor/templates/db/migrate/create_validation_conditions.rb +5 -4
  93. data/lib/generators/surveyor/templates/db/migrate/create_validations.rb +3 -2
  94. data/lib/generators/surveyor/templates/db/migrate/drop_unique_index_on_access_code_in_surveys.rb +10 -0
  95. data/lib/generators/surveyor/templates/db/migrate/update_blank_api_ids_on_question_group.rb +22 -0
  96. data/lib/generators/surveyor/templates/db/migrate/update_blank_versions_on_surveys.rb +13 -0
  97. data/lib/generators/surveyor/templates/surveys/date_survey.rb +1 -0
  98. data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +54 -24
  99. data/lib/generators/surveyor/templates/surveys/quiz.rb +1 -0
  100. data/lib/generators/surveyor/templates/{public/stylesheets/sass → vendor/assets/stylesheets}/custom.sass +1 -1
  101. data/lib/surveyor/common.rb +16 -31
  102. data/lib/surveyor/engine.rb +2 -4
  103. data/lib/surveyor/helpers/asset_pipeline.rb +13 -0
  104. data/lib/surveyor/helpers/formtastic_custom_input.rb +17 -0
  105. data/lib/surveyor/helpers/surveyor_helper_methods.rb +10 -8
  106. data/lib/surveyor/models/answer_methods.rb +3 -0
  107. data/lib/surveyor/models/dependency_condition_methods.rb +27 -28
  108. data/lib/surveyor/models/dependency_methods.rb +3 -0
  109. data/lib/surveyor/models/question_group_methods.rb +3 -0
  110. data/lib/surveyor/models/question_methods.rb +10 -7
  111. data/lib/surveyor/models/response_methods.rb +16 -0
  112. data/lib/surveyor/models/response_set_methods.rb +71 -64
  113. data/lib/surveyor/models/survey_methods.rb +19 -28
  114. data/lib/surveyor/models/survey_section_methods.rb +3 -0
  115. data/lib/surveyor/models/validation_condition_methods.rb +4 -2
  116. data/lib/surveyor/models/validation_methods.rb +3 -0
  117. data/lib/surveyor/parser.rb +198 -148
  118. data/lib/surveyor/redcap_parser.rb +120 -80
  119. data/lib/surveyor/surveyor_controller_methods.rb +86 -37
  120. data/lib/surveyor/version.rb +2 -2
  121. data/lib/surveyor.rb +5 -6
  122. data/lib/tasks/surveyor_tasks.rake +19 -7
  123. data/spec/controllers/surveyor_controller_spec.rb +166 -92
  124. data/spec/factories.rb +33 -32
  125. data/spec/helpers/formtastic_custom_input_spec.rb +16 -0
  126. data/spec/lib/common_spec.rb +0 -39
  127. data/spec/lib/redcap_parser_spec.rb +24 -24
  128. data/spec/models/answer_spec.rb +12 -0
  129. data/spec/models/dependency_condition_spec.rb +279 -323
  130. data/spec/models/dependency_spec.rb +10 -0
  131. data/spec/models/question_group_spec.rb +12 -0
  132. data/spec/models/question_spec.rb +12 -0
  133. data/spec/models/response_set_spec.rb +189 -139
  134. data/spec/models/response_spec.rb +60 -0
  135. data/spec/models/survey_section_spec.rb +9 -0
  136. data/spec/models/survey_spec.rb +72 -9
  137. data/spec/models/validation_condition_spec.rb +9 -1
  138. data/spec/models/validation_spec.rb +10 -0
  139. data/spec/spec_helper.rb +25 -6
  140. data/surveyor.gemspec +5 -4
  141. metadata +332 -291
  142. data/features/step_definitions/common_steps.rb +0 -3
  143. data/lib/formtastic/surveyor_builder.rb +0 -82
  144. data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery.blockUI.js +0 -499
data/.gitignore CHANGED
@@ -19,6 +19,7 @@ rdoc
19
19
  pkg
20
20
  Gemfile.lock
21
21
  reports
22
+ chromedriver.log
22
23
 
23
24
  ## PROJECT::SPECIFIC
24
25
  testbed
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color -fn
data/CHANGELOG.md ADDED
@@ -0,0 +1,83 @@
1
+ History for Surveyor
2
+ ====================
3
+
4
+ 1.0.0
5
+ ------
6
+
7
+ ### Features
8
+
9
+ - Official support for Rails 3.2, including declaring of all mass-assignable
10
+ attributes with `attr_accessible`.
11
+
12
+ - Breaking change: Surveys are now explicitly versioned. If you loaded a survey
13
+ when another survey with the same title/access code had already been loaded,
14
+ Surveyor would previously have appended a serial number to the title. As of
15
+ this version, Surveyor keeps the serial number in a separate `survey_version`
16
+ field. (#262)
17
+
18
+ - Add encoding comments for generated files. (#329)
19
+
20
+ - Asset pipeline support for Rails 3.1+. Rails 3.0 is still supported.
21
+ (#307, #314, #315)
22
+
23
+ - Upgrade to Formtastic 2.1. (#227)
24
+
25
+ - `:pick => :one` and `:pick => :any` questions may now have date, time,
26
+ datetime, integer, or float values, in addition to the already-supported
27
+ string values. (#207)
28
+
29
+ - Added Survey#as_json, ResponseSet#as_json. (#291)
30
+
31
+ - Changed defaults for and interpretation of for Survey#active_at and
32
+ Survey#inactive_at. (#258)
33
+
34
+ - JSON export representation of DateTimes is 2010-04-08T10:30+00:00 and Dates is
35
+ 2010-04-08 and Times is 10:30. (#355)
36
+
37
+ - JSON representation of Response includes response_group. (#349)
38
+
39
+ - Use Object#extend to inject SuryeyorParser and SurveyorRedcapParser methods into
40
+ instances of models instead of reopening classes. Move responsibility for keeping
41
+ track of and reporting duplicate and bad references from the models to the parsers.
42
+ Upgrade SurveyorRedcapParser to trace only when rake --trace is specified. (#341)
43
+
44
+ - export Question#data_export_identifier, Answer#data_export_identifier,
45
+ Answer#reference_identifier in survey JSON export. (#368)
46
+
47
+ ### Fixes
48
+
49
+ - Ensure response set is available to `render_context` (#320)
50
+
51
+ - Hide dependent rows of grids. (#343)
52
+
53
+ - Dependency condition with '!=' now returns true if there is no response. (#337)
54
+
55
+ - Properly handle multiple "exclusive" checkboxes in a single question. (#336)
56
+
57
+ - Correct storing of "correct" answers when parsing a survey. (#326)
58
+
59
+ - Restore "slider" renderer. (#230)
60
+
61
+ - Ensure that duplicate responses cannot be created by parallel AJAX requests.
62
+ (#328)
63
+
64
+ - Create default identifiers in before_create, not in the initializer. (#369)
65
+
66
+ - Eliminate unnecessary (and incorrect) access code uniqueness checks.
67
+ Use SecureRandom for generating access codes. (#370)
68
+
69
+ - Use json_spec for testing JSON responses, instead of
70
+ Surveyor::Common#deep_compare_excluding_wildcards. (#350)
71
+
72
+ - Parser now sets Question#correct_answer_id correctly. The association is changed from
73
+ Question :has_one correct_answer => Question :belongs_to correct_answer. (#365)
74
+
75
+ ### Infrastructure
76
+
77
+ - Enabled Selenium-backed cucumber features in CI. (#333)
78
+
79
+ - Added `testbed:surveys` task to load all sample surveys in the testbed.
80
+
81
+ - Begin formal changelog.
82
+
83
+ - Change test infra so that tx behavior can be tested. (#360)
@@ -4,9 +4,15 @@
4
4
  if ENV['RAILS_VERSION']
5
5
  case ENV['RAILS_VERSION']
6
6
  when /3.0$/
7
- gem 'rails', '~> 3.0.10'
7
+ gem 'rails', '~> 3.0.15'
8
8
  when /3.1$/
9
9
  gem 'rails', '~> 3.1.0'
10
+ # A JS runtime is required for Rails 3.1+
11
+ gem 'therubyracer'
12
+ when /3.2$/
13
+ gem 'rails', '~> 3.2.0'
14
+ # A JS runtime is required for Rails 3.1+
15
+ gem 'therubyracer'
10
16
  else
11
17
  fail "Unknown Rails version #{ENV['RAILS_VERSION']}"
12
18
  end
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Surveys On Rails
2
2
 
3
- Surveyor is a ruby gem and developer tool that brings surveys into Rails applications. Surveys are written in the Surveyor DSL (Domain Specific Language). Before Rails 2.3, it was implemented as a Rails Engine. It also existed previously as a plugin. Today it is a gem only.
3
+ Surveyor is a developer tool that brings surveys into Rails
4
+ applications. Surveys are written in the Surveyor DSL (Domain Specific
5
+ Language). Internally, Surveyor is a Rails engine distributed as a
6
+ ruby gem, meaning it is straightforward to override or extend its
7
+ behaviors in your Rails app without maintaining a fork.
4
8
 
5
9
  ## Why you might want to use Surveyor
6
10
 
@@ -55,7 +59,7 @@ The first question is "pick one" (radio buttons) with "other". The second questi
55
59
 
56
60
  # Installation
57
61
 
58
- 1. Add surveyor to your Gemfile:
62
+ Add surveyor to your Gemfile:
59
63
 
60
64
  gem "surveyor"
61
65
 
@@ -63,16 +67,16 @@ Then run:
63
67
 
64
68
  bundle install
65
69
 
66
- 2. Generate assets, run migrations:
70
+ Generate assets, run migrations:
67
71
 
68
72
  script/rails generate surveyor:install
69
- rake db:migrate
73
+ bundle exec rake db:migrate
70
74
 
71
- 3. Try out the "kitchen sink" survey. The rake task above generates surveys from our custom survey DSL (a good format for end users and stakeholders).
75
+ Try out the "kitchen sink" survey. The rake task above generates surveys from our custom survey DSL (a good format for end users and stakeholders).
72
76
 
73
- rake surveyor FILE=surveys/kitchen_sink_survey.rb
77
+ bundle exec rake surveyor FILE=surveys/kitchen_sink_survey.rb
74
78
 
75
- 4. Start up your app and visit http://localhost:3000/surveys
79
+ Start up your app and visit http://localhost:3000/surveys
76
80
 
77
81
  Try taking the survey and compare it to the contents of the DSL file kitchen\_sink\_survey.rb. See how the DSL maps to what you see.
78
82
 
@@ -82,14 +86,71 @@ There are two other useful rake tasks:
82
86
  * `rake surveyor:unparse` exports a survey from the application into a
83
87
  file in the surveyor DSL.
84
88
 
89
+ # Upgrading
90
+
91
+ When you are ready to update to the latest version of Surveyor, just do
92
+
93
+ bundle update surveyor
94
+
95
+ and you'll get the latest version that bundler thinks you can use based on the
96
+ constraints in your Gemfile.
97
+
98
+ After you've installed a new version, you should always re-run the surveyor
99
+ generator:
100
+
101
+ script/rails generate surveyor:install
102
+
103
+ This will copy over any new or updated assets and new migrations. Use your VCS'
104
+ utilities to review what's changed, then commit the new versions.
105
+
106
+ git status
107
+ git diff
108
+ [...]
109
+ git add -A
110
+ git commit
111
+
112
+ If there were new migrations, you'll want to be sure to run them before the next
113
+ time you start your app:
114
+
115
+ bundle exec rake db:migrate
116
+
117
+ Finally, review the [changelog][] entries corresponding to the versions between
118
+ your original version and the version you've updated to. There may be changes
119
+ which will affect your customizations. There should be hints in the changelog
120
+ or the referenced issues for what to update when necessary.
121
+
122
+ [changelog]: https://github.com/NUBIC/surveyor/blob/master/CHANGELOG.md
123
+
124
+ ## Following master
125
+
126
+ If you are following along with pre-release versions of Surveyor using a `:git`
127
+ source in your Gemfile, be particularly careful about reviewing migrations after
128
+ updating Surveyor and re-running the generator. We will never change a migration
129
+ between two released versions of Surveyor. However, we may on rare occasions
130
+ change a migration which has been merged into master. When this happens, you'll
131
+ need to assess the differences and decide on an appropriate course of action for
132
+ your app.
133
+
134
+ If you aren't sure what this means, we do not recommend that you deploy an app
135
+ that's locked to surveyor master into production.
136
+
85
137
  # Customizing surveyor
86
138
 
87
139
  Surveyor's controller, models, and views may be customized via classes in your app/models, app/helpers and app/controllers directories. To generate a sample custom controller and layout, run:
88
140
 
89
- `script/rails generate surveyor:custom`
141
+ script/rails generate surveyor:custom
90
142
 
91
143
  and read surveys/EXTENDING\_SURVEYOR
92
144
 
145
+ # The asset pipeline
146
+
147
+ Surveyor is now aware of the Rails asset pipeline (http://guides.rubyonrails.org/asset_pipeline.html). With the asset pipeline enabled `Rails.application.config.assets.enabled == true`, then the `surveyor:install` generator will generate `app/assets/stylesheets/surveyor_all.css` and `app/assets/javascripts/surveyor_all.js` manifest files and link them from the surveyor\_default layout. Assets remain in the gem and are picked up for inclusion and pre-compilation from there if `config/environments/production.rb` is set to include surveyor assets.
148
+
149
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
150
+ config.assets.precompile += %w( surveyor_all.js surveyor_all.css )
151
+
152
+ The previous copy-to-application behavior still exists in the case where the asset pipeline is missing or disabled.
153
+
93
154
  # PDF support
94
155
 
95
156
  * Add the following lines to your Gemfile:
@@ -120,17 +181,33 @@ or on OSX:
120
181
 
121
182
  # Requirements
122
183
 
123
- Surveyor depends on:
184
+ Surveyor works with:
185
+
186
+ * Ruby 1.8.7, 1.9.2, and 1.9.3
187
+ * Rails 3.0-3.2
188
+
189
+ Some key library dependencies are:
124
190
 
125
- * Ruby (1.8.7 - 1.9.2)
126
- * Rails 3.0-3.1
127
191
  * HAML
128
- * SASS
129
- * fastercsv (or CSV for ruby 1.9) for csv exports
130
- * formtastic
131
- * UUID
192
+ * Sass
193
+ * Formtastic
194
+
195
+ A more exhaustive list can be found in the gemspec.
196
+
197
+ # Support
198
+
199
+ For general discussion (e.g., "how do I do this?"), please send a message to the
200
+ [surveyor-dev][] group. This group is moderated to keep out spam; don't be
201
+ surprised if your message isn't posted immediately.
132
202
 
133
- Specific versions of the gem dependencies are listed in the gemspec.
203
+ For reproducible bugs, please file an issue on the [GitHub issue
204
+ tracker][issues]. Please include a minimal test case (a detailed description of
205
+ how to trigger the bug in a clean rails application). If you aren't sure how to
206
+ isolate the bug, send a message to [surveyor-dev][] with what you know and we'll
207
+ try to help.
208
+
209
+ [surveyor-dev]: https://groups.google.com/group/surveyor-dev
210
+ [issues]: https://github.com/NUBIC/surveyor/issues
134
211
 
135
212
  # Contributing, testing
136
213
 
@@ -155,4 +232,25 @@ to run the features and start writing tests!
155
232
 
156
233
  [bundler]: http://gembundler.com/
157
234
 
235
+ ## Selenium
236
+
237
+ Some of Surveyor's integration tests use Selenium WebDriver and Capybara. The
238
+ WebDriver-based tests default to running in Chrome due to an unfortunate
239
+ [Firefox bug][FF566671]. For them to run, you'll either need:
240
+
241
+ * Chrome and [chromedriver][] installed, or
242
+ * to switch to use Firefox instead
243
+
244
+ To use Firefox instead of Chrome, invoke one or more features with
245
+ `SELENIUM_BROWSER` set in the environment:
246
+
247
+ $ SELENIUM_BROWSER=firefox bundle exec rake cucumber
248
+ $ SELENIUM_BROWSER=firefox bundle exec cucumber features/ajax_submissions.feature
249
+
250
+ Note that when running features in Firefox, you must allow the WebDriver-driven
251
+ Firefox to retain focus, otherwise some tests will fail.
252
+
253
+ [FF566671]: https://bugzilla.mozilla.org/show_bug.cgi?id=566671
254
+ [chromedriver]: http://code.google.com/p/selenium/wiki/ChromeDriver
255
+
158
256
  Copyright (c) 2008-2011 Brian Chamberlain and Mark Yoon, released under the MIT license
data/Rakefile CHANGED
@@ -40,18 +40,14 @@ task :testbed => 'testbed:rebuild'
40
40
  namespace :testbed do
41
41
  desc 'Generate a minimal surveyor-using rails app'
42
42
  task :generate do
43
- sh 'bundle exec rails new testbed'
43
+ sh 'bundle exec rails new testbed --skip-bundle' # don't run bundle install until the Gemfile modifications
44
44
  chdir('testbed') do
45
- File.open('Gemfile', 'w') do |f|
46
- f.puts %q{source :rubygems}
47
- f.puts %q{plugin_root = File.expand_path('../..', __FILE__)}
48
- f.puts %q{eval(File.read File.join(plugin_root, 'Gemfile.rails_version'))}
49
- f.puts %q{gem 'sqlite3'}
50
- f.puts %q{gem 'surveyor', :path => plugin_root}
51
- end
45
+ gem_file_contents = File.read('Gemfile')
46
+ gem_file_contents.sub!(/^(gem 'rails'.*)$/, %Q{# \\1\nplugin_root = File.expand_path('../..', __FILE__)\neval(File.read File.join(plugin_root, 'Gemfile.rails_version'))\ngem 'surveyor', :path => plugin_root})
47
+ File.open('Gemfile', 'w'){|f| f.write(gem_file_contents) }
52
48
 
53
49
  Bundler.with_clean_env do
54
- sh 'bundle update'
50
+ sh 'bundle install' # run bundle install after Gemfile modifications
55
51
  end
56
52
  end
57
53
  end
@@ -72,6 +68,16 @@ namespace :testbed do
72
68
  end
73
69
 
74
70
  task :rebuild => [:remove, :generate, :migrate]
71
+
72
+ desc 'Load all the sample surveys into the testbed instance'
73
+ task :surveys do
74
+ cd('testbed') do
75
+ Dir[File.join('surveys', '*.rb')].each do |fn|
76
+ puts "Installing #{fn} into the testbed"
77
+ system("rake surveyor FILE='#{fn}'")
78
+ end
79
+ end
80
+ end
75
81
  end
76
82
 
77
83
  ###### CI
@@ -0,0 +1,5 @@
1
+ class QuietInput < Formtastic::Inputs::HiddenInput
2
+ def to_html
3
+ super
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ class SurveyorCheckBoxesInput < Formtastic::Inputs::CheckBoxesInput
2
+ include Surveyor::Helpers::FormtasticCustomInput
3
+ def to_html
4
+ super
5
+ end
6
+ def choice_html(choice)
7
+ output = ""
8
+ output << template.content_tag(:label,
9
+ hidden_fields? ?
10
+ check_box_with_hidden_input(choice) :
11
+ check_box_without_hidden_input(choice) <<
12
+ choice_label(choice),
13
+ label_html_options.merge(:for => choice_input_dom_id(choice), :class => nil)
14
+ )
15
+ output << builder.text_field(:response_other, input_html_options_with(choice, :response_other)) if options[:response_class] == "other_and_string"
16
+ output << builder.text_field(response_class_to_method(options[:response_class]), input_html_options_with(choice, options[:response_class])) if %w(date datetime time float integer string other_and_string).include? options[:response_class]
17
+ output << builder.text_area(:text_value, input_html_options_with(choice, :text_value)) if options[:response_class] == "text"
18
+ output.html_safe
19
+ end
20
+ def checked?(value)
21
+ selected_values.include?(value.to_s)
22
+ end
23
+ def disabled?(value)
24
+ disabled_values.include?(value) || input_html_options[:disabled] == true
25
+ end
26
+ def make_selected_values
27
+ if object.respond_to?(method)
28
+ selected_items = [object.send(method)].compact.flatten.map(&:to_s)
29
+
30
+ [*selected_items.map { |o| send_or_call_or_object(value_method, o) }].compact
31
+ else
32
+ []
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ class SurveyorRadioInput < Formtastic::Inputs::RadioInput
2
+ include Surveyor::Helpers::FormtasticCustomInput
3
+ def to_html
4
+ super
5
+ end
6
+ def choice_html(choice)
7
+ output = ""
8
+ output << template.content_tag(:label,
9
+ builder.radio_button(input_name, choice_value(choice), input_html_options.merge(choice_html_options(choice)).merge(:required => false)) <<
10
+ choice_label(choice),
11
+ label_html_options.merge(:for => choice_input_dom_id(choice), :class => nil)
12
+ )
13
+ output << builder.text_field(:response_other, input_html_options_with(choice, :response_other)) if options[:response_class] == "other_and_string"
14
+ output << builder.text_field(response_class_to_method(options[:response_class]), input_html_options_with(choice, options[:response_class])) if %w(date datetime time float integer string other_and_string).include? options[:response_class]
15
+ output << builder.text_area(:text_value, input_html_options_with(choice, :text_value)) if options[:response_class] == "text"
16
+ output.html_safe
17
+ end
18
+ end
@@ -4,9 +4,9 @@
4
4
  - i = response_idx(q.pick != "one") # argument will be false (don't increment i) if we're on radio buttons
5
5
  - disabled = defined?(disableFlag) ? disableFlag : false
6
6
  = f.semantic_fields_for i, r do |ff|
7
- = ff.quiet_input :question_id unless q.pick == "one" # don't repeat question_id if we're on radio buttons
8
- = ff.quiet_input :id unless q.pick == "one" or r.new_record?
9
- = ff.quiet_input :response_group, :value => rg if q.pick != "one" && g && g.display_type == "repeater"
7
+ = ff.input :question_id, :as => :quiet unless q.pick == "one" # don't repeat question_id if we're on radio buttons
8
+ = ff.input :api_id, :as => :quiet unless q.pick == "one"
9
+ = ff.input :response_group, :value => rg, :as => :quiet if q.pick != "one" && g && g.display_type == "repeater"
10
10
  - case q.pick
11
11
  - when "one"
12
12
  = ff.input :answer_id, :as => :surveyor_radio, :collection => [[a_text(a, nil, @render_context), a.id]], :label => false, :input_html => {:class => a.css_class, :disabled => disabled}, :response_class => a.response_class
@@ -14,7 +14,7 @@
14
14
  = ff.input :answer_id, :as => :surveyor_check_boxes, :collection => [[a_text(a, nil, @render_context), a.id]], :label => false, :input_html => {:class => a.css_class, :disabled => disabled}, :response_class => a.response_class
15
15
  - when "none"
16
16
  - if %w(date datetime time float integer string text).include? a.response_class
17
- = ff.quiet_input :answer_id, :input_html => {:class => a.css_class, :value => a.id}
17
+ = ff.input :answer_id, :as => :quiet, :input_html => {:class => a.css_class, :value => a.id}
18
18
  = ff.input rc_to_attr(a.response_class), :as => rc_to_as(a.response_class), :label => a_text(a, :pre, @render_context).blank? ? false : a_text(a, :pre, @render_context), :hint => a_text(a, :post, @render_context), :input_html => generate_pick_none_input_html(r.as(a.response_class), a.default_value, a.css_class, a.response_class, disabled)
19
19
  - else
20
20
  = a_text(a, nil, @render_context)
@@ -10,18 +10,18 @@
10
10
  - r = response_for(@response_set, q, nil, rg)
11
11
  - i = response_idx
12
12
  = f.semantic_fields_for i, r do |ff|
13
- = ff.quiet_input :question_id
14
- = ff.quiet_input :response_group, :value => rg if g && g.display_type == "repeater"
15
- = ff.quiet_input :id unless r.new_record?
16
- = ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :label => q.text, :input_html => { :disabled => disabled }
13
+ = ff.input :question_id, :as => :quiet
14
+ = ff.input :response_group, :as => :quiet, :value => rg if g && g.display_type == "repeater"
15
+ = ff.input :api_id, :as => :quiet
16
+ = ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :include_blank => (renderer != :slider), :label => q.text, :input_html => { :disabled => disabled }
17
17
  - else # :default, :inline, :inline_default
18
18
  - if q.pick == "one"
19
19
  - r = response_for(@response_set, q, nil, rg)
20
20
  - i = response_idx # increment the response index since the answer partial skips for q.pick == one
21
21
  = f.semantic_fields_for i, r do |ff|
22
- = ff.quiet_input :question_id
23
- = ff.quiet_input :response_group, :value => rg if g && g.display_type == "repeater"
24
- = ff.quiet_input :id unless r.new_record?
22
+ = ff.input :question_id, :as => :quiet
23
+ = ff.input :response_group, :as => :quiet, :value => rg if g && g.display_type == "repeater"
24
+ = ff.input :api_id, :as => :quiet
25
25
  - q.answers.each do |a|
26
26
  - next if (q.pick == "one" or q.pick == "any") and disabled and @response_set.responses.where( :question_id => q.id, :answer_id => a.id).empty?
27
27
  = render a.custom_renderer || '/partials/answer', :q => q, :a => a, :f => f, :rg => rg, :g => g, :disableFlag => disabled
@@ -6,7 +6,7 @@
6
6
  %li
7
7
  %table
8
8
  %col.pre
9
- - qs.first.answers.each do |a|
9
+ - qs.first.answers.each do |a|
10
10
  %col{:class => cycle("odd", "even")}
11
11
  %col.post
12
12
  %tbody
@@ -18,13 +18,14 @@
18
18
  %th &nbsp;
19
19
  - ten_questions.each_with_index do |q, i|
20
20
  %tr{:id => "q_#{q.id}", :class => "q_#{renderer} #{q.css_class(@response_set)}"}
21
- - if q.pick == "one"
22
- - r = response_for(@response_set, q, nil, g)
23
- - i = response_idx # increment the response index since the answer partial skips for q.pick == one
24
- = f.semantic_fields_for i, r do |ff|
25
- = ff.quiet_input :question_id
26
- = ff.quiet_input :id unless r.new_record?
27
- %th= q.split_text(:pre)
21
+ %th
22
+ = q.split_text(:pre)
23
+ - if q.pick == "one"
24
+ - r = response_for(@response_set, q, nil, g)
25
+ - i = response_idx # increment the response index since the answer partial skips for q.pick == one
26
+ = f.semantic_fields_for i, r do |ff|
27
+ = ff.input :question_id, :as => :quiet
28
+ = ff.input :api_id, :as => :quiet
28
29
  - q.answers.each do |a|
29
30
  %td= render a.custom_renderer || '/partials/answer', :g => g, :q => q, :a => a, :f => f
30
31
  %th= q.split_text(:post)
@@ -1,36 +1,39 @@
1
1
  object @survey
2
2
  attribute :title
3
- attribute :api_id => :uuid
4
- node(:description, :if => lambda {|s| !s.description.blank? }){|s| s.description }
5
- node(:reference_identifier, :if => lambda {|s| !s.reference_identifier.blank? }){|s| s.reference_identifier }
3
+ attribute :api_id => :uuid
4
+ node(:description, :if => lambda {|s| !s.description.blank? }){|s| s.description }
5
+ node(:reference_identifier, :if => lambda {|s| !s.reference_identifier.blank? }){|s| s.reference_identifier }
6
6
 
7
7
  child :sections => :sections do
8
8
  attributes :title, :display_order
9
- node(:description, :if => lambda {|s| !s.description.blank? }){|s| s.description }
10
- node(:reference_identifier, :if => lambda {|s| !s.reference_identifier.blank? }){|s| s.reference_identifier }
11
-
9
+ node(:description, :if => lambda {|s| !s.description.blank? }){|s| s.description }
10
+ node(:reference_identifier, :if => lambda {|s| !s.reference_identifier.blank? }){|s| s.reference_identifier }
11
+
12
12
  child :questions_and_groups => :questions_and_groups do
13
13
  # both questions and question_groups have uuid, text, help_text, reference_identifier, and type
14
- attribute :api_id => :uuid
15
- node(:text, :if => lambda { |q| q.is_a?(Question)}){ |q| q.split_text(:pre) }
16
- node(:text, :if => lambda { |q| q.is_a?(QuestionGroup)}){ |q| q.text }
17
- node(:help_text, :if => lambda { |q| !q.help_text.blank? }){ |q| q.help_text }
18
- node(:reference_identifier, :if => lambda { |q| !q.reference_identifier.blank? }){ |q| q.reference_identifier }
19
- node(:type, :if => lambda { |q| q.display_type != "default" }){ |q| q.display_type }
20
-
14
+ attribute :api_id => :uuid
15
+ node(:text, :if => lambda { |q| q.is_a?(Question)}){ |q| q.split_text(:pre) }
16
+ node(:text, :if => lambda { |q| q.is_a?(QuestionGroup)}){ |q| q.text }
17
+ node(:help_text, :if => lambda { |q| !q.help_text.blank? }){ |q| q.help_text }
18
+ node(:reference_identifier, :if => lambda { |q| !q.reference_identifier.blank? }){ |q| q.reference_identifier }
19
+ node(:data_export_identifier, :if => lambda { |q| !q.data_export_identifier.blank? }){ |q| q.data_export_identifier }
20
+ node(:type, :if => lambda { |q| q.display_type != "default" }){ |q| q.display_type }
21
+
21
22
  # only questions
22
- node(:pick, :if => lambda { |q| q.is_a?(Question) && q.pick != "none" }){ |q| q.pick }
23
- node(:post_text, :if => lambda { |q| q.is_a?(Question) && !q.split_text(:post).blank? }){ |q| q.split_text(:post) }
24
-
23
+ node(:pick, :if => lambda { |q| q.is_a?(Question) && q.pick != "none" }){ |q| q.pick }
24
+ node(:post_text, :if => lambda { |q| q.is_a?(Question) && !q.split_text(:post).blank? }){ |q| q.split_text(:post) }
25
+
25
26
  child :answers, :if => lambda { |q| q.is_a?(Question) && !q.answers.blank? } do
26
- attribute :api_id => :uuid
27
- node(:help_text, :if => lambda { |a| !a.help_text.blank? }){ |a| a.help_text }
28
- node(:exclusive, :if => lambda { |a| a.is_exclusive }){ |a| a.is_exclusive }
27
+ attribute :api_id => :uuid
28
+ node(:help_text, :if => lambda { |a| !a.help_text.blank? }){ |a| a.help_text }
29
+ node(:exclusive, :if => lambda { |a| a.is_exclusive }){ |a| a.is_exclusive }
29
30
  node(:text){ |a| a.split_or_hidden_text(:pre) }
30
- node(:post_text, :if => lambda { |a| !a.split_or_hidden_text(:post).blank? }){ |a| a.split_or_hidden_text(:post) }
31
- node(:type, :if => lambda { |a| a.response_class != "answer" }){ |a| a.response_class }
31
+ node(:post_text, :if => lambda { |a| !a.split_or_hidden_text(:post).blank? }){ |a| a.split_or_hidden_text(:post) }
32
+ node(:type, :if => lambda { |a| a.response_class != "answer" }){ |a| a.response_class }
33
+ node(:reference_identifier, :if => lambda { |a| !a.reference_identifier.blank? }){ |a| a.reference_identifier }
34
+ node(:data_export_identifier, :if => lambda { |a| !a.data_export_identifier.blank? }){ |a| a.data_export_identifier }
32
35
  end
33
-
36
+
34
37
  # both questions and question_groups have dependencies
35
38
  child :dependency, :if => lambda { |q| q.dependency } do
36
39
  attributes :rule
@@ -41,7 +44,7 @@ child :sections => :sections do
41
44
  node(:value, :if => lambda { |d| d.answer && d.answer.response_class != "answer" && d.as(d.answer.response_class) }){ |d| d.as(d.answer.response_class)}
42
45
  end
43
46
  end
44
-
47
+
45
48
  child(:questions, :if => lambda{|x| x.is_a?(QuestionGroup)}) do
46
49
  attributes :api_id => :uuid
47
50
  node(:text){ |q| q.split_text(:pre) }
@@ -50,7 +53,7 @@ child :sections => :sections do
50
53
  node(:reference_identifier, :if => lambda { |q| !q.reference_identifier.blank? }){ |q| q.reference_identifier }
51
54
  node(:type, :if => lambda { |q| q.display_type != "default" }){ |q| q.display_type }
52
55
  node(:pick, :if => lambda { |q| q.pick != "none" }){ |q| q.pick }
53
-
56
+
54
57
  child :answers, :if => lambda { |q| !q.answers.blank? } do
55
58
  attributes :api_id => :uuid
56
59
  node(:help_text, :if => lambda { |a| !a.help_text.blank? }){ |a| a.help_text }
@@ -59,7 +62,7 @@ child :sections => :sections do
59
62
  node(:post_text, :if => lambda { |a| !a.split_or_hidden_text(:post).blank? }){ |a| a.split_or_hidden_text(:post) }
60
63
  node(:type, :if => lambda { |a| a.response_class != "answer" }){ |a| a.response_class }
61
64
  end
62
-
65
+
63
66
  child :dependency, :if => lambda { |q| q.dependency } do
64
67
  attributes :rule
65
68
  child :dependency_conditions => :conditions do
@@ -7,13 +7,16 @@
7
7
  %br
8
8
  #survey_list
9
9
  %ul
10
- - unless @surveys.empty?
11
- - @surveys.each do |survey|
10
+ - unless @codes.empty?
11
+ - @codes.each do |access_code, values|
12
12
  %li
13
- = form_tag(take_survey_path(:survey_code => survey.access_code)) do
13
+ = form_tag take_survey_path(:survey_code => access_code) do
14
14
  = hidden_field_tag :surveyor_javascript_enabled, false
15
-
16
- = survey.title
15
+
16
+ = values[:title]
17
+ &nbsp;
18
+ = label_tag :survey_version, 'version:'
19
+ = select_tag(:survey_version, options_for_select([["-- Current version --", ""]] + values[:survey_versions]))
17
20
  &nbsp;
18
21
  = submit_tag( t('surveyor.take_it') )
19
22
  - else
@@ -4,11 +4,12 @@ attribute :created_at
4
4
  attribute :completed_at
5
5
  node(:survey_id){|rs| rs.survey.api_id }
6
6
 
7
- child :responses do
7
+ child (@response_set.responses || []) => :responses do
8
8
  attribute :api_id => :uuid
9
9
  attribute :created_at
10
10
  attribute :updated_at => :modified_at
11
+ attribute :response_group
11
12
  node(:answer_id){|r| r.answer.api_id }
12
13
  node(:question_id){|r| r.question.api_id }
13
- node(:value, :if => lambda{|r| r.answer.response_class != "answer"}){|r| r.as(r.answer.response_class) }
14
+ node(:value, :if => lambda{|r| r.answer.response_class != "answer"}){|r| r.json_value }
14
15
  end
data/ci-exec.sh CHANGED
@@ -1,19 +1,25 @@
1
1
  #!/bin/bash -xe
2
2
 
3
- BUNDLER_VERSION=1.1.rc
3
+ BUNDLER_VERSION=1.1.5
4
4
  GEMSET=surveyor
5
5
 
6
- export TMPDIR="`pwd`/tmp"
7
- mkdir -p tmp
6
+ if [ -z $CI_RUBY ]; then
7
+ echo "CI_RUBY must be set"
8
+ exit 1
9
+ fi
10
+
11
+ # TMPDIR under the workspace causes gconfd-2 to stop responding and eat all
12
+ # memory when Firefox is running for the Selenium tests. TMPDIR in user home
13
+ # seems to work fine.
14
+ export TMPDIR="${HOME}/tmp/surveyor-ci-${CI_RUBY}"
8
15
 
9
16
  if [ -n "${RAILS_VERSION}" ]; then
10
17
  GEMSET="${GEMSET}-${RAILS_VERSION}"
18
+ TMPDIR="${TMPDIR}-${RAILS_VERSION}"
11
19
  fi
12
20
 
13
- if [ -z $CI_RUBY ]; then
14
- echo "CI_RUBY must be set"
15
- exit 1
16
- fi
21
+ rm -rf "${TMPDIR}"
22
+ mkdir -p "${TMPDIR}"
17
23
 
18
24
  set +xe
19
25
  echo "Initializing RVM"
data/cucumber.yml CHANGED
@@ -4,7 +4,7 @@ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'pr
4
4
  std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
5
5
  %>
6
6
  default: <%= std_opts %> features
7
- wip: --tags @wip:3 --wip features
7
+ wip: --tags @wip --wip features
8
8
  rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
9
- ci: --tags ~@wip --tags ~@javascript --format html --out reports/cucumber.html --format junit --out reports/cucumber-xml --format pretty --strict features
10
- ci_wip: --wip --tags @wip --tags ~@javascript --format html --out reports/cucumber_wip.html --format pretty features
9
+ ci: --tags ~@wip --format html --out reports/cucumber.html --format junit --out reports/cucumber-xml --format pretty --strict features
10
+ ci_wip: --wip --tags @wip --format html --out reports/cucumber_wip.html --format pretty features