quby-compiler 0.5.22 → 0.5.24

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07f0d4268936ab1120ebb48d593645367e443a2b236f705de943599aa5e44847
4
- data.tar.gz: e7462e8862d04e7b54badb52f833371aa304d42798c28c5da5edb4fe3d2be5f3
3
+ metadata.gz: 4562dd43458813b4fcb9602d10ec82732aea08c22ca12dd1f0b0b934dd25282b
4
+ data.tar.gz: '041953ff8c41909b57b03f98fa20f14bb6094d4392b911cbc56a464b454ad6d1'
5
5
  SHA512:
6
- metadata.gz: f34d09ad62cbcf84a1749d014c651960409c0bde03a408be228f2940f7efb81c01c97bdeb7a82889d92c16aad637bdaf8cf7674a94bf513dd78454546ee15dc5
7
- data.tar.gz: 3743a39d0850ee252b3c9d6fa32ef8d89c6ee88e69ffd1a280f39d49af97c5635943b47fec4bce53b0ab9920d408a790e780cb09907691b779254d1957893a01
6
+ metadata.gz: 280c9f616bf3d451f82ccb35ab8eda3e5f1983b1a050171cebe12c4f59e334e61a4d58f51172ed69663733cb65bb7d44e1ef716d219e248745e6cc87ed5cce8e
7
+ data.tar.gz: 4c7ce2ae68ddd2c044dd24d02b7d29f7172b19a6424a8728328d3b79a352f97a0a5e9a9634928703670e27c14e7138d1fac2b76010a015fdf9a61acae1c0bd30
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 0.5.24
2
+
3
+ * frontend_v_2: Add dependsOnQuestions and DependsOnOptions to requires_answer validation.
4
+
5
+ # 0.5.23
6
+
7
+ * Validate check_all_option and uncheck_all_option exists.
8
+ * Validate checkbox keys start with question key (disable with do_not_check_checkbox_options_start_with_question_key)
9
+
1
10
  # 0.5.22
2
11
 
3
12
  * quby2: Add questionKeys to panels, so we can validate completeness and make quby2 simpler.
@@ -292,6 +292,10 @@ module Quby
292
292
  @questionnaire.add_outcome_table(**table_options)
293
293
  end
294
294
 
295
+ def do_not_check_checkbox_options_start_with_question_key
296
+ @questionnaire.check_checkbox_options_start_with_question_key = false
297
+ end
298
+
295
299
  private
296
300
 
297
301
  def default_panel_options
@@ -10,8 +10,6 @@ module Quby
10
10
 
11
11
  MARKDOWN_ATTRIBUTES = %w(description title).freeze
12
12
 
13
- set_callback :after_dsl_enhance, :expand_depends_on_input_keys
14
-
15
13
  # Standard attributes
16
14
  attr_accessor :key
17
15
  validates :key, presence: true, 'quby/compiler/type': {is_a: Symbol}
@@ -183,7 +181,7 @@ module Quby
183
181
 
184
182
  # Require subquestions of required questions by default
185
183
  options[:required] = true if @parent&.validations&.first&.fetch(:type, nil) == :requires_answer
186
- @validations << {type: :requires_answer, explanation: options[:error_explanation]} if options[:required]
184
+ @validations << {type: :requires_answer, explanation: options[:error_explanation] } if options[:required]
187
185
 
188
186
  if @type == :float
189
187
  @validations << {type: :valid_float, explanation: options[:error_explanation]}
@@ -232,14 +230,6 @@ module Quby
232
230
  end
233
231
  # rubocop:enable AccessorMethodName
234
232
 
235
- def expand_depends_on_input_keys
236
- return unless @depends_on
237
- @depends_on = questionnaire.expand_input_keys(@depends_on)
238
- @extra_data[:"depends-on"] = @depends_on.to_json
239
- rescue => e
240
- raise e.class, "Question #{key} depends_on contains an error: #{e.message}"
241
- end
242
-
243
233
  def col_span
