quby-compiler 0.5.19 → 0.5.20

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: 17f81efe58813638140bea17b261bfd5145556b8641ed56792058e6e5cfe2e9c
4
- data.tar.gz: b28acaf67f88390312252210a18a2c2bb878dae86887fb4ce0bfad433bcb98a1
3
+ metadata.gz: 58538613874bd655f416eba086f07ba45321bab1306a6bd710df279e3a9cead0
4
+ data.tar.gz: 1a0c1ea24a9c0fd6e8387f6b1760e14d387e1ed41061d66c8176bf642e72f64e
5
5
  SHA512:
6
- metadata.gz: df24763f87fec0e7dc98d7c14aeb1b21923574684b1c7dba9da22ca6c9ab58f410625094fc6bb934e182e7733072b296f1c32298ab08c32a0963397ab66f7450
7
- data.tar.gz: 55adee69bb962303f1a12415037845b5a4a1675cd8b9d88b0a701258bcf8513ea4b528add011fe8c96f16fc71d6032481b82567b13b6a4717ee20688638e6c32
6
+ metadata.gz: 68251dfd41c4d5054e0d23c7cfa202f6acced87251d2f16b9373c5494d2cbea52955d241479d807e11af8617ced647b49769204b38907bb3728d045a254431cb
7
+ data.tar.gz: 6f34cd861fec8ae281c6fffb8dea442054d5500f5e90fb5ff3594cf1d41e3dd28200e601edc29f05e68e7be32653e084f2e5c5c02ea92cbdac87c64c6581e438
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.5.20
2
+
3
+ * dsl: Add info_block support
4
+ * quby2: Add info_block support
5
+
1
6
  # 0.5.19
2
7
 
3
8
  * quby2: Make the key for inner title predictable, so the json doesn't change each time, making Roqua think the questionnaire has changed.
@@ -24,6 +24,12 @@ module Quby
24
24
  end
25
25
  end
26
26
 
27
+ def check_key_uniqueness(key, questionnaire:)
28
+ if questionnaire.key_in_use? key
29
+ fail "#{questionnaire.key}:#{key}: is already used."
30
+ end
31
+ end
32
+
27
33
  def video_tag(*urls, poster: nil, autoplay: false, loop: false)
28
34
  # assume the file extension is the video format
29
35
  # otherwise, the host's declared mime type is used to figure out compatibility
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'quby/compiler/entities'
4
+
5
+ module Quby
6
+ module Compiler
7
+ module DSL
8
+ class InfoBlockBuilder < Base
9
+ attr_reader :info_block, :default_question_options
10
+
11
+ delegate :panel, to: :info_block
12
+ delegate :questionnaire, to: :panel
13
+
14
+ def initialize(key, start_open: true, panel:, default_question_options:)
15
+ @info_block = Entities::InfoBlock.new(key: , panel:, start_open:)
16
+ @default_question_options = default_question_options
17
+ check_key_uniqueness(key, questionnaire:)
18
+ questionnaire.fields.info_block_keys << key
19
+ panel.items << @info_block
20
+ end
21
+
22
+ def info_html(value)
23
+ raise "Can only add one info_html item per info_block" if info_block.html.present?
24
+ info_block.html = value
25
+ end
26
+
27
+ def html(value)
28
+ info_block.items << Entities::Text.new('', html_content: value.to_s)
29
+ end
30
+
31
+ def question(key, **options, &block)
32
+ options = default_question_options.merge(options).merge(questionnaire:)
33
+
34
+ check_question_keys_uniqueness key, options, questionnaire
35
+
36
+ question = QuestionBuilder.build(key, **options, &block)
37
+
38
+ questionnaire.register_question(question)
39
+ info_block.items << question
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -65,6 +65,15 @@ module Quby
65
65
  table_builder.instance_eval(&block) if block
66
66
  end
67
67
 
68
+ def info_block(key, **options, &block)
69
+ info_block_builder = DSL::InfoBlockBuilder.new \
70
+ key,
71
+ panel: @panel,
72
+ default_question_options: @default_question_options,
73
+ **options
74
+ info_block_builder.instance_eval(&block)
75
+ end
76
+
68
77
  def method_missing(method_sym, *args, **kwargs, &block)
69
78
  if @custom_methods.key? method_sym
70
79
  instance_exec(*args, **kwargs, &@custom_methods[method_sym])
@@ -9,6 +9,7 @@ require 'quby/compiler/dsl/charting/radar_chart_builder'
9
9
  require 'quby/compiler/dsl/charting/bar_chart_builder'
