quby-compiler 0.4.5 → 0.4.9

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: c8a3b1948f1047978b5362a22a102cadcf1e73614008ab01ba4c9700ca8a2f49
4
- data.tar.gz: 854cd8345cf21de03ba5262ce08db475b39c106d9ea1874a2106c24a33196820
3
+ metadata.gz: 8adddc572c511a6145f59379fa1c54d49f53fcd3487a3d9a5026fb0634b54c54
4
+ data.tar.gz: 5b173fb296fd7a7b88d9d60eb2357117c6f9f80eb1c800a5fe781a427d359efa
5
5
  SHA512:
6
- metadata.gz: df9bf74043519c50553993a151d30c75ad98d894ed56504705f32d525a5f927e67c54d8af83b287eafe6d05bfef5e744e107527b7dbeb2f898eb1665124b1c5f
7
- data.tar.gz: 2eae0ecda1fa65a11b0fb97189f006136f8c8bff684e6884b8b9b25cbd20c09ef143e3c6a4d0729a4c43b00718994b2d2c85fa2321a02fae6e1fad6cd1093f21
6
+ metadata.gz: 6e23e0347aa449053801f045533b26d10108d8f4a62783a71a121b9cc41215dab348ca3da8e8acf528a58e4689f05219c96237218478c2368acbfcff07c220ce
7
+ data.tar.gz: 47e5d45f09c1452db50e29e3933967256b890090991ed715f91003b7622076aafa0adbe0d0f414506b79707187c03bc37c7217c94bad39bfd5f3a2d681dec72d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ # 0.4.9
2
+
3
+ * roqua.json: Fix html stripping for string with no whitespace
4
+
5
+ # 0.4.8
6
+
7
+ * roqua.json:
8
+ * sort parent questions before it's children, to make the order more logical to just dumbly show
9
+ * parse markdown before stripping tags (questiom.title, option.description)
10
+ * context-free-titles no longer contain the title as fallback
11
+ * quby2.json
12
+ * sort visibility rules: flags first, then in question order, so we can apply them in order without issue
13
+
14
+ # 0.4.7
15
+
16
+ * seeds.yml: Fix missing title questions (broken by 0.4.6)
17
+
18
+ # 0.4.6
19
+
20
+ * Added type validations for boolean attributes
21
+ * roqua.json
22
+ * add unit to questions
23
+ * add title_question_key to questions
24
+ * add parent_question_key and parent_option_key to questions
25
+ * add child_question_keys to question_options
26
+ * models
27
+ * Made title_question attribute on question instead of adding options.last.questions.
28
+ * Made v1 serializer create backward compatible json (for now)
29
+ * Made v1 serializer add the full title_question json to question.title_question.
30
+
1
31
  # 0.4.5
2
32
 
3
33
  * roqua.json: Don't add inner titles and placeholder options
@@ -114,16 +114,6 @@ module Quby
114
114
  def initialize(key, **options, &block)
115
115
  super
116
116
  @default_question_options = options[:default_question_options] || {}
117
- @title_question = nil
118
- end
119
-
120
- def build
121
- if @title_question
122
- @question.options.last.questions << @title_question
123
- @title_question = nil
124
- end
125
-
126
- super
127
117
  end
128
118
 
129
119
  def title_question(key, **options, &block)
@@ -138,7 +128,7 @@ module Quby
138
128
  question = QuestionBuilder.build(key, **options, &block)
139
129
 
140
130
  @questionnaire.register_question(question)
141
- @title_question = question
131
+ @question.title_question = question
142
132
  end
143
133
 
144
134
  def question(key, **options, &block)
@@ -31,17 +31,6 @@ module Quby
31
31
  "#{description} (true - '#{description_true}', false - '#{description_false}')"
32
32
  end
33
33
 
34
- def to_codebook(_options = {})
35
- output = []
36
- output << "#{key} flag"
37
- output << "'#{description}'" if description.present?
38
- output << " 'true' - #{description_true}"
39
- output << " 'false' - #{description_false}"
40
- output << " '' (leeg) - Vlag niet ingesteld, informatie onbekend"
41
- output << ""
42
- output.join("\n")
43
- end
44
-
45
34
  private
46
35
 
47
36
  def ensure_valid_descriptions
@@ -30,10 +30,6 @@ module Quby
30
30
  class: self.class.to_s
31
31
  }
32
32
  end
33
-
34
- def to_codebook(questionnaire, options = {})
35
- ""
36
- end
37
33
  end
38
34
  end
39
35
  end
@@ -29,9 +29,11 @@ module Quby
29
29
 
30
30
  # To hide old questions
31
31
  attr_accessor :hidden
32
+ validates :hidden, inclusion: {in: [true, false, nil], message: "must be boolean"}
32
33
 
33
34
  # Whether to skip the uniqueness validation on radio and select option values
34
35
  attr_reader :allow_duplicate_option_values
36
+ validates :allow_duplicate_option_values, inclusion: {in: [true, false, nil], message: "must be boolean"}
35
37
 
36
38
  # In what modes do we display this question
37
39
  # NOTE We always display questions in print-view (if they have an answer)
@@ -40,9 +42,13 @@ module Quby
40
42
  # Multiple-choice questions have options to choose from
41
43
  attr_accessor :options
42
44
 
45
+ # string question that is displayed after the title of this question.
46
+ attr_accessor :title_question
47
+
43
48
  # Question validation fails when there are no title and no context_free_title.
44
49
  # When :allow_blank_titles => true passed, validation does not fail. Any other value will raise the failure.
45
50
  attr_accessor :allow_blank_titles
51
+ validates :allow_blank_titles, inclusion: {in: [true, false, nil], message: "must be boolean"}
46
52
 
47
53
  # Minimum and maximum values for float and integer types
48
54
  attr_accessor :minimum
@@ -72,6 +78,7 @@ module Quby
72
78
 
73
79
  # Whether this radio question is deselectable
74
80
  attr_accessor :deselectable
81
+ validates :deselectable, inclusion: {in: [true, false, nil], message: "must be boolean"}
75
82
 
76
83
  # Some questions are a tree.
77
84
  attr_accessor :parent
@@ -79,6 +86,7 @@ module Quby
79
86
 
80
87
  # Whether we can collapse this in bulk view
81
88
  attr_accessor :disallow_bulk
89
+ validates :disallow_bulk, inclusion: {in: [true, false, nil], message: "must be boolean"}
82
90
 
83
91
  # This question should not validate itself unless the depends_on question is answered.
84
92
  # May also be an array of "#{question_key}_#{option_key}" strings that specify options
@@ -115,6 +123,7 @@ module Quby
115
123
  attr_accessor :row_span
116
124
 
117
125
  attr_accessor :default_invisible
126
+ validates :default_invisible, inclusion: {in: [true, false], message: "must be boolean"}
118
127
 
119
128
  # Slider only: where to place the sliding thing by default
120
129
  # Can have value :hidden for a hidden handle.
@@ -200,6 +209,10 @@ module Quby
200
209
  end
201
210
  # rubocop:enable CyclomaticComplexity, Metrics/MethodLength
202
211
 
212
+ def context_free_title_or_title
213
+ context_free_title || title
214
+ end
215
+
203
216
  # rubocop:disable AccessorMethodName
204
217
  def set_depends_on(keys)
205
218
  return if keys.blank?
@@ -208,10 +221,6 @@ module Quby
208
221
  end
209
222
  # rubocop:enable AccessorMethodName
210
223
 
211
- def context_free_title
212
- @context_free_title || @title
213
- end
214
-
215
224
  def expand_depends_on_input_keys
216
225
  return unless @depends_on
217
226
  @depends_on = questionnaire.expand_input_keys(@depends_on)
@@ -247,6 +256,10 @@ module Quby
247
256
  end
248
257
  end
249
258
 
259
+ def title_question?
260
+ presentation == :next_to_title
261
+ end
262
+
250
263
  # Returns all keys belonging to html inputs generated by this question.
251
264
  def input_keys