244
234
  options.length > 0 && type != :select ? options.length : @col_span
245
235
  end
@@ -58,6 +58,7 @@ module Quby
58
58
  @versions = []
59
59
  @seeds_patch = {}
60
60
  @anonymous_conditions = Entities::AnonymousConditions.new
61
+ @check_checkbox_options_start_with_question_key = true
61
62
  end
62
63
 
63
64
  attr_accessor :key
@@ -110,6 +111,8 @@ module Quby
110
111
  attr_accessor :lookup_tables
111
112
  attr_accessor :anonymous_conditions
112
113
 
114
+ attr_accessor :check_checkbox_options_start_with_question_key
115
+
113
116
  delegate :question_hash, :input_keys, :answer_keys, :expand_input_keys, to: :fields
114
117
 
115
118
  def tags=(tags)
@@ -68,7 +68,7 @@ module Quby
68
68
  description: question.description,
69
69
  presentation: question.presentation,
70
70
  hidden: question.hidden,
71
- depends_on: question.depends_on,
71
+ depends_on: expand_depends_on_input_keys(question),
72
72
  default_position: question.default_position,
73
73
  col_span: question.col_span,
74
74
  row_span: question.row_span,
@@ -366,6 +366,14 @@ module Quby
366
366
  exclude_end: range.exclude_end?
367
367
  }
368
368
  end
369
+
370
+ def expand_depends_on_input_keys(question)
371
+ return unless question.depends_on.present?
372
+
373
+ questionnaire.expand_input_keys(question.depends_on)
374
+ rescue => e
375
+ raise e.class, "Question #{question.key} depends_on contains an error: #{e.message}"
376
+ end
369
377
  end
370
378
  end
371
379
  end
@@ -90,7 +90,7 @@ module Quby
90
90
  {
91
91
  type: 'info',
92
92
  key: info_block.key,
93
- html: handle_html(info_block.html, type: :question_description, v1_markdown: false),
93
+ html: handle_html(info_block.html, type: :prose, v1_markdown: false),
94
94
  startOpen: info_block.start_open,
95
95
  items: info_block.items.map { panel_item(_1) }.compact
96
96
  }
@@ -289,15 +289,44 @@ module Quby
289
289
  @questionnaire.validations.map do |validation|
290
290
  validation.config.compact
291
291
  .transform_keys{ _1.to_s.camelize(:lower) }
292
- .tap do |validation_hsh|
292
+ .tap { |validation_hsh|
293
293
  # otherwise ruby will put a (?-mix around the regex, which js errors on.
294
294
  validation_hsh['matcher'] = validation_hsh['matcher'].source.to_s if validation_hsh['matcher']
295
295
  validation_hsh['type'] = 'minimum_date' if validation_hsh['type'] == :minimum && validation_hsh['subtype'] == :date
296
296
  validation_hsh['type'] = 'maximum_date' if validation_hsh['type'] == :maximum && validation_hsh['subtype'] == :date
297
- end.as_json
297
+ validation_hsh['dependsOnQuestions'] = depends_on(validation_hsh) if validation_hsh['type'] == :requires_answer
298
+ validation_hsh['dependsOnOptions'] = depends_on_options(validation_hsh) if validation_hsh['type'] == :requires_answer
299
+ }.compact.as_json
298
300
  end
299
301
  end
300
302
 
