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 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.6.10'
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.6.10', :source => 'http://gemcutter.org'
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.6.10
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.in_order
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)
@@ -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| {:include => :dependency_conditions, :conditions => {:dependency_conditions => {:question_id => 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|\)|\(|\d|\s)+$/ #TODO properly formed parenthesis etc.
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("rexp: #{rgx.inspect} FOO: #{keyed_pairs.inspect} --- subbed rules: #{rule.gsub(rgx){|m| keyed_pairs[m.to_sym]}} --> #{eval(self.rule.gsub(rgx){|m| keyed_pairs[m.to_sym]})}")
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
 
@@ -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 = "default"
26
- self.pick = "none"
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 = "inline"
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
@@ -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,7 @@
1
1
  class SurveySection < ActiveRecord::Base
2
2
 
3
3
  # Associations
4
- has_many :questions
4
+ has_many :questions, :order => "display_order ASC"
5
5
  belongs_to :survey
6
6
 
7
7
  # Scopes
@@ -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 :common_identitier # maping to a common vocab
18
+ t.string :common_identifier # maping to a common vocab
19
19
 
20
20
  # Display
21
21
  t.integer :display_order
@@ -3,6 +3,7 @@ class CreateDependencies < ActiveRecord::Migration
3
3
  create_table :dependencies do |t|
4
4
  # Context
5
5
  t.integer :question_id # the dependent question
6
+ t.integer :question_group_id
6
7
 
7
8
  # Conditional
8
9
  t.string :rule
@@ -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 :common_identitier # maping to a common vocab
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 :common_identitier # maping to a common vocab
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 :common_identitier # maping to a common vocab
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 :common_identitier # maping to a common vocab
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 "&#8220;Kitchen Sink&#8221; 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 # :other is a custom answer symbol type, it has associated pre-sets with it
24
-
25
- question_2 "Choose the colors you don't like", :pick => :any
26
- answer_1 "red"
27
- answer_2 "blue"
28
- answer_3 "green"
29
- answer_4 "yellow"
30
- answer :omit
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 "&#8220;Kitchen Sink&#8221; survey" do
37
32
  condition_C :q_2, "==", :a_3
38
33
  condition_D :q_2, "==", :a_4
39
34
 
40
- # question definitions can be abreviated as shown below
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
- q "Give your response"
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
- q "How many pets do you own?"
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 would you like to meet?"
59
+ q "What time do you usually take a lunch break?"
66
60
  a :time
67
61
 
68
- q "What date would you like to meet?"
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{ |num| a num.to_s}
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, :unit => "F"
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, :hide_label => true
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 "&#8220;Kitchen Sink&#8221; 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 "&#8220;Kitchen Sink&#8221; 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 "&#8220;Kitchen Sink&#8221; 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
- a "|pizza", :integer
168
- a "|salad", :integer
169
- a "|sushi", :integer
170
- a "|ice cream", :integer
171
- a "|breakfast ceral", :integer
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 "&#8220;Kitchen Sink&#8221; 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, :unit => "years"
184
+ a "Age|years", :integer
198
185
  end
199
186
 
200
187
  end
@@ -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 || String, Symbol, 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 || Symbol, 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 << %( id: #{@id})
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
- self.question_id = question.id
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 =[ %(#{question_id}_#{@id}:) ]
30
- out << %( id: #{@id})
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 =[ %(#{@question_id}_#{@dependency_id}_#{id}:) ]
33
- out << %( id: #{@id})
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} in Survey: #{Survey.current_survey.title}"
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
@@ -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 << %( id: #{@id})
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, :section_id, :section, :parser
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 << %( id: #{@id})
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
 
@@ -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 << %( id: #{@id})
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
- self.current_question.dependency = (self.current_dependency = Dependency.new(current_question, args, options))
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 = {:reference_identifier => reference_identifier}
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
- question = nil
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 << %( id: #{@id})
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.6.10"
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-16}
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.6.10
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-16 00:00:00 -05:00
13
+ date: 2009-10-20 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency