class Quby::Compiler::Services::QubyProxy
Constants
- HEADERS
Attributes
options[R]
questionnaire[R]
Public Class Methods
new(questionnaire, options)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 20 def initialize(questionnaire, options) @questionnaire = questionnaire @options = options end
Private Class Methods
keys_for_score(score)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 406 def self.keys_for_score(score) score.map { |subscore| subscore[:key] } end
Public Instance Methods
generate(seed)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 25 def generate(seed) question_titles = generate_question_titles d_qtypes = {} vars = [] @hidden_questions = {} # hash containing questions hidden by other questions for question in questions_flat if question.hidden && question.type != :check_box d_qtypes[question.key.to_s] = { depends: :present } unless options[:without_depends] end unless question.hidden && (question.type == :check_box || question.type == :hidden) vars << question.key.to_s end case question.type when :radio, :scale handle_scale(question, question_titles, d_qtypes, vars) when :select d_qtypes[question.key.to_s] = { type: :discrete } for option in question.options d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "") unless option.placeholder end update_hidden_questions_for(question) when :check_box d_qtypes[question.key.to_s] = { type: :check_box } question.options.each do |option| next if option.inner_title vars << option.key.to_s if question.hidden question_titles[option.key.to_s] = strip_tags question.context_free_title end value = 1 option_type = { type: :discrete } option_type[value.to_s] = (option.context_free_description || "") option_type[:depends] = { values: [value, value.to_s].uniq, variable: option.key.to_s } unless options[:without_depends] d_qtypes[option.key.to_s] = option_type values = [value, value.to_s].uniq handle_subquestions(question, question_titles, d_qtypes, vars, option, values, option.key.to_s) end update_hidden_questions_for(question, for_checkbox: true) when :textarea d_qtypes[question.key.to_s] = { type: :text_field } when :string, :integer, :float handle_textfield(question, d_qtypes) when :date d_qtypes[question.key.to_s] = question.components.each_with_object({ type: :date }) do |component, hash| key = question.send("#{component}_key") vars << key.to_s hash[component] = key.to_s end when :hidden if question.options.blank? # string question_titles[question.key.to_s] = strip_tags question.context_free_title vars << question.key.to_s unless vars.include? question.key.to_s d_qtypes[question.key.to_s] = { type: :text } d_qtypes[question.key.to_s][:depends] = :present unless options[:without_depends] else no_keys = true values = [] question.options.each do |option| if option.value # scale or radio vars << question.key.to_s unless vars.include? question.key.to_s next if option.inner_title d_qtypes[question.key.to_s] ||= { type: :scale } values << option.value.to_s d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "") # TODO: missing sub-questions else # check_box d_qtypes[question.key.to_s] ||= { type: :check_box } no_keys = false question_titles[option.key.to_s] = strip_tags question.context_free_title vars << option.key.to_s value = option.value || 1 option_type = { type: :discrete } option_type[value.to_s] = (option.context_free_description || "") option_type[:depends] = { values: [value, value.to_s].uniq, variable: option.key.to_s } unless options[:without_depends] d_qtypes[option.key.to_s] = option_type # TODO: missing sub-questions end end if no_keys # scale or radio d_qtypes[question.key.to_s][:depends] = { values: values, variable: question.key.to_s } unless options[:without_depends] question_titles[question.key.to_s] = strip_tags question.context_free_title end end else fail "WARNING: Unimplemented type #{question.type}." end update_dqtypes_depends(d_qtypes, question, options) end strip_question_number_slashes(question_titles) seed["quests"] = sort_nested_hash(question_titles) seed["d_qtypes"] = sort_nested_hash(d_qtypes) seed["name"] = questionnaire.title seed["short_description"] = questionnaire.short_description unless questionnaire.short_description.blank? seed["description"] = questionnaire.description unless questionnaire.description.blank? # this approach preserves the order of vars as much as possible, adding new vars to the end of the list old_vars = (seed["vars"]&.split(",") || []).map(&:to_s) new_vars = vars.map(&:to_s) seed["vars"] = ((old_vars & new_vars) | new_vars).join(",") scores = process_scores seed["properties"] ||= {} # headers outcome (humanized) seed["properties"][:score_headers] = scores[:headers] # headers data-export seed["properties"][:score_keys] = scores[:keys] # score names outcome (humanized) seed["properties"][:score_labels] = scores[:labels] seed["properties"].merge!(@options[:properties]) if @options.key?(:properties) seed["properties"] = sort_nested_hash(seed["properties"]) data = {"key" => seed["key"] || options[:roqua_key] || questionnaire.key, "remote_id" => questionnaire.key} attrs = %w(name vars quests d_qtypes properties short_description) attrs.sort.each do |name| data[name] = seed[name] end data end
generate_question_titles()
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 188 def generate_question_titles question_titles = {} for question in questions_flat unless question.hidden && (question.type == :check_box || question.type == :hidden) title = question.context_free_title || question.description || "" question_titles[question.key.to_s] = strip_tags(title) end end question_titles end
handle_scale(question, quests, d_qtypes, vars)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 271 def handle_scale(question, quests, d_qtypes, vars) d_qtypes[question.key.to_s] = { type: :scale } values = [] update_hidden_questions_for(question) for option in question.options next if option.inner_title d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "") values << option.value.to_s key = question.key.to_s handle_subquestions(question, quests, d_qtypes, vars, option, [option.value.to_s], key) end end
handle_subquestions(question, quests, d_qtypes, vars, option, values, key)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 207 def handle_subquestions(question, quests, d_qtypes, vars, option, values, key) option.questions.each do |quest| if quest.presentation == :next_to_title && ![:string, :integer, :float].include?(quest.type) fail "unsupported title question type" end case quest.type when :string, :integer, :float subquestion(question, quests, d_qtypes, vars, quest, values, key) when :textarea sub_textfield(question, quests, d_qtypes, vars, quest, values, key) when :radio sub_radio(question, quests, d_qtypes, vars, quest, values, key) when :date sub_date(question, quests, d_qtypes, vars, quest, values, key) else fail "Unimplemented type #{quest.type} for sub_question" end end end
handle_textfield(question, d_qtypes)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 284 def handle_textfield(question, d_qtypes) d_qtypes[question.key.to_s] = { type: :text } d_qtypes[question.key.to_s][:label] = question.unit unless question.unit.blank? end
process_scores()
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 299 def process_scores scores_from_schemas end
questions_flat()
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 201 def questions_flat @questions_flat ||= questionnaire.panels.map do |panel| panel.items.select { |item| item.is_a? Quby::Compiler::Entities::Question } end.flatten.compact end
scores_from_schemas()
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 303 def scores_from_schemas score_headers = [] # headers outcome (humanized name for subscores) score_keys = [] # headers data-export (not all of it, just the score_subscore part, shortened) score_labels = [] # score names outcome (humanized name for score as a whole) questionnaire.score_schemas.values.each do |score_schema| score_labels << score_schema.label score_keys << score_schema.subscore_schemas.map do |subschema| hash = { key: subschema.key, header: subschema.export_key.to_s # a shortened key used as PART OF the csv export column headers } if subschema.only_for_export hash.merge(hidden: true) else hash end end headers = score_schema.subscore_schemas.map(&:label) score_headers += headers - score_headers end { headers: score_headers, keys: score_keys, labels: score_labels } end
sort_nested_hash(obj)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 390 def sort_nested_hash(obj) case obj when Hash obj.transform_values { |v| sort_nested_hash(v) } .sort_by_alphanum { |k, _v| k.to_s } .to_h when Array obj.map { |v| sort_nested_hash(v) } else obj end end
strip_p_tag(text)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 289 def strip_p_tag(text) text.gsub /^<p>(.*)<\/p>\n?$/, '\1' end
strip_question_number_slashes(quests)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 293 def strip_question_number_slashes(quests) quests.transform_values! do |value| value&.gsub /^(\s*\d+)\\/, '\1' end end
sub_date(question, quests, d_qtypes, vars, quest, values, key)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 262 def sub_date(question, quests, d_qtypes, vars, quest, values, key) d_qtypes[quest.key.to_s] = quest.components.each_with_object({ type: :date }) do |component, hash| key = quest.send("#{component}_key") vars << key hash[component] = key.to_s end quests[quest.key.to_s] = strip_tags(quest.context_free_title || "") end
sub_radio(question, quests, d_qtypes, vars, quest, values, key)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 250 def sub_radio(question, quests, d_qtypes, vars, quest, values, key) d_qtypes[quest.key.to_s] = { type: :scale } d_qtypes[quest.key.to_s][:depends] = { values: values, variable: key } unless options[:without_depends] quests[quest.key.to_s] = strip_tags(quest.context_free_title || "") for option in quest.options next if option.inner_title d_qtypes[quest.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "") end vars << quest.key.to_s update_hidden_questions_for(quest) end
sub_textfield(question, quests, d_qtypes, vars, quest, values, key)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 243 def sub_textfield(question, quests, d_qtypes, vars, quest, values, key) d_qtypes[quest.key.to_s] = { type: :text_field } d_qtypes[quest.key.to_s][:depends] = { values: values, variable: key } unless options[:without_depends] quests[quest.key.to_s] = strip_tags(quest.context_free_title || "") vars << quest.key.to_s end
subquestion(question, quests, d_qtypes, vars, quest, values, key)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 227 def subquestion(question, quests, d_qtypes, vars, quest, values, key) d_qtypes[quest.key.to_s] = { type: :text } unless options[:without_depends] if quest.presentation == :next_to_title # make title questons dependent on themselves so we don't have to dig into quby's depends relations # which sometimes refer to some of the parent's options, but not always the correct ones d_qtypes[quest.key.to_s][:depends] = :present else d_qtypes[quest.key.to_s][:depends] = { values: values, variable: key } end end d_qtypes[quest.key.to_s][:label] = quest.unit unless quest.unit.blank? quests[quest.key.to_s] = strip_tags(quest.context_free_title || "") vars << quest.key.to_s end
update_dqtypes_depends(d_qtypes, question, options)
click to toggle source
# File lib/quby/compiler/services/quby_proxy.rb, line 182 def update_dqtypes_depends(d_qtypes, question, options) if hidden = @hidden_questions[question.key.to_s] d_qtypes[question.key.to_s][:depends] ||= hidden unless options[:without_depends] end end