252
265
  if options.blank?
@@ -316,39 +329,8 @@ module Quby
316
329
  !parent_option_key.nil?
317
330
  end
318
331
 
319
- def to_codebook(questionnaire, opts = {})
320
- output = []
321
- question_key = codebook_key(key, questionnaire, opts)
322
- output << "#{question_key} #{codebook_output_type} #{codebook_output_range}#{' deprecated' if hidden}"
323
- output << "\"#{context_free_title}\"" unless context_free_title.blank?
324
- options_string = options.map do |option|
325
- option.to_codebook(questionnaire, opts)
326
- end.compact.join("\n")
327
- output << options_string unless options.blank?
328
- output.join("\n")
329
- end
330
-
331
- def codebook_key(key, questionnaire, opts = {})
332
- key.to_s.gsub(/^v_/, "#{opts[:roqua_key] || questionnaire.key.to_s}_")
333
- end
334
-
335
- def codebook_output_type
336
- type
337
- end
338
-
339
- def codebook_output_range
340
- range_min = validations.find { |i| i[:type] == :minimum }&.fetch(:value, nil)
341
- range_max = validations.find { |i| i[:type] == :maximum }&.fetch(:value, nil)
342
-
343
- if range_min || range_max
344
- "(#{[range_min, "value", range_max].compact.join(" &lt;= ")})"
345
- else
346
- ""
347
- end
348
- end
349
-
350
332
  def variable_descriptions
351
- {key => context_free_title}.with_indifferent_access
333
+ {key => context_free_title_or_title}.with_indifferent_access
352
334
  end
353
335
  end
354
336
  end
@@ -4,23 +4,26 @@ module Quby
4
4
  module Compiler
5
5
  module Entities
6
6
  class QuestionOption
7
+ include ActiveModel::Validations
8
+
7
9
  MARKDOWN_ATTRIBUTES = %w(description).freeze
8
10
 
9
11
  attr_reader :key
10
12
  attr_reader :value
11
- attr_reader :description
13
+ attr_reader :description, :context_free_description
12
14
  attr_reader :questions
13
15
  attr_reader :inner_title
16
+ validates :inner_title, inclusion: {in: [true, false, nil], message: "must be boolean"}
14
17
  attr_reader :hides_questions
15
18
  attr_reader :shows_questions
16
19
  attr_reader :hidden
20
+ validates :hidden, inclusion: {in: [true, false], message: "must be boolean"}
17
21
  attr_reader :placeholder
22
+ validates :placeholder, inclusion: {in: [true, false], message: "must be boolean"}
18
23
  attr_reader :question
19
24
  attr_reader :view_id
20
25
  attr_reader :input_key
21
26
 
22
- attr_reader :start_chosen
23
-
24
27
  def initialize(key, question, options = {})
25
28
  @key = key
26
29
  @question = question
@@ -49,10 +52,6 @@ module Quby
49
52
  false
50
53
  end
51
54
 
52
- def context_free_description
53
- @context_free_description || @description
54
- end
55
-
56
55
  def as_json(options = {})
57
56
  {
58
57
  key: key,
@@ -72,28 +71,6 @@ module Quby
72
71
  viewId: view_id
73
72
  }
74
73
  end
75
-
76
- def to_codebook(questionnaire, opts)
77
- return nil if inner_title
78
- output = []
79
-
80
- if question.type == :check_box
81
- option_key = question.codebook_key(key, questionnaire, opts)
82
- output << "#{option_key} #{question.codebook_output_type}#{' deprecated' if hidden || question.hidden }"
83
- output << "\"#{question.title} -- #{description}\"" unless question.title.blank? and description.blank?
84
- output << "1\tChecked"
85
- output << "0\tUnchecked"
86
- output << "empty\tUnchecked"
87
- else
88
- output << "#{value || key}\t\"#{description}\"#{' deprecated' if hidden}"
89
- end
90
-
91
- questions.each do |subquestion|
92
- output << "\t#{subquestion.to_codebook(questionnaire, opts).gsub("\n", "\n\t")}"
93
- end
94
-
95
- output.join("\n")
96
- end
97
74
  end
