affectiva-surveyor 1.5.0.pre.disco.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +198 -0
- data/Gemfile +5 -0
- data/Gemfile.rails_version +27 -0
- data/MIT-LICENSE +20 -0
- data/README.md +166 -0
- data/Rakefile +106 -0
- data/app/controllers/surveyor_controller.rb +5 -0
- data/app/helpers/results_helper.rb +20 -0
- data/app/helpers/survey_form_builder.rb +37 -0
- data/app/helpers/surveyor_helper.rb +3 -0
- data/app/inputs/quiet_input.rb +5 -0
- data/app/inputs/surveyor_check_boxes_input.rb +35 -0
- data/app/inputs/surveyor_radio_input.rb +18 -0
- data/app/models/answer.rb +3 -0
- data/app/models/dependency.rb +3 -0
- data/app/models/dependency_condition.rb +3 -0
- data/app/models/question.rb +3 -0
- data/app/models/question_group.rb +4 -0
- data/app/models/response.rb +4 -0
- data/app/models/response_set.rb +3 -0
- data/app/models/survey.rb +3 -0
- data/app/models/survey_section.rb +4 -0
- data/app/models/survey_section_sweeper.rb +15 -0
- data/app/models/survey_translation.rb +4 -0
- data/app/models/validation.rb +3 -0
- data/app/models/validation_condition.rb +3 -0
- data/app/views/layouts/results.html.erb +13 -0
- data/app/views/layouts/surveyor_default.html.erb +12 -0
- data/app/views/partials/_answer.html.haml +25 -0
- data/app/views/partials/_dependents.html.haml +5 -0
- data/app/views/partials/_question.html.haml +28 -0
- data/app/views/partials/_question_group.html.haml +44 -0
- data/app/views/partials/_section.html.haml +12 -0
- data/app/views/partials/_section_menu.html.haml +12 -0
- data/app/views/surveyor/edit.html.haml +24 -0
- data/app/views/surveyor/export.json.rabl +85 -0
- data/app/views/surveyor/new.html.haml +24 -0
- data/app/views/surveyor/show.html.haml +74 -0
- data/app/views/surveyor/show.json.rabl +15 -0
- data/ci-exec.sh +56 -0
- data/config/routes.rb +8 -0
- data/cucumber.yml +10 -0
- data/doc/REPRESENTATIONS.md +34 -0
- data/doc/api_id_schema.json +7 -0
- data/doc/question types.png +0 -0
- data/doc/response_set_schema.json +54 -0
- data/doc/surveyor question combinations.png +0 -0
- data/doc/surveyor reject or delete decision matrix.png +0 -0
- data/doc/surveyor_models.png +0 -0
- data/doc/surveyor_models2.png +0 -0
- data/doc/surveyor_timestamp_schema.json +9 -0
- data/features/ajax_submissions.feature +140 -0
- data/features/export_to_json.feature +344 -0
- data/features/internationalization.feature +121 -0
- data/features/no_duplicates.feature +110 -0
- data/features/show_survey.feature +71 -0
- data/features/step_definitions/parser_steps.rb +145 -0
- data/features/step_definitions/surveyor_steps.rb +325 -0
- data/features/step_definitions/ui_steps.rb +25 -0
- data/features/step_definitions/web_steps.rb +225 -0
- data/features/support/REDCapDemoDatabase_DataDictionary.csv +127 -0
- data/features/support/database_cleaner.rb +16 -0
- data/features/support/env.rb +56 -0
- data/features/support/hooks.rb +4 -0
- data/features/support/paths.rb +39 -0
- data/features/support/redcap_new_headers.csv +1 -0
- data/features/support/redcap_siblings.csv +1 -0
- data/features/support/redcap_whitespace.csv +1 -0
- data/features/support/selectors.rb +39 -0
- data/features/support/simultaneous_ajax.rb +101 -0
- data/features/support/single_quit_selenium_driver.rb +23 -0
- data/features/support/slow_updates.rb +18 -0
- data/features/surveyor.feature +895 -0
- data/features/surveyor_dependencies.feature +476 -0
- data/features/surveyor_parser.feature +504 -0
- data/features/z_redcap_parser.feature +62 -0
- data/lib/assets/images/surveyor/next.gif +0 -0
- data/lib/assets/images/surveyor/prev.gif +0 -0
- data/lib/assets/images/surveyor/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/assets/images/surveyor/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/assets/images/surveyor/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/assets/images/surveyor/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/assets/images/surveyor/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/assets/images/surveyor/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/assets/images/surveyor/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/assets/images/surveyor/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/assets/images/surveyor/ui-icons_222222_256x240.png +0 -0
- data/lib/assets/images/surveyor/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/assets/images/surveyor/ui-icons_454545_256x240.png +0 -0
- data/lib/assets/images/surveyor/ui-icons_888888_256x240.png +0 -0
- data/lib/assets/images/surveyor/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/assets/javascripts/surveyor/jquery-1.9.0.js +9555 -0
- data/lib/assets/javascripts/surveyor/jquery-ui-1.10.0.custom.js +14850 -0
- data/lib/assets/javascripts/surveyor/jquery-ui-timepicker-addon.js +1919 -0
- data/lib/assets/javascripts/surveyor/jquery.maskedinput.js +338 -0
- data/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js +240 -0
- data/lib/assets/javascripts/surveyor/jquery.surveyor.js +154 -0
- data/lib/assets/stylesheets/surveyor.sass +132 -0
- data/lib/assets/stylesheets/surveyor/jquery-ui-1.10.0.custom.css +1174 -0
- data/lib/assets/stylesheets/surveyor/jquery-ui-timepicker-addon.css +11 -0
- data/lib/assets/stylesheets/surveyor/reset.css +48 -0
- data/lib/assets/stylesheets/surveyor/results.css +125 -0
- data/lib/assets/stylesheets/surveyor/ui.slider.extras.css +110 -0
- data/lib/generators/surveyor/custom_generator.rb +18 -0
- data/lib/generators/surveyor/install_generator.rb +101 -0
- data/lib/generators/surveyor/templates/app/assets/javascripts/surveyor_all.js +6 -0
- data/lib/generators/surveyor/templates/app/assets/stylesheets/surveyor_all.css +9 -0
- data/lib/generators/surveyor/templates/app/controllers/surveyor_controller.rb +40 -0
- data/lib/generators/surveyor/templates/app/views/layouts/surveyor_custom.html.erb +13 -0
- data/lib/generators/surveyor/templates/config/locales/surveyor_en.yml +19 -0
- data/lib/generators/surveyor/templates/config/locales/surveyor_es.yml +19 -0
- data/lib/generators/surveyor/templates/config/locales/surveyor_he.yml +19 -0
- data/lib/generators/surveyor/templates/config/locales/surveyor_ko.yml +19 -0
- data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/add_api_ids.rb +14 -0
- data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +12 -0
- data/lib/generators/surveyor/templates/db/migrate/add_correct_answer_id_to_questions.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/add_default_value_to_answers.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/add_display_order_to_surveys.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/add_display_type_to_answers.rb +14 -0
- data/lib/generators/surveyor/templates/db/migrate/add_index_to_response_sets.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/add_index_to_surveys.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/add_input_mask_attributes_to_answer.rb +12 -0
- data/lib/generators/surveyor/templates/db/migrate/add_section_id_to_responses.rb +12 -0
- data/lib/generators/surveyor/templates/db/migrate/add_unique_index_on_access_code_and_version_in_surveys.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/add_unique_indicies.rb +18 -0
- data/lib/generators/surveyor/templates/db/migrate/add_version_to_surveys.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/api_ids_must_be_unique.rb +23 -0
- data/lib/generators/surveyor/templates/db/migrate/create_answers.rb +38 -0
- data/lib/generators/surveyor/templates/db/migrate/create_dependencies.rb +23 -0
- data/lib/generators/surveyor/templates/db/migrate/create_dependency_conditions.rb +30 -0
- data/lib/generators/surveyor/templates/db/migrate/create_question_groups.rb +28 -0
- data/lib/generators/surveyor/templates/db/migrate/create_questions.rb +37 -0
- data/lib/generators/surveyor/templates/db/migrate/create_response_sets.rb +23 -0
- data/lib/generators/surveyor/templates/db/migrate/create_responses.rb +34 -0
- data/lib/generators/surveyor/templates/db/migrate/create_survey_sections.rb +30 -0
- data/lib/generators/surveyor/templates/db/migrate/create_survey_translations.rb +19 -0
- data/lib/generators/surveyor/templates/db/migrate/create_surveys.rb +32 -0
- data/lib/generators/surveyor/templates/db/migrate/create_validation_conditions.rb +33 -0
- data/lib/generators/surveyor/templates/db/migrate/create_validations.rb +21 -0
- data/lib/generators/surveyor/templates/db/migrate/drop_unique_index_on_access_code_in_surveys.rb +10 -0
- data/lib/generators/surveyor/templates/db/migrate/update_blank_api_ids_on_question_group.rb +22 -0
- data/lib/generators/surveyor/templates/db/migrate/update_blank_versions_on_surveys.rb +13 -0
- data/lib/generators/surveyor/templates/surveys/EXTENDING_SURVEYOR.md +52 -0
- data/lib/generators/surveyor/templates/surveys/MODIFYING_SURVEYOR.md +91 -0
- data/lib/generators/surveyor/templates/surveys/date_survey.rb +16 -0
- data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +280 -0
- data/lib/generators/surveyor/templates/surveys/languages.rb +14 -0
- data/lib/generators/surveyor/templates/surveys/quiz.rb +11 -0
- data/lib/generators/surveyor/templates/surveys/translations/languages.es.yml +18 -0
- data/lib/generators/surveyor/templates/surveys/translations/languages.he.yml +18 -0
- data/lib/generators/surveyor/templates/surveys/translations/languages.ko.yml +18 -0
- data/lib/generators/surveyor/templates/vendor/assets/stylesheets/custom.sass +5 -0
- data/lib/surveyor.rb +13 -0
- data/lib/surveyor/acts_as_response.rb +17 -0
- data/lib/surveyor/common.rb +59 -0
- data/lib/surveyor/engine.rb +10 -0
- data/lib/surveyor/helpers/asset_pipeline.rb +18 -0
- data/lib/surveyor/helpers/formtastic_custom_input.rb +13 -0
- data/lib/surveyor/helpers/surveyor_helper_methods.rb +103 -0
- data/lib/surveyor/models/answer_methods.rb +83 -0
- data/lib/surveyor/models/dependency_condition_methods.rb +69 -0
- data/lib/surveyor/models/dependency_methods.rb +57 -0
- data/lib/surveyor/models/question_group_methods.rb +58 -0
- data/lib/surveyor/models/question_methods.rb +112 -0
- data/lib/surveyor/models/response_methods.rb +126 -0
- data/lib/surveyor/models/response_set_methods.rb +188 -0
- data/lib/surveyor/models/survey_methods.rb +100 -0
- data/lib/surveyor/models/survey_section_methods.rb +53 -0
- data/lib/surveyor/models/survey_translation_methods.rb +30 -0
- data/lib/surveyor/models/validation_condition_methods.rb +54 -0
- data/lib/surveyor/models/validation_methods.rb +45 -0
- data/lib/surveyor/mustache_context.rb +11 -0
- data/lib/surveyor/parser.rb +427 -0
- data/lib/surveyor/redcap_parser.rb +288 -0
- data/lib/surveyor/surveyor_controller_methods.rb +236 -0
- data/lib/surveyor/unparser.rb +147 -0
- data/lib/surveyor/version.rb +3 -0
- data/lib/tasks/surveyor_tasks.rake +88 -0
- data/rails/init.rb +1 -0
- data/spec/controllers/surveyor_controller_spec.rb +311 -0
- data/spec/factories.rb +166 -0
- data/spec/helpers/formtastic_custom_input_spec.rb +15 -0
- data/spec/helpers/surveyor_helper_spec.rb +117 -0
- data/spec/lib/benchmark_spec.rb +22 -0
- data/spec/lib/chinese_survey.rb +14 -0
- data/spec/lib/common_spec.rb +34 -0
- data/spec/lib/parser_spec.rb +204 -0
- data/spec/lib/rake_kitchen_sink.rb +40 -0
- data/spec/lib/redcap_parser_spec.rb +75 -0
- data/spec/lib/tasks_spec.rake +26 -0
- data/spec/lib/unparser_spec.rb +126 -0
- data/spec/models/answer_spec.rb +174 -0
- data/spec/models/dependency_condition_spec.rb +439 -0
- data/spec/models/dependency_spec.rb +101 -0
- data/spec/models/question_group_spec.rb +93 -0
- data/spec/models/question_spec.rb +206 -0
- data/spec/models/response_set_spec.rb +477 -0
- data/spec/models/response_spec.rb +218 -0
- data/spec/models/survey_section_spec.rb +85 -0
- data/spec/models/survey_spec.rb +191 -0
- data/spec/models/validation_condition_spec.rb +113 -0
- data/spec/models/validation_spec.rb +74 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +56 -0
- data/stacktests.sh +65 -0
- data/surveyor.gemspec +53 -0
- metadata +601 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'surveyor/common'
|
2
|
+
require 'rabl'
|
3
|
+
|
4
|
+
module Surveyor
|
5
|
+
module Models
|
6
|
+
module SurveyMethods
|
7
|
+
def self.included(base)
|
8
|
+
# Associations
|
9
|
+
base.instance_eval {has_many :sections, ->{order "#{SurveySection.quoted_table_name}.display_order"}, :class_name => "SurveySection", :dependent => :destroy}
|
10
|
+
base.instance_eval {has_many :sections_with_questions, ->{includes(:questions).order("#{SurveySection.quoted_table_name}.display_order")}, :class_name => "SurveySection"}
|
11
|
+
base.send :has_many, :response_sets
|
12
|
+
base.send :has_many, :translations, :class_name => "SurveyTranslation"
|
13
|
+
|
14
|
+
# Scopes
|
15
|
+
base.instance_eval {scope :with_sections, ->{includes :sections}}
|
16
|
+
|
17
|
+
@@validations_already_included ||= nil
|
18
|
+
unless @@validations_already_included
|
19
|
+
# Validations
|
20
|
+
base.send :validates_presence_of, :title
|
21
|
+
base.send :validates_uniqueness_of, :survey_version, :scope => :access_code, :message => "survey with matching access code and version already exists"
|
22
|
+
|
23
|
+
@@validations_already_included = true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Derived attributes
|
27
|
+
base.send :before_save, :generate_access_code
|
28
|
+
base.send :before_save, :increment_version
|
29
|
+
|
30
|
+
# Class methods
|
31
|
+
base.instance_eval do
|
32
|
+
def to_normalized_string(value)
|
33
|
+
# replace non-alphanumeric with "-". remove repeat "-"s. don't start or end with "-"
|
34
|
+
value.to_s.downcase.gsub(/[^a-z0-9]/,"-").gsub(/-+/,"-").gsub(/-$|^-/,"")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Instance methods
|
40
|
+
def initialize(*args)
|
41
|
+
super(*args)
|
42
|
+
default_args
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_args
|
46
|
+
self.api_id ||= Surveyor::Common.generate_api_id
|
47
|
+
self.display_order ||= Survey.count
|
48
|
+
end
|
49
|
+
|
50
|
+
def active?
|
51
|
+
self.active_as_of?(DateTime.now)
|
52
|
+
end
|
53
|
+
def active_as_of?(date)
|
54
|
+
(active_at && active_at < date && (!inactive_at || inactive_at > date)) ? true : false
|
55
|
+
end
|
56
|
+
def activate!
|
57
|
+
self.active_at = DateTime.now
|
58
|
+
self.inactive_at = nil
|
59
|
+
end
|
60
|
+
def deactivate!
|
61
|
+
self.inactive_at = DateTime.now
|
62
|
+
self.active_at = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def as_json(options = nil)
|
66
|
+
template_paths = ActionController::Base.view_paths.collect(&:to_path)
|
67
|
+
Rabl.render(filtered_for_json, 'surveyor/export.json', :view_path => template_paths, :format => "hash")
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# A hook that allows the survey object to be modified before it is
|
72
|
+
# serialized by the #as_json method.
|
73
|
+
def filtered_for_json
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def default_access_code
|
78
|
+
self.class.to_normalized_string(title)
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_access_code
|
82
|
+
self.access_code ||= default_access_code
|
83
|
+
end
|
84
|
+
|
85
|
+
def increment_version
|
86
|
+
surveys = self.class.select(:survey_version).where(:access_code => access_code).order("survey_version DESC")
|
87
|
+
next_version = surveys.any? ? surveys.first.survey_version.to_i + 1 : 0
|
88
|
+
|
89
|
+
self.survey_version = next_version
|
90
|
+
end
|
91
|
+
|
92
|
+
def translation(locale_symbol)
|
93
|
+
t = self.translations.where(:locale => locale_symbol.to_s).first
|
94
|
+
{:title => self.title, :description => self.description}.with_indifferent_access.merge(
|
95
|
+
t ? YAML.load(t.translation || "{}").with_indifferent_access : {}
|
96
|
+
)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Surveyor
|
2
|
+
module Models
|
3
|
+
module SurveySectionMethods
|
4
|
+
def self.included(base)
|
5
|
+
# Associations
|
6
|
+
base.send :has_many, :questions, :dependent => :destroy
|
7
|
+
base.send :belongs_to, :survey
|
8
|
+
|
9
|
+
# Scopes
|
10
|
+
base.instance_eval {scope :with_includes, ->{ includes :questions => [:answers, :question_group, {:dependency => :dependency_conditions}]}}
|
11
|
+
|
12
|
+
@@validations_already_included ||= nil
|
13
|
+
unless @@validations_already_included
|
14
|
+
# Validations
|
15
|
+
base.send :validates_presence_of, :title, :display_order
|
16
|
+
# this causes issues with building and saving
|
17
|
+
#, :survey
|
18
|
+
|
19
|
+
@@validations_already_included = true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Instance Methods
|
24
|
+
def initialize(*args)
|
25
|
+
super(*args)
|
26
|
+
default_args
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_args
|
30
|
+
self.data_export_identifier ||= Surveyor::Common.normalize(title)
|
31
|
+
end
|
32
|
+
|
33
|
+
def questions_and_groups
|
34
|
+
qs = []
|
35
|
+
questions.each_with_index.map do |q,i|
|
36
|
+
if q.part_of_group?
|
37
|
+
if (i+1 >= questions.size) or (q.question_group_id != questions[i+1].question_group_id)
|
38
|
+
q.question_group
|
39
|
+
end
|
40
|
+
else
|
41
|
+
q
|
42
|
+
end
|
43
|
+
end.compact
|
44
|
+
end
|
45
|
+
|
46
|
+
def translation(locale)
|
47
|
+
{:title => self.title, :description => self.description}.with_indifferent_access.merge(
|
48
|
+
(self.survey.translation(locale)[:survey_sections] || {})[self.reference_identifier] || {}
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Surveyor
|
2
|
+
module Models
|
3
|
+
module SurveyTranslationMethods
|
4
|
+
def self.included(base)
|
5
|
+
# Associations
|
6
|
+
base.send :belongs_to, :survey
|
7
|
+
|
8
|
+
@@validations_already_included ||= nil
|
9
|
+
unless @@validations_already_included
|
10
|
+
# Validations
|
11
|
+
base.send :validates_presence_of, :locale, :translation
|
12
|
+
base.send :validates_uniqueness_of, :locale, :scope => :survey_id
|
13
|
+
# this causes issues with building and saving
|
14
|
+
#, :survey
|
15
|
+
|
16
|
+
@@validations_already_included = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Instance Methods
|
21
|
+
def initialize(*args)
|
22
|
+
super(*args)
|
23
|
+
default_args
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_args
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Surveyor
|
2
|
+
module Models
|
3
|
+
module ValidationConditionMethods
|
4
|
+
def self.included(base)
|
5
|
+
# Associations
|
6
|
+
base.send :belongs_to, :validation
|
7
|
+
|
8
|
+
# Scopes
|
9
|
+
@@validations_already_included ||= nil
|
10
|
+
unless @@validations_already_included
|
11
|
+
# Validations
|
12
|
+
base.send :validates_presence_of, :operator, :rule_key
|
13
|
+
base.send :validates_inclusion_of, :operator, :in => Surveyor::Common::OPERATORS
|
14
|
+
base.send :validates_uniqueness_of, :rule_key, :scope => :validation_id
|
15
|
+
# this causes issues with building and saving
|
16
|
+
# base.send :validates_numericality_of, :validation_id #, :question_id, :answer_id
|
17
|
+
|
18
|
+
@@validations_already_included = true
|
19
|
+
end
|
20
|
+
|
21
|
+
base.send :include, Surveyor::ActsAsResponse # includes "as" instance method
|
22
|
+
|
23
|
+
# Class methods
|
24
|
+
base.instance_eval do
|
25
|
+
def operators
|
26
|
+
Surveyor::Common::OPERATORS
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Instance Methods
|
32
|
+
def to_hash(response)
|
33
|
+
{rule_key.to_sym => (response.nil? ? false : self.is_valid?(response))}
|
34
|
+
end
|
35
|
+
|
36
|
+
def is_valid?(response)
|
37
|
+
klass = response.answer.response_class
|
38
|
+
compare_to = Response.find_by_question_id_and_answer_id(self.question_id, self.answer_id) || self
|
39
|
+
case self.operator
|
40
|
+
when "==", "<", ">", "<=", ">="
|
41
|
+
response.as(klass).send(self.operator, compare_to.as(klass))
|
42
|
+
when "!="
|
43
|
+
!(response.as(klass) == compare_to.as(klass))
|
44
|
+
when "=~"
|
45
|
+
return false if compare_to != self
|
46
|
+
# SMELL Eval regex!!
|
47
|
+
!(response.as(klass).to_s =~ Regexp.new(eval(self.regexp) || "")).nil?
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Surveyor
|
2
|
+
module Models
|
3
|
+
module ValidationMethods
|
4
|
+
def self.included(base)
|
5
|
+
# Associations
|
6
|
+
base.send :belongs_to, :answer
|
7
|
+
base.send :has_many, :validation_conditions, :dependent => :destroy
|
8
|
+
|
9
|
+
# Scopes
|
10
|
+
|
11
|
+
@@validations_already_included ||= nil
|
12
|
+
unless @@validations_already_included
|
13
|
+
# Validations
|
14
|
+
base.send :validates_presence_of, :rule
|
15
|
+
base.send :validates_format_of, :rule, :with => /^(?:and|or|\)|\(|[A-Z]|\s)+$/, :multiline => true # SMELL with :multiline => true Rails reports a security risk
|
16
|
+
# this causes issues with building and saving
|
17
|
+
# base.send :validates_numericality_of, :answer_id
|
18
|
+
|
19
|
+
@@validations_already_included = true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Instance Methods
|
24
|
+
def is_valid?(response_set)
|
25
|
+
ch = conditions_hash(response_set)
|
26
|
+
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
|
27
|
+
# logger.debug "v: #{self.inspect}"
|
28
|
+
# logger.debug "rule: #{self.rule.inspect}"
|
29
|
+
# logger.debug "rexp: #{rgx.inspect}"
|
30
|
+
# logger.debug "keyp: #{ch.inspect}"
|
31
|
+
# logger.debug "subd: #{self.rule.gsub(rgx){|m| ch[m.to_sym]}}"
|
32
|
+
eval(self.rule.gsub(rgx){|m| ch[m.to_sym]})
|
33
|
+
end
|
34
|
+
|
35
|
+
# A hash of the conditions (keyed by rule_key) and their evaluation (boolean) in the context of response_set
|
36
|
+
def conditions_hash(response_set)
|
37
|
+
hash = {}
|
38
|
+
response = response_set.responses.detect{|r| r.answer_id.to_i == self.answer_id.to_i}
|
39
|
+
# logger.debug "r: #{response.inspect}"
|
40
|
+
self.validation_conditions.each{|vc| hash.merge!(vc.to_hash(response))}
|
41
|
+
return hash
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,427 @@
|
|
1
|
+
%w(survey survey_translation survey_section question_group question dependency dependency_condition answer validation validation_condition).each {|model| require model }
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Surveyor
|
6
|
+
class ParserError < StandardError; end
|
7
|
+
class Parser
|
8
|
+
class << self; attr_accessor :options, :log end
|
9
|
+
|
10
|
+
# Attributes
|
11
|
+
attr_accessor :context
|
12
|
+
|
13
|
+
# Class methods
|
14
|
+
def self.parse_file(filename, options={})
|
15
|
+
self.parse(File.read(filename),{:filename => filename}.merge(options))
|
16
|
+
end
|
17
|
+
def self.parse(str, options={})
|
18
|
+
self.ensure_attrs
|
19
|
+
self.options = options
|
20
|
+
self.log[:source] = str
|
21
|
+
Surveyor::Parser.rake_trace "\n"
|
22
|
+
Surveyor::Parser.new.parse(str)
|
23
|
+
Surveyor::Parser.rake_trace "\n"
|
24
|
+
end
|
25
|
+
def self.ensure_attrs
|
26
|
+
self.options ||= {}
|
27
|
+
self.log ||= {}
|
28
|
+
self.log[:indent] ||= 0
|
29
|
+
self.log[:source] ||= ""
|
30
|
+
end
|
31
|
+
def self.rake_trace(str, indent_increment=0)
|
32
|
+
self.ensure_attrs
|
33
|
+
unless str.blank?
|
34
|
+
puts "#{' ' * self.log[:indent]}#{str}" if self.options[:trace] == true
|
35
|
+
end
|
36
|
+
self.log[:indent] += indent_increment
|
37
|
+
end
|
38
|
+
# from https://github.com/rails/rails/blob/master/actionpack/lib/action_view/template/error.rb#L81
|
39
|
+
def self.source_extract(line)
|
40
|
+
source_code = self.log[:source].split("\n")
|
41
|
+
radius = 3
|
42
|
+
start_on_line = [ line - radius - 1, 0 ].max
|
43
|
+
end_on_line = [ line + radius - 1, source_code.length].min
|
44
|
+
|
45
|
+
return unless source_code = source_code[start_on_line..end_on_line]
|
46
|
+
line_counter = start_on_line
|
47
|
+
source_code.sum do |line|
|
48
|
+
line_counter += 1
|
49
|
+
"#{line_counter}: #{line}\n"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def self.raise_error(str, skip_trace = false)
|
53
|
+
self.ensure_attrs
|
54
|
+
line = caller[1].split('/').last.split(':')[1].to_i
|
55
|
+
|
56
|
+
raise Surveyor::ParserError, "#{str}\n" if skip_trace
|
57
|
+
raise Surveyor::ParserError, "#{self.source_extract(line)}\nline \##{line}: #{str}\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Instance methods
|
61
|
+
def initialize
|
62
|
+
self.context = {}
|
63
|
+
end
|
64
|
+
def parse(str)
|
65
|
+
instance_eval(str)
|
66
|
+
return context[:survey]
|
67
|
+
end
|
68
|
+
# This method_missing does all the heavy lifting for the DSL
|
69
|
+
def method_missing(missing_method, *args, &block)
|
70
|
+
method_name, reference_identifier = missing_method.to_s.split("_", 2)
|
71
|
+
type = full(method_name)
|
72
|
+
Surveyor::Parser.raise_error( "\"#{type}\" is not a surveyor method." )if !%w(survey survey_translation survey_section question_group question dependency dependency_condition answer validation validation_condition).include?(type)
|
73
|
+
|
74
|
+
Surveyor::Parser.rake_trace(reference_identifier.blank? ? "#{type} #{args.map(&:inspect).join ', '}" : "#{type}_#{reference_identifier} #{args.map(&:inspect).join ', '}",
|
75
|
+
block_models.include?(type) ? 2 : 0)
|
76
|
+
|
77
|
+
# check for blocks
|
78
|
+
Surveyor::Parser.raise_error "A #{type.humanize.downcase} should take a block" if block_models.include?(type) && !block_given?
|
79
|
+
Surveyor::Parser.raise_error "A #{type.humanize.downcase} doesn't take a block" if !block_models.include?(type) && block_given?
|
80
|
+
|
81
|
+
# parse and build
|
82
|
+
type.classify.constantize.new.extend("SurveyorParser#{type.classify}Methods".constantize).parse_and_build(context, args, method_name, reference_identifier)
|
83
|
+
|
84
|
+
# evaluate and clear context for block models
|
85
|
+
if block_models.include?(type)
|
86
|
+
self.instance_eval(&block)
|
87
|
+
if type == 'survey'
|
88
|
+
resolve_dependency_condition_references
|
89
|
+
resolve_question_correct_answers
|
90
|
+
report_lost_and_duplicate_references
|
91
|
+
report_missing_default_locale
|
92
|
+
Surveyor::Parser.rake_trace("", -2)
|
93
|
+
if context[:survey].save
|
94
|
+
Surveyor::Parser.rake_trace "Survey saved."
|
95
|
+
else
|
96
|
+
Surveyor::Parser.raise_error "Survey not saved: #{context[:survey].errors.full_messages.join(", ")}"
|
97
|
+
end
|
98
|
+
else
|
99
|
+
Surveyor::Parser.rake_trace("", -2)
|
100
|
+
context[type.to_sym].clear(context)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Private methods
|
106
|
+
private
|
107
|
+
|
108
|
+
def full(method_name)
|
109
|
+
case method_name.to_s
|
110
|
+
when /^translations$/; "survey_translation"
|
111
|
+
when /^section$/; "survey_section"
|
112
|
+
when /^g$|^grid$|^group$|^repeater$/; "question_group"
|
113
|
+
when /^q$|^label$|^image$/; "question"
|
114
|
+
when /^a$/; "answer"
|
115
|
+
when /^d$/; "dependency"
|
116
|
+
when /^c(ondition)?$/; context[:validation] ? "validation_condition" : "dependency_condition"
|
117
|
+
when /^v$/; "validation"
|
118
|
+
when /^dc(ondition)?$/; "dependency_condition"
|
119
|
+
when /^vc(ondition)?$/; "validation_condition"
|
120
|
+
else method_name
|
121
|
+
end
|
122
|
+
end
|
123
|
+
def block_models
|
124
|
+
%w(survey survey_section question_group)
|
125
|
+
end
|
126
|
+
def report_missing_default_locale
|
127
|
+
if !self.context[:survey].translations.empty? && self.context[:survey].translations.select{|t|YAML::load(t.translation)=={}}.empty?
|
128
|
+
Surveyor::Parser.raise_error("No default locale specified for translations.",true)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
def report_lost_and_duplicate_references
|
132
|
+
Surveyor::Parser.raise_error("Bad references: #{self.context[:bad_references].join("; ")}", true) unless self.context[:bad_references].empty?
|
133
|
+
Surveyor::Parser.raise_error("Duplicate references: #{self.context[:duplicate_references].join("; ")}", true) unless self.context[:duplicate_references].empty?
|
134
|
+
end
|
135
|
+
def resolve_question_correct_answers
|
136
|
+
self.context[:questions_with_correct_answers].each do |question_reference_idenitifer, correct_answer_reference|
|
137
|
+
# Looking up references for quiz answers
|
138
|
+
if self.context[:answer_references][question_reference_idenitifer] &&
|
139
|
+
(a = self.context[:answer_references][question_reference_idenitifer][correct_answer_reference]) &&
|
140
|
+
a.save
|
141
|
+
self.context[:question_references][question_reference_idenitifer].correct_answer_id = a.id
|
142
|
+
else
|
143
|
+
self.context[:bad_references].push "q_#{question_reference_idenitifer}.correct => a_#{correct_answer_reference}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
def resolve_dependency_condition_references
|
148
|
+
self.context[:dependency_conditions].each do |dc|
|
149
|
+
# Looking up references to questions and answers for linking the dependency objects
|
150
|
+
self.context[:bad_references].push "q_#{dc.question_reference}" unless (dc.question = self.context[:question_references][dc.question_reference])
|
151
|
+
self.context[:answer_references][dc.question_reference] ||= {}
|
152
|
+
self.context[:bad_references].push "q_#{dc.question_reference}, a_#{dc.answer_reference}" if !dc.answer_reference.blank? and (dc.answer = self.context[:answer_references][dc.question_reference][dc.answer_reference]).nil?
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Surveyor models with extra parsing methods
|
159
|
+
|
160
|
+
# Survey model
|
161
|
+
module SurveyorParserSurveyMethods
|
162
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
163
|
+
# clear context
|
164
|
+
clear(context)
|
165
|
+
|
166
|
+
# build and set context
|
167
|
+
title = args[0]
|
168
|
+
args[1] ||= {}
|
169
|
+
context[:default_mandatory] = args[1].delete(:default_mandatory) || false
|
170
|
+
self.attributes = ({
|
171
|
+
:title => title,
|
172
|
+
:reference_identifier => reference_identifier }.merge(args[1]))
|
173
|
+
context[:survey] = self
|
174
|
+
end
|
175
|
+
def clear(context)
|
176
|
+
context.delete_if{|k,v| true}
|
177
|
+
context.merge!({
|
178
|
+
:question_references => {},
|
179
|
+
:answer_references => {},
|
180
|
+
:bad_references => [],
|
181
|
+
:duplicate_references => [],
|
182
|
+
:dependency_conditions => [],
|
183
|
+
:questions_with_correct_answers => {},
|
184
|
+
:default_mandatory => false
|
185
|
+
})
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# SurveySection model
|
190
|
+
module SurveyorParserSurveyTranslationMethods
|
191
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
192
|
+
dir = Surveyor::Parser.options[:filename].nil? ? Dir.pwd : File.dirname(Surveyor::Parser.options[:filename])
|
193
|
+
# build, no change in context
|
194
|
+
args[0].each do |k,v|
|
195
|
+
case v
|
196
|
+
when Hash
|
197
|
+
trans = YAML::dump(v)
|
198
|
+
when String
|
199
|
+
trans = File.read(File.join(dir,v))
|
200
|
+
when :default
|
201
|
+
trans = YAML::dump({})
|
202
|
+
end
|
203
|
+
context[:survey].translations << self.class.new(:locale => k.to_s, :translation => trans)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# SurveySection model
|
209
|
+
module SurveyorParserSurveySectionMethods
|
210
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
211
|
+
# clear context
|
212
|
+
clear(context)
|
213
|
+
|
214
|
+
# build and set context
|
215
|
+
title = args[0]
|
216
|
+
self.attributes = ({
|
217
|
+
:title => title,
|
218
|
+
:reference_identifier => reference_identifier,
|
219
|
+
:display_order => context[:survey].sections.size }.merge(args[1] || {}))
|
220
|
+
context[:survey].sections << context[:survey_section] = self
|
221
|
+
end
|
222
|
+
def clear(context)
|
223
|
+
[ :survey_section,
|
224
|
+
:question_group,
|
225
|
+
:grid_answers,
|
226
|
+
:question,
|
227
|
+
:dependency,
|
228
|
+
:dependency_condition,
|
229
|
+
:answer,
|
230
|
+
:validation,
|
231
|
+
:validation_condition ].each{|k| context.delete k}
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# QuestionGroup model
|
236
|
+
module SurveyorParserQuestionGroupMethods
|
237
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
238
|
+
# clear context
|
239
|
+
clear(context)
|
240
|
+
|
241
|
+
# build and set context
|
242
|
+
self.attributes = ({
|
243
|
+
:text => args[0] || "Question Group",
|
244
|
+
:reference_identifier => reference_identifier,
|
245
|
+
:display_type => (original_method =~ /grid|repeater/ ? original_method : "default")}.merge(args[1] || {}))
|
246
|
+
context[:question_group] = self
|
247
|
+
end
|
248
|
+
def clear(context)
|
249
|
+
[ :question_group,
|
250
|
+
:grid_answers,
|
251
|
+
:question,
|
252
|
+
:dependency,
|
253
|
+
:dependency_condition,
|
254
|
+
:answer,
|
255
|
+
:validation,
|
256
|
+
:validation_condition ].each{|k| context.delete k}
|
257
|
+
context[:grid_answers] = []
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Question model
|
262
|
+
module SurveyorParserQuestionMethods
|
263
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
264
|
+
# clear context
|
265
|
+
[ :question,
|
266
|
+
:dependency,
|
267
|
+
:dependency_condition,
|
268
|
+
:answer,
|
269
|
+
:validation,
|
270
|
+
:validation_condition ].each{|k| context.delete k}
|
271
|
+
|
272
|
+
# build and set context
|
273
|
+
text = args[0] || "Question"
|
274
|
+
hash_args = args[1] || {}
|
275
|
+
correct = hash_args.delete :correct
|
276
|
+
self.attributes = ({
|
277
|
+
:question_group => context[:question_group],
|
278
|
+
:reference_identifier => reference_identifier,
|
279
|
+
:is_mandatory => context[:default_mandatory],
|
280
|
+
:text => text,
|
281
|
+
:display_type => (original_method =~ /label|image/ ? original_method : "default"),
|
282
|
+
:display_order => context[:survey_section].questions.size }.merge(hash_args))
|
283
|
+
context[:survey_section].questions << context[:question] = self
|
284
|
+
|
285
|
+
# keep reference for correct answers
|
286
|
+
context[:questions_with_correct_answers][self.reference_identifier] = correct unless self.reference_identifier.blank? or correct.blank?
|
287
|
+
|
288
|
+
# keep reference for dependencies
|
289
|
+
unless self.reference_identifier.blank?
|
290
|
+
context[:duplicate_references].push "q_#{self.reference_identifier}" if context[:question_references].has_key?(self.reference_identifier)
|
291
|
+
context[:question_references][self.reference_identifier] = context[:question]
|
292
|
+
end
|
293
|
+
|
294
|
+
# add grid answers
|
295
|
+
if context[:question_group] && context[:question_group].display_type == "grid"
|
296
|
+
(context[:grid_answers] || []).each do |grid_answer|
|
297
|
+
a = context[:question].answers.build(grid_answer.attributes.reject{|k,v| %w(id api_id created_at updated_at).include?(k)})
|
298
|
+
context[:answer_references][self.reference_identifier] ||= {} unless self.reference_identifier.blank?
|
299
|
+
context[:answer_references][self.reference_identifier][grid_answer.reference_identifier] = a unless self.reference_identifier.blank? or grid_answer.reference_identifier.blank?
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
# Dependency model
|
306
|
+
module SurveyorParserDependencyMethods
|
307
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
308
|
+
# clear context
|
309
|
+
[ :dependency,
|
310
|
+
:dependency_condition ].each{|k| context.delete k}
|
311
|
+
|
312
|
+
# build and set context
|
313
|
+
self.attributes = (args[0] || {})
|
314
|
+
if context[:question]
|
315
|
+
context[:dependency] = context[:question].dependency = self
|
316
|
+
elsif context[:question_group]
|
317
|
+
context[:dependency] = context[:question_group].dependency = self
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# DependencyCondition model
|
323
|
+
module SurveyorParserDependencyConditionMethods
|
324
|
+
DependencyCondition.instance_eval do
|
325
|
+
attr_accessor :question_reference, :answer_reference
|
326
|
+
end
|
327
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
328
|
+
# clear context
|
329
|
+
context.delete :dependency_condition
|
330
|
+
|
331
|
+
# build and set context
|
332
|
+
a0, a1, a2 = args
|
333
|
+
self.attributes = ({
|
334
|
+
:operator => a1 || "==",
|
335
|
+
:question_reference => a0.to_s.gsub(/^q_|^question_/, ""),
|
336
|
+
:rule_key => reference_identifier
|
337
|
+
}.merge( a2.is_a?(Hash) ? a2 : { :answer_reference => a2.to_s.gsub(/^a_|^answer_/, "") }))
|
338
|
+
context[:dependency].dependency_conditions << context[:dependency_condition] = self
|
339
|
+
context[:dependency_conditions] << self
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
# Answer model
|
344
|
+
module SurveyorParserAnswerMethods
|
345
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
346
|
+
# clear context
|
347
|
+
[ :answer,
|
348
|
+
:validation,
|
349
|
+
:validation_condition ].each{|k| context.delete k}
|
350
|
+
attrs = { :reference_identifier => reference_identifier }.merge(parse_args(args))
|
351
|
+
|
352
|
+
# add answers to grid
|
353
|
+
if context[:question_group] && context[:question_group].display_type == "grid"
|
354
|
+
self.attributes = ({:display_order => context[:grid_answers].size}.merge(attrs))
|
355
|
+
context[:grid_answers] << context[:answer] = self
|
356
|
+
else
|
357
|
+
self.attributes = ({:display_order => context[:question].answers.size}.merge(attrs))
|
358
|
+
context[:question].answers << context[:answer] = self
|
359
|
+
# keep reference for dependencies
|
360
|
+
unless context[:question].reference_identifier.blank? or self.reference_identifier.blank?
|
361
|
+
context[:answer_references][context[:question].reference_identifier] ||= {}
|
362
|
+
context[:duplicate_references].push "q_#{context[:question].reference_identifier}, a_#{self.reference_identifier}" if context[:answer_references][context[:question].reference_identifier].has_key?(self.reference_identifier)
|
363
|
+
context[:answer_references][context[:question].reference_identifier][self.reference_identifier] = context[:answer]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
def parse_args(args)
|
368
|
+
case args[0]
|
369
|
+
when Hash # Hash
|
370
|
+
text_args(args[0][:text]).merge(args[0])
|
371
|
+
when String # (String, Hash) or (String, Symbol, Hash)
|
372
|
+
text_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
|
373
|
+
when Symbol # (Symbol, Hash) or (Symbol, Symbol, Hash)
|
374
|
+
symbol_args(args[0]).merge(hash_from args[1]).merge(args[2] || {})
|
375
|
+
else
|
376
|
+
text_args(nil)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
def text_args(text = "Answer")
|
380
|
+
{:text => text.to_s}
|
381
|
+
end
|
382
|
+
def hash_from(arg)
|
383
|
+
arg.is_a?(Symbol) ? {:response_class => arg.to_s} : arg.is_a?(Hash) ? arg : {}
|
384
|
+
end
|
385
|
+
def symbol_args(arg)
|
386
|
+
case arg
|
387
|
+
when :other
|
388
|
+
text_args("Other")
|
389
|
+
when :other_and_string
|
390
|
+
text_args("Other").merge({:response_class => "string"})
|
391
|
+
when :none, :omit # is_exclusive erases and disables other checkboxes and input elements
|
392
|
+
text_args(arg.to_s.humanize).merge({:is_exclusive => true})
|
393
|
+
when :integer, :float, :date, :time, :datetime, :text, :datetime, :string
|
394
|
+
text_args(arg.to_s.humanize).merge({:response_class => arg.to_s, :display_type => "hidden_label"})
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Validation model
|
400
|
+
module SurveyorParserValidationMethods
|
401
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
402
|
+
# clear context
|
403
|
+
[ :validation,
|
404
|
+
:validation_condition ].each{|k| context.delete k}
|
405
|
+
|
406
|
+
context.delete_if{|k,v| %w(validation validation_condition).map(&:to_sym).include? k}
|
407
|
+
|
408
|
+
# build and set context
|
409
|
+
self.attributes = ({:rule => "A"}.merge(args[0] || {}))
|
410
|
+
context[:answer].validations << context[:validation] = self
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
# ValidationCondition model
|
415
|
+
module SurveyorParserValidationConditionMethods
|
416
|
+
def parse_and_build(context, args, original_method, reference_identifier)
|
417
|
+
# clear context
|
418
|
+
context.delete :validation_condition
|
419
|
+
|
420
|
+
# build and set context
|
421
|
+
a0, a1 = args
|
422
|
+
self.attributes = ({
|
423
|
+
:operator => a0 || "==",
|
424
|
+
:rule_key => reference_identifier}.merge(a1 || {}))
|
425
|
+
context[:validation].validation_conditions << context[:validation_condition] = self
|
426
|
+
end
|
427
|
+
end
|