surveyor 0.6.10 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +13 -2
- data/VERSION +1 -1
- data/app/controllers/surveyor_controller.rb +1 -1
- data/app/models/dependency.rb +21 -6
- data/app/models/question.rb +3 -7
- data/app/models/question_group.rb +13 -1
- data/app/models/response_set.rb +1 -1
- data/app/models/survey_section.rb +1 -1
- data/app/views/partials/_question_group.html.haml +2 -1
- data/generators/surveyor/templates/migrate/create_answers.rb +1 -1
- data/generators/surveyor/templates/migrate/create_dependencies.rb +1 -0
- data/generators/surveyor/templates/migrate/create_question_groups.rb +1 -1
- data/generators/surveyor/templates/migrate/create_questions.rb +1 -1
- data/generators/surveyor/templates/migrate/create_survey_sections.rb +1 -1
- data/generators/surveyor/templates/migrate/create_surveys.rb +1 -1
- data/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +54 -67
- data/script/surveyor/answer.rb +7 -21
- data/script/surveyor/dependency.rb +11 -6
- data/script/surveyor/dependency_condition.rb +8 -19
- data/script/surveyor/question.rb +6 -19
- data/script/surveyor/question_group.rb +8 -13
- data/script/surveyor/survey.rb +5 -13
- data/script/surveyor/survey_section.rb +12 -24
- data/surveyor.gemspec +2 -2
- metadata +2 -2
data/README.md
CHANGED
@@ -7,12 +7,12 @@ Surveyor is a rails (gem) plugin, that brings surveys to your rails app. Before
|
|
7
7
|
As a plugin:
|
8
8
|
|
9
9
|
sudo gem install haml
|
10
|
-
script/plugin install git://github.com/breakpointer/surveyor.git -r 'tag v0.
|
10
|
+
script/plugin install git://github.com/breakpointer/surveyor.git -r 'tag v0.7.0'
|
11
11
|
|
12
12
|
Or as a gem plugin:
|
13
13
|
|
14
14
|
# in environment.rb
|
15
|
-
config.gem "surveyor", :version => '>=0.
|
15
|
+
config.gem "surveyor", :version => '>=0.7.0', :source => 'http://gemcutter.org'
|
16
16
|
|
17
17
|
sudo gem install gemcutter
|
18
18
|
gem tumble
|
@@ -103,4 +103,15 @@ The <code>surveyor\_includes</code> helper just calls <code>surveyor\_stylsheets
|
|
103
103
|
|
104
104
|
Surveyor depends on Rails 2.3 and the SASS style sheet language, part of HAML (http://haml.hamptoncatlin.com/download)
|
105
105
|
|
106
|
+
# Changes
|
107
|
+
|
108
|
+
0.7.0
|
109
|
+
|
110
|
+
* new kitchen sink survey with better documentation of DSL
|
111
|
+
* migration misspelling
|
112
|
+
* fixing ordering, dependency conditions evaluation, and changing named scopes for now
|
113
|
+
* DRYing up surveyor DSL models
|
114
|
+
* working on adding dependencies for question groups
|
115
|
+
|
116
|
+
|
106
117
|
Copyright (c) 2008-2009 Brian Chamberlain and Mark Yoon, released under the MIT license
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
@@ -40,7 +40,7 @@ class SurveyorController < ApplicationController
|
|
40
40
|
@survey = Survey.with_sections.find_by_id(@response_set.survey_id)
|
41
41
|
@sections = @survey.sections
|
42
42
|
@section = params[:section] ? @sections.with_includes.find(section_id_from(params[:section])) || @sections.with_includes.first : @sections.with_includes.first
|
43
|
-
@questions = @section.questions
|
43
|
+
@questions = @section.questions
|
44
44
|
else
|
45
45
|
flash[:notice] = "Unable to find your responses to the survey"
|
46
46
|
redirect_to(available_surveys_path)
|
data/app/models/dependency.rb
CHANGED
@@ -1,19 +1,30 @@
|
|
1
1
|
class Dependency < ActiveRecord::Base
|
2
2
|
# Associations
|
3
3
|
belongs_to :question
|
4
|
+
belongs_to :question_group
|
4
5
|
has_many :dependency_conditions
|
5
6
|
|
6
7
|
# Scopes
|
7
|
-
named_scope :depending_on_questions, lambda {|question_ids| {:
|
8
|
+
named_scope :depending_on_questions, lambda {|question_ids| {:joins => :dependency_conditions, :conditions => {:dependency_conditions => {:question_id => question_ids}} }}
|
8
9
|
|
9
10
|
# Validations
|
10
11
|
validates_presence_of :rule
|
11
|
-
validates_format_of :rule, :with => /^(?:and|or|\)|\(|\
|
12
|
-
validates_numericality_of :question_id
|
12
|
+
validates_format_of :rule, :with => /^(?:and|or|\)|\(|[A-Z]|\s)+$/ #TODO properly formed parenthesis etc.
|
13
|
+
# validates_numericality_of :question_id
|
13
14
|
|
14
15
|
# Attribute aliases
|
15
16
|
alias_attribute :dependent_question_id, :question_id
|
16
|
-
|
17
|
+
|
18
|
+
def question_group_id=(i)
|
19
|
+
write_attribute(:question_id, nil)
|
20
|
+
write_attribute(:question_group_id, i)
|
21
|
+
end
|
22
|
+
|
23
|
+
def question_id=(i)
|
24
|
+
write_attribute(:question_group_id, nil)
|
25
|
+
write_attribute(:question_id, i)
|
26
|
+
end
|
27
|
+
|
17
28
|
# Is the method that determines if this dependency has been met within
|
18
29
|
# the provided response set
|
19
30
|
def met?(response_set)
|
@@ -29,6 +40,7 @@ class Dependency < ActiveRecord::Base
|
|
29
40
|
# calling keyed_condition_pairs will return {:A => true, :B => false}
|
30
41
|
def keyed_conditions(response_set)
|
31
42
|
keyed_pairs = {}
|
43
|
+
# logger.debug dependency_conditions.inspect
|
32
44
|
self.dependency_conditions.each do |dc|
|
33
45
|
keyed_pairs.merge!(dc.to_evaluation_hash(response_set))
|
34
46
|
end
|
@@ -38,8 +50,11 @@ class Dependency < ActiveRecord::Base
|
|
38
50
|
# Does the substiution and evaluation of the dependency rule with the keyed pairs
|
39
51
|
def rule_evaluation(keyed_pairs)
|
40
52
|
# subtitute into rule for evaluation
|
41
|
-
rgx = Regexp.new(self.dependency_conditions.map{|dc| dc.rule_key}.join("|")) # Making a regexp to only look for the keys used in the child conditions
|
42
|
-
#logger.debug
|
53
|
+
rgx = Regexp.new(self.dependency_conditions.map{|dc| ["a","o"].include?(dc.rule_key) ? "#{dc.rule_key}(?!nd|r)" : dc.rule_key}.join("|")) # Making a regexp to only look for the keys used in the child conditions
|
54
|
+
# logger.debug "rule: #{self.rule.inspect}"
|
55
|
+
# logger.debug "rexp: #{rgx.inspect}"
|
56
|
+
# logger.debug "keyp: #{keyed_pairs.inspect}"
|
57
|
+
# logger.debug "subd: #{self.rule.gsub(rgx){|m| keyed_pairs[m.to_sym]}}"
|
43
58
|
eval(self.rule.gsub(rgx){|m| keyed_pairs[m.to_sym]}) # returns the evaluation of the rule and the conditions
|
44
59
|
end
|
45
60
|
|
data/app/models/question.rb
CHANGED
@@ -3,12 +3,11 @@ class Question < ActiveRecord::Base
|
|
3
3
|
# Associations
|
4
4
|
belongs_to :survey_section
|
5
5
|
belongs_to :question_group
|
6
|
-
has_many :answers # it might not always have answers
|
6
|
+
has_many :answers, :order => "display_order ASC" # it might not always have answers
|
7
7
|
has_one :dependency
|
8
8
|
|
9
9
|
# Scopes
|
10
10
|
default_scope :order => "display_order ASC"
|
11
|
-
named_scope :in_order, {:order => "display_order ASC"}
|
12
11
|
|
13
12
|
# Validations
|
14
13
|
validates_presence_of :text, :survey_section_id, :display_order
|
@@ -22,8 +21,8 @@ class Question < ActiveRecord::Base
|
|
22
21
|
|
23
22
|
def default_args
|
24
23
|
self.is_mandatory ||= true
|
25
|
-
self.display_type
|
26
|
-
self.pick
|
24
|
+
self.display_type ||= "default"
|
25
|
+
self.pick ||= "none"
|
27
26
|
end
|
28
27
|
|
29
28
|
def mandatory?
|
@@ -39,9 +38,6 @@ class Question < ActiveRecord::Base
|
|
39
38
|
def dep_class(response_set)
|
40
39
|
dependent? ? triggered?(response_set) ? "dependent" : "hidden dependent" : nil
|
41
40
|
end
|
42
|
-
def dependency_satisfied?(response_set)
|
43
|
-
self.has_dependency? and self.dependency.met?(response_set)
|
44
|
-
end
|
45
41
|
|
46
42
|
def part_of_group?
|
47
43
|
!self.question_group.nil?
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class QuestionGroup < ActiveRecord::Base
|
2
2
|
|
3
3
|
has_many :questions
|
4
|
+
has_one :dependency
|
4
5
|
|
5
6
|
# Instance Methods
|
6
7
|
def initialize(*args)
|
@@ -9,10 +10,21 @@ class QuestionGroup < ActiveRecord::Base
|
|
9
10
|
end
|
10
11
|
|
11
12
|
def default_args
|
12
|
-
self.display_type
|
13
|
+
self.display_type ||= "inline"
|
13
14
|
end
|
14
15
|
|
15
16
|
def renderer
|
16
17
|
display_type.blank? ? :default : display_type.to_sym
|
17
18
|
end
|
19
|
+
|
20
|
+
def dependent?
|
21
|
+
self.dependency != nil
|
22
|
+
end
|
23
|
+
def triggered?(response_set)
|
24
|
+
dependent? ? self.dependency.met?(response_set) : true
|
25
|
+
end
|
26
|
+
def dep_class(response_set)
|
27
|
+
dependent? ? triggered?(response_set) ? "dependent" : "hidden dependent" : nil
|
28
|
+
end
|
29
|
+
|
18
30
|
end
|
data/app/models/response_set.rb
CHANGED
@@ -105,7 +105,7 @@ class ResponseSet < ActiveRecord::Base
|
|
105
105
|
|
106
106
|
def all_dependencies
|
107
107
|
arr = dependencies.partition{|d| d.met?(self) }
|
108
|
-
{:show => arr[0].map{|d| "question_#{d.question_id}"}, :hide => arr[1].map{|d| "question_#{d.question_id}"}}
|
108
|
+
{:show => arr[0].map{|d| d.question_group_id.nil? ? "question_#{d.question_id}" : "question_group#{d.question_group_id}"}, :hide => arr[1].map{|d| d.question_group_id.nil? ? "question_#{d.question_id}" : "question_group#{d.question_group_id}"}}
|
109
109
|
end
|
110
110
|
|
111
111
|
protected
|
@@ -1,7 +1,8 @@
|
|
1
1
|
- renderer = question_group.renderer
|
2
|
+
- dep_class = question_group.dep_class(response_set)
|
2
3
|
- locals = {:question_group => question_group, :response_set => response_set, :hide_label => true}
|
3
4
|
|
4
|
-
- div_for question_group do
|
5
|
+
- div_for question_group, :class => dep_class do
|
5
6
|
.head
|
6
7
|
.number= next_number
|
7
8
|
%span.text= question_group.text
|
@@ -15,7 +15,7 @@ class CreateAnswers < ActiveRecord::Migration
|
|
15
15
|
t.string :reference_identifier # from paper
|
16
16
|
t.string :data_export_identifier # data export
|
17
17
|
t.string :common_namespace # maping to a common vocab
|
18
|
-
t.string :
|
18
|
+
t.string :common_identifier # maping to a common vocab
|
19
19
|
|
20
20
|
# Display
|
21
21
|
t.integer :display_order
|
@@ -9,7 +9,7 @@ class CreateQuestionGroups < ActiveRecord::Migration
|
|
9
9
|
t.string :reference_identifier # from paper
|
10
10
|
t.string :data_export_identifier # data export
|
11
11
|
t.string :common_namespace # maping to a common vocab
|
12
|
-
t.string :
|
12
|
+
t.string :common_identifier # maping to a common vocab
|
13
13
|
|
14
14
|
# Display
|
15
15
|
t.string :display_type
|
@@ -15,7 +15,7 @@ class CreateQuestions < ActiveRecord::Migration
|
|
15
15
|
t.string :reference_identifier # from paper
|
16
16
|
t.string :data_export_identifier # data export
|
17
17
|
t.string :common_namespace # maping to a common vocab
|
18
|
-
t.string :
|
18
|
+
t.string :common_identifier # maping to a common vocab
|
19
19
|
|
20
20
|
# Display
|
21
21
|
t.integer :display_order
|
@@ -12,7 +12,7 @@ class CreateSurveySections < ActiveRecord::Migration
|
|
12
12
|
t.string :reference_identifier # from paper
|
13
13
|
t.string :data_export_identifier # data export
|
14
14
|
t.string :common_namespace # maping to a common vocab
|
15
|
-
t.string :
|
15
|
+
t.string :common_identifier # maping to a common vocab
|
16
16
|
|
17
17
|
# Display
|
18
18
|
t.integer :display_order
|
@@ -10,7 +10,7 @@ class CreateSurveys < ActiveRecord::Migration
|
|
10
10
|
t.string :reference_identifier # from paper
|
11
11
|
t.string :data_export_identifier # data export
|
12
12
|
t.string :common_namespace # maping to a common vocab
|
13
|
-
t.string :
|
13
|
+
t.string :common_identifier # maping to a common vocab
|
14
14
|
|
15
15
|
# Expiry
|
16
16
|
t.datetime :active_at
|
@@ -1,34 +1,29 @@
|
|
1
1
|
survey "“Kitchen Sink” survey" do
|
2
2
|
|
3
3
|
section "Basic questions" do
|
4
|
-
|
5
|
-
# exclusive
|
6
|
-
# name people you live with (choose all that apply)
|
7
|
-
# husband, friend, partner, siblings, other, alone, choose not to answer
|
8
|
-
# alone unchecks/erases, and disables all the others
|
9
|
-
# omit (choose not to answer) is exclusive as well
|
10
|
-
|
11
|
-
# a label is a question that accepts no answers
|
12
|
-
# reference_identifier => label
|
4
|
+
# A label is a question that accepts no answers
|
13
5
|
label "These questions are examples of the basic supported input types"
|
14
6
|
|
15
|
-
|
16
|
-
# a basic question,
|
17
|
-
# reference_identifier => 1
|
7
|
+
# A basic question with radio buttons
|
18
8
|
question_1 "What is your favorite color?", :pick => :one
|
19
9
|
answer "red"
|
20
10
|
answer "blue"
|
21
11
|
answer "green"
|
22
12
|
answer "yellow"
|
23
|
-
answer :other
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
13
|
+
answer :other
|
14
|
+
|
15
|
+
# A basic question with checkboxes
|
16
|
+
# "question" and "answer" may be abbreviated as "q" and "a"
|
17
|
+
q_2 "Choose the colors you don't like", :pick => :any
|
18
|
+
a_1 "red"
|
19
|
+
a_2 "blue"
|
20
|
+
a_3 "green"
|
21
|
+
a_4 "yellow"
|
22
|
+
a :omit
|
23
|
+
|
24
|
+
# A dependent question, with conditions and rule to logically join them
|
25
|
+
# the question's reference identifier is "2a", and the answer's reference_identifier is "1"
|
26
|
+
# question reference identifiers used in conditions need to be unique for the lookups to work
|
32
27
|
q_2a "Please explain why you don't like this color?"
|
33
28
|
a_1 "explanation", :text
|
34
29
|
dependency :rule => "A or B or C or D"
|
@@ -37,67 +32,54 @@ survey "“Kitchen Sink” survey" do
|
|
37
32
|
condition_C :q_2, "==", :a_3
|
38
33
|
condition_D :q_2, "==", :a_4
|
39
34
|
|
40
|
-
#
|
41
|
-
# questions and answers don't need to have numbers. Only if they are referenced in a dependency condition
|
35
|
+
# When :pick isn't specified, the default is :none (no checkbox or radio button)
|
42
36
|
q "What is your name?"
|
43
37
|
a :string
|
44
38
|
|
45
|
-
|
39
|
+
# Surveys, sections, questions, groups, and answers all take the following reference arguments
|
40
|
+
# :reference_identifier # usually from paper
|
41
|
+
# :data_export_identifier # data export
|
42
|
+
# :common_namespace # maping to a common vocab
|
43
|
+
# :common_identitier # maping to a common vocab
|
44
|
+
q "Get me started on an improv sketch", :reference_identifier => "improv_start", :data_export_identifier => "i_s", :common_namespace => "sketch comedy questions", :common_identifer => "get me started"
|
46
45
|
a "who", :string
|
47
46
|
a "what", :string
|
48
47
|
a "where", :string
|
49
|
-
|
50
|
-
|
48
|
+
|
49
|
+
# Various types of respones can be accepted
|
50
|
+
q "How many pets do you own?"
|
51
51
|
a :integer
|
52
52
|
|
53
|
-
q "What is your address?"
|
53
|
+
q "What is your address?"
|
54
54
|
a :text
|
55
|
-
#
|
56
|
-
# q "Pick your favorite date"
|
57
|
-
# a :date
|
58
|
-
#
|
59
|
-
# q "Pick your favorite time"
|
60
|
-
# a :time
|
61
55
|
|
62
56
|
q "Pick your favorite date AND time"
|
63
57
|
a :datetime
|
64
58
|
|
65
|
-
q "What time
|
59
|
+
q "What time do you usually take a lunch break?"
|
66
60
|
a :time
|
67
61
|
|
68
|
-
q "
|
62
|
+
q "When would you like to meet for dinner?"
|
69
63
|
a :date
|
70
|
-
|
64
|
+
|
65
|
+
# Sliders deprecate to select boxes when javascript is off
|
66
|
+
# Valid Ruby code may be used to shorted repetitive tasks
|
71
67
|
q "Adjust the slider to reflect your level of awesomeness", :pick => :one, :display_type => :slider
|
72
|
-
(1..10).to_a.each{
|
68
|
+
(1..10).to_a.each{|num| a num.to_s}
|
73
69
|
|
74
70
|
q "How much do you like Ruby?", :pick => :one, :display_type => :slider
|
75
71
|
["not at all", "a little", "some", "a lot", "a ton"].each{|level| a level}
|
76
|
-
|
77
|
-
# range "When did you start working at NUBIC?", :range_type => :date do
|
78
|
-
# q "From"
|
79
|
-
# a :date
|
80
|
-
#
|
81
|
-
# q "To"
|
82
|
-
# a :date
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# range "What times are you awake?", :range_type => :integer do
|
86
|
-
# q "From"
|
87
|
-
# a :integer
|
88
|
-
#
|
89
|
-
# q "To"
|
90
|
-
# a :integer
|
91
|
-
# end
|
92
72
|
|
73
|
+
# The "|" pipe is used to place labels before or after the input elements
|
93
74
|
q "How much money do you want?"
|
94
|
-
a "$|USD", :float
|
75
|
+
a "$|USD", :float
|
95
76
|
|
77
|
+
# Questions may be grouped
|
96
78
|
group "How much oil do you use per day?", :display_type => :inline do
|
97
79
|
q "Quantity"
|
98
80
|
a "Quantity", :float
|
99
81
|
|
100
|
-
q "Unit", :pick => :one, :display_type => :dropdown
|
82
|
+
q "Unit", :pick => :one, :display_type => :dropdown
|
101
83
|
a "Barrels"
|
102
84
|
a "Gallons"
|
103
85
|
a "Quarts"
|
@@ -124,7 +106,8 @@ survey "“Kitchen Sink” survey" do
|
|
124
106
|
"St. Clair","Stark", "Stephenson","Tazewell","Union",
|
125
107
|
"Vermilion","Wabash","Warren","Washington","Wayne",
|
126
108
|
"White","Whiteside","Will","Williamson","Winnebago","Woodford"].each{ |county| a county}
|
127
|
-
|
109
|
+
|
110
|
+
# When an is_exclusive answer is checked, it unchecks all other options and disables them (using Javascript)
|
128
111
|
q "Choose your favorite meats", :display_type => :inline, :pick => :any
|
129
112
|
a "Chicken"
|
130
113
|
a "Pork"
|
@@ -141,7 +124,8 @@ survey "“Kitchen Sink” survey" do
|
|
141
124
|
end
|
142
125
|
|
143
126
|
section "Complicated questions" do
|
144
|
-
|
127
|
+
|
128
|
+
# Grids are useful for repeated questions with the same set of answers, which are specified before the questions
|
145
129
|
grid "Tell us how often do you cover these each day" do
|
146
130
|
a "1"
|
147
131
|
a "2"
|
@@ -150,33 +134,35 @@ survey "“Kitchen Sink” survey" do
|
|
150
134
|
q "Knees", :pick => :one
|
151
135
|
q "Toes", :pick => :one
|
152
136
|
end
|
153
|
-
|
137
|
+
|
138
|
+
# "grid" is a shortcut for group with :display_type => :grid
|
139
|
+
# The answers will be repeated every 10 rows, but long grids aren't recommended as they are generally tedious
|
154
140
|
grid "Tell us how you feel today day" do
|
155
141
|
a "-2"
|
156
142
|
a "-1"
|
157
143
|
a "0"
|
158
144
|
a "1"
|
159
145
|
a "2"
|
160
|
-
a :omit
|
161
146
|
q "down|up" , :pick => :one
|
162
147
|
q "sad|happy", :pick => :one
|
163
148
|
q "limp|perky", :pick => :one
|
164
149
|
end
|
165
150
|
|
166
151
|
q "Please rank the following foods based on how much you like them"
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
152
|
+
a "|pizza", :integer
|
153
|
+
a "|salad", :integer
|
154
|
+
a "|sushi", :integer
|
155
|
+
a "|ice cream", :integer
|
156
|
+
a "|breakfast ceral", :integer
|
172
157
|
|
173
|
-
|
158
|
+
# :other, :string allows someone to specify both the "other" and some other information
|
174
159
|
q "Choose your favorite utensils and enter frequency of use (daily, weekly, monthly, etc...)", :pick => :any
|
175
160
|
a "spoon", :string
|
176
161
|
a "fork", :string
|
177
162
|
a "knife", :string
|
178
163
|
a :other, :string
|
179
|
-
|
164
|
+
|
165
|
+
# Repeaters allow multiple responses to a question or set of questions
|
180
166
|
repeater "Tell us about the cars you own" do
|
181
167
|
q "Make", :pick => :one, :display_type => :dropdown
|
182
168
|
a "Toyota"
|
@@ -191,10 +177,11 @@ survey "“Kitchen Sink” survey" do
|
|
191
177
|
q "Year"
|
192
178
|
a :string
|
193
179
|
end
|
180
|
+
|
194
181
|
repeater "Tell us the name and age of your siblings" do
|
195
182
|
q "Sibling"
|
196
183
|
a "Name", :string
|
197
|
-
a "Age", :integer
|
184
|
+
a "Age|years", :integer
|
198
185
|
end
|
199
186
|
|
200
187
|
end
|
data/script/surveyor/answer.rb
CHANGED
@@ -23,7 +23,6 @@ class Answer
|
|
23
23
|
{ :short_text => text,
|
24
24
|
:data_export_identifier => Columnizer.to_normalized_column(text),
|
25
25
|
:is_exclusive => false,
|
26
|
-
:is_a_disabler => false,
|
27
26
|
:hide_label => false,
|
28
27
|
:response_class => "answer"
|
29
28
|
}
|
@@ -36,11 +35,11 @@ class Answer
|
|
36
35
|
if a0.is_a?(Hash)
|
37
36
|
{:text => "Answer"}.merge(a0)
|
38
37
|
|
39
|
-
# String, Hash
|
38
|
+
# (String, Hash) or (String, Symbol, Hash)
|
40
39
|
elsif a0.is_a?(String)
|
41
40
|
a1.is_a?(Symbol) ? {:text => a0, :response_class => a1.to_s}.merge(a2 || {}) : {:text => a0}.merge(a1 || {})
|
42
41
|
|
43
|
-
# Symbol, Hash
|
42
|
+
# (Symbol, Hash) or (Symbol, Symbol, Hash)
|
44
43
|
elsif a0.is_a?(Symbol)
|
45
44
|
shortcuts = case a0
|
46
45
|
when :other
|
@@ -60,25 +59,12 @@ class Answer
|
|
60
59
|
end
|
61
60
|
end
|
62
61
|
|
62
|
+
def yml_attrs
|
63
|
+
instance_variables.sort - ["@parser"]
|
64
|
+
end
|
63
65
|
def to_yml
|
64
|
-
out =[ %(#{@data_export_identifier}_#{@id}:) ]
|
65
|
-
out <<
|
66
|
-
out << %( question_id: #{@question_id})
|
67
|
-
out << %( text: "#{@text}")
|
68
|
-
out << %( short_text: "#{@short_text}")
|
69
|
-
out << %( help_text: "#{@help_text}")
|
70
|
-
out << %( weight: #{@weight})
|
71
|
-
out << %( response_class: "#{@response_class}")
|
72
|
-
out << %( reference_identifier: "#{@reference_identifier}")
|
73
|
-
out << %( data_export_identifier: "#{@data_export_identifier}")
|
74
|
-
out << %( common_namespace: "#{@common_namespace}")
|
75
|
-
out << %( common_identitier: "#{@common_identitier}")
|
76
|
-
out << %( display_order: #{@display_order} )
|
77
|
-
out << %( is_exclusive: #{@is_exclusive})
|
78
|
-
out << %( hide_label: #{@hide_label})
|
79
|
-
out << %( display_length: #{@display_length} )
|
80
|
-
out << %( custom_class: "#{@custom_class}")
|
81
|
-
out << %( custom_renderer: "#{@custom_renderer}")
|
66
|
+
out = [ %(#{@data_export_identifier}_#{@id}:) ]
|
67
|
+
yml_attrs.each{|a| out << " #{a[1..-1]}: #{instance_variable_get(a).is_a?(String) ? "\"#{instance_variable_get(a)}\"" : instance_variable_get(a) }"}
|
82
68
|
(out << nil ).join("\r\n")
|
83
69
|
end
|
84
70
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Dependency
|
2
2
|
|
3
3
|
# Context, Conditional, Children
|
4
|
-
attr_accessor :id, :question_id, :parser
|
4
|
+
attr_accessor :id, :question_id, :question_group_id, :parser
|
5
5
|
attr_accessor :rule
|
6
6
|
attr_accessor :dependency_conditions
|
7
7
|
|
@@ -9,7 +9,11 @@ class Dependency
|
|
9
9
|
def initialize(question, args, options)
|
10
10
|
self.parser = question.parser
|
11
11
|
self.id = parser.new_dependency_id
|
12
|
-
|
12
|
+
if question.class == QuestionGroup
|
13
|
+
self.question_group_id = question.id
|
14
|
+
else
|
15
|
+
self.question_id = question.id
|
16
|
+
end
|
13
17
|
self.rule = (args[0] || {})[:rule]
|
14
18
|
self.dependency_conditions = []
|
15
19
|
self.default_options().merge(options).merge(args[1] || {}).each{|key,value| self.instance_variable_set("@#{key}", value)}
|
@@ -25,11 +29,12 @@ class Dependency
|
|
25
29
|
self.dependency_conditions << dc_obj
|
26
30
|
end
|
27
31
|
|
32
|
+
def yml_attrs
|
33
|
+
instance_variables.sort - ["@parser", "@dependency_conditions", "@reference_identifier"]
|
34
|
+
end
|
28
35
|
def to_yml
|
29
|
-
out =[ %(#{
|
30
|
-
out <<
|
31
|
-
out << %( question_id: #{@question_id})
|
32
|
-
out << %( rule: "#{@rule}")
|
36
|
+
out = [ %(#{@data_export_identifier}_#{@id}:) ]
|
37
|
+
yml_attrs.each{|a| out << " #{a[1..-1]}: #{instance_variable_get(a).is_a?(String) ? "\"#{instance_variable_get(a)}\"" : instance_variable_get(a) }"}
|
33
38
|
(out << nil ).join("\r\n")
|
34
39
|
end
|
35
40
|
|
@@ -11,11 +11,8 @@ class DependencyCondition
|
|
11
11
|
self.parser = dependency.parser
|
12
12
|
self.id = parser.new_dependency_condition_id
|
13
13
|
self.dependency_id = dependency.id
|
14
|
-
self.rule_key = options[:reference_identifier]
|
15
|
-
|
16
14
|
args_options = parse_args_options(args)
|
17
15
|
self.default_options().merge(options).merge(args_options).each{|key,value| self.instance_variable_set("@#{key}", value)}
|
18
|
-
|
19
16
|
end
|
20
17
|
|
21
18
|
def default_options()
|
@@ -28,29 +25,21 @@ class DependencyCondition
|
|
28
25
|
a2.is_a?(Hash) ? options.merge(a2) : options.merge({:answer_reference => a2.to_s.gsub("a_", "")})
|
29
26
|
end
|
30
27
|
|
28
|
+
def yml_attrs
|
29
|
+
instance_variables.sort - ["@parser", "@question_reference", "@answer_reference", "@reference_identifier"]
|
30
|
+
end
|
31
31
|
def to_yml
|
32
|
-
out =[ %(#{@
|
33
|
-
out <<
|
34
|
-
out << %( dependency_id: #{@dependency_id})
|
35
|
-
out << %( rule_key: "#{@rule_key}")
|
36
|
-
out << %( question_id: #{@question_id})
|
37
|
-
out << %( operator: "#{@operator}")
|
38
|
-
out << %( answer_id: #{@answer_id})
|
39
|
-
out << %( datetime_value: #{@date_value})
|
40
|
-
out << %( integer_value: #{@integer_value})
|
41
|
-
out << %( float_value: #{@float_value})
|
42
|
-
out << %( unit: "#{@unit}")
|
43
|
-
out << %( text_value: "#{@text_value}")
|
44
|
-
out << %( string_value: "#{@string_value}")
|
45
|
-
out << %( response_other: "#{@response_other}")
|
32
|
+
out = [ %(#{@data_export_identifier}_#{@id}:) ]
|
33
|
+
yml_attrs.each{|a| out << " #{a[1..-1]}: #{instance_variable_get(a).is_a?(String) ? "\"#{instance_variable_get(a)}\"" : instance_variable_get(a) }"}
|
46
34
|
(out << nil ).join("\r\n")
|
47
35
|
end
|
48
36
|
|
49
37
|
def reconcile_dependencies
|
50
38
|
# Looking up references to questions and answers for linking the dependency objects
|
51
|
-
puts "Looking up references for question: #{@question_reference}
|
52
|
-
ref_question = Survey.current_survey.find_question_by_reference(@question_reference) # Argh. I can't think of a better way to get a hold of this reference here...
|
39
|
+
puts "Looking up references for question: #{@question_reference}"
|
40
|
+
ref_question = Survey.current_survey.find_question_by_reference(@question_reference) # TODO change this. Argh. I can't think of a better way to get a hold of this reference here...
|
53
41
|
if ref_question
|
42
|
+
puts " found question: #{ref_question.data_export_identifier} (id:#{ref_question.id})"
|
54
43
|
@question_id = ref_question.id
|
55
44
|
ref_answer = ref_question.find_answer_by_reference(@answer_reference)
|
56
45
|
if ref_answer
|
data/script/surveyor/question.rb
CHANGED
@@ -49,26 +49,13 @@ class Question
|
|
49
49
|
puts " found answer: '#{answer.text}' (id:#{answer.id})" unless answer.nil?
|
50
50
|
answer
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
|
+
def yml_attrs
|
54
|
+
instance_variables.sort - ["@parser", "@answers", "@dependency"]
|
55
|
+
end
|
53
56
|
def to_yml
|
54
|
-
out =[ %(#{@data_export_identifier}_#{@id}:) ]
|
55
|
-
out <<
|
56
|
-
out << %( survey_section_id: #{@survey_section_id})
|
57
|
-
out << %( question_group_id: #{@question_group_id})
|
58
|
-
out << %( text: "#{@text}")
|
59
|
-
out << %( short_text: "#{@short_text}")
|
60
|
-
out << %( help_text: "#{@help_text}")
|
61
|
-
out << %( pick: "#{pick}")
|
62
|
-
out << %( reference_identifier: "#{@reference_identifier}")
|
63
|
-
out << %( data_export_identifier: "#{@data_export_identifier}")
|
64
|
-
out << %( common_namespace: "#{@common_namespace}")
|
65
|
-
out << %( common_identitier: "#{@common_identitier}")
|
66
|
-
out << %( display_order: #{@display_order})
|
67
|
-
out << %( display_type: "#{@display_type}")
|
68
|
-
out << %( is_mandatory: #{@is_mandatory})
|
69
|
-
out << %( display_width: #{@display_width})
|
70
|
-
out << %( custom_class: "#{@custom_class}")
|
71
|
-
out << %( custom_renderer: "#{@custom_renderer}")
|
57
|
+
out = [ %(#{@data_export_identifier}_#{@id}:) ]
|
58
|
+
yml_attrs.each{|a| out << " #{a[1..-1]}: #{instance_variable_get(a).is_a?(String) ? "\"#{instance_variable_get(a)}\"" : instance_variable_get(a) }"}
|
72
59
|
(out << nil ).join("\r\n")
|
73
60
|
end
|
74
61
|
|
@@ -1,10 +1,11 @@
|
|
1
1
|
class QuestionGroup
|
2
2
|
|
3
|
-
# Context, Content, Display
|
4
|
-
attr_accessor :id, :
|
3
|
+
# Context, Content, Display, Children
|
4
|
+
attr_accessor :id, :parser
|
5
5
|
attr_accessor :text, :help_text
|
6
6
|
attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
|
7
7
|
attr_accessor :display_type, :custom_class, :custom_renderer
|
8
|
+
attr_accessor :dependency
|
8
9
|
|
9
10
|
# id, section and text required
|
10
11
|
def initialize(section, args, options)
|
@@ -18,18 +19,12 @@ class QuestionGroup
|
|
18
19
|
{:display_type => "default"}
|
19
20
|
end
|
20
21
|
|
22
|
+
def yml_attrs
|
23
|
+
instance_variables.sort - ["@parser", "@dependency"]
|
24
|
+
end
|
21
25
|
def to_yml
|
22
|
-
out =[ %(#{@id}:) ]
|
23
|
-
out <<
|
24
|
-
out << %( text: "#{@text}")
|
25
|
-
out << %( help_text: "#{@help_text}")
|
26
|
-
out << %( reference_identifier: "#{@reference_identifier}")
|
27
|
-
out << %( data_export_identifier: "#{@data_export_identifier}")
|
28
|
-
out << %( common_namespace: "#{@common_namespace}")
|
29
|
-
out << %( common_identitier: "#{@common_identitier}")
|
30
|
-
out << %( display_type: "#{@display_type}")
|
31
|
-
out << %( custom_class: "#{@custom_class}")
|
32
|
-
out << %( custom_renderer: "#{@custom_renderer}")
|
26
|
+
out = [ %(#{@id}:) ]
|
27
|
+
yml_attrs.each{|a| out << " #{a[1..-1]}: #{instance_variable_get(a).is_a?(String) ? "\"#{instance_variable_get(a)}\"" : instance_variable_get(a) }"}
|
33
28
|
(out << nil ).join("\r\n")
|
34
29
|
end
|
35
30
|
|
data/script/surveyor/survey.rb
CHANGED
@@ -86,20 +86,12 @@ class Survey
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
def yml_attrs
|
90
|
+
instance_variables.sort - ["@parser", "@survey_sections"]
|
91
|
+
end
|
89
92
|
def to_yml
|
90
|
-
out =[ %(survey_#{@id}:) ]
|
91
|
-
out <<
|
92
|
-
out << %( title: "#{@title}")
|
93
|
-
out << %( description: "#{@description}")
|
94
|
-
out << %( access_code: "#{@access_code}")
|
95
|
-
out << %( reference_identifier: "#{@reference_identifier}")
|
96
|
-
out << %( data_export_identifier: "#{@data_export_identifier}")
|
97
|
-
out << %( common_namespace: "#{@common_namespace}")
|
98
|
-
out << %( common_identitier: "#{@common_identitier}")
|
99
|
-
out << %( active_at: #{@active_at})
|
100
|
-
out << %( inactive_at: #{@inactive_at})
|
101
|
-
out << %( css_url: "#{@css_url}")
|
102
|
-
out << %( custom_class: "#{@custom_class}")
|
93
|
+
out = [ %(survey_#{@id}:) ]
|
94
|
+
yml_attrs.each{|a| out << " #{a[1..-1]}: #{instance_variable_get(a).is_a?(String) ? "\"#{instance_variable_get(a)}\"" : instance_variable_get(a) }"}
|
103
95
|
(out << nil ).join("\r\n")
|
104
96
|
end
|
105
97
|
|
@@ -41,13 +41,14 @@ class SurveySection
|
|
41
41
|
# This method_missing magic does all the heavy lifting for the DSL
|
42
42
|
def method_missing(missing_method, *args, &block)
|
43
43
|
method_name, reference_identifier = missing_method.to_s.split("_")
|
44
|
-
|
44
|
+
|
45
45
|
case method_name
|
46
46
|
|
47
47
|
when "group", "g", "grid", "repeater"
|
48
48
|
puts " Group: #{reference_identifier}"
|
49
49
|
raise "Error: A question group cannot be empty" unless block_given?
|
50
50
|
|
51
|
+
clear_current_question
|
51
52
|
options = {:reference_identifier => reference_identifier, :display_type => (method_name =~ /grid|repeater/)? method_name : nil }
|
52
53
|
self.question_groups << (self.current_question_group = QuestionGroup.new(self, args, options))
|
53
54
|
self.instance_eval(&block)
|
@@ -67,17 +68,17 @@ class SurveySection
|
|
67
68
|
when "dependency", "d"
|
68
69
|
puts " Dependency: #{reference_identifier}"
|
69
70
|
raise "Error: I'm dropping the block like it's hot" if block_given?
|
70
|
-
raise "Error: " unless self.current_question
|
71
|
+
raise "Error: No question or question group" unless (d = self.current_question_group || self.current_question)
|
71
72
|
|
72
|
-
options = {:reference_identifier => reference_identifier}
|
73
|
-
|
73
|
+
options = {}# {:reference_identifier => reference_identifier}
|
74
|
+
d.dependency = (self.current_dependency = Dependency.new(d, args, options))
|
74
75
|
|
75
76
|
when "condition", "c"
|
76
77
|
puts " Condition: #{reference_identifier}"
|
77
78
|
raise "Error, I'm dropping the block like it's hot" if block_given?
|
78
79
|
raise "Error: No current dependency" unless self.current_dependency
|
79
80
|
|
80
|
-
options = {:
|
81
|
+
options = {:rule_key => reference_identifier}
|
81
82
|
self.current_dependency.add_dependency_condition DependencyCondition.new(self, args, options)
|
82
83
|
|
83
84
|
when "answer", "a"
|
@@ -121,28 +122,15 @@ class SurveySection
|
|
121
122
|
|
122
123
|
# Used to find questions for dependency linking
|
123
124
|
def find_question_by_reference(ref_id)
|
124
|
-
|
125
|
-
count = 0
|
126
|
-
while question.nil? and count < questions.size
|
127
|
-
question = self.questions[count] if self.questions[count].reference_identifier == ref_id
|
128
|
-
count +=1
|
129
|
-
end
|
130
|
-
question
|
125
|
+
self.questions.detect{|q| q.reference_identifier == ref_id}
|
131
126
|
end
|
132
127
|
|
128
|
+
def yml_attrs
|
129
|
+
instance_variables.sort - ["@parser", "@question_groups", "@questions", "@grid_answers", "@current_question_group", "@current_question", "@current_dependency"]
|
130
|
+
end
|
133
131
|
def to_yml
|
134
|
-
out =[ %(#{@data_export_identifier}_#{@id}:) ]
|
135
|
-
out <<
|
136
|
-
out << %( survey_id: #{@survey_id})
|
137
|
-
out << %( title: "#{@title}")
|
138
|
-
out << %( description: "#{@description}")
|
139
|
-
out << %( reference_identifier: "#{@reference_identifier}")
|
140
|
-
out << %( data_export_identifier: "#{@data_export_identifier}")
|
141
|
-
out << %( common_namespace: "#{@common_namespace}")
|
142
|
-
out << %( common_identitier: "#{@common_identitier}")
|
143
|
-
out << %( display_order: #{@display_order})
|
144
|
-
out << %( custom_class: "#{@custom_class}")
|
145
|
-
|
132
|
+
out = [ %(#{@data_export_identifier}_#{@id}:) ]
|
133
|
+
yml_attrs.each{|a| out << " #{a[1..-1]}: #{instance_variable_get(a).is_a?(String) ? "\"#{instance_variable_get(a)}\"" : instance_variable_get(a) }"}
|
146
134
|
(out << nil ).join("\r\n")
|
147
135
|
end
|
148
136
|
|
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.
|
8
|
+
s.version = "0.7.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{2009-10-
|
12
|
+
s.date = %q{2009-10-20}
|
13
13
|
s.email = %q{yoon@northwestern.edu}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"README.md"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: surveyor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Chamberlain
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-10-
|
13
|
+
date: 2009-10-20 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|