quby-compiler 0.4.0 → 0.4.4

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: feb162904faed7446d9fae791dcf0a03872121a4a0e4ddb5bcb01de6d936e44c
4
- data.tar.gz: 04ca9df119e3f7aca8a6724d762f59edc2da56b95649aaef4642c3dc4e72d45a
3
+ metadata.gz: affdedce52abd30377ecb0919b012353f6af8139cea5747acc4b82c67d9923a8
4
+ data.tar.gz: d21ad635fd6d232a58d0fd691b91d5f9f9a35f5fe36a024b3056e501870a05ac
5
5
  SHA512:
6
- metadata.gz: ef6516baf27276cdc608583257f48a26c171e4930d8cb4dca035d1c35faf9ef35584f0fcabb4845807901e0f47e2fa81d49e5df280c99acdd13bdad5b63b4040
7
- data.tar.gz: 4b1cd0e9fa3eeacff0e2e6684ce3d3a74460cd7db9723d176bd3c471efb441f509b36d7fe35310479139af7de31346dca1fc807ff7ac1199a83973e39a951792
6
+ metadata.gz: 83a2a47a517f5666bd34b76d1528ca1ccb7f38e60991eda82c134bec2116640e191954cc643d588a3aa8f95c9bc779ddeabe2152d1d689f3dcdd53a7a029da35
7
+ data.tar.gz: e44964d5ea73973db1058018ce460fa0a5ef2da25d7acdf0ee6d1891ef7a42254cf55c2485b04af9fa02af881ae7ef6fb3c4c0e5b3ff452a39f6769d97f63bef
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ # 0.4.4
2
+
3
+ * quby-compile will now validate, not compile invalid questionnaires and return 1 when any invalid.
4
+ * roqua.json
5
+ * add questions hash
6
+ * quby2.json
7
+ * add `as` to all questions, defaulting to type.
8
+ * add `minimum` and `maximum` to integer/float questions.
9
+ * add `step`, `defaultPosition`, `startThumbHidden`, `valueTooltip` and `labels` to slider questions.
10
+
11
+ # 0.4.3
12
+
13
+ * roqua.json: add scores hash.
14
+
15
+ # 0.4.2
16
+
17
+ * quby2: Added labels to slider questions.
18
+
19
+ # 0.4.1
20
+
21
+ * seeds: Fix depends: :present rule being overridden.
22
+
1
23
  # 0.4.0
2
24
 
3
25
  * rename flag visibilty rule value to trigger_on
data/exe/quby-compile CHANGED
@@ -30,11 +30,21 @@ end
30
30
 
31
31
  lookup_tables = Quby::Compiler::Entities::LookupTables.new(lookup_tables_path)
32
32
 
33
+ validation_errors_found = false
33
34
  paths.each do |path|
34
35
  puts "Compiling #{path}"
35
36
 
36
37
  key = File.basename(File.dirname(path))
37
38
  sourcecode = File.read(path)
39
+
40
+ definition = Quby::Compiler.validate(key, sourcecode, lookup_tables: lookup_tables)
41
+ if definition.errors.any?
42
+ error = definition.errors[:sourcecode].first
43
+ STDERR.puts error[:message], error[:backtrace], ''
44
+ validation_errors_found = true
45
+ next # let's not create new output files for questionnaires with errors
46
+ end
47
+
38
48
  compiled = Quby::Compiler.compile(key, sourcecode, path: path, lookup_tables: lookup_tables)
39
49
 
40
50
  FileUtils.mkdir_p(File.join(output_path, key))
@@ -45,3 +55,7 @@ paths.each do |path|
45
55
  end
46
56
  end
47
57
  end
58
+
59
+ if validation_errors_found
60
+ exit(1)
61
+ end
@@ -89,7 +89,7 @@ module Quby
89
89
  end
90
90
 
91
91
  def as_json
92
- question_hash
92
+ question_hash.as_json
93
93
  end
94
94
 
95
95
  private
@@ -231,7 +231,6 @@ module Quby
231
231
  title: Quby::MarkdownParser.new(title).to_html,
232
232
  description: Quby::MarkdownParser.new(description).to_html,
233
233
  type: type,
234
- unit: unit,
235
234
  size: size,
236
235
  hidden: hidden?,
237
236
  displayModes: display_modes,
@@ -241,9 +240,11 @@ module Quby
241
240
  parentOptionKey: parent_option_key,
242
241
  deselectable: deselectable,
243
242
  presentation: presentation,
244
- as: as,
243
+ as: as || type, # default to type so typescript can narrow on it.
245
244
  questionGroup: question_group
