surveyor 0.19.7 → 0.20.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 (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