98
75
  end
99
76
  end
@@ -172,6 +172,19 @@ module Quby
172
172
  end)
173
173
  end
174
174
 
175
+ # sorts parents before children, so showing makes more sense and visiblity rules are ordered correctly
176
+ def sorted_questions
177
+ return @sorted_questions if @sorted_questions
178
+
179
+ key_to_order_by = questions.map.with_index.to_h { [_1.key, [_2]] }
180
+ questions.each do |question|
181
+ if question.parent
182
+ key_to_order_by[question.key].unshift(key_to_order_by[question.parent.key].first)
183
+ end
184
+ end
185
+ @sorted_questions = questions.sort_by { key_to_order_by[_1.key] }
186
+ end
187
+
175
188
  def questions
176
189
  question_hash.values
177
190
  end
@@ -201,43 +214,6 @@ module Quby
201
214
  }
202
215
  end
203
216
 
204
- # rubocop:disable Metrics/MethodLength
205
- def to_codebook(options = {})
206
- output = []
207
- output << title
208
- output << "Date unknown"
209
- output << ""
210
-
211
- options[:extra_vars]&.each do |var|
212
- output << "#{var[:key]} #{var[:type]}"
213
- output << "\"#{var[:description]}\""
214
- output << ""
215
- end
216
-
217
- top_questions = panels.map do |panel|
218
- panel.items.select { |item| item.is_a? Question }
219
- end.flatten.compact
220
-
221
- top_questions.each do |question|
222
- output << question.to_codebook(self, options)
223
- output << ""
224
- end
225
-
226
- flags.each_value do |flag|
227
- output << flag.to_codebook(options)
228
- output << ""
229
- end
230
-
231
- textvars.each_value do |textvar|
232
- output << textvar.to_codebook(options)
233
- output << ""
234
- end
235
-
236
- output = output.join("\n")
237
- strip_tags(output.gsub(/\<([ 1-9])/, '&lt;\1')).gsub("&lt;", "<")
238
- end
239
- # rubocop:enable Metrics/MethodLength
240
-
241
217
  def key_in_use?(key)
242
218
  fields.key_in_use?(key) || score_calculations.key?(key)
243
219
  end
@@ -415,9 +391,14 @@ module Quby
415
391
  end.uniq(&:config)
416
392
  end
417
393
 
394
+ # Order is important
395
+ # quby2 follows them one by one and ignores rules by hidden question, so needs to be in order of interface.
396
+ # Flags don't have this issue, so as long as they are first, their order doesn't matter.
418
397
  def visibility_rules
419
- @visibility_rules ||= fields.question_hash.values.flat_map { |question| VisibilityRule.from(question) } \
420
- + flags.values.flat_map { |flag| VisibilityRule.from_flag(flag) }
398
+ @visibility_rules ||= [
399
+ *flags.values.flat_map { |flag| VisibilityRule.from_flag(flag) },
400
+ *sorted_questions.flat_map { |question| VisibilityRule.from(question) }
401
+ ]
421
402
  end
422
403
 
423
404
  private
@@ -51,9 +51,9 @@ module Quby
51
51
  end
52
52
 
53
53
  def variable_descriptions
54
- options.each_with_object(key => context_free_title) do |option, hash|
54
+ options.each_with_object(key => context_free_title_or_title) do |option, hash|
55
55
  next if option.input_key.blank?
56
- hash[option.input_key] = "#{context_free_title} - #{option.description}"
56
+ hash[option.input_key] = "#{context_free_title_or_title} - #{option.description}"
57
57
  end.with_indifferent_access
58
58
  end
59
59
 
@@ -69,12 +69,6 @@ module Quby
69
69
  def as_json(options = {})
70
70
  super.merge(options: @options.as_json)
71
71
  end
72
-
73
- def to_codebook(questionnaire, opts = {})
74
- options.map do |option|
75
- option.to_codebook(questionnaire, opts)
76
- end.compact.join("\n\n")
77
- end
78
72
  end
