surveyor 0.8.0 → 0.9.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 +22 -5
- data/VERSION +1 -1
- data/app/models/dependency.rb +16 -32
- data/app/models/question.rb +1 -1
- data/app/models/question_group.rb +1 -1
- data/app/models/response.rb +1 -4
- data/app/models/response_set.rb +4 -3
- data/app/models/survey.rb +0 -1
- data/app/models/validation.rb +20 -0
- data/app/models/validation_condition.rb +19 -17
- data/generators/surveyor/surveyor_generator.rb +9 -5
- data/generators/surveyor/templates/migrate/add_display_order_to_surveys.rb +9 -0
- data/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +15 -4
- data/lib/surveyor.rb +16 -0
- data/script/surveyor/answer.rb +32 -55
- data/script/surveyor/base.rb +61 -0
- data/script/surveyor/dependency.rb +4 -41
- data/script/surveyor/dependency_condition.rb +13 -38
- data/script/surveyor/question.rb +16 -50
- data/script/surveyor/question_group.rb +7 -19
- data/script/surveyor/specs/answer_spec.rb +15 -52
- data/script/surveyor/specs/question_spec.rb +37 -85
- data/script/surveyor/specs/spec_helper.rb +6 -0
- data/script/surveyor/specs/survey_section_spec.rb +23 -0
- data/script/surveyor/specs/validation_condition_spec.rb +20 -0
- data/script/surveyor/specs/validation_spec.rb +20 -0
- data/script/surveyor/survey.rb +10 -85
- data/script/surveyor/survey_parser.rb +160 -38
- data/script/surveyor/survey_section.rb +6 -130
- data/script/surveyor/validation.rb +19 -0
- data/script/surveyor/validation_condition.rb +19 -0
- data/spec/lib/surveyor_spec.rb +44 -0
- data/spec/models/dependency_spec.rb +9 -16
- data/spec/models/question_group_spec.rb +3 -3
- data/spec/models/question_spec.rb +1 -1
- data/spec/models/validation_condition_spec.rb +29 -0
- data/spec/models/validation_spec.rb +27 -0
- data/spec/spec_helper.rb +0 -2
- data/surveyor.gemspec +12 -7
- metadata +12 -7
- data/lib/tiny_code.rb +0 -58
- data/script/surveyor/columnizer.rb +0 -36
- data/script/surveyor/specs/question_dependency_spec.rb +0 -46
- data/script/surveyor/specs/question_group_spec.rb +0 -9
- data/script/surveyor/specs/section_spec.rb +0 -58
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.9.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.9.0', :source => 'http://gemcutter.org'
|
16
16
|
|
17
17
|
sudo gem install gemcutter
|
18
18
|
gem tumble
|
@@ -105,11 +105,28 @@ Surveyor depends on Rails 2.3 and the SASS style sheet language, part of HAML (h
|
|
105
105
|
|
106
106
|
# Changes
|
107
107
|
|
108
|
+
0.9.0
|
109
|
+
|
110
|
+
* validations in dsl and surveyor models
|
111
|
+
* preserve underscores in reference identifiers
|
112
|
+
* dsl specs, refactoring into base class
|
113
|
+
* adding display order to surveys
|
114
|
+
* moving columnizer and tiny column functionality to surveyor module
|
115
|
+
* columnizer (and tiny code) refactoring, columnizer spec extracted from answer spec
|
116
|
+
* cleanup of scopes with joins
|
117
|
+
* refactoring dependency
|
118
|
+
|
119
|
+
0.8.0
|
120
|
+
|
121
|
+
* question group dependencies
|
122
|
+
* expanded examples in kitchen sink survey
|
123
|
+
* specs
|
124
|
+
|
108
125
|
0.7.1
|
109
126
|
|
110
|
-
custom index page
|
111
|
-
custom classes and renderers
|
112
|
-
fixing typo in kitchen sink survey
|
127
|
+
* custom index page
|
128
|
+
* custom classes and renderers
|
129
|
+
* fixing typo in kitchen sink survey
|
113
130
|
|
114
131
|
0.7.0
|
115
132
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/app/models/dependency.rb
CHANGED
@@ -4,9 +4,6 @@ class Dependency < ActiveRecord::Base
|
|
4
4
|
belongs_to :question_group
|
5
5
|
has_many :dependency_conditions
|
6
6
|
|
7
|
-
# Scopes
|
8
|
-
named_scope :depending_on_questions, lambda {|question_ids| {:joins => :dependency_conditions, :conditions => {:dependency_conditions => {:question_id => question_ids}} }}
|
9
|
-
|
10
7
|
# Validations
|
11
8
|
validates_presence_of :rule
|
12
9
|
validates_format_of :rule, :with => /^(?:and|or|\)|\(|[A-Z]|\s)+$/ #TODO properly formed parenthesis etc.
|
@@ -26,37 +23,24 @@ class Dependency < ActiveRecord::Base
|
|
26
23
|
write_attribute(:question_id, i)
|
27
24
|
end
|
28
25
|
|
29
|
-
#
|
30
|
-
# the
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
else
|
35
|
-
return(false)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# Pairs up the substitution key with the evaluated condition result for substitution into the rule
|
40
|
-
# Example: If you have two dependency conditions with rule keys "A" and "B" in the rule "A or B"
|
41
|
-
# calling keyed_condition_pairs will return {:A => true, :B => false}
|
42
|
-
def keyed_conditions(response_set)
|
43
|
-
keyed_pairs = {}
|
44
|
-
# logger.debug dependency_conditions.inspect
|
45
|
-
self.dependency_conditions.each do |dc|
|
46
|
-
keyed_pairs.merge!(dc.to_hash(response_set))
|
47
|
-
end
|
48
|
-
return(keyed_pairs)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Does the substiution and evaluation of the dependency rule with the keyed pairs
|
52
|
-
def rule_evaluation(keyed_pairs)
|
53
|
-
# subtitute into rule for evaluation
|
54
|
-
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
|
26
|
+
# Has this dependency has been met in the context of response_set?
|
27
|
+
# Substitutes the conditions hash into the rule and evaluates it
|
28
|
+
def is_met?(response_set)
|
29
|
+
ch = conditions_hash(response_set)
|
30
|
+
return false if ch.blank?
|
55
31
|
# logger.debug "rule: #{self.rule.inspect}"
|
56
32
|
# logger.debug "rexp: #{rgx.inspect}"
|
57
|
-
# logger.debug "keyp: #{
|
58
|
-
# logger.debug "subd: #{self.rule.gsub(rgx){|m|
|
59
|
-
|
33
|
+
# logger.debug "keyp: #{ch.inspect}"
|
34
|
+
# logger.debug "subd: #{self.rule.gsub(rgx){|m| ch[m.to_sym]}}"
|
35
|
+
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
|
36
|
+
eval(self.rule.gsub(rgx){|m| ch[m.to_sym]})
|
37
|
+
end
|
38
|
+
|
39
|
+
# A hash of the conditions (keyed by rule_key) and their evaluation (boolean) in the context of response_set
|
40
|
+
def conditions_hash(response_set)
|
41
|
+
hash = {}
|
42
|
+
self.dependency_conditions.each{|dc| hash.merge!(dc.to_hash(response_set))}
|
43
|
+
return hash
|
60
44
|
end
|
61
45
|
|
62
46
|
end
|
data/app/models/question.rb
CHANGED
@@ -33,7 +33,7 @@ class Question < ActiveRecord::Base
|
|
33
33
|
self.dependency != nil
|
34
34
|
end
|
35
35
|
def triggered?(response_set)
|
36
|
-
dependent? ? self.dependency.
|
36
|
+
dependent? ? self.dependency.is_met?(response_set) : true
|
37
37
|
end
|
38
38
|
def css_class(response_set)
|
39
39
|
[(dependent? ? "dependent" : nil), (triggered?(response_set) ? nil : "hidden"), custom_class].compact.join(" ")
|
@@ -21,7 +21,7 @@ class QuestionGroup < ActiveRecord::Base
|
|
21
21
|
self.dependency != nil
|
22
22
|
end
|
23
23
|
def triggered?(response_set)
|
24
|
-
dependent? ? self.dependency.
|
24
|
+
dependent? ? self.dependency.is_met?(response_set) : true
|
25
25
|
end
|
26
26
|
def css_class(response_set)
|
27
27
|
[(dependent? ? "dependent" : nil), (triggered?(response_set) ? nil : "hidden"), custom_class].compact.join(" ")
|
data/app/models/response.rb
CHANGED
@@ -8,10 +8,7 @@ class Response < ActiveRecord::Base
|
|
8
8
|
|
9
9
|
# Validations
|
10
10
|
validates_presence_of :response_set_id, :question_id, :answer_id
|
11
|
-
|
12
|
-
# Named scopes
|
13
|
-
named_scope :in_section, lambda {|section_id| {:include => :question, :conditions => ['questions.survey_section_id =?', section_id.to_i ]}}
|
14
|
-
|
11
|
+
|
15
12
|
acts_as_response # includes "as" instance method
|
16
13
|
|
17
14
|
def selected
|
data/app/models/response_set.rb
CHANGED
@@ -100,11 +100,11 @@ class ResponseSet < ActiveRecord::Base
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def unanswered_dependencies
|
103
|
-
dependencies.select{|d| d.
|
103
|
+
dependencies.select{|d| d.is_met?(self) and self.has_not_answered_question?(d.question)}.map(&:question)
|
104
104
|
end
|
105
105
|
|
106
106
|
def all_dependencies
|
107
|
-
arr = dependencies.partition{|d| d.
|
107
|
+
arr = dependencies.partition{|d| d.is_met?(self) }
|
108
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
|
|
@@ -112,7 +112,8 @@ class ResponseSet < ActiveRecord::Base
|
|
112
112
|
|
113
113
|
def dependencies
|
114
114
|
question_ids = Question.find_all_by_survey_section_id(current_section_id).map(&:id)
|
115
|
-
|
115
|
+
depdendecy_ids = DependencyCondition.all(:conditions => {:question_id => question_ids}).map(&:dependency_id)
|
116
|
+
Dependency.find(depdendecy_ids, :include => :dependency_conditions)
|
116
117
|
end
|
117
118
|
end
|
118
119
|
|
data/app/models/survey.rb
CHANGED
data/app/models/validation.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
class Validation < ActiveRecord::Base
|
2
2
|
# Associations
|
3
3
|
belongs_to :answer
|
4
|
+
has_many :validation_conditions
|
4
5
|
|
5
6
|
# Scopes
|
6
7
|
|
@@ -10,4 +11,23 @@ class Validation < ActiveRecord::Base
|
|
10
11
|
validates_numericality_of :answer_id
|
11
12
|
|
12
13
|
# Instance Methods
|
14
|
+
def is_valid?(response_set)
|
15
|
+
ch = conditions_hash(response_set)
|
16
|
+
rgx = Regexp.new(self.validation_conditions.map{|vc| ["a","o"].include?(vc.rule_key) ? "#{vc.rule_key}(?!nd|r)" : vc.rule_key}.join("|")) # exclude and, or
|
17
|
+
# logger.debug "v: #{self.inspect}"
|
18
|
+
# logger.debug "rule: #{self.rule.inspect}"
|
19
|
+
# logger.debug "rexp: #{rgx.inspect}"
|
20
|
+
# logger.debug "keyp: #{ch.inspect}"
|
21
|
+
# logger.debug "subd: #{self.rule.gsub(rgx){|m| ch[m.to_sym]}}"
|
22
|
+
eval(self.rule.gsub(rgx){|m| ch[m.to_sym]})
|
23
|
+
end
|
24
|
+
|
25
|
+
# A hash of the conditions (keyed by rule_key) and their evaluation (boolean) in the context of response_set
|
26
|
+
def conditions_hash(response_set)
|
27
|
+
hash = {}
|
28
|
+
response = response_set.responses.detect{|r| r.answer_id.to_i == self.answer_id.to_i}
|
29
|
+
# logger.debug "r: #{response.inspect}"
|
30
|
+
self.validation_conditions.each{|vc| hash.merge!(vc.to_hash(response))}
|
31
|
+
return hash
|
32
|
+
end
|
13
33
|
end
|
@@ -13,27 +13,29 @@ class ValidationCondition < ActiveRecord::Base
|
|
13
13
|
validates_inclusion_of :operator, :in => OPERATORS
|
14
14
|
validates_uniqueness_of :rule_key, :scope => :validation_id
|
15
15
|
|
16
|
+
acts_as_response # includes "as" instance method
|
17
|
+
|
16
18
|
# Class methods
|
17
19
|
def self.operators
|
18
20
|
OPERATORS
|
19
21
|
end
|
20
22
|
|
21
23
|
# Instance Methods
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
24
|
+
def to_hash(response)
|
25
|
+
{rule_key.to_sym => (response.nil? ? false : self.is_valid?(response))}
|
26
|
+
end
|
27
|
+
|
28
|
+
def is_valid?(response)
|
29
|
+
klass = response.answer.response_class
|
30
|
+
case self.operator
|
31
|
+
when "==", "<", ">", "<=", ">="
|
32
|
+
response.as(klass).send(self.operator, self.as(klass))
|
33
|
+
when "!="
|
34
|
+
!(response.as(klass) == self.as(klass))
|
35
|
+
when "=~"
|
36
|
+
!(response.as(klass).to_s =~ Regexp.new(self.regexp || "")).nil?
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
39
41
|
end
|
@@ -25,12 +25,16 @@ class SurveyorGenerator < Rails::Generator::Base
|
|
25
25
|
# not using m.migration_template because all migration timestamps end up the same, causing a collision when running rake db:migrate
|
26
26
|
# coped functionality from RAILS_GEM_PATH/lib/rails_generator/commands.rb
|
27
27
|
m.directory "db/migrate"
|
28
|
-
[
|
29
|
-
|
30
|
-
|
28
|
+
[ "create_surveys", "create_survey_sections", "create_questions", "create_question_groups", "create_answers",
|
29
|
+
"create_response_sets", "create_responses",
|
30
|
+
"create_dependencies", "create_dependency_conditions",
|
31
|
+
"create_validations", "create_validation_conditions",
|
32
|
+
"add_display_order_to_surveys"].each_with_index do |model, i|
|
33
|
+
unless (prev_migrations = Dir.glob("db/migrate/[0-9]*_*.rb").grep(/[0-9]+_#{model}.rb$/)).empty?
|
34
|
+
prev_migration_timestamp = prev_migrations[0].match(/([0-9]+)_#{model}.rb$/)[1]
|
31
35
|
end
|
32
|
-
# raise "Another migration is already named
|
33
|
-
m.template("migrate
|
36
|
+
# raise "Another migration is already named #{model}" if not Dir.glob("db/migrate/[0-9]*_*.rb").grep(/[0-9]+_#{model}.rb$/).empty?
|
37
|
+
m.template("migrate/#{model}.rb", "db/migrate/#{(prev_migration_timestamp || Time.now.utc.strftime("%Y%m%d%H%M%S").to_i + i).to_s}_#{model}.rb")
|
34
38
|
end
|
35
39
|
|
36
40
|
# Generate CSS
|
@@ -23,7 +23,7 @@ survey "“Kitchen Sink” survey" do
|
|
23
23
|
|
24
24
|
# A dependent question, with conditions and rule to logically join them
|
25
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
|
26
|
+
# question reference identifiers used in conditions need to be unique on a survey for the lookups to work
|
27
27
|
q_2a "Please explain why you don't like this color?"
|
28
28
|
a_1 "explanation", :text
|
29
29
|
dependency :rule => "A or B or C or D"
|
@@ -62,22 +62,33 @@ survey "“Kitchen Sink” survey" do
|
|
62
62
|
a "what", :string
|
63
63
|
a "where", :string
|
64
64
|
|
65
|
-
# Various types of
|
65
|
+
# Various types of responses can be accepted, and validated
|
66
66
|
q "How many pets do you own?"
|
67
67
|
a :integer
|
68
|
+
validation :rule => "A"
|
69
|
+
condition_A ">=", :integer_value => 0
|
68
70
|
|
69
71
|
# Surveys, sections, questions, groups, and answers also take a custom css class for covenience in custom styling
|
70
72
|
q "What is your address?", :custom_class => 'address'
|
71
73
|
a :text, :custom_class => 'mapper'
|
74
|
+
# validations can use regexp values
|
75
|
+
validation :rule => "A"
|
76
|
+
condition_A "=~", :regexp => /[0-9a-zA-z\. #]/
|
72
77
|
|
73
78
|
# Questions, groups, and answers take a custom renderer (a partial in the application's views dir)
|
74
79
|
# defaults are "/partials/question_group", "/partials/question", "/partials/answer", so the custom renderers should have a different name
|
75
80
|
q "Pick your favorite date AND time" #, :custom_renderer => "/partials/custom_question"
|
76
81
|
a :datetime
|
77
82
|
|
78
|
-
|
79
|
-
|
83
|
+
q_time_lunch "What time do you usually take a lunch break?"
|
84
|
+
a_1 :time
|
80
85
|
|
86
|
+
# # validation conditions can look up the response to another question/answer pair
|
87
|
+
# q_time_dinner "What time do you usually take a dinner break?"
|
88
|
+
# a :time
|
89
|
+
# validation :rule => "A"
|
90
|
+
# condition_A ">=", :question_reference => "time_lunch", :answer_reference => "1"
|
91
|
+
|
81
92
|
q "When would you like to meet for dinner?"
|
82
93
|
a :date
|
83
94
|
|
data/lib/surveyor.rb
CHANGED
@@ -5,4 +5,20 @@ require 'surveyor/config'
|
|
5
5
|
require 'surveyor/acts_as_response'
|
6
6
|
|
7
7
|
module Surveyor
|
8
|
+
RAND_CHARS = [('a'..'z'), ('A'..'Z'), (0..9)].map(&:to_a).flatten.to_s
|
9
|
+
|
10
|
+
def self.make_tiny_code(len = 10)
|
11
|
+
len.times.map{|i| RAND_CHARS[rand(RAND_CHARS.size), 1] }.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.to_normalized_string(text)
|
15
|
+
words_to_omit = %w(a be but has have in is it of on or the to when)
|
16
|
+
col_text = text.gsub(/(<[^>]*>)|\n|\t/s, ' ') # Remove html tags
|
17
|
+
col_text.downcase! # Remove capitalization
|
18
|
+
col_text.gsub!(/\"|\'/, '') # Remove potential problem characters
|
19
|
+
col_text.gsub!(/\(.*?\)/,'') # Remove text inside parens
|
20
|
+
col_text.gsub!(/\W/, ' ') # Remove all other non-word characters
|
21
|
+
cols = (col_text.split(' ') - words_to_omit)
|
22
|
+
(cols.size > 5 ? cols[-5..-1] : cols).join("_")
|
23
|
+
end
|
8
24
|
end
|
data/script/surveyor/answer.rb
CHANGED
@@ -1,75 +1,52 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class Answer
|
4
|
-
include Columnizer
|
5
|
-
|
1
|
+
class Answer < SurveyParser::Base
|
6
2
|
# Context, Content, Reference, Display
|
7
3
|
attr_accessor :id, :parser, :question_id
|
8
4
|
attr_accessor :text, :short_text, :help_text, :weight, :response_class
|
9
5
|
attr_accessor :reference_identifier, :data_export_identifier, :common_namespace, :common_identitier
|
10
6
|
attr_accessor :display_order, :is_exclusive, :hide_label, :display_length, :custom_class, :custom_renderer
|
11
|
-
|
12
|
-
def initialize(question, args, options)
|
13
|
-
self.parser = question ? question.parser : nil
|
14
|
-
self.id = parser ? parser.new_answer_id : nil
|
15
|
-
self.question_id = question ? question.id : nil
|
7
|
+
attr_accessor :validation
|
16
8
|
|
17
|
-
|
18
|
-
|
19
|
-
self.default_options(args_options[:text]).merge(options).merge(args_options).each{|key,value| self.instance_variable_set("@#{key}", value)}
|
20
|
-
end
|
21
|
-
|
22
|
-
def default_options(text)
|
23
|
-
{ :short_text => text,
|
24
|
-
:data_export_identifier => Columnizer.to_normalized_column(text),
|
25
|
-
:is_exclusive => false,
|
9
|
+
def default_options
|
10
|
+
{ :is_exclusive => false,
|
26
11
|
:hide_label => false,
|
27
12
|
:response_class => "answer"
|
28
13
|
}
|
29
14
|
end
|
30
15
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
elsif a0.is_a?(String)
|
40
|
-
a1.is_a?(Symbol) ? {:text => a0, :response_class => a1.to_s}.merge(a2 || {}) : {:text => a0}.merge(a1 || {})
|
41
|
-
|
42
|
-
# (Symbol, Hash) or (Symbol, Symbol, Hash)
|
43
|
-
elsif a0.is_a?(Symbol)
|
44
|
-
shortcuts = case a0
|
45
|
-
when :other
|
46
|
-
{:text => "Other"}
|
47
|
-
when :other_and_string
|
48
|
-
{:text => "Other", :response_class => "string"}
|
49
|
-
when :none, :omit #a disabler erases and disables all other answer options (text, checkbox, dropdowns, etc). Unchecking the omit box is the only way to enable other options (except in the case limit => :one)
|
50
|
-
{:text => a0.to_s.humanize, :is_exclusive => true} # "omit" is no longer a response class... it's treated as any other answer type
|
51
|
-
when :integer, :date, :time, :datetime, :text, :datetime, :string
|
52
|
-
{:text => a0.to_s.humanize, :response_class => a0.to_s, :hide_label => true}
|
53
|
-
else
|
54
|
-
{:text => a0.to_s.humanize}
|
55
|
-
end
|
56
|
-
a1.is_a?(Symbol) ? shortcuts.merge({:response_class => a1.to_s}).merge(a2 || {}) : shortcuts.merge(a1 || {})
|
16
|
+
def parse_args(args)
|
17
|
+
case args[0]
|
18
|
+
when Hash # Hash
|
19
|
+
text_args(args[0][:text]).merge(args[0])
|
20
|
+
when String # (String, Hash) or (String, Symbol, Hash)
|
21
|
+
text_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
|
22
|
+
when Symbol # (Symbol, Hash) or (Symbol, Symbol, Hash)
|
23
|
+
symbol_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
|
57
24
|
else
|
58
|
-
|
25
|
+
text_args(nil)
|
59
26
|
end
|
60
27
|
end
|
61
|
-
|
62
|
-
def
|
63
|
-
|
28
|
+
|
29
|
+
def text_args(text = "Answer")
|
30
|
+
{:text => text.to_s, :short_text => text, :data_export_identifier => Surveyor.to_normalized_string(text)}
|
64
31
|
end
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
32
|
+
def hash_from(arg)
|
33
|
+
arg.is_a?(Symbol) ? {:response_class => arg.to_s} : arg.is_a?(Hash) ? arg : {}
|
34
|
+
end
|
35
|
+
def symbol_args(arg)
|
36
|
+
case arg
|
37
|
+
when :other
|
38
|
+
text_args("Other")
|
39
|
+
when :other_and_string
|
40
|
+
text_args("Other").merge({:response_class => "string"})
|
41
|
+
when :none, :omit # is_exclusive erases and disables other checkboxes and input elements
|
42
|
+
text_args(arg.to_s.humanize).merge({:is_exclusive => true})
|
43
|
+
when :integer, :date, :time, :datetime, :text, :datetime, :string
|
44
|
+
text_args(arg.to_s.humanize).merge({:response_class => arg.to_s, :hide_label => true})
|
45
|
+
end
|
69
46
|
end
|
70
|
-
|
71
47
|
def to_file
|
72
|
-
|
48
|
+
super
|
49
|
+
if self.validation then self.validation.to_file end
|
73
50
|
end
|
74
51
|
|
75
52
|
end
|