10
10
  require 'quby/compiler/dsl/charting/overview_chart_builder'
11
11
  require 'quby/compiler/dsl/sexp_variable_builder'
12
+ require 'quby/compiler/dsl/info_block_builder'
12
13
 
13
14
  require_relative 'standardized_panel_generators'
14
15
 
@@ -23,11 +23,14 @@ module Quby
23
23
  # targeted by :depends_on relations.
24
24
  attr_reader :input_keys
25
25
 
26
+ attr_reader :info_block_keys
27
+
26
28
  def initialize(questionnaire)
27
29
  @question_hash = HashWithIndifferentAccess.new
28
30
  @option_hash = HashWithIndifferentAccess.new
29
31
  @answer_keys = Set.new
30
32
  @input_keys = Set.new
33
+ @info_block_keys = Set.new
31
34
  @questionnaire = questionnaire
32
35
  end
33
36
 
@@ -59,7 +62,7 @@ module Quby
59
62
  end
60
63
 
61
64
  def key_in_use?(key)
62
- @question_hash.key?(key) || input_keys.include?(key.to_sym)
65
+ @question_hash.key?(key) || input_keys.include?(key.to_sym) || info_block_keys.include?(key)
63
66
  end
64
67
 
65
68
  # Given a list of question and option keys returns a list of input-keys. If a given key is a question-key,
@@ -0,0 +1,28 @@
1
+ module Quby
2
+ module Compiler
3
+ module Entities
4
+ class InfoBlock < Item
5
+ attr_reader :key, :items, :start_open, :panel
6
+ attr_accessor :html
7
+
8
+ validates :key, presence: true, 'quby/compiler/type': {is_a: Symbol}
9
+ validates :html, presence: true
10
+
11
+ def initialize(key:, panel:, start_open: true)
12
+ @panel = panel
13
+ @key = key
14
+ @start_open = start_open
15
+ @items = []
16
+ end
17
+
18
+ def index
19
+ panel.items.index(self)
20
+ end
21
+
22
+ def path_str
23
+ "#{panel.questionnaire.key}:InfoBlock:#{key}"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -216,6 +216,10 @@ module Quby
216
216
  def after_build
217
217
  end
218
218
 
219
+ def path_str
220
+ "#{questionnaire.key}:Question:#{key}"
221
+ end
222
+
219
223
  def context_free_title_or_title
220
224
  context_free_title || title
221
225
  end
@@ -57,6 +57,10 @@ module Quby
57
57
  @questions.each { |q| return true if q.key_in_use?(k) }
58
58
  false
59
59
  end
60
+
61
+ def path_str
62
+ "#{question.path_str}:Option:#{key}"
63
+ end
60
64
  end
61
65
  end
62
66
  end
@@ -24,6 +24,7 @@ require 'quby/compiler/entities/charting/plottable'
24
24
  require 'quby/compiler/entities/panel'
25
25
  require 'quby/compiler/entities/text'
26
26
  require 'quby/compiler/entities/table'
27
+ require 'quby/compiler/entities/info_block'
27
28
 
28
29
  require 'quby/compiler/entities/outcome_table'
29
30
 
@@ -15,7 +15,7 @@ module Quby
15
15
  {
16
16
  key: panel.key,
17
17
  title: panel.title,
18
- items: panel.items.reject { |item| item.respond_to?(:table) && item.table }.map { |item| item_as_json(item) }
18
+ items: panel.items.reject { |item| item.respond_to?(:table) && item.table }.flat_map { |item| item_as_json(item) }
19
19
  }
20
20
  end
21
21
  end
@@ -28,6 +28,8 @@ module Quby
28
28
  question_as_json(item)
29
29
  when Quby::Compiler::Entities::Table
30
30
  table_as_json(item)
31
+ when Quby::Compiler::Entities::InfoBlock
32
+ item.items.map { item_as_json(_1) }
31
33
  end
32
34
  end
33
35
 
@@ -44,11 +44,23 @@ module Quby
44
44
  when Quby::Compiler::Entities::Question
45
45
  return if item.table # things inside a table are added to the table, AND ALSO to the panel. skip them.
46
46
  { type: 'question', key: item.key }
47
+ when Quby::Compiler::Entities::InfoBlock
48
+ info_block_item(item)
47
49
  when Quby::Compiler::Entities::Table
48
50
  { type: "table" }
49
51
  end
50
52
  end
51
53
 
