surveyor 0.19.6 → 0.19.7

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,14 @@
1
+ 0.19.7
2
+
3
+ * fix accidentally allowing through blank pick => any answers
4
+ * rewrote a test to reflect re-saving a survey via an admin controller
5
+ * stop survey titles from appending '1' to itself when calling update attributes
6
+ * fix response saving and dependencies on pick one/many with string. closes #158
7
+ * changed fastercsv to csv for ruby 1.9. closes #111
8
+ * changed .to_s to .join for ruby 1.9
9
+ * Merge pull request #137 from keviniano/master
10
+ * surveyor models
11
+
1
12
  0.19.6
2
13
 
3
14
  * fix parsing of group questions with dependencies. closes #160
data/README.md CHANGED
@@ -97,11 +97,12 @@ and read surveys/EXTENDING\_SURVEYOR
97
97
 
98
98
  Surveyor depends on:
99
99
 
100
- * Ruby (1.8.7 - 1.9.1)
100
+ * Ruby (1.8.7 - 1.9.2)
101
101
  * Rails 2.3
102
- * HAML/SASS
102
+ * HAML
103
+ * SASS
104
+ * fastercsv (or CSV for ruby 1.9) for csv exports
103
105
  * formtastic
104
- * fastercsv for csv exports
105
106
  * UUID
106
107
 
107
108
  To work on the code fork this github project. Run:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.19.6
1
+ 0.19.7
@@ -1,7 +1,7 @@
1
1
  -# TODO: js for slider
2
2
  - rg ||= nil
3
3
  - renderer = q.renderer(g ||= nil)
4
- - f.inputs q_text(q), :id => rg ? "q_#{q.id}_#{rg.id}" : "q_#{q.id}", :class => "q_#{renderer} #{q.css_class(@response_set)}" do
4
+ - f.inputs q_text(q), :id => rg ? "q_#{q.id}_#{rg}" : "q_#{q.id}", :class => "q_#{renderer} #{q.css_class(@response_set)}" do
5
5
  %span.help= q.help_text
6
6
  - case renderer
7
7
  - when :image, :label
Binary file
Binary file
@@ -1,14 +1,14 @@
1
1
  module Surveyor
2
2
  class Common
3
- RAND_CHARS = [('a'..'z'), ('A'..'Z'), (0..9)].map{|r| r.to_a}.flatten.to_s
3
+ RAND_CHARS = [('a'..'z'), ('A'..'Z'), (0..9)].map{|r| r.to_a}.flatten.join
4
4
  OPERATORS = %w(== != < > <= >= =~)
5
5
 
6
6
  class << self
7
7
  def make_tiny_code(len = 10)
8
8
  if RUBY_VERSION < "1.8.7"
9
- (1..len).to_a.map{|i| RAND_CHARS[rand(RAND_CHARS.size), 1] }.to_s
9
+ (1..len).to_a.map{|i| RAND_CHARS[rand(RAND_CHARS.size), 1] }.join
10
10
  else
11
- len.times.map{|i| RAND_CHARS[rand(RAND_CHARS.size), 1] }.to_s
11
+ len.times.map{|i| RAND_CHARS[rand(RAND_CHARS.size), 1] }.join
12
12
  end
13
13
  end
14
14
 
@@ -48,6 +48,7 @@ module Surveyor
48
48
  end
49
49
  end || responses.first
50
50
  klass = response.answer.response_class
51
+ klass = "answer" if self.as(klass).nil?
51
52
  return case self.operator
52
53
  when "==", "<", ">", "<=", ">="
53
54
  response.as(klass).send(self.operator, self.as(klass))
@@ -1,3 +1,5 @@
1
+ require 'fastercsv'
2
+ require 'csv'
1
3
  module Surveyor
2
4
  module Models
3
5
  module ResponseSetMethods
@@ -36,7 +38,9 @@ module Surveyor
36
38
  result
37
39
  end
38
40
  def has_blank_value?(hash)
