surveyor 0.6.1
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/.gitignore +6 -0
- data/MIT-LICENSE +20 -0
- data/README.md +104 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/app/controllers/surveyor_controller.rb +117 -0
- data/app/helpers/survey_form_builder.rb +37 -0
- data/app/helpers/surveyor_helper.rb +66 -0
- data/app/models/answer.rb +21 -0
- data/app/models/dependency.rb +46 -0
- data/app/models/dependency_condition.rb +79 -0
- data/app/models/question.rb +54 -0
- data/app/models/question_group.rb +18 -0
- data/app/models/response.rb +47 -0
- data/app/models/response_set.rb +185 -0
- data/app/models/survey.rb +57 -0
- data/app/models/survey_section.rb +15 -0
- data/app/views/layouts/surveyor_default.html.erb +13 -0
- data/app/views/partials/_answer.html.haml +49 -0
- data/app/views/partials/_question.html.haml +73 -0
- data/app/views/partials/_question_group.html.haml +41 -0
- data/app/views/surveyor/edit.html.haml +32 -0
- data/app/views/surveyor/new.html.haml +17 -0
- data/app/views/surveyor/show.html.haml +12 -0
- data/config/routes.rb +10 -0
- data/generators/surveyor/EXTENDING_SURVEYOR +12 -0
- data/generators/surveyor/extend_surveyor_generator.rb +22 -0
- data/generators/surveyor/surveyor_generator.rb +60 -0
- data/generators/surveyor/templates/README +10 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_leftright.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_updown.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_close.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_doc.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_closed.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_open.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_minus.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_plus.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_resize_se.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_35x9_colorpicker_indicator.gif.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_down.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_left.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_right.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_up.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_leftright.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_updown.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_close.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_doc.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_closed.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_open.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_minus.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_plus.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_down.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_left.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_right.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_up.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_leftright.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_updown.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_close.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_doc.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_closed.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_open.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_minus.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_plus.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_down.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_left.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_right.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_up.gif +0 -0
- data/generators/surveyor/templates/assets/images/dadada_40x100_textures_02_glass_75.png +0 -0
- data/generators/surveyor/templates/assets/images/e6e6e6_40x100_textures_02_glass_75.png +0 -0
- data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_01_flat_0.png +0 -0
- data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_02_glass_65.png +0 -0
- data/generators/surveyor/templates/assets/javascripts/accessibleUISlider.jQuery.js +201 -0
- data/generators/surveyor/templates/assets/javascripts/jquery-1.2.6.js +3549 -0
- data/generators/surveyor/templates/assets/javascripts/jquery-ui-personalized-1.5.3.js +7616 -0
- data/generators/surveyor/templates/assets/javascripts/jquery.form.js +637 -0
- data/generators/surveyor/templates/assets/javascripts/surveyor.js +28 -0
- data/generators/surveyor/templates/assets/stylesheets/jquery-ui-slider-additions.css +71 -0
- data/generators/surveyor/templates/assets/stylesheets/reset.css +46 -0
- data/generators/surveyor/templates/assets/stylesheets/sass/surveyor.sass +245 -0
- data/generators/surveyor/templates/assets/stylesheets/surveyor.css +231 -0
- data/generators/surveyor/templates/assets/stylesheets/ui.theme.css +851 -0
- data/generators/surveyor/templates/extensions/survey_extensions.rb +18 -0
- data/generators/surveyor/templates/extensions/surveyor_controller_extensions.rb +28 -0
- data/generators/surveyor/templates/extensions/surveyor_custom.html.erb +13 -0
- data/generators/surveyor/templates/extensions/surveyor_helper_extensions.rb +18 -0
- data/generators/surveyor/templates/initializers/haml.rb +8 -0
- data/generators/surveyor/templates/initializers/surveyor.rb +11 -0
- data/generators/surveyor/templates/migrate/create_answers.rb +45 -0
- data/generators/surveyor/templates/migrate/create_dependencies.rb +21 -0
- data/generators/surveyor/templates/migrate/create_dependency_conditions.rb +29 -0
- data/generators/surveyor/templates/migrate/create_question_groups.rb +18 -0
- data/generators/surveyor/templates/migrate/create_questions.rb +33 -0
- data/generators/surveyor/templates/migrate/create_response_sets.rb +22 -0
- data/generators/surveyor/templates/migrate/create_responses.rb +33 -0
- data/generators/surveyor/templates/migrate/create_survey_sections.rb +25 -0
- data/generators/surveyor/templates/migrate/create_surveys.rb +25 -0
- data/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +201 -0
- data/generators/surveyor/templates/tasks/surveyor.rb +4 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/lib/surveyor.rb +7 -0
- data/lib/surveyor/config.rb +45 -0
- data/lib/tasks/surveyor_tasks.rake +33 -0
- data/lib/tiny_code.rb +58 -0
- data/lib/xml_formatter.rb +12 -0
- data/script/surveyor/answer.rb +84 -0
- data/script/surveyor/columnizer.rb +36 -0
- data/script/surveyor/dependency.rb +43 -0
- data/script/surveyor/dependency_condition.rb +74 -0
- data/script/surveyor/question.rb +76 -0
- data/script/surveyor/question_group.rb +33 -0
- data/script/surveyor/specs/answer_spec.rb +66 -0
- data/script/surveyor/specs/question_dependency_spec.rb +46 -0
- data/script/surveyor/specs/question_group_spec.rb +9 -0
- data/script/surveyor/specs/question_spec.rb +111 -0
- data/script/surveyor/specs/section_spec.rb +58 -0
- data/script/surveyor/survey.rb +108 -0
- data/script/surveyor/survey_parser.rb +64 -0
- data/script/surveyor/survey_section.rb +153 -0
- data/script/surveyor/whr_dsl.tmproj +244 -0
- data/spec/controllers/surveyor_controller_spec.rb +328 -0
- data/spec/factories.rb +107 -0
- data/spec/models/answer_spec.rb +29 -0
- data/spec/models/dependency_condition_spec.rb +338 -0
- data/spec/models/dependency_spec.rb +82 -0
- data/spec/models/question_group_spec.rb +11 -0
- data/spec/models/question_spec.rb +75 -0
- data/spec/models/response_set_spec.rb +153 -0
- data/spec/models/response_spec.rb +94 -0
- data/spec/models/survey_section_spec.rb +34 -0
- data/spec/models/survey_spec.rb +72 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +14 -0
- data/surveyor.gemspec +187 -0
- data/uninstall.rb +1 -0
- metadata +211 -0
data/init.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Init hook code here
|
data/install.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Install hook code here
|
data/lib/surveyor.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Surveyor
|
|
2
|
+
#
|
|
3
|
+
# The Surveyor::Config object emulates a hash with simple bracket methods
|
|
4
|
+
# which allow you to get and set values in the configuration table:
|
|
5
|
+
#
|
|
6
|
+
# Surveyor::Config['setting.name'] = 'value'
|
|
7
|
+
# Surveyor::Config['setting.name'] #=> "value"
|
|
8
|
+
#
|
|
9
|
+
# Currently, there is not a way to edit configuration through the admin
|
|
10
|
+
# system so it must be done manually. The console script is probably the
|
|
11
|
+
# easiest way to this:
|
|
12
|
+
#
|
|
13
|
+
# % script/console production
|
|
14
|
+
# Loading production environment.
|
|
15
|
+
# >> Surveyor::Config['setting.name'] = 'value'
|
|
16
|
+
# => "value"
|
|
17
|
+
# >>
|
|
18
|
+
#
|
|
19
|
+
# Surveyor currently uses the following settings:
|
|
20
|
+
#
|
|
21
|
+
# defaults.title :: the title of the survey system
|
|
22
|
+
# defaults.layout :: the layout used by the survey system
|
|
23
|
+
|
|
24
|
+
class Config
|
|
25
|
+
@@config_hash = {}
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
def [](key)
|
|
29
|
+
@@config_hash[key]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def []=(key, value)
|
|
33
|
+
@@config_hash[key] = value
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_hash
|
|
37
|
+
@@config_hash
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def run
|
|
41
|
+
yield self if block_given?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
desc "generate and load survey (specify FILE=surveys/your_survey.rb)"
|
|
2
|
+
task :surveyor => :"surveyor:default"
|
|
3
|
+
|
|
4
|
+
namespace :surveyor do
|
|
5
|
+
|
|
6
|
+
task :default => [:generate_fixtures, :load_fixtures]
|
|
7
|
+
|
|
8
|
+
desc "generate survey fixtures from survey file"
|
|
9
|
+
task :generate_fixtures => :environment do
|
|
10
|
+
require File.join(File.dirname(__FILE__), "../../script/surveyor/survey_parser")
|
|
11
|
+
raise "USAGE: file name required e.g. 'FILE=surveys/kitchen_sink_survey.rb'" if ENV["FILE"].blank?
|
|
12
|
+
fixture_dir = File.join(RAILS_ROOT, "surveys", "fixtures")
|
|
13
|
+
mkdir fixture_dir unless File.exists?(fixture_dir)
|
|
14
|
+
SurveyParser.parse(File.join(RAILS_ROOT, ENV["FILE"]))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "load survey fixtures"
|
|
18
|
+
task :load_fixtures => :environment do
|
|
19
|
+
require 'active_record/fixtures'
|
|
20
|
+
|
|
21
|
+
ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
|
|
22
|
+
|
|
23
|
+
fixture_dir = File.join(RAILS_ROOT, "surveys", "fixtures")
|
|
24
|
+
fixtures = Dir.glob("#{fixture_dir}/*.yml")
|
|
25
|
+
raise "No fixtures found." if fixtures.empty?
|
|
26
|
+
|
|
27
|
+
fixtures.each do |file_name|
|
|
28
|
+
puts "Loading #{file_name}..."
|
|
29
|
+
Fixtures.create_fixtures(fixture_dir, File.basename(file_name, '.*'))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
data/lib/tiny_code.rb
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module TinyCode
|
|
2
|
+
|
|
3
|
+
module ClassMethods
|
|
4
|
+
|
|
5
|
+
RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvwxyz"
|
|
6
|
+
|
|
7
|
+
def make_tiny_code
|
|
8
|
+
random_string(10)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def random_string(len)
|
|
12
|
+
rand_max = RAND_CHARS.size
|
|
13
|
+
ret = ""
|
|
14
|
+
len.times{ ret << RAND_CHARS[rand(rand_max)] }
|
|
15
|
+
ret
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def self.to_normalized_string(text)
|
|
20
|
+
words_to_omit = ["a", "to", "the", "of", "has", "have", "it", "is", "in", "on", "or", "but", "when", "be"]
|
|
21
|
+
|
|
22
|
+
# strip all the html tags from the text data
|
|
23
|
+
col_text = text.gsub(/(<[^>]*>)|\n|\t/s, ' ')
|
|
24
|
+
|
|
25
|
+
# Removing capitalization
|
|
26
|
+
col_text.downcase!
|
|
27
|
+
# Removing potential problem characters
|
|
28
|
+
col_text.gsub!(/\"|\'/, '')
|
|
29
|
+
# Removing text inside parens
|
|
30
|
+
col_text.gsub!(/\(.*?\)/,'')
|
|
31
|
+
|
|
32
|
+
# Removing all other non-word characters
|
|
33
|
+
col_text.gsub!(/\W/, ' ')
|
|
34
|
+
|
|
35
|
+
column_words = []
|
|
36
|
+
words = col_text.split(' ')
|
|
37
|
+
words.each do |word|
|
|
38
|
+
if !words_to_omit.include?(word)
|
|
39
|
+
column_words << word
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#reducing the word list to limit column length
|
|
44
|
+
if column_words.length > 5
|
|
45
|
+
column_words.slice!(0, column_words.length - 5)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
#re-assemble the string
|
|
49
|
+
column_words.join("_")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.included(klass)
|
|
55
|
+
klass.extend(ClassMethods)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module XmlFormatter
|
|
2
|
+
def to_xml(options = {})
|
|
3
|
+
options[:indent] ||= 2
|
|
4
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
|
5
|
+
xml.instruct! unless options[:skip_instruct]
|
|
6
|
+
xml.tag!(self.class.name.downcase.to_sym, self.attributes) do
|
|
7
|
+
self.class.reflect_on_all_associations.to_a.each do |assoc|
|
|
8
|
+
xml.tag!(assoc.name)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/columnizer'
|
|
2
|
+
|
|
3
|
+
class Answer
|
|
4
|
+
include Columnizer
|
|
5
|
+
|
|
6
|
+
# Context, Content, Display, Reference
|
|
7
|
+
attr_accessor :id, :question_id, :parser
|
|
8
|
+
attr_accessor :text, :short_text, :help_text, :numerical_value
|
|
9
|
+
attr_accessor :response_class, :display_order, :is_exclusive, :is_a_disabler, :hide_label
|
|
10
|
+
attr_accessor :reference_identifier, :data_export_identifier
|
|
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
|
|
16
|
+
|
|
17
|
+
#self.text is set in args
|
|
18
|
+
args_options = parse_args_options(args)
|
|
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,
|
|
26
|
+
:is_a_disabler => false,
|
|
27
|
+
:hide_label => false,
|
|
28
|
+
:response_class => "answer"
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def parse_args_options(args)
|
|
33
|
+
a0, a1, a2 = args
|
|
34
|
+
|
|
35
|
+
# Hash
|
|
36
|
+
if a0.is_a?(Hash)
|
|
37
|
+
{:text => "Answer"}.merge(a0)
|
|
38
|
+
|
|
39
|
+
# String, Hash || String, Symbol, Hash
|
|
40
|
+
elsif a0.is_a?(String)
|
|
41
|
+
a1.is_a?(Symbol) ? {:text => a0, :response_class => a1.to_s}.merge(a2 || {}) : {:text => a0}.merge(a1 || {})
|
|
42
|
+
|
|
43
|
+
# Symbol, Hash || Symbol, Symbol, Hash
|
|
44
|
+
elsif a0.is_a?(Symbol)
|
|
45
|
+
shortcuts = case a0
|
|
46
|
+
when :other
|
|
47
|
+
{:text => "Other"}
|
|
48
|
+
when :other_and_string
|
|
49
|
+
{:text => "Other", :response_class => "string"}
|
|
50
|
+
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)
|
|
51
|
+
{:text => a0.to_s.humanize, :is_exclusive => true} # "omit" is no longer a response class... it's treated as any other answer type
|
|
52
|
+
when :integer, :date, :time, :datetime, :text, :datetime, :string
|
|
53
|
+
{:text => a0.to_s.humanize, :response_class => a0.to_s, :hide_label => true}
|
|
54
|
+
else
|
|
55
|
+
{:text => a0.to_s.humanize}
|
|
56
|
+
end
|
|
57
|
+
a1.is_a?(Symbol) ? shortcuts.merge({:response_class => a1.to_s}).merge(a2 || {}) : shortcuts.merge(a1 || {})
|
|
58
|
+
else
|
|
59
|
+
{:text => "Answer"}
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
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 << %( display_order: #{display_order} )
|
|
73
|
+
out << %( is_exclusive: #{@is_exclusive})
|
|
74
|
+
out << %( hide_label: #{@hide_label})
|
|
75
|
+
out << %( reference_identifier: #{@reference_identifier})
|
|
76
|
+
out << %( data_export_identifier: "#{@data_export_identifier}")
|
|
77
|
+
(out << nil ).join("\r\n")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def to_file
|
|
81
|
+
File.open(self.parser.answers_yml, File::CREAT|File::APPEND|File::WRONLY){ |f| f << to_yml }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Columnizer
|
|
2
|
+
|
|
3
|
+
def self.to_normalized_column(text)
|
|
4
|
+
words_to_omit = ["a", "to", "the", "of", "has", "have", "it", "is", "in", "on", "or", "but", "when", "be"]
|
|
5
|
+
|
|
6
|
+
# strip all the html tags from the text data
|
|
7
|
+
col_text = text.gsub(/(<[^>]*>)|\n|\t/s, ' ')
|
|
8
|
+
|
|
9
|
+
# Removing capitalization
|
|
10
|
+
col_text.downcase!
|
|
11
|
+
# Removing potential problem characters
|
|
12
|
+
col_text.gsub!(/\"|\'/, '')
|
|
13
|
+
# Removing text inside parens
|
|
14
|
+
col_text.gsub!(/\(.*?\)/,'')
|
|
15
|
+
|
|
16
|
+
# Removing all other non-word characters
|
|
17
|
+
col_text.gsub!(/\W/, ' ')
|
|
18
|
+
|
|
19
|
+
column_words = []
|
|
20
|
+
words = col_text.split(' ')
|
|
21
|
+
words.each do |word|
|
|
22
|
+
if !words_to_omit.include?(word)
|
|
23
|
+
column_words << word
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#reducing the word list to limit column length
|
|
28
|
+
if column_words.length > 5
|
|
29
|
+
column_words.slice!(0, column_words.length - 5)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#re-assemble the string
|
|
33
|
+
column_words.join("_")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
class Dependency
|
|
2
|
+
|
|
3
|
+
# Context, Conditional, Children
|
|
4
|
+
attr_accessor :id, :question_id, :parser
|
|
5
|
+
attr_accessor :rule
|
|
6
|
+
attr_accessor :dependency_conditions
|
|
7
|
+
|
|
8
|
+
# id, question, and rule required
|
|
9
|
+
def initialize(question, args, options)
|
|
10
|
+
self.parser = question.parser
|
|
11
|
+
self.id = parser.new_dependency_id
|
|
12
|
+
self.question_id = question.id
|
|
13
|
+
self.rule = (args[0] || {})[:rule]
|
|
14
|
+
self.dependency_conditions = []
|
|
15
|
+
self.default_options().merge(options).merge(args[1] || {}).each{|key,value| self.instance_variable_set("@#{key}", value)}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def default_options()
|
|
19
|
+
{}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Injecting the id of the current dependency object into the dependency_condition on assignment
|
|
23
|
+
def add_dependency_condition(dc_obj)
|
|
24
|
+
dc_obj.dependency_id = self.id
|
|
25
|
+
self.dependency_conditions << dc_obj
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_yml
|
|
29
|
+
out =[ %(#{question_id}_#{@id}:) ]
|
|
30
|
+
out << %( id: #{@id})
|
|
31
|
+
out << %( question_id: #{@question_id})
|
|
32
|
+
out << %( rule: "#{@rule}")
|
|
33
|
+
(out << nil ).join("\r\n")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_file
|
|
37
|
+
File.open(self.parser.dependencies_yml, File::CREAT|File::APPEND|File::WRONLY) {|f| f << to_yml}
|
|
38
|
+
self.dependency_conditions.compact.map(&:to_file)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
class DependencyCondition
|
|
2
|
+
|
|
3
|
+
# Context, Conditional, Value
|
|
4
|
+
attr_accessor :id, :dependency_id, :rule_key, :parser
|
|
5
|
+
attr_accessor :question_id, :operator
|
|
6
|
+
attr_accessor :answer_id, :datetime_value, :integer_value, :float_value, :unit, :text_value, :string_value, :response_other
|
|
7
|
+
attr_accessor :question_reference, :answer_reference
|
|
8
|
+
|
|
9
|
+
# id, dependency, and question_id required
|
|
10
|
+
def initialize(dependency, args, options)
|
|
11
|
+
self.parser = dependency.parser
|
|
12
|
+
self.id = parser.new_dependency_condition_id
|
|
13
|
+
self.dependency_id = dependency.id
|
|
14
|
+
self.rule_key = options[:reference_identifier]
|
|
15
|
+
|
|
16
|
+
args_options = parse_args_options(args)
|
|
17
|
+
self.default_options().merge(options).merge(args_options).each{|key,value| self.instance_variable_set("@#{key}", value)}
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def default_options()
|
|
22
|
+
{ :operator => "==" }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def parse_args_options(args)
|
|
26
|
+
a0, a1, a2 = args
|
|
27
|
+
options = {:question_reference => a0.to_s.gsub("q_", ""), :operator => a1}
|
|
28
|
+
a2.is_a?(Hash) ? options.merge(a2) : options.merge({:answer_reference => a2.to_s.gsub("a_", "")})
|
|
29
|
+
end
|
|
30
|
+
|
|
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}")
|
|
46
|
+
(out << nil ).join("\r\n")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def reconcile_dependencies
|
|
50
|
+
# 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...
|
|
53
|
+
if ref_question
|
|
54
|
+
@question_id = ref_question.id
|
|
55
|
+
ref_answer = ref_question.find_answer_by_reference(@answer_reference)
|
|
56
|
+
if ref_answer
|
|
57
|
+
@answer_id = ref_answer.id
|
|
58
|
+
else
|
|
59
|
+
raise "Could not find referenced answer #{@answer_reference}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
else
|
|
63
|
+
raise "Could not find referenced question #{@question_reference}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def to_file
|
|
68
|
+
# Reconciling the references used in the dsl to actual object ids
|
|
69
|
+
#puts "Reconcile of dependency:"
|
|
70
|
+
# reconcile_dependencies
|
|
71
|
+
File.open(self.parser.dependency_conditions_yml, File::CREAT|File::APPEND|File::WRONLY) {|f| f << to_yml}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/columnizer'
|
|
2
|
+
|
|
3
|
+
class Question
|
|
4
|
+
include Columnizer
|
|
5
|
+
|
|
6
|
+
# Context, Content, Display, Reference, Children
|
|
7
|
+
attr_accessor :id, :survey_section_id, :parser
|
|
8
|
+
attr_accessor :text, :short_text, :help_text
|
|
9
|
+
attr_accessor :pick, :display_type, :display_order, :question_group_id, :is_mandatory
|
|
10
|
+
attr_accessor :reference_identifier, :data_export_identifier
|
|
11
|
+
attr_accessor :answers, :dependency
|
|
12
|
+
|
|
13
|
+
def initialize(section, args, options)
|
|
14
|
+
self.parser = section.parser
|
|
15
|
+
self.id = parser.new_question_id
|
|
16
|
+
self.display_order = self.id
|
|
17
|
+
self.survey_section_id = section.id
|
|
18
|
+
self.text = args[0]
|
|
19
|
+
self.answers = []
|
|
20
|
+
self.dependency = nil
|
|
21
|
+
self.default_options(text).merge(options).merge(args[1] || {}).each{|key,value| self.instance_variable_set("@#{key}", value)}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def default_options(text)
|
|
25
|
+
{ :short_text => text,
|
|
26
|
+
:pick => :none,
|
|
27
|
+
:display_type => :default,
|
|
28
|
+
:is_mandatory => true,
|
|
29
|
+
:data_export_identifier => Columnizer.to_normalized_column(text)
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Injecting the id of this question object into the dependency object on assignment
|
|
34
|
+
def dependency=(dep)
|
|
35
|
+
unless dep.nil?
|
|
36
|
+
dep.question_id = self.id
|
|
37
|
+
end
|
|
38
|
+
@dependency = dep
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def find_answer_by_reference(ref_id)
|
|
42
|
+
answer = nil
|
|
43
|
+
count = 0
|
|
44
|
+
puts "Looking up answer with ref: #{ref_id}"
|
|
45
|
+
while answer.nil? and count < self.answers.size
|
|
46
|
+
answer = self.answers[count] if self.answers[count].reference_identifier == ref_id
|
|
47
|
+
count += 1
|
|
48
|
+
end
|
|
49
|
+
puts " found answer: '#{answer.text}' (id:#{answer.id})" unless answer.nil?
|
|
50
|
+
answer
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_yml
|
|
54
|
+
out =[ %(#{@data_export_identifier}_#{@id}:) ]
|
|
55
|
+
out << %( id: #{@id})
|
|
56
|
+
out << %( survey_section_id: #{@survey_section_id})
|
|
57
|
+
out << %( text: "#{@text}")
|
|
58
|
+
out << %( short_text: "#{@short_text}")
|
|
59
|
+
out << %( help_text: "#{@help_text}")
|
|
60
|
+
out << %( pick: #{pick})
|
|
61
|
+
out << %( display_type: #{display_type})
|
|
62
|
+
out << %( display_order: #{display_order})
|
|
63
|
+
out << %( question_group_id: #{question_group_id})
|
|
64
|
+
out << %( is_mandatory: #{@is_mandatory})
|
|
65
|
+
out << %( reference_identifier: #{@reference_identifier})
|
|
66
|
+
out << %( data_export_identifier: "#{@data_export_identifier}")
|
|
67
|
+
(out << nil ).join("\r\n")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_file
|
|
71
|
+
File.open(self.parser.questions_yml, File::CREAT|File::APPEND|File::WRONLY){ |f| f << to_yml }
|
|
72
|
+
self.answers.compact.map(&:to_file)
|
|
73
|
+
if self.dependency then self.dependency.to_file end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|