79
73
  end
80
74
  end
@@ -53,9 +53,9 @@ module Quby
53
53
  end
54
54
 
55
55
  def variable_descriptions
56
- components.each_with_object(key => context_free_title) do |component, hash|
56
+ components.each_with_object(key => context_free_title_or_title) do |component, hash|
57
57
  key = send("#{component}_key")
58
- hash[key] = "#{context_free_title} (#{I18n.t component})"
58
+ hash[key] = "#{context_free_title_or_title} (#{I18n.t component})"
59
59
  end.with_indifferent_access
60
60
  end
61
61
 
@@ -65,18 +65,6 @@ module Quby
65
65
  end
66
66
  super.merge(components: components).merge(component_keys)
67
67
  end
68
-
69
- def to_codebook(questionnaire, opts = {})
70
- output = []
71
- components.each do |component|
72
- output << "#{codebook_key(send("#{component}_key"), questionnaire, opts)} " \
73
- "#{type}_#{component} #{codebook_output_range}"
74
- output << "\"#{title}\"" unless title.blank?
75
- output << options.map(&:to_codebook).join("\n") unless options.blank?
76
- output << ""
77
- end
78
- output.join("\n")
79
- end
80
68
  end
81
69
  end
82
70
  end
@@ -8,10 +8,6 @@ module Quby
8
8
  def as_json(options = {})
9
9
  super.merge(options: @options.as_json)
10
10
  end
11
-
12
- def codebook_output_type
13
- :radio
14
- end
15
11
  end
16
12
  end
17
13
  end
@@ -8,10 +8,6 @@ module Quby
8
8
  def as_json(options = {})
9
9
  super.merge(options: @options.as_json)
10
10
  end
11
-
12
- def codebook_output_type
13
- :radio
14
- end
15
11
  end
16
12
  end
17
13
  end
@@ -10,13 +10,6 @@ module Quby
10
10
  super(key, description, default, depends_on_flag)
11
11
  end
12
12
  # rubocop:enable ParameterLists
13
-
14
- def to_codebook(_options = {})
15
- output = []
16
- output << "#{key} Textvariabele"
17
- output << description
18
- output.join("\n")
19
- end
20
13
  end
21
14
  end
22
15
  end
@@ -61,6 +61,7 @@ module Quby
61
61
  question_type: question.type,
62
62
  key: question.key,
63
63
  title: question.title,
64
+ title_question: (question_as_json(question.title_question) if question.title_question),
64
65
  context_free_title: question.context_free_title,
65
66
  description: question.description,
66
67
  presentation: question.presentation,
@@ -96,7 +97,7 @@ module Quby
96
97
  case question
97
98
  when Quby::Compiler::Entities::Questions::CheckboxQuestion
98
99
  base_options.merge(
99
- options: question.options.map { |option| option_as_json(option) },
100
+ options: options_as_json(question),
100
101
  check_all_option: question.check_all_option,
101
102
  uncheck_all_option: question.uncheck_all_option,
102
103
  maximum_checked_allowed: question.maximum_checked_allowed,
@@ -114,7 +115,7 @@ module Quby
114
115
  )
115
116
  when Quby::Compiler::Entities::Questions::DeprecatedQuestion
116
117
  base_options.merge(
117
- options: question.options.map { |option| option_as_json(option) }
118
+ options: options_as_json(question)
118
119
  )
119
120
  when Quby::Compiler::Entities::Questions::FloatQuestion
120
121
  base_options.merge(
@@ -130,11 +131,11 @@ module Quby
130
131
  )
131
132
  when Quby::Compiler::Entities::Questions::RadioQuestion
132
133
  base_options.merge(
133
- options: question.options.map { |option| option_as_json(option) }
134
+ options: options_as_json(question)
134
135
  )
135
136
  when Quby::Compiler::Entities::Questions::SelectQuestion
136
137
  base_options.merge(
137
- options: question.options.map { |option| option_as_json(option) }
138
+ options: options_as_json(question)
138
139
  )
139
140
  when Quby::Compiler::Entities::Questions::StringQuestion
