surveyor 0.19.7 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/CHANGELOG +22 -0
  2. data/README.md +1 -1
  3. data/Rakefile +1 -0
  4. data/VERSION +1 -1
  5. data/app/helpers/surveyor_helper.rb +5 -1
  6. data/app/views/partials/_answer.html.haml +4 -4
  7. data/app/views/partials/_question.html.haml +2 -1
  8. data/app/views/partials/_question_group.html.haml +7 -2
  9. data/features/redcap_parser.feature +24 -0
  10. data/features/step_definitions/surveyor_steps.rb +22 -1
  11. data/features/support/redcap_new_headers.csv +1 -0
  12. data/features/support/redcap_whitespace.csv +1 -0
  13. data/features/surveyor.feature +161 -1
  14. data/features/surveyor_parser.feature +49 -1
  15. data/generators/surveyor/surveyor_generator.rb +3 -2
  16. data/generators/surveyor/templates/assets/javascripts/jquery.surveyor.js +23 -9
  17. data/generators/surveyor/templates/assets/stylesheets/sass/custom.sass +5 -0
  18. data/generators/surveyor/templates/assets/stylesheets/sass/surveyor.sass +9 -2
  19. data/generators/surveyor/templates/migrate/add_display_type_to_answers.rb +13 -0
  20. data/lib/surveyor/models/answer_methods.rb +2 -2
  21. data/lib/surveyor/models/dependency_methods.rb +1 -1
  22. data/lib/surveyor/models/response_methods.rb +1 -1
  23. data/lib/surveyor/models/response_set_methods.rb +7 -0
  24. data/lib/surveyor/parser.rb +3 -3
  25. data/lib/surveyor/redcap_parser.rb +21 -18
  26. data/lib/surveyor/surveyor_controller_methods.rb +3 -2
  27. data/lib/surveyor/unparser.rb +1 -1
  28. data/spec/factories.rb +1 -1
  29. data/spec/lib/benchmark_spec.rb +22 -0
  30. data/spec/lib/redcap_parser_spec.rb +22 -0
  31. data/spec/models/answer_spec.rb +2 -2
  32. data/spec/models/response_set_spec.rb +20 -0
  33. data/surveyor.gemspec +8 -3
  34. metadata +11 -7
  35. data/.rvmrc +0 -1
data/CHANGELOG CHANGED
@@ -1,3 +1,25 @@
1
+ 0.20.0
2
+
3
+ * allow answers to be images. closes #171
4
+ * moving from answer.hide_label => true to answer.display_type => 'hidden_label'
5
+ * don't parse redcap formulas. really closes #179
6
+ * allow more of less whitespace in answer options. closes #179
7
+ * fixing date, time, and datetime saving via ajax. closes #133
8
+ * not using separate gemset, using passenger in development
9
+ * fixed an issue where the last date was sent instead of the currently choosen date for a date field
10
+ * Save grid responses and ids. Closes #161
11
+ * dropdowns should save their response ids. closes #180
12
+ * README should reflect that it is 2011
13
+ * separate file for custom css and gem upgrade message. closes #151
14
+ * benchmarking surveyor dump for #166
15
+ * two-lettered rule keys. this one actually closes #159
16
+ * two-lettered rule keys. closes #159
17
+ * fix parsing of question and answer references with q_ and a_ in their names. closes #170
18
+ * more redcap branching logic. closes #177
19
+ * dynamically require some columns. closes #178
20
+ * Fixes problem with updating checkboxes on postgers.
21
+ * Fix problem when calling Answer.exists?('') under postgers.
22
+
1
23
  0.19.7
2
24
 
3
25
  * fix accidentally allowing through blank pick => any answers
data/README.md CHANGED
@@ -111,4 +111,4 @@ To work on the code fork this github project. Run:
111
111
 
112
112
  which will generate a test app in testbed. Run rake spec and rake cucumber there, and start writing tests!
113
113
 
114
- Copyright (c) 2008-2010 Brian Chamberlain and Mark Yoon, released under the MIT license
114
+ Copyright (c) 2008-2011 Brian Chamberlain and Mark Yoon, released under the MIT license
data/Rakefile CHANGED
@@ -15,6 +15,7 @@ begin
15
15
  gem.add_dependency 'formtastic'
16
16
  gem.add_dependency 'uuid'
17
17
  gem.add_development_dependency "yard", ">= 0"
18
+ gem.post_install_message = "Thanks for installing surveyor! The time has come to run the surveyor generator and migrate your database, even if you are upgrading."
18
19
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
20
  end
20
21
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.19.7
1
+ 0.20.0
@@ -4,7 +4,7 @@ module SurveyorHelper
4
4
  surveyor_stylsheets + surveyor_javascripts
5
5
  end
6
6
  def surveyor_stylsheets
7
- stylesheet_link_tag 'surveyor/reset', 'surveyor/dateinput', 'surveyor'
7
+ stylesheet_link_tag 'surveyor/reset', 'surveyor/dateinput', 'surveyor', 'custom'
8
8
  end
9
9
  def surveyor_javascripts
10
10
  javascript_include_tag 'surveyor/jquery.tools.min', 'surveyor/jquery.surveyor'
@@ -50,6 +50,10 @@ module SurveyorHelper
50
50
  # end
51
51
 
52
52
  # Answers
53
+ def a_text(obj, pos=nil)
54
+ return image_tag(obj.text) if obj.is_a?(Answer) and obj.display_type == "image"
55
+ obj.split_or_hidden_text(pos)
56
+ end
53
57
  def rc_to_attr(type_sym)
54
58
  case type_sym.to_s
55
59
  when /^date|time$/ then :datetime_value
@@ -8,12 +8,12 @@
8
8
  = ff.quiet_input :response_group, :value => rg if q.pick != "one" && g && g.display_type == "repeater"
9
9
  - case q.pick
10
10
  - when "one"
11
- = ff.input :answer_id, :as => :surveyor_radio, :collection => [[a.text, a.id]], :label => false, :input_html => {:class => a.css_class}, :response_class => a.response_class
11
+ = ff.input :answer_id, :as => :surveyor_radio, :collection => [[a_text(a), a.id]], :label => false, :input_html => {:class => a.css_class}, :response_class => a.response_class
12
12
  - when "any"