39
- hash["answer_id"].blank? or hash.any?{|k,v| v.is_a?(Array) ? v.all?{|x| x.to_s.blank?} : v.to_s.blank?}
41
+ return true if hash["answer_id"].blank?
42
+ return false if (q = Question.find_by_id(hash["question_id"])) and q.pick == "one"
43
+ hash.any?{|k,v| v.is_a?(Array) ? v.all?{|x| x.to_s.blank?} : v.to_s.blank?}
40
44
  end
41
45
  end
42
46
  end
@@ -63,8 +67,8 @@ module Surveyor
63
67
  qcols = Question.content_columns.map(&:name) - %w(created_at updated_at)
64
68
  acols = Answer.content_columns.map(&:name) - %w(created_at updated_at)
65
69
  rcols = Response.content_columns.map(&:name)
66
- require 'fastercsv'
67
- FCSV(result = "") do |csv|
70
+ csvlib = CSV.const_defined?(:Reader) ? FasterCSV : CSV
71
+ result = csvlib.generate do |csv|
68
72
  csv << (access_code ? ["response set access code"] : []) + qcols.map{|qcol| "question.#{qcol}"} + acols.map{|acol| "answer.#{acol}"} + rcols.map{|rcol| "response.#{rcol}"} if print_header
69
73
  responses.each do |response|
70
74
  csv << (access_code ? [self.access_code] : []) + qcols.map{|qcol| response.question.send(qcol)} + acols.map{|acol| response.answer.send(acol)} + rcols.map{|rcol| response.send(rcol)}
@@ -42,6 +42,7 @@ module Surveyor
42
42
  end
43
43
 
44
44
  def title=(value)
45
+ return if value == self.title
45
46
  adjusted_value = value
46
47
  while Survey.find_by_access_code(Survey.to_normalized_string(adjusted_value))
47
48
  i ||= 0
@@ -49,7 +50,7 @@ module Surveyor
49
50
  adjusted_value = "#{value} #{i.to_s}"
50
51
  end
51
52
  self.access_code = Survey.to_normalized_string(adjusted_value)
52
- super(adjusted_value)
53
+ super(adjusted_value)
53
54
  # self.access_code = Survey.to_normalized_string(value)
54
55
  # super
55
56
  end
@@ -76,4 +77,4 @@ module Surveyor
76
77
  end
77
78
  end
78
79
  end
79
- end
80
+ end
@@ -1,6 +1,7 @@
1
1
  %w(survey survey_section question_group question dependency dependency_condition answer validation validation_condition).each {|model| require model }
2
- require 'fastercsv'
3
2
  require 'active_support' # for humanize
3
+ require 'fastercsv'
4
+ require 'csv'
4
5
  module Surveyor
5
6
  class RedcapParser
6
7
  # Attributes
@@ -19,8 +20,9 @@ module Surveyor
19
20
  self.context = {}
20
21
  end
21
22
  def parse(str, filename)
23
+ csvlib = CSV.const_defined?(:Reader) ? FasterCSV : CSV
22
24
  begin
23
- FasterCSV.parse(str, :headers => :first_row, :return_headers => true, :header_converters => :symbol) do |r|
25
+ csvlib.parse(str, :headers => :first_row, :return_headers => true, :header_converters => :symbol) do |r|
24
26
  if r.header_row? # header row
25
27
  return puts "Missing headers: #{missing_columns(r).inspect}\n\n" unless missing_columns(r).blank?
26
28
  context[:survey] = Survey.new(:title => filename)
@@ -35,7 +37,7 @@ module Surveyor
35
37
  end
36
38
  print context[:survey].save ? "saved. " : " not saved! #{context[:survey].errors.each_full{|x| x }.join(", ")} "
37
39
  # print context[:survey].sections.map(&:questions).flatten.map(&:answers).flatten.map{|x| x.errors.each_full{|y| y}.join}.join
38
- rescue FasterCSV::MalformedCSVError
40
+ rescue csvlib::MalformedCSVError
39
41
  puts = "Oops. Not a valid CSV file."
40
42
  # ensure
41
43
  end