140
141
  base_options.merge(
@@ -177,6 +178,16 @@ module Quby
177
178
  end
178
179
  end
179
180
 
181
+ # Also adds the title question under the last option.
182
+ # TODO old dsl put it there, remove after quby gem uses title_question
183
+ def options_as_json(question)
184
+ question.options.map { |option| option_as_json(option) }.tap do |options_json|
185
+ if question.title_question
186
+ options_json.last[:questions] << question_as_json(question.title_question)
187
+ end
188
+ end
189
+ end
190
+
180
191
  def option_as_json(option)
181
192
  {
182
193
  key: option.key,
@@ -160,31 +160,39 @@ module Quby
160
160
  # sbg_key [nil/string] _not_ defaulted to key
161
161
  # type [string]
162
162
  # title [nil/string] no html
163
- # context_free_title [nil/string] no html, defaulted to title
163
+ # context_free_title [nil/string] no html, not defaulted to title!
164
+ # unit [nil/string] no html (not in quby either)
164
165
  # deprecated [nil/true] only show if filled for old answers
165
166
  # default_invisible [nil/true] only show if filled or when all questions are shown
167
+ # parent_question_key [nil/string] title_questions or question defined under option
168
+ # parent_option_key [nil/string] question defined under option
169
+ # title_question_key [nil/string]
166
170
  # date_parts [nil/{..}]
167
171
  # options: [nil/{..}]
168
172
  def questions
169
- questionnaire.questions.reject{_1.type == :hidden}.to_h { |question|
173
+ questionnaire.sorted_questions.reject{_1.type == :hidden}.to_h { |question|
170
174
  [
171
175
  question.key,
172
176
  {
173
177
  key: question.key,
174
178
  sbg_key: question.sbg_key,
175
179
  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),
180
+ title: parse_markdown_and_strip_tags(question.title),
181
+ context_free_title: question.context_free_title,
182
+ unit: question.unit,
178
183
  deprecated: question.hidden.presence,
179
184
  default_invisible: question.default_invisible.presence,
185
+ parent_question_key: question.parent&.key,
186
+ parent_option_key: question.parent_option_key,
187
+ title_question_key: question.title_question&.key,
180
188
  date_parts: date_parts_for(question),
181
- options: options_for(question),
189
+ options: options_for(question)
182
190
  }.compact
183
191
  ]
184
192
  }
185
193
  end
186
194
 
187
- # {year_key: {key: "v_date_yyyy"}, ..}
195
+ # {year: {key: "v_date_yyyy"}, ..}
188
196
  # key [string]
189
197
  def date_parts_for(question)
190
198
  return nil unless question.type == :date
@@ -202,7 +210,8 @@ module Quby
202
210
  # {a1: {..}}
203
211
  # key [string]
204
212
  # value [nil/string] nil for check_box, string otherwise
205
- # description [nil/string] context_free_description, no html
213
+ # description [nil/string] context_free_description or parsed/stripped description, no html
214
+ # child_question_keys [nil/[string]]
206
215
  def options_for(question)
207
216
  return nil if question.options.empty?
208
217
 
@@ -213,7 +222,8 @@ module Quby
213
222
  {
214
223
  key: option.key,
215
224
  value: (option.value.to_s unless question.type == :check_box),
216
- description: strip_tags_without_html_encode(option.context_free_description)
225
+ description: option.context_free_description || parse_markdown_and_strip_tags(option.description),
226
+ child_question_keys: option.questions.map(&:key).presence
217
227
  }.compact
218
228
  ]
219
229
  }
@@ -245,8 +255,17 @@ module Quby
245
255
  }
246
256
  end
247
257
 
258
+ def parse_markdown_and_strip_tags(markdown)
259
+ strip_tags_without_html_encode(Quby::MarkdownParser.new(markdown).to_html)
260
+ end
261
+
248
262
  def strip_tags_without_html_encode(html)
