surveyor 0.14.5 → 0.15.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.
- data/README.md +12 -4
- data/VERSION +1 -1
- data/features/step_definitions/surveyor_steps.rb +64 -4
- data/features/surveyor.feature +144 -11
- data/lib/surveyor.rb +0 -4
- data/lib/surveyor/acts_as_response.rb +13 -29
- data/lib/surveyor/common.rb +2 -2
- data/lib/surveyor/models/answer_methods.rb +14 -1
- data/lib/surveyor/models/dependency_condition_methods.rb +4 -3
- data/lib/surveyor/models/question_methods.rb +11 -1
- data/lib/surveyor/models/response_methods.rb +2 -1
- data/lib/surveyor/models/survey_methods.rb +10 -2
- data/lib/surveyor/models/survey_section_methods.rb +11 -1
- data/lib/surveyor/models/validation_condition_methods.rb +3 -2
- data/lib/surveyor/models/validation_methods.rb +2 -2
- data/lib/surveyor/parser.rb +274 -0
- data/lib/tasks/surveyor_tasks.rake +25 -25
- data/spec/factories.rb +1 -1
- data/spec/lib/common_spec.rb +22 -0
- data/spec/lib/parser_spec.rb +30 -0
- data/spec/models/answer_spec.rb +6 -5
- data/spec/models/dependency_condition_spec.rb +7 -6
- data/spec/models/question_spec.rb +12 -10
- data/spec/models/survey_section_spec.rb +3 -2
- data/spec/models/survey_spec.rb +11 -0
- data/spec/models/validation_condition_spec.rb +5 -5
- data/spec/models/validation_spec.rb +5 -4
- data/surveyor.gemspec +7 -23
- metadata +10 -26
- data/lib/fixtures_extensions.rb +0 -6
- data/script/surveyor/answer.rb +0 -54
- data/script/surveyor/base.rb +0 -75
- data/script/surveyor/dependency.rb +0 -13
- data/script/surveyor/dependency_condition.rb +0 -40
- data/script/surveyor/parser.rb +0 -223
- data/script/surveyor/question.rb +0 -59
- data/script/surveyor/question_group.rb +0 -26
- data/script/surveyor/specs/answer_spec.rb +0 -29
- data/script/surveyor/specs/question_spec.rb +0 -63
- data/script/surveyor/specs/spec_helper.rb +0 -7
- data/script/surveyor/specs/survey_section_spec.rb +0 -23
- data/script/surveyor/specs/validation_condition_spec.rb +0 -20
- data/script/surveyor/specs/validation_spec.rb +0 -20
- data/script/surveyor/survey.rb +0 -34
- data/script/surveyor/survey_section.rb +0 -21
- data/script/surveyor/validation.rb +0 -21
- data/script/surveyor/validation_condition.rb +0 -21
- data/script/surveyor/whr_dsl.tmproj +0 -244
- data/spec/lib/surveyor_spec.rb +0 -44
data/README.md
CHANGED
@@ -84,10 +84,6 @@ Try out the "kitchen sink" survey:
|
|
84
84
|
|
85
85
|
rake surveyor FILE=surveys/kitchen_sink_survey.rb
|
86
86
|
|
87
|
-
The rake surveyor task overwrites previous surveys by default, but can append instead:
|
88
|
-
|
89
|
-
rake surveyor FILE=surveys/kitchen_sink_survey.rb APPEND=true
|
90
|
-
|
91
87
|
The rake tasks above generate surveys in our custom survey DSL (which is a great format for end users and stakeholders to use).
|
92
88
|
After you have run them start up your app and go to:
|
93
89
|
|
@@ -114,6 +110,18 @@ To work on the plugin code (for enhancements, and bug fixes, etc...) fork this g
|
|
114
110
|
|
115
111
|
# Changes
|
116
112
|
|
113
|
+
0.15.0
|
114
|
+
|
115
|
+
* prevent duplicate survey titles by appending incrementing numbers
|
116
|
+
* rake task to remove a survey. closes #64
|
117
|
+
* cleanup of old parsing strategy
|
118
|
+
* features and specs and new parser. closes #62
|
119
|
+
* first test driven work on parser
|
120
|
+
* moving parser and common specs so they run automatically. fixing some spec errors
|
121
|
+
* first shot a surveyor parser. some parts untested, but coded to determine style. references #62
|
122
|
+
* refactoring counters
|
123
|
+
* fixing failing specs. fixes acts\_as\_response issues
|
124
|
+
|
117
125
|
0.14.5
|
118
126
|
|
119
127
|
* use modules to include model methods. re-closes #77
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.15.0
|
@@ -1,7 +1,67 @@
|
|
1
|
-
Given /^I
|
2
|
-
|
1
|
+
Given /^I parse$/ do |string|
|
2
|
+
Surveyor::Parser.parse(string)
|
3
3
|
end
|
4
4
|
|
5
|
-
Then /^
|
6
|
-
|
5
|
+
Then /^there should be (\d+) survey(?:s?) with:$/ do |x, table|
|
6
|
+
Survey.count.should == x.to_i
|
7
|
+
table.hashes.each do |hash|
|
8
|
+
Survey.find(:first, :conditions => hash).should_not be_nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Then /^there should be (\d+) question groups with:$/ do |x, table|
|
13
|
+
QuestionGroup.count.should == x.to_i
|
14
|
+
table.hashes.each do |hash|
|
15
|
+
QuestionGroup.find(:first, :conditions => hash).should_not be_nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^there should be (\d+) question(?:s?) with:$/ do |x, table|
|
20
|
+
Question.count.should == x.to_i
|
21
|
+
table.hashes.each do |hash|
|
22
|
+
hash["reference_identifier"] = nil if hash["reference_identifier"] == "nil"
|
23
|
+
hash["custom_class"] = nil if hash["custom_class"] == "nil"
|
24
|
+
Question.find(:first, :conditions => hash).should_not be_nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^there should be (\d+) answer(?:s?) with:$/ do |x, table|
|
29
|
+
Answer.count.should == x.to_i
|
30
|
+
table.hashes.each do |hash|
|
31
|
+
hash["reference_identifier"] = nil if hash["reference_identifier"] == "nil"
|
32
|
+
Answer.find(:first, :conditions => hash).should_not be_nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Then /^there should be (\d+) dependency with:$/ do |x, table|
|
37
|
+
Dependency.count.should == x.to_i
|
38
|
+
table.hashes.each do |hash|
|
39
|
+
Dependency.find(:first, :conditions => hash).should_not be_nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Then /^there should be (\d+) resolved dependency_condition(?:s?) with:$/ do |x, table|
|
44
|
+
DependencyCondition.count.should == x.to_i
|
45
|
+
table.hashes.each do |hash|
|
46
|
+
d = DependencyCondition.find(:first, :conditions => hash)
|
47
|
+
d.should_not be_nil
|
48
|
+
d.question.should_not be_nil
|
49
|
+
d.answer.should_not be_nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
Then /^there should be (\d+) validation(?:s?) with:$/ do |x, table|
|
55
|
+
Validation.count.should == x.to_i
|
56
|
+
table.hashes.each do |hash|
|
57
|
+
Validation.find(:first, :conditions => hash).should_not be_nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Then /^there should be (\d+) validation_condition(?:s?) with:$/ do |x, table|
|
62
|
+
ValidationCondition.count.should == x.to_i
|
63
|
+
table.hashes.each do |hash|
|
64
|
+
hash["integer_value"] = nil if hash["integer_value"] == "nil"
|
65
|
+
ValidationCondition.find(:first, :conditions => hash).should_not be_nil
|
66
|
+
end
|
7
67
|
end
|
data/features/surveyor.feature
CHANGED
@@ -1,11 +1,144 @@
|
|
1
|
-
Feature:
|
2
|
-
As
|
3
|
-
I want to
|
4
|
-
So that I can
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
Feature: Survey creation
|
2
|
+
As a
|
3
|
+
I want to write out the survey in the DSL
|
4
|
+
So that I can give it to survey participants
|
5
|
+
|
6
|
+
Scenario: Basic questions
|
7
|
+
Given I parse
|
8
|
+
"""
|
9
|
+
survey "Simple survey" do
|
10
|
+
section "Basic questions" do
|
11
|
+
label "These questions are examples of the basic supported input types"
|
12
|
+
|
13
|
+
question_1 "What is your favorite color?", :pick => :one
|
14
|
+
answer "red"
|
15
|
+
answer "blue"
|
16
|
+
answer "green"
|
17
|
+
answer :other
|
18
|
+
|
19
|
+
q_2b "Choose the colors you don't like", :pick => :any
|
20
|
+
a_1 "orange"
|
21
|
+
a_2 "purple"
|
22
|
+
a_3 "brown"
|
23
|
+
a :omit
|
24
|
+
end
|
25
|
+
end
|
26
|
+
"""
|
27
|
+
Then there should be 1 survey with:
|
28
|
+
| title |
|
29
|
+
| Simple survey |
|
30
|
+
And there should be 3 questions with:
|
31
|
+
| reference_identifier | text | pick | display_type |
|
32
|
+
| nil | These questions are examples of the basic supported input types | none | label |
|
33
|
+
| 1 | What is your favorite color? | one | default |
|
34
|
+
| 2b | Choose the colors you don't like | any | default |
|
35
|
+
And there should be 8 answers with:
|
36
|
+
| reference_identifier | text | response_class |
|
37
|
+
| nil | red | answer |
|
38
|
+
| nil | blue | answer |
|
39
|
+
| nil | green | answer |
|
40
|
+
| nil | Other | answer |
|
41
|
+
| 1 | orange | answer |
|
42
|
+
| 2 | purple | answer |
|
43
|
+
| 3 | brown | answer |
|
44
|
+
| nil | Omit | answer |
|
45
|
+
|
46
|
+
Scenario: More complex questions
|
47
|
+
Given I parse
|
48
|
+
"""
|
49
|
+
survey "Complex survey" do
|
50
|
+
section "Complicated questions" do
|
51
|
+
grid "Tell us how you feel today" do
|
52
|
+
a "-2"
|
53
|
+
a "-1"
|
54
|
+
a "0"
|
55
|
+
a "1"
|
56
|
+
a "2"
|
57
|
+
q "down|up" , :pick => :one
|
58
|
+
q "sad|happy", :pick => :one
|
59
|
+
q "limp|perky", :pick => :one
|
60
|
+
end
|
61
|
+
|
62
|
+
q "Choose your favorite utensils and enter frequency of use (daily, weekly, monthly, etc...)", :pick => :any
|
63
|
+
a "spoon", :string
|
64
|
+
a "fork", :string
|
65
|
+
a "knife", :string
|
66
|
+
a :other, :string
|
67
|
+
|
68
|
+
repeater "Tell us about the cars you own" do
|
69
|
+
q "Make", :pick => :one, :display_type => :dropdown
|
70
|
+
a "Toyota"
|
71
|
+
a "Ford"
|
72
|
+
a "GMChevy"
|
73
|
+
a "Ferrari"
|
74
|
+
a "Tesla"
|
75
|
+
a "Honda"
|
76
|
+
a "Other weak brand"
|
77
|
+
q "Model"
|
78
|
+
a :string
|
79
|
+
q "Year"
|
80
|
+
a :string
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
"""
|
85
|
+
Then there should be 1 survey with:
|
86
|
+
| title |
|
87
|
+
| Complex survey |
|
88
|
+
And there should be 2 question groups with:
|
89
|
+
| text | display_type |
|
90
|
+
| Tell us how you feel today | grid |
|
91
|
+
| Tell us about the cars you own | repeater |
|
92
|
+
And there should be 7 questions with:
|
93
|
+
| text | pick | display_type |
|
94
|
+
| Make | one | dropdown |
|
95
|
+
And there should be 28 answers with:
|
96
|
+
| text | response_class |
|
97
|
+
| -2 | answer |
|
98
|
+
| Other | string |
|
99
|
+
|
100
|
+
Scenario: Dependencies and validations
|
101
|
+
Given I parse
|
102
|
+
"""
|
103
|
+
survey "Dependency and validation survey" do
|
104
|
+
section "Conditionals" do
|
105
|
+
q_montypython3 "What... is your name? (e.g. It is 'Arthur', King of the Britons)"
|
106
|
+
a_1 :string
|
107
|
+
|
108
|
+
q_montypython4 "What... is your quest? (e.g. To seek the Holy Grail)"
|
109
|
+
a_1 :string
|
110
|
+
dependency :rule => "A"
|
111
|
+
condition_A :q_montypython3, "==", {:string_value => "It is 'Arthur', King of the Britons", :answer_reference => "1"}
|
112
|
+
|
113
|
+
q "How many pets do you own?"
|
114
|
+
a :integer
|
115
|
+
validation :rule => "A"
|
116
|
+
condition_A ">=", :integer_value => 0
|
117
|
+
|
118
|
+
q "What is your address?", :custom_class => 'address'
|
119
|
+
a :text, :custom_class => 'mapper'
|
120
|
+
validation :rule => "AC"
|
121
|
+
vcondition_AC "=~", :regexp => /[0-9a-zA-z\. #]/
|
122
|
+
end
|
123
|
+
end
|
124
|
+
"""
|
125
|
+
Then there should be 1 survey with:
|
126
|
+
| title |
|
127
|
+
| Dependency and validation survey |
|
128
|
+
And there should be 4 questions with:
|
129
|
+
| text | pick | display_type | custom_class |
|
130
|
+
| What... is your name? (e.g. It is 'Arthur', King of the Britons) | none | default | nil |
|
131
|
+
| What is your address? | none | default | address |
|
132
|
+
And there should be 1 dependency with:
|
133
|
+
| rule |
|
134
|
+
| A |
|
135
|
+
And there should be 1 resolved dependency_condition with:
|
136
|
+
| rule_key |
|
137
|
+
| A |
|
138
|
+
And there should be 2 validations with:
|
139
|
+
| rule |
|
140
|
+
| A |
|
141
|
+
| AC |
|
142
|
+
And there should be 2 validation_conditions with:
|
143
|
+
| rule_key | integer_value |
|
144
|
+
| A | 0 |
|
data/lib/surveyor.rb
CHANGED
@@ -1,33 +1,17 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
1
|
module Surveyor
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# Returns the response as a particular response_class type
|
17
|
-
def as(type_symbol)
|
18
|
-
return case type_symbol.to_sym
|
19
|
-
when :string, :text, :integer, :float, :datetime
|
20
|
-
self.send("#{type_symbol}_value".to_sym)
|
21
|
-
when :date
|
22
|
-
self.datetime_value.nil? ? nil : self.datetime_value.to_date
|
23
|
-
when :time
|
24
|
-
self.datetime_value.nil? ? nil : self.datetime_value.to_time
|
25
|
-
else # :answer_id
|
26
|
-
self.answer_id
|
27
|
-
end
|
2
|
+
module ActsAsResponse
|
3
|
+
# Returns the response as a particular response_class type
|
4
|
+
def as(type_symbol)
|
5
|
+
return case type_symbol.to_sym
|
6
|
+
when :string, :text, :integer, :float, :datetime
|
7
|
+
self.send("#{type_symbol}_value".to_sym)
|
8
|
+
when :date
|
9
|
+
self.datetime_value.nil? ? nil : self.datetime_value.to_date
|
10
|
+
when :time
|
11
|
+
self.datetime_value.nil? ? nil : self.datetime_value.to_time
|
12
|
+
else # :answer_id
|
13
|
+
self.answer_id
|
28
14
|
end
|
29
15
|
end
|
30
16
|
end
|
31
|
-
end
|
32
|
-
|
33
|
-
ActiveRecord::Base.send(:include, Surveyor::Response)
|
17
|
+
end
|
data/lib/surveyor/common.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Surveyor
|
2
2
|
class Common
|
3
3
|
RAND_CHARS = [('a'..'z'), ('A'..'Z'), (0..9)].map{|r| r.to_a}.flatten.to_s
|
4
|
-
OPERATORS = %w(== != < > <= >=)
|
4
|
+
OPERATORS = %w(== != < > <= >= =~)
|
5
5
|
|
6
6
|
class << self
|
7
7
|
def make_tiny_code(len = 10)
|
@@ -14,7 +14,7 @@ module Surveyor
|
|
14
14
|
|
15
15
|
def to_normalized_string(text)
|
16
16
|
words_to_omit = %w(a be but has have in is it of on or the to when)
|
17
|
-
col_text = text.gsub(/(<[^>]*>)|\n|\t/s, ' ') # Remove html tags
|
17
|
+
col_text = text.to_s.gsub(/(<[^>]*>)|\n|\t/s, ' ') # Remove html tags
|
18
18
|
col_text.downcase! # Remove capitalization
|
19
19
|
col_text.gsub!(/\"|\'/, '') # Remove potential problem characters
|
20
20
|
col_text.gsub!(/\(.*?\)/,'') # Remove text inside parens
|
@@ -12,10 +12,23 @@ module Surveyor
|
|
12
12
|
|
13
13
|
# Validations
|
14
14
|
base.send :validates_presence_of, :text
|
15
|
-
|
15
|
+
# this causes issues with building and saving
|
16
|
+
# base.send :validates_numericality_of, :question_id, :allow_nil => false, :only_integer => true
|
16
17
|
end
|
17
18
|
|
18
19
|
# Instance Methods
|
20
|
+
def initialize(*args)
|
21
|
+
super(*args)
|
22
|
+
default_args
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_args
|
26
|
+
self.display_order ||= self.question ? self.question.answers.count : 0
|
27
|
+
# self.is_exclusive ||= false
|
28
|
+
# self.hide_label ||= false
|
29
|
+
# self.response_class ||= "answer"
|
30
|
+
end
|
31
|
+
|
19
32
|
def renderer(q = question)
|
20
33
|
r = [q.pick.to_s, self.response_class].compact.map(&:downcase).join("_")
|
21
34
|
r.blank? ? :default : r.to_sym
|
@@ -9,12 +9,13 @@ module Surveyor
|
|
9
9
|
base.send :belongs_to, :question
|
10
10
|
|
11
11
|
# Validations
|
12
|
-
base.send :validates_numericality_of, :dependency_id, :question_id, :answer_id
|
13
12
|
base.send :validates_presence_of, :operator, :rule_key
|
14
13
|
base.send :validates_inclusion_of, :operator, :in => Surveyor::Common::OPERATORS
|
15
14
|
base.send :validates_uniqueness_of, :rule_key, :scope => :dependency_id
|
16
|
-
|
17
|
-
base.send :
|
15
|
+
# this causes issues with building and saving
|
16
|
+
# base.send :validates_numericality_of, :question_id, :answer_id, :dependency_id
|
17
|
+
|
18
|
+
base.send :include, Surveyor::ActsAsResponse # includes "as" instance method
|
18
19
|
|
19
20
|
# Class methods
|
20
21
|
base.instance_eval do
|
@@ -12,7 +12,9 @@ module Surveyor
|
|
12
12
|
base.send :default_scope, :order => "display_order ASC"
|
13
13
|
|
14
14
|
# Validations
|
15
|
-
base.send :validates_presence_of, :text, :
|
15
|
+
base.send :validates_presence_of, :text, :display_order
|
16
|
+
# this causes issues with building and saving
|
17
|
+
#, :survey_section_id
|
16
18
|
base.send :validates_inclusion_of, :is_mandatory, :in => [true, false]
|
17
19
|
end
|
18
20
|
|
@@ -26,6 +28,14 @@ module Surveyor
|
|
26
28
|
self.is_mandatory ||= true
|
27
29
|
self.display_type ||= "default"
|
28
30
|
self.pick ||= "none"
|
31
|
+
self.display_order ||= self.survey_section ? self.survey_section.questions.count : 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def pick=(val)
|
35
|
+
write_attribute(:pick, val.nil? ? nil : val.to_s)
|
36
|
+
end
|
37
|
+
def display_type=(val)
|
38
|
+
write_attribute(:display_type, val.nil? ? nil : val.to_s)
|
29
39
|
end
|
30
40
|
|
31
41
|
def mandatory?
|
@@ -10,7 +10,8 @@ module Surveyor
|
|
10
10
|
# Validations
|
11
11
|
base.send :validates_presence_of, :response_set_id, :question_id, :answer_id
|
12
12
|
|
13
|
-
base.send :
|
13
|
+
base.send :include, Surveyor::ActsAsResponse # includes "as" instance method
|
14
|
+
|
14
15
|
end
|
15
16
|
|
16
17
|
# Instance Methods
|
@@ -34,8 +34,16 @@ module Surveyor
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def title=(value)
|
37
|
-
|
38
|
-
|
37
|
+
adjusted_value = value
|
38
|
+
while Survey.find_by_access_code(Survey.to_normalized_string(adjusted_value))
|
39
|
+
i ||= 0
|
40
|
+
i += 1
|
41
|
+
adjusted_value = "#{value} #{i.to_s}"
|
42
|
+
end
|
43
|
+
self.access_code = Survey.to_normalized_string(adjusted_value)
|
44
|
+
super(adjusted_value)
|
45
|
+
# self.access_code = Survey.to_normalized_string(value)
|
46
|
+
# super
|
39
47
|
end
|
40
48
|
|
41
49
|
def active?
|
@@ -11,10 +11,20 @@ module Surveyor
|
|
11
11
|
base.send :named_scope, :with_includes, { :include => {:questions => [:answers, :question_group, {:dependency => :dependency_conditions}]}}
|
12
12
|
|
13
13
|
# Validations
|
14
|
-
base.send :validates_presence_of, :title, :
|
14
|
+
base.send :validates_presence_of, :title, :display_order
|
15
|
+
# this causes issues with building and saving
|
16
|
+
#, :survey
|
15
17
|
end
|
16
18
|
|
17
19
|
# Instance Methods
|
20
|
+
def initialize(*args)
|
21
|
+
super(*args)
|
22
|
+
default_args
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_args
|
26
|
+
self.display_order ||= self.survey ? self.survey.sections.count : 0
|
27
|
+
end
|
18
28
|
|
19
29
|
end
|
20
30
|
end
|