@@ -339,7 +339,28 @@ describe DependencyCondition do
339
339
  @dep_c.is_met?([@response]).should be_true
340
340
  end
341
341
  end
342
-
342
+
343
+ describe "when evaluating a pick one/many with response_class e.g. string" do
344
+ it "should compare answer ids when the string_value is nil" do
345
+ a = Factory(:answer, :response_class => "string")
346
+ dc = Factory(:dependency_condition, :question_id => a.question.id, :answer_id => a.id, :operator => "==")
347
+ r = Factory(:response, :question_id => a.question.id, :answer_id => a.id, :string_value => "")
348
+ r.should_receive(:as).with("answer").and_return(a.id)
349
+ dc.is_met?([r]).should be_true
350
+ end
351
+ it "should compare strings when the string_value is not nil, even if it is blank" do
352
+ a = Factory(:answer, :response_class => "string")
353
+ dc = Factory(:dependency_condition, :question_id => a.question.id, :answer_id => a.id, :operator => "==", :string_value => "foo")
354
+ r = Factory(:response, :question_id => a.question.id, :answer_id => a.id, :string_value => "foo")
355
+ r.should_receive(:as).with("string").and_return("foo")
356
+ dc.is_met?([r]).should be_true
357
+
358
+ dc2 = Factory(:dependency_condition, :question_id => a.question.id, :answer_id => a.id, :operator => "==", :string_value => "")
359
+ r2 = Factory(:response, :question_id => a.question.id, :answer_id => a.id, :string_value => "")
360
+ r2.should_receive(:as).with("string").and_return("")
361
+ dc2.is_met?([r2]).should be_true
362
+ end
363
+ end
343
364
  describe "when given responses whether the dependency is satisfied using 'count'" do
344
365
  before(:each) do
345
366
  @dep_c = DependencyCondition.new(:answer_id => nil,
@@ -90,7 +90,7 @@ describe ResponseSet do
90
90
  "28" => {"question_id" => "16", "answer_id" => "", "string_value" => "foo"}, # new radio with string value, blank
91
91
  "29" => {"question_id" => "17", "answer_id" => "261", "string_value" => "bar"}, # new radio with string value, selected
92
92
  "30" => {"id" => "110", "question_id" => "18", "answer_id" => "271", "string_value" => "moo"}, # existing radio with string value, changed
93
- "31" => {"id" => "111", "question_id" => "19", "answer_id" => "281", "string_value" => "mar"}, # existing radio with string value, unchanged
93
+ "31" => {"id" => "111", "question_id" => "19", "answer_id" => "281", "string_value" => "mar"} # existing radio with string value, unchanged
94
94
  }
95
95
  ResponseSet.reject_or_destroy_blanks(hash_of_hashes).should == {
96
96
  # "11" => {"question_id" => "1", "answer_id" => [""]}, # new checkbox, blank
@@ -113,7 +113,16 @@ describe ResponseSet do
113
113
  # "28" => {"question_id" => "16", "answer_id" => "", "string_value" => "foo"}, # new radio with string value, blank
114
114
  "29" => {"question_id" => "17", "answer_id" => "261", "string_value" => "bar"}, # new radio with string value, selected
115
115
  "30" => {"id" => "110", "question_id" => "18", "answer_id" => "271", "string_value" => "moo"}, # existing radio with string value, changed
116
- "31" => {"id" => "111", "question_id" => "19", "answer_id" => "281", "string_value" => "mar"}, # existing radio with string value, unchanged
116
+ "31" => {"id" => "111", "question_id" => "19", "answer_id" => "281", "string_value" => "mar"} # existing radio with string value, unchanged
117
+ }
118
+ end
119
+ it "should clean up radio and string responses_attributes before passing to nested_attributes" do
120
+ @qone = Factory(:question, :pick => "one")
121
+ hash_of_hashes = {
122
+ "32" => {"question_id" => @qone.id, "answer_id" => "291", "string_value" => ""} # new radio with blank string value, selected
123
+ }
124
+ ResponseSet.reject_or_destroy_blanks(hash_of_hashes).should == {
125
+ "32" => {"question_id" => @qone.id, "answer_id" => "291", "string_value" => ""} # new radio with blank string value, selected
117
126
  }