13
- = ff.input :answer_id, :as => :surveyor_check_boxes, :collection => [[a.text, a.id]], :label => false, :input_html => {:class => a.css_class}, :response_class => a.response_class
13
+ = ff.input :answer_id, :as => :surveyor_check_boxes, :collection => [[a_text(a), a.id]], :label => false, :input_html => {:class => a.css_class}, :response_class => a.response_class
14
14
  - when "none"
15
15
  - if %w(date datetime time float integer string text).include? a.response_class
16
16
  = ff.quiet_input :answer_id, :input_html => {:class => a.css_class, :value => a.id}
17
- = ff.input rc_to_attr(a.response_class), :as => rc_to_as(a.response_class), :label => a.split_or_hidden_text(:pre).blank? ? false : a.split_or_hidden_text(:pre), :hint => a.split_or_hidden_text(:post), :input_html => generate_pick_none_input_html(r.as(a.response_class), a.default_value, a.css_class)
17
+ = ff.input rc_to_attr(a.response_class), :as => rc_to_as(a.response_class), :label => a_text(a, :pre).blank? ? false : a_text(a, :pre), :hint => a_text(a, :post), :input_html => generate_pick_none_input_html(r.as(a.response_class), a.default_value, a.css_class)
18
18
  - else
19
- = a.text
19
+ = a_text(a)
@@ -11,7 +11,8 @@
11
11
  - f.semantic_fields_for i, r do |ff|
12
12
  = ff.quiet_input :question_id
13
13
  = ff.quiet_input :response_group, :value => rg if g && g.display_type == "repeater"
14
- = ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :label => false
14
+ = ff.quiet_input :id unless r.new_record?
15
+ = ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :label => q.text
15
16
  - else # :default, :inline, :inline_default
16
17
  - if q.pick == "one"
17
18
  - r = response_for(@response_set, q, nil, rg)
@@ -14,12 +14,17 @@
14
14
  %tr
15
15
  %th  
16
16
  - ten_questions.first.answers.each do |a|
17
- %th= a.text
17
+ %th= a_text(a)
18
18
  %th  
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?
21
27
  %th= q.split_text(:pre)
22
- - response_idx if q.pick == "one" # increment the response index since the answer partial skips for q.pick == one
23
28
  - q.answers.each do |a|
24
29
  %td= render a.custom_renderer || '/partials/answer', :g => g, :q => q, :a => a, :f => f
25
30
  %th= q.split_text(:post)
@@ -31,3 +31,27 @@ Feature: Survey creation
31
31
  And there should be 1 dependencies with:
32
32
  | rule |
33
33
  | A |
34
+ Scenario: with different headers
35
+ Given I parse redcap file "redcap_new_headers.csv"
36
+ Then there should be 1 survey with:
37
+ ||
38
+ And there should be 1 questions with:
39
+ ||
40
+ And there should be 2 answers with:
41
+ ||
42
+ @focus
43
+ Scenario: with different whitespace
44
+ Given I parse redcap file "redcap_whitespace.csv"
45
+ Then there should be 1 survey with:
46
+ ||
47
+ And there should be 2 questions with:
48
+ ||
49
+ And there should be 7 answers with:
50
+ | reference_identifier | text |
51
+ | 1 | Lexapro |
52
+ | 2 | Celexa |
53
+ | 3 | Prozac |
54
+ | 4 | Paxil |
55
+ | 5 | Zoloft |
56
+ | 0 | No |
57
+ | 1 | Yes |
@@ -22,7 +22,7 @@ Then /^there should be (\d+) response set with (\d+) responses? with:$/ do |rs_n
22
22
  end
23
23
  end
24
24
 
25
- Then /^there should be (\d+) dependencies$/ do |x|
25
+ Then /^there should be (\d+) dependenc(?:y|ies)$/ do |x|
26
26
  Dependency.count.should == x.to_i
27
27
  end
28
28
 
@@ -60,3 +60,24 @@ Then /^there should be (\d+) text areas$/ do |count|
60
60
  response.should have_selector('textarea', :count => count.to_i)
61
61
  end
62
62
 
