Class: Quby::Compiler::Services::QubyProxy
- Inherits:
-
Object
- Object
- Quby::Compiler::Services::QubyProxy
- Defined in:
- lib/quby/compiler/services/quby_proxy.rb
Defined Under Namespace
Classes: ShortenKeysUniq
Constant Summary collapse
- HEADERS =
{ value: "Score", interpretation: "Interpretatie", clin_interp: "Klinisch", norm: "Norm", tscore: "T-Score", dimensie: "Dimensie", mean: "Gemiddelde" }
Instance Attribute Summary collapse
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#questionnaire ⇒ Object
readonly
Returns the value of attribute questionnaire.
Instance Method Summary collapse
- #generate ⇒ Object
- #generate_question_titles ⇒ Object
- #handle_scale(question, quests, d_qtypes, vars) ⇒ Object
- #handle_subquestions(question, quests, d_qtypes, vars, option, values, key) ⇒ Object
- #handle_textfield(question, d_qtypes) ⇒ Object
-
#initialize(questionnaire, options) ⇒ QubyProxy
constructor
A new instance of QubyProxy.
- #process_scores ⇒ Object
- #questions_flat ⇒ Object
- #scores_from_schemas ⇒ Object
- #sort_nested_hash(obj) ⇒ Object
- #strip_p_tag(text) ⇒ Object
- #strip_question_number_slashes(quests) ⇒ Object
- #sub_date(question, quests, d_qtypes, vars, quest, values, key) ⇒ Object
- #sub_radio(question, quests, d_qtypes, vars, quest, values, key) ⇒ Object
- #sub_textfield(question, quests, d_qtypes, vars, quest, values, key) ⇒ Object
- #subquestion(question, quests, d_qtypes, vars, quest, values, key) ⇒ Object
- #update_dqtypes_depends(d_qtypes, question, options) ⇒ Object
- #update_hidden_questions_for(question, for_checkbox: false) ⇒ Object
Constructor Details
#initialize(questionnaire, options) ⇒ QubyProxy
Returns a new instance of QubyProxy.
20 21 22 23 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 20 def initialize(questionnaire, ) @questionnaire = questionnaire @options = end |
Instance Attribute Details
#options ⇒ Object (readonly)
Returns the value of attribute options.
18 19 20 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 18 def @options end |
#questionnaire ⇒ Object (readonly)
Returns the value of attribute questionnaire.
18 19 20 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 18 def questionnaire @questionnaire end |
Instance Method Details
#generate ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# 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 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. d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || option.description || "") unless option.placeholder end update_hidden_questions_for(question) when :check_box d_qtypes[question.key.to_s] = { type: :check_box } question..each do |option| next if option.inner_title vars << option.key.to_s if question.hidden question_titles[option.key.to_s] = (question.context_free_title_or_title) end value = 1 option_type = { type: :discrete } option_type[value.to_s] = (option.context_free_description || option.description || "") option_type[:depends] = { values: [value, value.to_s].uniq, variable: option.key.to_s } unless [: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 if question.title_question subquestion(question, question_titles, d_qtypes, vars, question.title_question, nil, nil) 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..blank? # string question_titles[question.key.to_s] = (question.context_free_title_or_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 [:without_depends] else no_keys = true values = [] question..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 || option.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] = (question.context_free_title_or_title) vars << option.key.to_s value = option.value || 1 option_type = { type: :discrete } option_type[value.to_s] = (option.context_free_description || option.description || "") option_type[:depends] = { values: [value, value.to_s].uniq, variable: option.key.to_s } unless [: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 [:without_depends] question_titles[question.key.to_s] = (question.context_free_title_or_title) end end else fail "WARNING: Unimplemented type #{question.type}." end update_dqtypes_depends(d_qtypes, question, ) 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"] || [: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 ⇒ Object
192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 192 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_or_title || question.description || "" question_titles[question.key.to_s] = (title) end end question_titles end |
#handle_scale(question, quests, d_qtypes, vars) ⇒ Object
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 275 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. next if option.inner_title d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || option.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 if question.title_question subquestion(question, quests, d_qtypes, vars, question.title_question, nil, nil) end end |
#handle_subquestions(question, quests, d_qtypes, vars, option, values, key) ⇒ Object
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 211 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) ⇒ Object
291 292 293 294 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 291 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 ⇒ Object
306 307 308 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 306 def process_scores scores_from_schemas end |
#questions_flat ⇒ Object
205 206 207 208 209 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 205 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 ⇒ Object
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 310 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| { key: subschema.key, header: subschema.export_key.to_s # a shortened key used as PART OF the csv export column headers } 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) ⇒ Object
392 393 394 395 396 397 398 399 400 401 402 403 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 392 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) ⇒ Object
296 297 298 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 296 def strip_p_tag(text) text.gsub(/^<p>(.*)<\/p>\n?$/, '\1') end |
#strip_question_number_slashes(quests) ⇒ Object
300 301 302 303 304 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 300 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) ⇒ Object
266 267 268 269 270 271 272 273 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 266 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] = (quest.context_free_title || quest.title || "") end |
#sub_radio(question, quests, d_qtypes, vars, quest, values, key) ⇒ Object
254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 254 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 [:without_depends] quests[quest.key.to_s] = (quest.context_free_title || quest.title || "") for option in quest. next if option.inner_title d_qtypes[quest.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || option.description || "") end vars << quest.key.to_s update_hidden_questions_for(quest) end |
#sub_textfield(question, quests, d_qtypes, vars, quest, values, key) ⇒ Object
247 248 249 250 251 252 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 247 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 [:without_depends] quests[quest.key.to_s] = (quest.context_free_title || quest.title || "") vars << quest.key.to_s end |
#subquestion(question, quests, d_qtypes, vars, quest, values, key) ⇒ Object
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 231 def subquestion(question, quests, d_qtypes, vars, quest, values, key) d_qtypes[quest.key.to_s] = { type: :text } unless [: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] = (quest.context_free_title || quest.title || "") vars << quest.key.to_s end |
#update_dqtypes_depends(d_qtypes, question, options) ⇒ Object
183 184 185 186 187 188 189 190 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 183 def update_dqtypes_depends(d_qtypes, question, ) if hidden = @hidden_questions[question.key.to_s] d_qtypes[question.key.to_s][:depends] ||= hidden unless [:without_depends] end if question.hidden && question.type != :check_box d_qtypes[question.key.to_s][:depends] = :present unless [:without_depends] end end |
#update_hidden_questions_for(question, for_checkbox: false) ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/quby/compiler/services/quby_proxy.rb', line 152 def update_hidden_questions_for(question, for_checkbox: false) shows = question..each_with_object({}) do |option, shows| next if option.inner_title for key in option.shows_questions skey = key.to_s if for_checkbox # is another checkbox option already showing the target question? if shows.key?(skey) # then set the target's depends on :present, since we cannot represent depending on multiple variables shows[skey] = :present else shows[skey] = { values: ["1", 1], variable: option.key.to_s } end else shows[skey] ||= { values: [], variable: question.key.to_s } shows[skey][:values] |= [option.value.to_s, option.value] end end end for skey, show in shows # if a different question is already showing the same question, we cannot register a dependency on both questions # (the 'variable' attribute accepts only 1 key). Thus it is better to show the question based on presence of # an answer instead of on the depended question's answers. if @hidden_questions.has_key?(skey) @hidden_questions[skey] = :present else @hidden_questions[skey] = show end end end |