quby-compiler 0.4.0 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
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