249
- Nokogiri::HTML(html).text
263
+ Nokogiri::HTML(html).tap do |doc|
264
+ doc.css('br, hr, img').each { |node| node.replace(' ') }
265
+ end \
266
+ .text
267
+ .gsub(/\s+/, ' ')
268
+ .presence
250
269
  end
251
270
  end
252
271
  end
@@ -100,6 +100,9 @@ module Quby
100
100
  def validate_question_options(questionnaire, question)
101
101
  question.options.each do |option|
102
102
  msg_base = "Question #{option.question.key} option #{option.key}"
103
+ unless option.valid?
104
+ fail "#{msg_base} #{option.errors.full_messages.to_sentence}"
105
+ end
103
106
  to_be_hidden_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: msg_base)
104
107
  to_be_shown_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: msg_base)
105
108
  end
@@ -40,7 +40,7 @@ module Quby
40
40
  when :select
41
41
  d_qtypes[question.key.to_s] = { type: :discrete }
42
42
  for option in question.options
43
- d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "") unless option.placeholder
43
+ d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || option.description || "") unless option.placeholder
44
44
  end
45
45
  update_hidden_questions_for(question)
46
46
  when :check_box
@@ -49,16 +49,19 @@ module Quby
49
49
  next if option.inner_title
50
50
  vars << option.key.to_s
51
51
  if question.hidden
52
- question_titles[option.key.to_s] = strip_tags question.context_free_title
52
+ question_titles[option.key.to_s] = strip_tags(question.context_free_title_or_title)
53
53
  end
54
54
  value = 1
55
55
  option_type = { type: :discrete }
56
- option_type[value.to_s] = (option.context_free_description || "")
56
+ option_type[value.to_s] = (option.context_free_description || option.description || "")
57
57
  option_type[:depends] = { values: [value, value.to_s].uniq, variable: option.key.to_s } unless options[:without_depends]
58
58
  d_qtypes[option.key.to_s] = option_type
59
59
  values = [value, value.to_s].uniq
60
60
  handle_subquestions(question, question_titles, d_qtypes, vars, option, values, option.key.to_s)
61
61
  end
62
+ if question.title_question
63
+ subquestion(question, question_titles, d_qtypes, vars, question.title_question, nil, nil)
64
+ end
62
65
  update_hidden_questions_for(question, for_checkbox: true)
63
66
  when :textarea
64
67
  d_qtypes[question.key.to_s] = { type: :text_field }
@@ -72,7 +75,7 @@ module Quby
72
75
  end
73
76
  when :hidden
74
77
  if question.options.blank? # string
75
- question_titles[question.key.to_s] = strip_tags question.context_free_title
78
+ question_titles[question.key.to_s] = strip_tags(question.context_free_title_or_title)
76
79
  vars << question.key.to_s unless vars.include? question.key.to_s
77
80
  d_qtypes[question.key.to_s] = { type: :text }
78
81
  d_qtypes[question.key.to_s][:depends] = :present unless options[:without_depends]
@@ -85,16 +88,16 @@ module Quby
85
88
  next if option.inner_title
86
89
  d_qtypes[question.key.to_s] ||= { type: :scale }
87
90
  values << option.value.to_s
88
- d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "")
91
+ d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || option.description || "")
89
92
  # TODO: missing sub-questions
90
93
  else # check_box
91
94
  d_qtypes[question.key.to_s] ||= { type: :check_box }
92
95
  no_keys = false
93
- question_titles[option.key.to_s] = strip_tags question.context_free_title
96
+ question_titles[option.key.to_s] = strip_tags(question.context_free_title_or_title)
94
97
  vars << option.key.to_s
95
98
  value = option.value || 1
96
99
  option_type = { type: :discrete }
97
- option_type[value.to_s] = (option.context_free_description || "")
100
+ option_type[value.to_s] = (option.context_free_description || option.description || "")
98
101
  option_type[:depends] = { values: [value, value.to_s].uniq, variable: option.key.to_s } unless options[:without_depends]
99
102
  d_qtypes[option.key.to_s] = option_type
100
103
  # TODO: missing sub-questions
@@ -102,7 +105,7 @@ module Quby
102
105
  end