246
- )
245
+ ).tap do |json|
246
+ json[:unit] = unit if %i[integer float string].include?(type) && as != :slider
247
+ end
247
248
  end
248
249
 
249
250
  # Returns all keys belonging to html inputs generated by this question.
@@ -193,7 +193,7 @@ module Quby
193
193
  outcomeDescription: outcome_description,
194
194
  shortDescription: short_description,
195
195
  panels: panels,
196
- fields: fields,
196
+ fields: fields.as_json,
197
197
  flags: flags,
198
198
  textvars: textvars,
199
199
  validations: validations,
@@ -0,0 +1,23 @@
1
+ module Quby::Compiler::Entities::Questions::Concerns
2
+ module Slider
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ validates :minimum, :maximum, presence: true, if: -> { as == :slider }
7
+ end
8
+
9
+ def as_json(options = {})
10
+ if as == :slider
11
+ super.merge(
12
+ step: step,
13
+ defaultPosition: default_position.is_a?(Numeric) ? default_position : minimum,
14
+ startThumbHidden: default_position == :hidden,
15
+ valueTooltip: input_data[:value_tooltip] || false,
16
+ labels: labels
17
+ )
18
+ else
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,22 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'concerns/slider'
4
+
3
5
  module Quby
4
6
  module Compiler
5
7
  module Entities
6
8
  module Questions
7
9
  class FloatQuestion < Question
10
+ include Concerns::Slider
11
+
8
12
  def as_json(options = {})
9
13
  super.merge(
10
14
  minimum: minimum,
11
- maximum: maximum,
12
- step: 0.01, # fixed in v1.
13
- # defaultPosition: default_position # Needs discussion, can be number or string "hidden"
15
+ maximum: maximum
14
16
  )
15
17
  end
16
18
 
17
19
  def size
18
20
  @size || 30
19
21
  end
22
+
23
+ def step
24
+ 0.01
25
+ end
20
26
  end
21
27
  end
22
28
  end
@@ -1,22 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'concerns/slider'
4
+
3
5
  module Quby
4
6
  module Compiler
5
7
  module Entities
6
8
  module Questions
7
9
  class IntegerQuestion < Question
10
+ include Concerns::Slider
11
+
8
12
  def as_json(options = {})
9
13
  super.merge(
10
14
  minimum: minimum,
11
- maximum: maximum,
12
- step: 1, # fixed in v1.
13
- # defaultPosition: default_position # Needs discussion, can be number or string "hidden"
15
+ maximum: maximum
14
16
  )
15
17
  end
16
18
 
17
19
  def size
18
20
  @size || 30
19
21
  end
22
+
23
+ def step
24
+ 1
25
+ end
20
26
  end
21
27
  end
22
28
  end
@@ -2,6 +2,18 @@ module Quby
2
2
  module Compiler
3
3
  module Outputs
4
4
  class RoquaSerializer
5
+ QUBY_TYPE_TO_ROQUA_TYPE = {
6
+ check_box: 'multi_select',
7
+ date: 'date_parts',
8
+ float: 'float',
9
+ integer: 'integer',
10
+ radio: 'single_select',
11
+ scale: 'single_select',
12
+ select: 'single_select',
13
+ string: 'text',
14
+ textarea: 'text'
15
+ }
16
+
5
17
  attr_reader :questionnaire
6
18
 
7
19
  def initialize(questionnaire)
@@ -22,6 +34,8 @@ module Quby
22
34
  tags: questionnaire.tags.to_h.keys,
23
35
  charts: charts,
24
36
  outcome_tables_schema: outcome_tables_schema,
37
+ questions: questions,
38
+ scores: scores,
25
39
  }
26
40
  end
27
41
 
@@ -139,7 +153,101 @@ module Quby
139
153
  tables: tables,
140
154
  }
141
155
  end