63
+ Then /^the question "([^"]*)" should be triggered$/ do |text|
64
+ response.should have_selector %(fieldset[name="#{text}"][class!="q_hidden"])
65
+ end
66
+
67
+ Then /^there should be (\d+) response with answer "([^"]*)"$/ do |count, answer_text|
68
+ Response.count.should == count.to_i
69
+ Response.find_by_answer_id(Answer.find_by_text(answer_text)).should_not be_blank
70
+ end
71
+
72
+ Then /^there should be (\d+) datetime responses with$/ do |count, table|
73
+ Response.count.should == count.to_i
74
+ table.hashes.each do |hash|
75
+ if hash.keys == ["datetime_value"]
76
+ Response.find_by_datetime_value(DateTime.parse(hash["datetime_value"])).should_not be_blank
77
+ end
78
+ end
79
+ end
80
+
81
+ Then /^I should see the image "([^"]*)"$/ do |src|
82
+ response.should have_selector %(img[src^="#{src}"])
83
+ end
@@ -0,0 +1 @@
1
+ Variable / Field Name,Form Name,Field Units,Section Header,Field Type,Field Label,Choices Calculations OR Slider Labels,Field Note,Text Validation Type OR Show Slider Number,Text Validation Min,Text Validation Max,Identifier?,Branching Logic (Show field only if...),Required Field?
@@ -0,0 +1 @@
1
+ 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?
@@ -168,4 +168,164 @@ Feature: Survey creation
168
168
  """
169
169
  When I start the "Websites" survey
170
170
  Then there should be 3 checkboxes
171
- And there should be 3 text areas
171
+ And there should be 3 text areas
172
+
173
+ Scenario: "Double letter rule keys"
174
+ Given the survey
175
+ """
176
+ survey "Doubles" do
177
+ section "Two" do
178
+ q_twin "Are you a twin?", :pick => :one
179
+ a_yes "Oh yes"
180
+ a_no "Oh no"
181
+
182
+ q_two_first_names "Do you have two first names?", :pick => :one
183
+ a_yes "Why yes"
184
+ a_no "Why no"
185
+
186
+ q "Do you want to be part of an SNL skit?", :pick => :one
187
+ a_yes "Um yes"
188
+ a_no "Um no"
189
+ dependency :rule => "A or AA"
190
+ condition_A :q_twin, "==", :a_yes
191
+ condition_AA :q_two_first_names, "==", :a_yes
192
+ end
193
+ section "Deux" do
194
+ label "Here for the ride"
195
+ end
196
+ section "Three" do
197
+ label "Here for the ride"
198
+ end
199
+ end
200
+ """
201
+ When I start the "Doubles" survey
202
+ Then I choose "Oh yes"
203
+ And I press "Deux"
204
+ And I press "Two"
205
+ Then the question "Do you want to be part of an SNL skit?" should be triggered
206
+
207
+ Scenario: "Changing dropdowns"
208
+ Given the survey
209
+ """
210
+ survey "Drop" do
211
+ section "Like it is hot" do
212
+ q "Name", :pick => :one, :display_type => :dropdown
213
+ a "Snoop"
214
+ a "Dogg"
215
+ a "D-O double G"
216
+ a "S-N double O-P, D-O double G"
217
+ end
218
+ section "Two" do
219
+ label "Here for the ride"
220
+ end
221
+ section "Three" do
222
+ label "Here for the ride"
223
+ end
224
+ end
225
+ """
226
+ When I start the "Drop" survey
227
+ Then I select "Snoop" from "Name"
228
+ And I press "Two"
229
+ And I press "Like it is hot"
230
+ And I select "Dogg" from "Name"
231
+ And I press "Two"
232
+ Then there should be 1 response with answer "Dogg"
233
+
234
+ Scenario: "Saving grids"
235
+ Given the survey
236
+ """
237
+ survey "Grid" do
238
+ section "One" do
239
+ grid "Tell us how often do you cover these each day" do
240
+ a "1"
241
+ a "2"
242
+ a "3"
243
+ q "Head", :pick => :one
244
+ q "Knees", :pick => :one
245
+ q "Toes", :pick => :one
246
+ end
247
+ end
248
+ section "Two" do
249
+ label "Here for the ride"
250
+ end
251
+ section "Three" do
252
+ label "Here for the ride"
253
+ end
254
+ end
255
+ """
256
+ When I start the "Grid" survey
257
+ Then I choose "1"
258
+ And I press "Two"
259
+ And I press "One"
260
+ Then there should be 1 response with answer "1"
261
+
262
+ Scenario: "Dates"
263
+ Given the survey
264
+ """
265
+ survey "When" do
266
+ section "One" do
267
+ q "Tell us when you want to meet"
268
+ a "Give me a date", :date
269
+ end
270
+ section "Two" do
271
+ q "Tell us when you'd like to eat"
272
+ a :time
273
+ end
274
+ section "Three" do
275
+ q "Tell us when you'd like a phone call"
276
+ a :datetime
277
+ end
278
+ end
279
+ """
280
+ When I start the "When" survey
281
+ # 2/14/11
282
+ And I fill in "Give me a date" with "2011-02-14"
283
+ # 1:30am
284
+ And I press "Two"
285
+ And I select "01" from "Hour"
286
+ And I select "30" from "Minute"
287
+ # 2/15/11 5:30pm
288
+ And I press "Three"
289
+ And I select "2011" from "Year"
290
+ And I select "February" from "Month"
291
+ And I select "15" from "Day"
292
+ And I select "17" from "Hour"
293
+ And I select "30" from "Minute"
294
+ And I press "One"
295
+
296
+ Then there should be 3 datetime responses with
297
+ | datetime_value |
298
+ | 2011-02-14 00:00:00 |
299
+ | 2001-01-01 01:30:00 |
300
+ | 2011-02-15 17:30:00 |
301
+
302
+ # 2/13/11
303
+ And I fill in "Give me a date" with "2011-02-13"
304
+ # 1:30pm
305
+ And I press "Two"
306
+ And I select "13" from "Hour"
307
+ # 2/15/11 5:00pm
308
+ And I press "Three"
309
+ And I select "00" from "Minute"
310
+ And I press "Click here to finish"
311
+
312
+ Then there should be 3 datetime responses with
313
+ | datetime_value |
314
+ | 2011-02-13 00:00:00 |
315
+ | 2001-01-01 13:30:00 |
316
+ | 2011-02-15 17:00:00 |
317
+
318
+ Scenario: "Images"
319
+ Given the survey
320
+ """
321
+ survey "Images" do
322
+ section "One" do
323
+ q "Which way?"
324
+ a "/images/surveyor/next.gif", :display_type => "image"
325
+ a "/images/surveyor/prev.gif", :display_type => "image"
326
+ end
327
+ end
328
+ """
329
+ When I start the "Images" survey
330
+ Then I should see the image "/images/surveyor/next.gif"
331
+ And I should see the image "/images/surveyor/prev.gif"
@@ -238,4 +238,52 @@ Feature: Survey creation
238
238
  """
239
239
  Then there should be 4 dependencies
240
240
  And 2 dependencies should depend on questions
241
- And 2 dependencies should depend on question groups
241
+ And 2 dependencies should depend on question groups
242
+
243
+ Scenario: Dependencies with "a"
244
+ Given the survey
245
+ """
246
+ survey "Dependencies with 'a'" do
247
+ section "First" do
248
+ q_data_collection "Disease data collection", :pick => :one
249
+ a_via_chart_review "Via chart review"
250
+ a_via_patient_interview "Via patient interview/questionnaire"
251
+
252
+ q_myocardial_infaction "Myocardinal Infarction", :pick => :one
253
+ dependency :rule => "A"
254
+ condition_A :q_data_collection, "==", :a_via_chart_review
255
+ a_yes "Yes"
256
+ a_no "No"
257
+ end
258
+ end
259
+ """
260
+ And there should be 1 dependency with:
261
+ | rule |
262
+ | A |
263
+ And there should be 1 resolved dependency_condition with:
264
+ | rule_key |
265
+ | A |
266
+
267
+ Scenario: Dependencies with "q"
268
+ Given the survey
269
+ """
270
+ survey "Dependencies with 'q'" do
271
+ section "First" do
272
+ q_rawq_collection "Your rockin rawq collection", :pick => :one
273
+ a_rawqs "Rawqs"
274
+ a_doesnt_rawq "Doesn't rawq"
275
+
276
+ q_do_you_rawq "Do you rawq with your rockin rawq collection?", :pick => :one
277
+ dependency :rule => "A"
278
+ condition_A :q_rawq_collection, "==", :a_rawqs
279
+ a_yes "Yes"
280
+ a_no "No"
281
+ end
282
+ end
283
+ """
284
+ And there should be 1 dependency with:
285
+ | rule |
286
+ | A |
287
+ And there should be 1 resolved dependency_condition with:
288
+ | rule_key |
289
+ | A |
@@ -28,7 +28,8 @@ class SurveyorGenerator < Rails::Generator::Base
28
28
  "add_display_order_to_surveys", "add_correct_answer_id_to_questions",