54
+ def info_block_item(info_block)
55
+ {
56
+ type: 'info',
57
+ key: info_block.key,
58
+ html: handle_html(info_block.html, type: :question_description, v1_markdown: false),
59
+ startOpen: info_block.start_open,
60
+ items: info_block.items.map { panel_item(_1) }.compact
61
+ }
62
+ end
63
+
52
64
  def questions
53
65
  fields.question_hash \
54
66
  .to_h { |k, question| [k, question(question)] } \
@@ -27,6 +27,7 @@ module Quby
27
27
  validate_markdown_fields(questionnaire) if questionnaire.validate_html
28
28
  validate_raw_content_items(questionnaire) if questionnaire.validate_html
29
29
  validate_sexp_variables(questionnaire)
30
+ validate_info_blocks(questionnaire)
30
31
  # Some compilation errors are Exceptions (pure syntax errors) and some StandardErrors (NameErrors)
31
32
  rescue Exception => exception # rubocop:disable Lint/RescueException
32
33
  definition.errors.add(:sourcecode, message: "Questionnaire error: #{definition.key}\n" \
@@ -67,7 +68,7 @@ module Quby
67
68
  end
68
69
 
69
70
  questionnaire.question_hash.each_value do |question|
70
- validate_question(question)
71
+ validate_item(question)
71
72
  subquestions_cant_have_default_invisible question
72
73
  validate_subquestion_absence_in_select question
73
74
  validate_placeholder_options_nil_values question
@@ -79,10 +80,10 @@ module Quby
79
80
  end
80
81
  end
81
82
 
82
- def validate_question(question)
83
- unless question.valid?
84
- fail "Question #{question.key} is invalid: #{question.errors.full_messages.join(', ')}"
85
- end
83
+ def validate_item(item)
84
+ return if item.valid?
85
+
86
+ fail "#{item.path_str} is invalid: #{item.errors.full_messages.join(', ')}"
86
87
  end
87
88
 
88
89
  def validate_scores(questionnaire)
@@ -105,12 +106,9 @@ module Quby
105
106
 
106
107
  def validate_question_options(questionnaire, question)
107
108
  question.options.each do |option|
108
- msg_base = "Question #{option.question.key} option #{option.key}"
109
- unless option.valid?
110
- fail "#{msg_base} #{option.errors.full_messages.to_sentence}"
111
- end
112
- to_be_hidden_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: msg_base)
113
- to_be_shown_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: msg_base)
109
+ validate_item(option)
110
+ to_be_hidden_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: option.path_str)
111
+ to_be_shown_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: option.path_str)
114
112
  end
115
113
  end
116
114
 
@@ -140,6 +138,16 @@ module Quby
140
138
  end
141
139
  end
142
140
 
141
+ def validate_info_blocks(questionnaire)
142
+ questionnaire.panels.each do |panel|
143
+ panel.items.each do |item|
144
+ next unless item.is_a?(Entities::InfoBlock)
145
+
146
+ validate_item(item)
147
+ end
148
+ end
149
+ end
150
+
143
151
  def ensure_valid_descriptions(questionnaire, flag)
144
152
  unless (flag.description_false.present? && flag.description_true.present?) || flag.description.present?
145
153
  fail ArgumentError, "Flag '#{flag.key}' Requires at least either both description_true and description_false or a description"
@@ -1,5 +1,5 @@
1
1
  module Quby
2
2
  module Compiler
3
- VERSION = "0.5.19"
3
+ VERSION = "0.5.20"
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.19
4
+ version: 0.5.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marten Veldthuis
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-05-06 00:00:00.000000000 Z
10
+ date: 2025-05-22 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activemodel
@@ -150,6 +150,7 @@ files:
150
150
  - lib/quby/compiler/dsl/charting/overview_chart_builder.rb
151
151
  - lib/quby/compiler/dsl/charting/radar_chart_builder.rb
152
152
  - lib/quby/compiler/dsl/helpers.rb
153
+ - lib/quby/compiler/dsl/info_block_builder.rb
153
154
  - lib/quby/compiler/dsl/panel_builder.rb
154
155
  - lib/quby/compiler/dsl/question_builder.rb
155
156
  - lib/quby/compiler/dsl/questionnaire_builder.rb
@@ -180,6 +181,7 @@ files:
180
181
  - lib/quby/compiler/entities/definition.rb
181
182
  - lib/quby/compiler/entities/fields.rb
182
183
  - lib/quby/compiler/entities/flag.rb
184
+ - lib/quby/compiler/entities/info_block.rb
183
185
  - lib/quby/compiler/entities/item.rb
184
186
  - lib/quby/compiler/entities/lookup_tables.rb
185
187
  - lib/quby/compiler/entities/outcome_table.rb