118
127
  end
119
128
  it "should remove responses" do
@@ -5,12 +5,12 @@ describe Survey, "when saving a new one" do
5
5
  before(:each) do
6
6
  @survey = Factory(:survey, :title => "Foo")
7
7
  end
8
-
8
+
9
9
  it "should be invalid without a title" do
10
10
  @survey.title = nil
11
11
  @survey.should have(1).error_on(:title)
12
12
  end
13
-
13
+
14
14
  it "should adjust the title to save unique titles" do
15
15
  original = Survey.new(:title => "Foo")
16
16
  original.save.should be_true
@@ -21,7 +21,14 @@ describe Survey, "when saving a new one" do
21
21
  bandwagoneer.save.should be_true
22
22
  bandwagoneer.title.should == "Foo 2"
23
23
  end
24
-
24
+
25
+ it "should not adjust the title when updating itself" do
26
+ original = Factory(:survey, :title => "Foo")
27
+ original.save.should be_true
28
+ original.update_attributes(:title => "Foo")
29
+ original.title.should == "Foo"
30
+ end
31
+
25
32
  it "should have an api_id" do
26
33
  @survey.api_id.length.should == 36
27
34
  end
@@ -44,7 +51,7 @@ describe Survey, "that has sections" do
44
51
  @survey.sections.should have(3).sections
45
52
  @survey.sections.should == [@s3, @s1, @s2]
46
53
  end
47
-
54
+
48
55
  it "should return survey_sections_with_questions in display order" do
49
56
  @survey.sections_with_questions.map(&:questions).flatten.should have(4).questions
50
57
  @survey.sections_with_questions.map(&:questions).flatten.should == [@q4,@q1,@q3,@q2]
@@ -72,19 +79,19 @@ describe Survey do
72
79
  @survey.active?.should be_true
73
80
  @survey.inactive_at.should be_nil
74
81
  end
75
-
82
+
76
83
  it "should be able to deactivate as of a certain date/time" do
77
84
  @survey.active_at = 2.days.ago
78
85
  @survey.inactive_at = 3.days.ago
79
86
  @survey.active?.should be_false
80
87
  @survey.active_at.should be_nil
81
88
  end
82
-
89
+
83
90
  it "should activate and deactivate" do
84
91
  @survey.activate!
85
92
  @survey.active?.should be_true
86
93
  @survey.deactivate!
87
94
  @survey.active?.should be_false
88
95
  end
89
-
90
- end
96
+
97
+ end
data/surveyor.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{surveyor}
8
- s.version = "0.19.6"
8
+ s.version = "0.19.7"
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-08}
12
+ s.date = %q{2011-06-23}
13
13
  s.email = %q{yoon@northwestern.edu}
14
14
  s.extra_rdoc_files = [
15
15
  "README.md"
@@ -52,6 +52,8 @@ Gem::Specification.new do |s|
52
52
  "app/views/surveyor/show.html.haml",
53
53
  "ci-env.sh",
54
54
  "config/routes.rb",
55
+ "doc/surveyor_models.png",
56
+ "doc/surveyor_models2.png",
55
57
  "features/redcap_parser.feature",
56
58
  "features/step_definitions/parser_steps.rb",
57
59
  "features/step_definitions/surveyor_steps.rb",
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: 95
4
+ hash: 93
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 19
9
- - 6
10
- version: 0.19.6
9
+ - 7
10
+ version: 0.19.7
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-08 00:00:00 -05:00
19
+ date: 2011-06-23 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -149,6 +149,8 @@ files:
149
149
  - app/views/surveyor/show.html.haml
150
150
  - ci-env.sh
151
151
  - config/routes.rb
152
+ - doc/surveyor_models.png
153
+ - doc/surveyor_models2.png
152
154
  - features/redcap_parser.feature
153
155
  - features/step_definitions/parser_steps.rb
154
156
  - features/step_definitions/surveyor_steps.rb