156
+
157
+ # {v_1: {.., options: {..}, date_parts: {..}}, ..}
158
+ # nils are removed from hash.
159
+ # key [string]
160
+ # sbg_key [nil/string] _not_ defaulted to key
161
+ # type [string]
162
+ # title [nil/string] no html
163
+ # context_free_title [nil/string] no html, defaulted to title
164
+ # deprecated [nil/true] only show if filled for old answers
165
+ # default_invisible [nil/true] only show if filled or when all questions are shown
166
+ # date_parts [nil/{..}]
167
+ # options: [nil/{..}]
168
+ def questions
169
+ questionnaire.questions.reject{_1.type == :hidden}.to_h { |question|
170
+ [
171
+ question.key,
172
+ {
173
+ key: question.key,
174
+ sbg_key: question.sbg_key,
175
+ type: QUBY_TYPE_TO_ROQUA_TYPE.fetch(question.type),
176
+ title: strip_tags_without_html_encode(question.title),
177
+ context_free_title: strip_tags_without_html_encode(question.context_free_title),
178
+ deprecated: question.hidden.presence,
179
+ default_invisible: question.default_invisible.presence,
180
+ date_parts: date_parts_for(question),
181
+ options: options_for(question),
182
+ }.compact
183
+ ]
184
+ }
185
+ end
186
+
187
+ # {year_key: {key: "v_date_yyyy"}, ..}
188
+ # key [string]
189
+ def date_parts_for(question)
190
+ return nil unless question.type == :date
191
+
192
+ question.components.to_h { |component|
193
+ [
194
+ component,
195
+ {
196
+ key: question.send("#{component}_key")
197
+ }
198
+ ]
199
+ }
200
+ end
201
+
202
+ # {a1: {..}}
203
+ # key [string]
204
+ # value [nil/string] nil for check_box, string otherwise
205
+ # description [nil/string] context_free_description, no html
206
+ def options_for(question)
207
+ return nil if question.options.empty?
208
+
209
+ question.options.to_h { |option|
210
+ [
211
+ option.key,
212
+ {
213
+ key: option.key,
214
+ value: (option.value.to_s unless question.type == :check_box),
215
+ description: strip_tags_without_html_encode(option.context_free_description)
216
+ }.compact
217
+ ]
218
+ }
219
+ end
220
+
221
+ # [{ key: { .., subscores: { subkey: {..} } } }]
222
+ def scores
223
+ questionnaire.score_schemas.transform_values { |score|
224
+ {
225
+ key: score.key,
226
+ label: score.label,
227
+ subscores: subscores_for(score)
228
+ }
229
+ }
230
+ end
231
+
232
+ # { subkey: {..} }
233
+ def subscores_for(score)
234
+ score.subscore_schemas.to_h { |subscore|
235
+ [
236
+ subscore.key,
237
+ {
238
+ key: subscore.key,
239
+ label: subscore.label,
240
+ export_key: subscore.export_key,
241
+ only_for_export: subscore.only_for_export.presence
242
+ }.compact
243
+ ]
244
+ }
245
+ end
246
+
247
+ def strip_tags_without_html_encode(html)
248
+ Nokogiri::HTML(html).text
249
+ end
142
250
  end
143
251
  end
144
252
  end
145
- end
253
+ end
@@ -30,9 +30,6 @@ module Quby
30
30
  @hidden_questions = {} # hash containing questions hidden by other questions
31
31
 
32
32
  for question in questions_flat
33
- if question.hidden && question.type != :check_box
34
- d_qtypes[question.key.to_s] = { depends: :present } unless options[:without_depends]
35
- end
36
33
  unless question.hidden && (question.type == :check_box || question.type == :hidden)
37
34
  vars << question.key.to_s
38
35
  end
@@ -184,6 +181,9 @@ module Quby
184
181
  if hidden = @hidden_questions[question.key.to_s]
185
182
  d_qtypes[question.key.to_s][:depends] ||= hidden unless options[:without_depends]
186
183
  end
184
+ if question.hidden && question.type != :check_box
185
+ d_qtypes[question.key.to_s][:depends] = :present unless options[:without_depends]
186
+ end
187
187
  end
188
188
 
189
189
  def generate_question_titles
@@ -1,5 +1,5 @@
1
1
  module Quby
2
2
  module Compiler
3
- VERSION = "0.4.0"
3
+ VERSION = "0.4.4"
4
4
  end
5
5
  end
data/lib/quby/compiler.rb CHANGED
@@ -38,7 +38,7 @@ module Quby
38
38
  )
39
39
  end
40
40
 
41
- def self.validate(key, sourcecode)
41
+ def self.validate(key, sourcecode, lookup_tables:)
42
42
  Quby::Compiler::Instance.new(lookup_tables: lookup_tables).validate(
43
43
  key: key,
44
44
  sourcecode: sourcecode,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quby-compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marten Veldthuis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-10 00:00:00.000000000 Z
11
+ date: 2022-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -204,6 +204,7 @@ files:
204
204
  - lib/quby/compiler/entities/question_option.rb
205
205
  - lib/quby/compiler/entities/questionnaire.rb
206
206
  - lib/quby/compiler/entities/questions/checkbox_question.rb
207
+ - lib/quby/compiler/entities/questions/concerns/slider.rb
207
208
  - lib/quby/compiler/entities/questions/date_question.rb
208
209
  - lib/quby/compiler/entities/questions/deprecated_question.rb
209
210
  - lib/quby/compiler/entities/questions/float_question.rb