103
106
  if no_keys # scale or radio
104
107
  d_qtypes[question.key.to_s][:depends] = { values: values, variable: question.key.to_s } unless options[:without_depends]
105
- question_titles[question.key.to_s] = strip_tags question.context_free_title
108
+ question_titles[question.key.to_s] = strip_tags(question.context_free_title_or_title)
106
109
  end
107
110
  end
108
111
  else
@@ -191,7 +194,7 @@ module Quby
191
194
 
192
195
  for question in questions_flat
193
196
  unless question.hidden && (question.type == :check_box || question.type == :hidden)
194
- title = question.context_free_title || question.description || ""
197
+ title = question.context_free_title_or_title || question.description || ""
195
198
  question_titles[question.key.to_s] = strip_tags(title)
196
199
  end
197
200
  end
@@ -237,24 +240,24 @@ module Quby
237
240
  end
238
241
  end
239
242
  d_qtypes[quest.key.to_s][:label] = quest.unit unless quest.unit.blank?
240
- quests[quest.key.to_s] = strip_tags(quest.context_free_title || "")
243
+ quests[quest.key.to_s] = strip_tags(quest.context_free_title || quest.title || "")
241
244
  vars << quest.key.to_s
242
245
  end
243
246
 
244
247
  def sub_textfield(question, quests, d_qtypes, vars, quest, values, key)
245
248
  d_qtypes[quest.key.to_s] = { type: :text_field }
246
249
  d_qtypes[quest.key.to_s][:depends] = { values: values, variable: key } unless options[:without_depends]
247
- quests[quest.key.to_s] = strip_tags(quest.context_free_title || "")
250
+ quests[quest.key.to_s] = strip_tags(quest.context_free_title || quest.title || "")
248
251
  vars << quest.key.to_s
249
252
  end
250
253
 
251
254
  def sub_radio(question, quests, d_qtypes, vars, quest, values, key)
252
255
  d_qtypes[quest.key.to_s] = { type: :scale }
253
256
  d_qtypes[quest.key.to_s][:depends] = { values: values, variable: key } unless options[:without_depends]
254
- quests[quest.key.to_s] = strip_tags(quest.context_free_title || "")
257
+ quests[quest.key.to_s] = strip_tags(quest.context_free_title || quest.title || "")
255
258
  for option in quest.options
256
259
  next if option.inner_title
257
- d_qtypes[quest.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "")
260
+ d_qtypes[quest.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || option.description || "")
258
261
  end
259
262
  vars << quest.key.to_s
260
263
  update_hidden_questions_for(quest)
@@ -266,7 +269,7 @@ module Quby
266
269
  vars << key
267
270
  hash[component] = key.to_s
268
271
  end
269
- quests[quest.key.to_s] = strip_tags(quest.context_free_title || "")
272
+ quests[quest.key.to_s] = strip_tags(quest.context_free_title || quest.title || "")
270
273
  end
271
274
 
272
275
  def handle_scale(question, quests, d_qtypes, vars)
@@ -275,11 +278,14 @@ module Quby
275
278
  update_hidden_questions_for(question)
276
279
  for option in question.options
277
280
  next if option.inner_title
278
- d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || "")
281
+ d_qtypes[question.key.to_s][option.value.to_s] = strip_p_tag(option.context_free_description || option.description || "")
279
282
  values << option.value.to_s
280
283
  key = question.key.to_s
281
284
  handle_subquestions(question, quests, d_qtypes, vars, option, [option.value.to_s], key)
282
285
  end
286
+ if question.title_question
287
+ subquestion(question, quests, d_qtypes, vars, question.title_question, nil, nil)
288
+ end
283
289
  end
284
290
 
285
291
  def handle_textfield(question, d_qtypes)
@@ -1,5 +1,5 @@
1
1
  module Quby
2
2
  module Compiler
3
- VERSION = "0.4.5"
3
+ VERSION = "0.4.9"
4
4
  end
5
5
  end
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.5
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marten Veldthuis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-21 00:00:00.000000000 Z
11
+ date: 2022-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel