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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/quby/compiler/dsl/questionnaire_builder.rb +4 -0
- data/lib/quby/compiler/entities/question.rb +1 -11
- data/lib/quby/compiler/entities/questionnaire.rb +3 -0
- data/lib/quby/compiler/outputs/quby_frontend_v1_serializer.rb +9 -1
- data/lib/quby/compiler/outputs/quby_frontend_v2_serializer.rb +32 -3
- data/lib/quby/compiler/services/definition_validator.rb +36 -1
- data/lib/quby/compiler/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4562dd43458813b4fcb9602d10ec82732aea08c22ca12dd1f0b0b934dd25282b
|
4
|
+
data.tar.gz: '041953ff8c41909b57b03f98fa20f14bb6094d4392b911cbc56a464b454ad6d1'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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: :
|
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
|
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
|
-
|
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
|
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.
|
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-
|
10
|
+
date: 2025-07-07 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activemodel
|