29
29
  "add_index_to_response_sets", "add_index_to_surveys",
30
30
  "add_unique_indicies", "add_section_id_to_responses",
31
- "add_default_value_to_answers", "add_api_ids"].each_with_index do |model, i|
31
+ "add_default_value_to_answers", "add_api_ids",
32
+ "add_display_type_to_answers"].each_with_index do |model, i|
32
33
  unless (prev_migrations = Dir.glob("db/migrate/[0-9]*_*.rb").grep(/[0-9]+_#{model}.rb$/)).empty?
33
34
  prev_migration_timestamp = prev_migrations[0].match(/([0-9]+)_#{model}.rb$/)[1]
34
35
  end
@@ -45,7 +46,7 @@ class SurveyorGenerator < Rails::Generator::Base
45
46
  end
46
47
  m.directory "public/stylesheets/sass"
47
48
  m.file "assets/stylesheets/sass/surveyor.sass", "public/stylesheets/sass/surveyor.sass"
48
-
49
+ m.file "assets/stylesheets/sass/custom.sass", "public/stylesheets/sass/custom.sass"
49
50
 
50
51
  # Locales
51
52
  m.directory "config/locales"
@@ -2,25 +2,37 @@
2
2
  jQuery(document).ready(function(){
3
3
  // if(jQuery.browser.msie){
4
4
  // // IE has trouble with the change event for form radio/checkbox elements - bind click instead
5
- // jQuery("form#survey_form input[type=radio], form#survey_form [type=checkbox]").bind("click", function(){
5
+ // jQuery("form#survey_form input[type=radio], form#survey_form [type=checkbox]").bind("click", function(){
6
6
  // jQuery(this).parents("form").ajaxSubmit({dataType: 'json', success: successfulSave});
7
7
  // });
8
8
  // // IE fires the change event for all other (not radio/checkbox) elements of the form
9
- // jQuery("form#survey_form *").not("input[type=radio], input[type=checkbox]").bind("change", function(){
10
- // jQuery(this).parents("form").ajaxSubmit({dataType: 'json', success: successfulSave});
9
+ // jQuery("form#survey_form *").not("input[type=radio], input[type=checkbox]").bind("change", function(){
10
+ // jQuery(this).parents("form").ajaxSubmit({dataType: 'json', success: successfulSave});
11
11
  // });
12
12
  // }else{
13
13
  // // Other browsers just use the change event on the form
14
+
15
+ // For a date input, i.e. using dateinput from jQuery tools, the value is not updated
16
+ // before the onChange or change event is fired, so we hang this in before the update is
17
+ // sent to the server and set the correct value from the dateinput object.
18
+ jQuery('li.date input').change(function(){
19
+ if ( $(this).data('dateinput') ) {
20
+ var date_obj = $(this).data('dateinput').getValue();
21
+ this.value = date_obj.getFullYear() + "-" + (date_obj.getMonth()+1) + "-" +
22
+ date_obj.getDate() + " 00:00:00 UTC";
23
+ }
24
+ });
25
+
14
26
  jQuery("form#survey_form input, form#survey_form select, form#survey_form textarea").change(function(){
15
- question_data = $(this).parents('fieldset[id^="q_"]').find("input, select, textarea").add($("form#survey_form input[name='authenticity_token']")).serialize();
27
+ question_data = $(this).parents('fieldset[id^="q_"],tr[id^="q_"]').find("input, select, textarea").add($("form#survey_form input[name='authenticity_token']")).serialize();
16
28
  // console.log(unescape(question_data));
17
29
  $.ajax({ type: "PUT", url: $(this).parents('form#survey_form').attr("action"), data: question_data, dataType: 'json', success: successfulSave })
18
30
  });
19
31
  // }
20
-
32
+
21
33
  // If javascript works, we don't need to show dependents from previous sections at the top of the page.
22
34
  jQuery("#dependents").remove();
23
-
35
+
24
36
  function successfulSave(responseText){ // for(key in responseText) { console.log("key is "+[key]+", value is "+responseText[key]); }
25
37
  // surveyor_controller returns a json object to show/hide elements and insert/remove ids e.g. {"ids": {"2" => 234}, "remove": {"4" => 21}, "hide":["question_12","question_13"],"show":["question_14"]}
26
38
  jQuery.each(responseText.show, function(){ jQuery('#' + this).show("fast"); });
@@ -29,7 +41,7 @@ jQuery(document).ready(function(){
29
41
  jQuery.each(responseText.remove, function(k,v){ jQuery('#r_'+k+'_id[value="'+v+'"]').remove(); });
30
42
  return false;
31
43
  }
32
-
44
+
33
45
  // is_exclusive checkboxes should disble sibling checkboxes
34
46
  $('input.exclusive:checked').parents('fieldset[id^="q_"]').find(':checkbox').not(".exclusive").attr('checked', false).attr('disabled', true);
35
47
  $('input.exclusive:checkbox').click(function(){
@@ -41,6 +53,8 @@ jQuery(document).ready(function(){
41
53
  others.attr('disabled', false);
42
54
  }
43
55
  });
44
-
45
- $('li.date input').dateinput();
56
+
57
+ $('li.date input').dateinput({
58
+ format: 'dd mmm yyyy'
59
+ });
46
60
  });
@@ -0,0 +1,5 @@
1
+ /* Add custom styles here. They will be
2
+ * loaded after the surveyor stylesheets */
3
+
4
+ #surveyor
5
+ :font-family "Century Gothic"
@@ -1,3 +1,9 @@
1
+ /* Do not change surveyor.sass or the generated
2
+ * surveyor.css. They will be overwritten by
3
+ * the surveyor generator. Instead, add
4
+ * custom styles to custom.sass, which will be
5
+ * loaded after the surveyor stylesheets */
6
+
1
7
  $background_color:#EEEEEE
2
8
  $surveyor_flash_background_color:#FFF1A8
3
9
  $surveyor_color:#FFFFF1
@@ -103,8 +109,9 @@ body
103
109
  legend
104
110
  :background-color $surveyor_dependent_color
105
111
  :padding 3px 3px 3px 0
106
-
107
-
112
+ fieldset.q_dropdown, fieldset.q_inline_dropdown, fieldset.q_slider, fieldset.q_repeater_dropdown
113
+ label
114
+ :display none
108
115
 
109
116
  // buttons
110
117
  input[type="submit"]
@@ -0,0 +1,13 @@
1
+ class AddDisplayTypeToAnswers < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :answers, :display_type, :string
4
+ Answer.all.each{|a| a.update_attributes(:display_type => "hidden_label") if a.hide_label == true}
5
+ remove_column :answers, :hide_label
6
+ end
7
+
8
+ def self.down
9
+ add_column :answers, :hide_label, :boolean
10
+ Answer.all.each{|a| a.update_attributes(:hide_label => true) if a.display_type == "hidden_label"}
11
+ remove_column :answers, :display_type
12
+ end
13
+ end
@@ -31,7 +31,7 @@ module Surveyor
31
31
  def default_args
32
32
  self.display_order ||= self.question ? self.question.answers.count : 0
33
33
  self.is_exclusive ||= false
34
- self.hide_label ||= false
34
+ self.display_type ||= "default"
35
35
  self.response_class ||= "answer"
36
36
  self.short_text ||= text
37
37
  self.data_export_identifier ||= Surveyor::Common.normalize(text)
@@ -43,7 +43,7 @@ module Surveyor
43
43
  end
44
44
 
45
45
  def split_or_hidden_text(part = nil)
46
- return "" if hide_label.to_s == "true"
46
+ return "" if display_type == "hidden_label"
47
47
  part == :pre ? text.split("|",2)[0] : (part == :post ? text.split("|",2)[1] : text)
48
48
  end
49
49
 
@@ -42,7 +42,7 @@ module Surveyor
42
42
  # logger.debug "rexp: #{rgx.inspect}"
43
43
  # logger.debug "keyp: #{ch.inspect}"
44
44
  # logger.debug "subd: #{self.rule.gsub(rgx){|m| ch[m.to_sym]}}"
45
- rgx = Regexp.new(self.dependency_conditions.map{|dc| ["a","o"].include?(dc.rule_key) ? "#{dc.rule_key}(?!nd|r)" : dc.rule_key}.join("|")) # exclude and, or
45
+ rgx = Regexp.new(self.dependency_conditions.map{|dc| ["a","o"].include?(dc.rule_key) ? "\\b#{dc.rule_key}(?!nd|r)\\b" : "\\b#{dc.rule_key}\\b"}.join("|")) # exclude and, or
46
46
  eval(self.rule.gsub(rgx){|m| ch[m.to_sym]})
47
47
  end
48
48
 
@@ -20,7 +20,7 @@ module Surveyor
20
20
  def applicable_attributes(attrs)
21
21
  result = HashWithIndifferentAccess.new(attrs)
22
22
  answer_id = result[:answer_id].is_a?(Array) ? result[:answer_id].last : result[:answer_id] # checkboxes are arrays / radio buttons are not arrays
23
- if result[:string_value] && Answer.exists?(answer_id)
23
+ if result[:string_value] && !answer_id.blank? && Answer.exists?(answer_id)
24
24
  answer = Answer.find(answer_id)
25
25
  result.delete(:string_value) unless answer.response_class && answer.response_class.to_sym == :string
26
26
  end
@@ -42,6 +42,13 @@ module Surveyor
42
42
  return false if (q = Question.find_by_id(hash["question_id"])) and q.pick == "one"
43
43
  hash.any?{|k,v| v.is_a?(Array) ? v.all?{|x| x.to_s.blank?} : v.to_s.blank?}
44
44
  end
45
+ def trim_for_lookups(hash_of_hashes)
46
+ result = {}
47
+ (reject_or_destroy_blanks(hash_of_hashes) || {}).each_pair do |k, hash|
48
+ result.merge!({k => {"question_id" => hash["question_id"], "answer_id" => hash["answer_id"]}.merge(hash.has_key?("response_group") ? {"response_group" => hash["response_group"]} : {} ).merge(hash.has_key?("id") ? {"id" => hash["id"]} : {} ).merge(hash.has_key?("_destroy") ? {"_destroy" => hash["_destroy"]} : {} )})
49
+ end
50
+ result
51
+ end
45
52
  end
46
53
  end
47
54
 
@@ -192,11 +192,11 @@ class DependencyCondition < ActiveRecord::Base
192
192
  {
193
193
  :context_reference => context,
194
194
  :operator => a1 || "==",
195
- :question_reference => a0.to_s.gsub("q_", ""),
195
+ :question_reference => a0.to_s.gsub(/^q_/, ""),
196
196
  :rule_key => reference_identifier
197
197
  }.merge(
198
198
  a2.is_a?(Hash) ? a2 : { :answer_reference =>
199
- a2.to_s.gsub("a_", "") }
199
+ a2.to_s.gsub(/^a_/, "") }
200
200
  )
201
201
  )
202
202
  end
@@ -258,7 +258,7 @@ class Answer < ActiveRecord::Base
258
258
  when :none, :omit # is_exclusive erases and disables other checkboxes and input elements
259
259
  self.text_args(arg.to_s.humanize).merge({:is_exclusive => true})
260
260
  when :integer, :date, :time, :datetime, :text, :datetime, :string
261
- self.text_args(arg.to_s.humanize).merge({:response_class => arg.to_s, :hide_label => true})
261
+ self.text_args(arg.to_s.humanize).merge({:response_class => arg.to_s, :display_type => "hidden_label"})
262
262
  end
263
263
  end
264
264
  end
@@ -24,7 +24,7 @@ module Surveyor
24
24
  begin
25
25
  csvlib.parse(str, :headers => :first_row, :return_headers => true, :header_converters => :symbol) do |r|
26
26
  if r.header_row? # header row
27
- return puts "Missing headers: #{missing_columns(r).inspect}\n\n" unless missing_columns(r).blank?
27
+ return puts "Missing headers: #{missing_columns(r.headers).inspect}\n\n" unless missing_columns(r.headers).blank?
28
28
  context[:survey] = Survey.new(:title => filename)
29
29
  print "survey_#{context[:survey].access_code} "
30
30
  else # non-header rows
@@ -44,10 +44,14 @@ module Surveyor
44
44
  return context[:survey]
45
45
  end
46
46
  def missing_columns(r)
47
- required_columns - r.headers.map(&:to_s)
47
+ missing = []
48
+ missing << "choices_or_calculations" unless r.map(&:to_s).include?("choices_or_calculations") or r.map(&:to_s).include?("choices_calculations_or_slider_labels")
49
+ missing << "text_validation_type" unless r.map(&:to_s).include?("text_validation_type") or r.map(&:to_s).include?("text_validation_type_or_show_slider_number")
50
+ missing += (static_required_columns - r.map(&:to_s))
48
51
  end
49
- def required_columns
50
- %w(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)
52
+ def static_required_columns
53
+ # no longer requiring field_units
54
+ %w(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)
51
55
  end
52
56
  end
53
57
  end
@@ -110,19 +114,18 @@ class Dependency < ActiveRecord::Base
110
114
  end
111
115
  end
112
116
  def self.decompose_component(str)
113
- # [initial_52] = "1"
114
- if match = str.match(/^\[(\w+)\] ?([!=><]+) ?"(\w+)"$/)
115
- {:question_reference => match[1], :operator => match[2].gsub(/^=$/, "=="), :answer_reference => match[3]}
116
- # [initial_119(2)] = "1"
117
- elsif match = str.match(/^\[(\w+)\((\w+)\)\] ?([!=><]+) ?"1"$/)
118
- {:question_reference => match[1], :operator => match[3].gsub(/^=$/, "=="), :answer_reference => match[2]}
119
- # [f1_q15] >= 21
120
- elsif match = str.match(/^\[(\w+)\] ?([!=><]+) ?(\d+)$/)
121
- {:question_reference => match[1], :operator => match[2].gsub(/^=$/, "=="), :integer_value => match[3]}
122
- # uhoh
117
+ # [initial_52] = "1" or [f1_q15] = '' or [f1_q15] = '-2' or [hi_event1_type] <> ''
118
+ if match = str.match(/^\[(\w+)\] ?([!=><]+) ?['"](-?\w*)['"]$/)
119
+ {:question_reference => match[1], :operator => match[2].gsub(/^=$/, "==").gsub(/^<>$/, "!="), :answer_reference => match[3]}
120
+ # [initial_119(2)] = "1" or [hiprep_heat2(97)] = '1'
121
+ elsif match = str.match(/^\[(\w+)\((\w+)\)\] ?([!=><]+) ?['"]1['"]$/)
122
+ {:question_reference => match[1], :operator => match[3].gsub(/^=$/, "==").gsub(/^<>$/, "!="), :answer_reference => match[2]}
123
+ # [f1_q15] >= 21 or [f1_q15] >= -21
124
+ elsif match = str.match(/^\[(\w+)\] ?([!=><]+) ?(-?\d+)$/)
125
+ {:question_reference => match[1], :operator => match[2].gsub(/^=$/, "==").gsub(/^<>$/, "!="), :integer_value => match[3]}
123
126
  else
124
127
  puts "\n!!! skipping dependency_condition #{str}"
125
- end
128
+ end
126
129
  end
127
130
  def self.decompose_rule(str)
128
131
  # see spec/lib/redcap_parser_spec.rb for examples
@@ -181,9 +184,9 @@ class Answer < ActiveRecord::Base
181
184
  when "file"
182
185
  puts "\n!!! skipping answer: file"
183
186
  end
184
- r[:choices_or_calculations].to_s.split("|").each do |pair|
185
- aref, atext = pair.strip.split(", ")
186
- if aref.blank? or atext.blank?
187
+ (r[:choices_or_calculations] || r[:choices_calculations_or_slider_labels]).to_s.split("|").each do |pair|
188
+ aref, atext = pair.split(",").map(&:strip)
189
+ if aref.blank? or atext.blank? or (aref.to_i.to_s != aref)
187
190
  puts "\n!!! skipping answer #{pair}"
188
191
  else
189
192
  context[:answer] = context[:question].answers.build(:reference_identifier => aref, :text => atext)
@@ -75,8 +75,9 @@ module Surveyor
75
75
  end
76
76
  format.js do
77
77
  ids, remove, question_ids = {}, {}, []
78
- ResponseSet.reject_or_destroy_blanks(params[:r]).each do |k,v|
79
- ids[k] = @response_set.responses.find(:first, :conditions => v).id if !v.has_key?("id")
78
+ ResponseSet.trim_for_lookups(params[:r]).each do |k,v|
79
+ v[:answer_id].reject!(&:blank?) if v[:answer_id].is_a?(Array)
80
+ ids[k] = @response_set.responses.find(:first, :conditions => v, :order => "created_at DESC").id if !v.has_key?("id")
80
81
  remove[k] = v["id"] if v.has_key?("id") && v.has_key?("_destroy")
81
82
  question_ids << v["question_id"]
82
83
  end
@@ -111,7 +111,7 @@ class Answer < ActiveRecord::Base
111
111
  dsl << " " if question.part_of_group?
112
112
  dsl << " a"
113
113
  dsl << "_#{reference_identifier}" unless reference_identifier.blank?
114
- if response_class.to_s.titlecase == text && attrs == {:hide_label => true}
114
+ if response_class.to_s.titlecase == text && attrs == {:display_type => "hidden_label"}
115
115
  dsl << " :#{response_class}"
116
116
  else
117
117
  dsl << [ text.blank? ? nil : text == "Other" ? " :other" : text == "Omit" ? " :omit" : " \"#{text}\"",
data/spec/factories.rb CHANGED
@@ -71,7 +71,7 @@ Factory.define :answer do |a|
71
71
  a.common_identifier {}
72
72
  a.display_order {Factory.next :answer_display_order}
73
73
  a.is_exclusive {}
74
- a.hide_label {}
74
+ a.display_type "default"
75
75
  a.display_length {}
76
76
  a.custom_class {}
77
77
  a.custom_renderer {}
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Surveyor do
4
+ it "should write thousands of response sets" do
5
+ Surveyor::Parser.parse(File.read(File.join(Rails.root, 'surveys', 'kitchen_sink_survey.rb')))
6
+ survey = Survey.last
7
+ rs = ResponseSet.create(:survey => survey)
8
+ survey.sections.each{|s| s.questions.each{|q| rs.responses.create(:question => q, :answer => q.answers.first)}}
9
+ Benchmark.bm 20 do |x|
10
+ x.report "a test" do
11
+ full_path = File.join(Rails.root,"#{survey.access_code}_#{Time.now.to_i}.csv")
12
+ File.open(full_path, 'w') do |f|
13
+ 100.times do # adjust this to test
14
+ survey.response_sets.each_with_index{|r,i| f.write(r.to_csv(true, i == 0)) } # print access code every time, print_header first time
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+
@@ -4,6 +4,20 @@ describe Surveyor::RedcapParser do
4
4
  before(:each) do
5
5
  # @parser = Surveyor::Parser.new
6
6
  end
7
+ it "should require specific columns" do
8
+ # with standard fields
9
+ 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)
10
+ Surveyor::RedcapParser.new.missing_columns(x).should be_blank
11
+ # without field_units
12
+ 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)
13
+ Surveyor::RedcapParser.new.missing_columns(y).should be_blank
14
+ # choices_or_calculations => choices_calculations_or_slider_labels
15
+ 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)
16
+ Surveyor::RedcapParser.new.missing_columns(z).should be_blank
17
+ # text_validation_type => text_validation_type_or_show_slider_number
18
+ 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)
19
+ Surveyor::RedcapParser.new.missing_columns(a).should be_blank
20
+ end
7
21
  it "should decompose dependency rules" do
8
22
  # basic
9
23
  Dependency.decompose_rule('[f1_q12]="1"').should == {:rule => "A", :components => ['[f1_q12]="1"']}
@@ -44,6 +58,14 @@ describe Surveyor::RedcapParser do
44
58
  Dependency.decompose_component('[initial_52] = "1"').should == {:question_reference => 'initial_52', :operator => '==', :answer_reference => '1'}
45
59
  Dependency.decompose_component('[initial_119(2)] = "1"').should == {:question_reference => 'initial_119', :operator => '==', :answer_reference => '2'}
46
60
  Dependency.decompose_component('[f1_q15] >= 21').should == {:question_reference => 'f1_q15', :operator => '>=', :integer_value => '21'}
61
+ # basic, blanks
62
+ Dependency.decompose_component("[f1_q15]=''").should == {:question_reference => 'f1_q15', :operator => '==', :answer_reference => ''}
63
+ # basic, negatives
64
+ Dependency.decompose_component("[f1_q15]='-2'").should == {:question_reference => 'f1_q15', :operator => '==', :answer_reference => '-2'}
65
+ # internal parenthesis
66
+ Dependency.decompose_component("[hiprep_heat2(97)] = '1'").should == {:question_reference => 'hiprep_heat2', :operator => '==', :answer_reference => '97'}
67
+ Dependency.decompose_component("[hi_event1_type] <> ''").should == {:question_reference => 'hi_event1_type', :operator => '!=', :answer_reference => ''}
68
+
47
69
  end
48
70
  it "should return a survey object" do
49
71
  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",,,,,,,,)
@@ -22,9 +22,9 @@ describe Answer, "when creating a new answer" do
22
22
  @answer.css_class.should == "exclusive foo bar"
23
23
  end
24
24
 
25
- it "should hide the label when hide_label is set" do
25
+ it "should hide the label when display_type hidden_label is set" do
26
26
  @answer.split_or_hidden_text.should == "Red"
27
- @answer.hide_label = true
27
+ @answer.display_type = "hidden_label"
28
28
  @answer.split_or_hidden_text.should == ""
29
29
  end
30
30
  it "should split up pre/post labels" do
@@ -125,6 +125,26 @@ describe ResponseSet do
125
125
  "32" => {"question_id" => @qone.id, "answer_id" => "291", "string_value" => ""} # new radio with blank string value, selected
126
126
  }
127
127
  end
128
+ it "should clean up responses for lookups to get ids after saving via ajax" do
129
+ hash_of_hashes = {"1"=>{"question_id"=>"2", "answer_id"=>"1"},
130
+ "2"=>{"question_id"=>"3", "answer_id"=>["", "6"]},
131
+ "9"=>{"question_id"=>"6", "string_value"=>"jack", "answer_id"=>"13"},
132
+ "17"=>{"question_id"=>"13", "datetime_value(1i)"=>"2006", "datetime_value(2i)"=>"2", "datetime_value(3i)"=>"4", "datetime_value(4i)"=>"02", "datetime_value(5i)"=>"05", "answer_id"=>"21"},
133
+ "18"=>{"question_id"=>"14", "datetime_value(1i)"=>"1", "datetime_value(2i)"=>"1", "datetime_value(3i)"=>"1", "datetime_value(4i)"=>"01", "datetime_value(5i)"=>"02", "answer_id"=>"22"},
134
+ "19"=>{"question_id"=>"15", "datetime_value"=>"", "answer_id"=>"23", "id" => "1"},
135
+ "47"=>{"question_id"=>"38", "answer_id"=>"220", "integer_value"=>"2", "id" => "2"},
136
+ "61"=>{"question_id"=>"44", "response_group"=>"0", "answer_id"=>"241", "integer_value"=>"12"}}
137
+ ResponseSet.trim_for_lookups(hash_of_hashes).should ==
138
+ { "1"=>{"question_id"=>"2", "answer_id"=>"1"},
139
+ "2"=>{"question_id"=>"3", "answer_id"=>["", "6"]},
140
+ "9"=>{"question_id"=>"6", "answer_id"=>"13"},
141
+ "17"=>{"question_id"=>"13", "answer_id"=>"21"},
142
+ "18"=>{"question_id"=>"14", "answer_id"=>"22"},
143
+ "19"=>{"question_id"=>"15", "answer_id"=>"23", "id" => "1", "_destroy" => "true"},
144
+ "47"=>{"question_id"=>"38", "answer_id"=>"220", "id" => "2"},
145
+ "61"=>{"question_id"=>"44", "response_group"=>"0", "answer_id"=>"241"}
146
+ }
147
+ end
128
148
  it "should remove responses" do
129
149
  r = @response_set.responses.create(:question_id => 1, :answer_id => 2)
130
150
  r.id.should_not be nil
data/surveyor.gemspec CHANGED
@@ -5,17 +5,16 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{surveyor}
8
- s.version = "0.19.7"
8
+ s.version = "0.20.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brian Chamberlain", "Mark Yoon"]
12
- s.date = %q{2011-06-23}
12
+ s.date = %q{2011-07-11}
13
13
  s.email = %q{yoon@northwestern.edu}
14
14
  s.extra_rdoc_files = [
15
15
  "README.md"
16
16
  ]
17
17
  s.files = [
18
- ".rvmrc",
19
18
  "CHANGELOG",
20
19
  "MIT-LICENSE",
21
20
  "README.md",
@@ -61,7 +60,9 @@ Gem::Specification.new do |s|
61
60
  "features/support/REDCapDemoDatabase_DataDictionary.csv",
62
61
  "features/support/env.rb",
63
62
  "features/support/paths.rb",
63
+ "features/support/redcap_new_headers.csv",
64
64
  "features/support/redcap_siblings.csv",
65
+ "features/support/redcap_whitespace.csv",
65
66
  "features/surveyor.feature",
66
67
  "features/surveyor_parser.feature",
67
68
  "generators/extend_surveyor/extend_surveyor_generator.rb",
@@ -77,6 +78,7 @@ Gem::Specification.new do |s|
77
78
  "generators/surveyor/templates/assets/stylesheets/dateinput.css",
78
79
  "generators/surveyor/templates/assets/stylesheets/reset.css",
79
80
  "generators/surveyor/templates/assets/stylesheets/results.css",
81
+ "generators/surveyor/templates/assets/stylesheets/sass/custom.sass",
80
82
  "generators/surveyor/templates/assets/stylesheets/sass/surveyor.sass",
81
83
  "generators/surveyor/templates/locales/surveyor_en.yml",
82
84
  "generators/surveyor/templates/locales/surveyor_es.yml",
@@ -85,6 +87,7 @@ Gem::Specification.new do |s|
85
87
  "generators/surveyor/templates/migrate/add_correct_answer_id_to_questions.rb",
86
88
  "generators/surveyor/templates/migrate/add_default_value_to_answers.rb",
87
89
  "generators/surveyor/templates/migrate/add_display_order_to_surveys.rb",
90
+ "generators/surveyor/templates/migrate/add_display_type_to_answers.rb",
88
91
  "generators/surveyor/templates/migrate/add_index_to_response_sets.rb",
89
92
  "generators/surveyor/templates/migrate/add_index_to_surveys.rb",
90
93
  "generators/surveyor/templates/migrate/add_section_id_to_responses.rb",
@@ -129,6 +132,7 @@ Gem::Specification.new do |s|
129
132
  "spec/controllers/surveyor_controller_spec.rb",
130
133
  "spec/factories.rb",
131
134
  "spec/helpers/surveyor_helper_spec.rb",
135
+ "spec/lib/benchmark_spec.rb",
132
136
  "spec/lib/common_spec.rb",
133
137
  "spec/lib/parser_spec.rb",
134
138
  "spec/lib/redcap_parser_spec.rb",
@@ -151,6 +155,7 @@ Gem::Specification.new do |s|
151
155
  "testbed/Gemfile"
152
156
  ]
153
157
  s.homepage = %q{http://github.com/NUBIC/surveyor}
158
+ s.post_install_message = %q{Thanks for installing surveyor! The time has come to run the surveyor generator and migrate your database, even if you are upgrading.}
154
159
  s.require_paths = ["lib"]
155
160
  s.rubygems_version = %q{1.6.2}
156
161
  s.summary = %q{A rails (gem) plugin to enable surveys in your application}
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: surveyor
3
3
  version: !ruby/object:Gem::Version
4
- hash: 93
4
+ hash: 79
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 19
9
- - 7
10
- version: 0.19.7
8
+ - 20
9
+ - 0
10
+ version: 0.20.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brian Chamberlain
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-06-23 00:00:00 -05:00
19
+ date: 2011-07-11 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -112,7 +112,6 @@ extensions: []
112
112
  extra_rdoc_files:
113
113
  - README.md
114
114
  files:
115
- - .rvmrc
116
115
  - CHANGELOG
117
116
  - MIT-LICENSE
118
117
  - README.md
@@ -158,7 +157,9 @@ files:
158
157
  - features/support/REDCapDemoDatabase_DataDictionary.csv
159
158
  - features/support/env.rb
160
159
  - features/support/paths.rb
160
+ - features/support/redcap_new_headers.csv
161
161
  - features/support/redcap_siblings.csv
162
+ - features/support/redcap_whitespace.csv
162
163
  - features/surveyor.feature
163
164
  - features/surveyor_parser.feature
164
165
  - generators/extend_surveyor/extend_surveyor_generator.rb
@@ -174,6 +175,7 @@ files:
174
175
  - generators/surveyor/templates/assets/stylesheets/dateinput.css
175
176
  - generators/surveyor/templates/assets/stylesheets/reset.css
176
177
  - generators/surveyor/templates/assets/stylesheets/results.css
178
+ - generators/surveyor/templates/assets/stylesheets/sass/custom.sass
177
179
  - generators/surveyor/templates/assets/stylesheets/sass/surveyor.sass
178
180
  - generators/surveyor/templates/locales/surveyor_en.yml
179
181
  - generators/surveyor/templates/locales/surveyor_es.yml
@@ -182,6 +184,7 @@ files:
182
184
  - generators/surveyor/templates/migrate/add_correct_answer_id_to_questions.rb
183
185
  - generators/surveyor/templates/migrate/add_default_value_to_answers.rb
184
186
  - generators/surveyor/templates/migrate/add_display_order_to_surveys.rb
187
+ - generators/surveyor/templates/migrate/add_display_type_to_answers.rb
185
188
  - generators/surveyor/templates/migrate/add_index_to_response_sets.rb
186
189
  - generators/surveyor/templates/migrate/add_index_to_surveys.rb
187
190
  - generators/surveyor/templates/migrate/add_section_id_to_responses.rb
@@ -226,6 +229,7 @@ files:
226
229
  - spec/controllers/surveyor_controller_spec.rb
227
230
  - spec/factories.rb
228
231
  - spec/helpers/surveyor_helper_spec.rb
232
+ - spec/lib/benchmark_spec.rb
229
233
  - spec/lib/common_spec.rb
230
234
  - spec/lib/parser_spec.rb
231
235
  - spec/lib/redcap_parser_spec.rb
@@ -250,7 +254,7 @@ has_rdoc: true
250
254
  homepage: http://github.com/NUBIC/surveyor
251
255
  licenses: []
252
256
 
253
- post_install_message:
257
+ post_install_message: Thanks for installing surveyor! The time has come to run the surveyor generator and migrate your database, even if you are upgrading.
254
258
  rdoc_options: []
255
259
 
256
260
  require_paths:
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm_gemset_create_on_use_flag=1; rvm gemset use surveyor-dev