303
+ def depends_on(validation_hsh)
304
+ question = @questionnaire.question_hash[validation_hsh['fieldKey']]
305
+ return unless question.depends_on.present?
306
+
307
+ question.depends_on.select { @questionnaire.question_hash.key?(_1) }
308
+ end
309
+
310
+ def depends_on_options(validation_hsh)
311
+ question = @questionnaire.question_hash[validation_hsh['fieldKey']]
312
+ return unless question.depends_on.present?
313
+
314
+ question.depends_on
315
+ .map(&:to_s)
316
+ .reject { @questionnaire.question_hash.key?(_1) }
317
+ .map { |key|
318
+ question_key, option_key = key.split(/_(?=[^_]+$)/) # split on last _, works for all existing questionnaires.
319
+ if @questionnaire.question_hash.key?(question_key)
320
+ if @questionnaire.question_hash[question_key].options.any? { _1.key.to_s == option_key } # single_select
321
+ next [question_key, option_key]
322
+ elsif @questionnaire.question_hash[question_key].options.any? { _1.key.to_s == key } # multi_select
323
+ next [question_key, key]
324
+ end
325
+ end
326
+ raise "#{validation_hsh['fieldKey']} depends_on: can't find key '#{question_key}_#{option_key}'."
327
+ }.group_by(&:first).transform_values{ _1.map(&:last) }
328
+ end
329
+
301
330
  def handle_html(html, type: :simple, v1_markdown: true)
302
331
  if layout_version == :v2
303
332
  case type
@@ -28,6 +28,7 @@ module Quby
28
28
  validate_raw_content_items(questionnaire) if questionnaire.validate_html
29
29
  validate_sexp_variables(questionnaire)
30
30
  validate_info_blocks(questionnaire)
31
+ validate_checkbox_options(questionnaire)
31
32
  # Some compilation errors are Exceptions (pure syntax errors) and some StandardErrors (NameErrors)
32
33
  rescue Exception => exception # rubocop:disable Lint/RescueException
33
34
  definition.errors.add(:sourcecode, message: "Questionnaire error: #{definition.key}\n" \
@@ -376,12 +377,46 @@ scores_schema tables to the resulting seed."
376
377
  def validate_sexp_variables(questionnaire)
377
378
  questionnaire.sexp_variables.each_value do |sexp_variable|
378
379
  sexp_variable.validate(questionnaire)
379
- end
380
+ end
380
381
  end
381
382
 
382
383
  def delete_prefix(key, questionnaire)
383
384
  key.delete_prefix("#{questionnaire.key}_")
384
385
  end
386
+
387
+ def validate_checkbox_options(questionnaire)
388
+ questionnaire.panels.each do |panel|
389
+ panel.items.each do |item|
390
+ return unless item.type == :check_box
391
+ validate_checkbox_options_are_assignable_to_question_key(item, questionnaire)
392
+ validate_check_all_question_exists(item)
393
+ end
394
+ end
395
+ end
396
+
397
+ def validate_checkbox_options_are_assignable_to_question_key(question, questionnaire)
398
+ return unless questionnaire.check_checkbox_options_start_with_question_key
399
+
400
+ question.options.each do |option|
401
+ next if option.key.to_s.start_with?(question.key.to_s)
402
+
403
+ fail "Question with key :#{question.key} has one or more invalid option keys: #{question.options.map(&:key)}"
404
+ end
405
+ end
406
+
407
+ def validate_check_all_question_exists(question)
408
+ return unless question.uncheck_all_option || question.check_all_option
409
+
410
+ option_keys = question.options.map(&:key)
411
+
412
+ if question.check_all_option && !option_keys.include?(question.check_all_option)
413
+ fail "check_all_option key :#{question.check_all_option} does not exist on question :#{question.key}"
414
+ end
415
+
416
+ if question.uncheck_all_option && !option_keys.include?(question.uncheck_all_option)
417
+ fail "uncheck_all_option key :#{question.uncheck_all_option} does not exist on question :#{question.key}"
418
+ end
419
+ end
385
420
  end
386
421
  end
387
422
  end
@@ -1,5 +1,5 @@
1
1
  module Quby
2
2
  module Compiler
3
- VERSION = "0.5.22"
3
+ VERSION = "0.5.24"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quby-compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.22
4
+ version: 0.5.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marten Veldthuis
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-06-17 00:00:00.000000000 Z
10
+ date: 2025-07-07 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activemodel