Class: Quby::Questionnaires::Entities::Question

Inherits:
Item
  • Object
show all
Defined in:
lib/quby/questionnaires/entities/question.rb

Constant Summary collapse

MARKDOWN_ATTRIBUTES =
%w(description title).freeze

Instance Attribute Summary collapse

Attributes inherited from Item

#presentation, #raw_content, #switch_cycle

Instance Method Summary collapse

Constructor Details

#initialize(key, options = {}) ⇒ Question

rubocop:disable CyclomaticComplexity, Metrics/MethodLength



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/quby/questionnaires/entities/question.rb', line 120

def initialize(key, options = {})
  super(options)

  @extra_data ||= {}
  @options = []
  @allow_duplicate_option_values = options[:allow_duplicate_option_values]
  @questionnaire = options[:questionnaire]
  @key = key
  @sbg_key = options[:sbg_key]
  @type = options[:type]
  @as = options[:as]
  @title = options[:title]
  @context_free_title = options[:context_free_title]
  @allow_blank_titles = options[:allow_blank_titles]
  @description = options[:description]
  @display_modes = options[:display_modes]
  @presentation = options[:presentation]
  @validations = options[:validations] || []
  @parent = options[:parent]
  @hidden = options[:hidden]
  @table = options[:table]
  @parent_option_key = options[:parent_option_key]
  @autocomplete = options[:autocomplete] || "off"
  @show_values = options[:show_values] || :bulk
  @deselectable = (options[:deselectable].nil? || options[:deselectable])
  @disallow_bulk = options[:disallow_bulk]
  @score_header = options[:score_header] || :none
  @sets_textvar = options[:sets_textvar]
  @unit = options[:unit]
  @lines = options[:lines] || 6
  @cols = options[:cols] || 40
  @default_invisible = options[:default_invisible] || false
  @labels = options[:labels] || []
  @size = options[:size]

  @col_span = options[:col_span] || 1
  @row_span = options[:row_span] || 1

  set_depends_on(options[:depends_on])

  @question_group = options[:question_group]
  @group_minimum_answered = options[:group_minimum_answered]
  @group_maximum_answered = options[:group_maximum_answered]

  @input_data = {}
  @input_data[:value_tooltip] = true if options[:value_tooltip]

  if options[:minimum] and (@type == :integer || @type == :float)
    fail "deprecated" # pretty sure this is not used anywhere
  end
  if options[:maximum] and (@type == :integer || @type == :float)
    fail "deprecated" # pretty sure this is not used anywhere
  end
  @default_position = options[:default_position]
end

Instance Attribute Details

#allow_blank_titlesObject

Question validation fails when there are no title and no context_free_title. When :allow_blank_titles => true passed, validation does not fail. Any other value will raise the failure.



43
44
45
# File 'lib/quby/questionnaires/entities/question.rb', line 43

def allow_blank_titles
  @allow_blank_titles
end

#allow_duplicate_option_valuesObject (readonly)

Whether to skip the uniqueness validation on radio and select option values



32
33
34
# File 'lib/quby/questionnaires/entities/question.rb', line 32

def allow_duplicate_option_values
  @allow_duplicate_option_values
end

#asObject

How should we display this question



26
27
28
# File 'lib/quby/questionnaires/entities/question.rb', line 26

def as
  @as
end

#autocompleteObject

Whether the browser should autocomplete this question (off by default)



46
47
48
# File 'lib/quby/questionnaires/entities/question.rb', line 46

def autocomplete
  @autocomplete
end

#col_spanObject



196
197
198
# File 'lib/quby/questionnaires/entities/question.rb', line 196

def col_span
  options.length > 0 && type != :select ? options.length : @col_span
end

#colsObject

Returns the value of attribute cols.



102
103
104
# File 'lib/quby/questionnaires/entities/question.rb', line 102

def cols
  @cols
end

#context_free_titleObject

rubocop:enable AccessorMethodName



185
186
187
# File 'lib/quby/questionnaires/entities/question.rb', line 185

def context_free_title
  @context_free_title || @title
end

#default_invisibleObject

Returns the value of attribute default_invisible.



111
112
113
# File 'lib/quby/questionnaires/entities/question.rb', line 111

def default_invisible
  @default_invisible
end

#default_positionObject



249
250
251
252
# File 'lib/quby/questionnaires/entities/question.rb', line 249

def default_position
  half = (type == :float) ? 2.0 : 2
  @default_position || ((minimum + maximum) / half if minimum && maximum)
end

#dependenciesObject

Returns the value of attribute dependencies.



60
61
62
# File 'lib/quby/questionnaires/entities/question.rb', line 60

def dependencies
  @dependencies
end

#depends_onObject

This question should not validate itself unless the depends_on question is answered. May also be an array of “#question_key_#option_key” strings that specify options this question depends on.



80
81
82
# File 'lib/quby/questionnaires/entities/question.rb', line 80

def depends_on
  @depends_on
end

#descriptionObject

Returns the value of attribute description.



18
19
20
# File 'lib/quby/questionnaires/entities/question.rb', line 18

def description
  @description
end

#deselectableObject

Whether this radio question is deselectable



68
69
70
# File 'lib/quby/questionnaires/entities/question.rb', line 68

def deselectable
  @deselectable
end

#disallow_bulkObject

Whether we can collapse this in bulk view



75
76
77
# File 'lib/quby/questionnaires/entities/question.rb', line 75

def disallow_bulk
  @disallow_bulk
end

#display_modesObject

In what modes do we display this question NOTE We always display questions in print-view (if they have an answer)



36
37
38
# File 'lib/quby/questionnaires/entities/question.rb', line 36

def display_modes
  @display_modes
end

#extra_dataObject



189
190
191
192
193
194
# File 'lib/quby/questionnaires/entities/question.rb', line 189

def extra_data
  result = @extra_data
  result = result.merge(:"depends-on" => @depends_on.to_json) if @depends_on
  result = result.merge(:placeholder => @options.find { |option| option.placeholder }&.key)
  result
end

#group_maximum_answeredObject

Returns the value of attribute group_maximum_answered.



94
95
96
# File 'lib/quby/questionnaires/entities/question.rb', line 94

def group_maximum_answered
  @group_maximum_answered
end

#group_minimum_answeredObject

Returns the value of attribute group_minimum_answered.



93
94
95
# File 'lib/quby/questionnaires/entities/question.rb', line 93

def group_minimum_answered
  @group_minimum_answered
end

#hiddenObject

To hide old questions



29
30
31
# File 'lib/quby/questionnaires/entities/question.rb', line 29

def hidden
  @hidden
end

#input_dataObject

data-attributes for the input tag.



86
87
88
# File 'lib/quby/questionnaires/entities/question.rb', line 86

def input_data
  @input_data
end

#keyObject

Standard attributes



12
13
14
# File 'lib/quby/questionnaires/entities/question.rb', line 12

def key
  @key
end

#labelsObject

Returns the value of attribute labels.



20
21
22
# File 'lib/quby/questionnaires/entities/question.rb', line 20

def labels
  @labels
end

#linesObject

Amount of rows and cols a textarea has



101
102
103
# File 'lib/quby/questionnaires/entities/question.rb', line 101

def lines
  @lines
end

#optionsObject

Multiple-choice questions have options to choose from



39
40
41
# File 'lib/quby/questionnaires/entities/question.rb', line 39

def options
  @options
end

#parentObject

Some questions are a tree.



71
72
73
# File 'lib/quby/questionnaires/entities/question.rb', line 71

def parent
  @parent
end

#parent_option_keyObject

Returns the value of attribute parent_option_key.



72
73
74
# File 'lib/quby/questionnaires/entities/question.rb', line 72

def parent_option_key
  @parent_option_key
end

#question_groupObject

options for grouping questions and setting a minimum or maximum number of answered questions in the group



92
93
94
# File 'lib/quby/questionnaires/entities/question.rb', line 92

def question_group
  @question_group
end

#questionnaireObject

Returns the value of attribute questionnaire.



15
16
17
# File 'lib/quby/questionnaires/entities/question.rb', line 15

def questionnaire
  @questionnaire
end

#row_spanObject

Returns the value of attribute row_span.



109
110
111
# File 'lib/quby/questionnaires/entities/question.rb', line 109

def row_span
  @row_span
end

#sbg_keyObject

Returns the value of attribute sbg_key.



14
15
16
# File 'lib/quby/questionnaires/entities/question.rb', line 14

def sbg_key
  @sbg_key
end

#score_headerObject

Whether we use the :description, the :value or :none for the score header above this question



89
90
91
# File 'lib/quby/questionnaires/entities/question.rb', line 89

def score_header
  @score_header
end

#sets_textvarObject

Text variable name that will be replaced with the answer to this question In all following text elements that support markdown



98
99
100
# File 'lib/quby/questionnaires/entities/question.rb', line 98

def sets_textvar
  @sets_textvar
end

#show_valuesObject

Whether we show the value for each option :all => in all questionnaire display modes :none => in none of display modes :paged => for only in :paged display mode :bulk => for only in :bulk display mode



53
54
55
# File 'lib/quby/questionnaires/entities/question.rb', line 53

def show_values
  @show_values
end

#sizeObject

To specify size of string/number input boxes



65
66
67
# File 'lib/quby/questionnaires/entities/question.rb', line 65

def size
  @size
end

#tableObject

Table this question might belong to



105
106
107
# File 'lib/quby/questionnaires/entities/question.rb', line 105

def table
  @table
end

#titleObject

Returns the value of attribute title.



16
17
18
# File 'lib/quby/questionnaires/entities/question.rb', line 16

def title
  @title
end

#typeObject

What kind of question is this?



23
24
25
# File 'lib/quby/questionnaires/entities/question.rb', line 23

def type
  @type
end

#unitObject

To display unit for number items



63
64
65
# File 'lib/quby/questionnaires/entities/question.rb', line 63

def unit
  @unit
end

#validationsObject

Structuring



59
60
61
# File 'lib/quby/questionnaires/entities/question.rb', line 59

def validations
  @validations
end

Instance Method Details

#answer_keysObject

Returns all possible answer keys of this question (excluding subquestions, including options). radio/select/scale-options do not create answer_keys, but answer values.



245
246
247
# File 'lib/quby/questionnaires/entities/question.rb', line 245

def answer_keys
  [key]
end

#as_json(options = {}) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/quby/questionnaires/entities/question.rb', line 200

def as_json(options = {})
  # rubocop:disable SymbolName
  super.merge(
    key: key,
    title: Quby::MarkdownParser.new(title).to_html,
    description: Quby::MarkdownParser.new(description).to_html,
    type: type,
    unit: unit,
    size: size,
    hidden: hidden?,
    displayModes: display_modes,
    defaultInvisible: default_invisible,
    viewSelector: view_selector,
    parentKey: parent&.key,
    parentOptionKey: parent_option_key,
    deselectable: deselectable,
    presentation: presentation,
    as: as,
    questionGroup: question_group
  )
end

#claimed_keysObject

The keys this question claims as his own. Not including options and subquestions. Includes keys for the question, inputs and answers.



239
240
241
# File 'lib/quby/questionnaires/entities/question.rb', line 239

def claimed_keys
  [key]
end

#codebook_key(key, questionnaire, opts = {}) ⇒ Object



304
305
306
# File 'lib/quby/questionnaires/entities/question.rb', line 304

def codebook_key(key, questionnaire, opts = {})
  key.to_s.gsub(/^v_/, "#{opts[:roqua_key] || questionnaire.key.to_s}_")
end

#codebook_output_rangeObject



312
313
314
315
316
317
318
319
320
321
# File 'lib/quby/questionnaires/entities/question.rb', line 312

def codebook_output_range
  range_min = validations.find { |i| i[:type] == :minimum }&.fetch(:value, nil)
  range_max = validations.find { |i| i[:type] == :maximum }&.fetch(:value, nil)

  if range_min || range_max
    "(#{[range_min, "value", range_max].compact.join(" <= ")})"
  else
    ""
  end
end

#codebook_output_typeObject



308
309
310
# File 'lib/quby/questionnaires/entities/question.rb', line 308

def codebook_output_type
  type
end

#hidden?Boolean

Returns:

  • (Boolean)


272
273
274
# File 'lib/quby/questionnaires/entities/question.rb', line 272

def hidden?
  hidden
end

#html_idObject



264
265
266
# File 'lib/quby/questionnaires/entities/question.rb', line 264

def html_id
  "answer_#{key}_input"
end

#input_keysObject

Returns all keys belonging to html inputs generated by this question.



223
224
225
226
227
228
229
230
# File 'lib/quby/questionnaires/entities/question.rb', line 223

def input_keys
  if options.blank?
    answer_keys
  else
    # Some options don't have a key (inner_title), they are stripped
    options.map { |opt| opt.input_key }.compact
  end
end

#key_in_use?(k) ⇒ Boolean

Returns:

  • (Boolean)


232
233
234
235
# File 'lib/quby/questionnaires/entities/question.rb', line 232

def key_in_use?(k)
  claimed_keys.include?(k) ||
  options.any? { |option| option.key_in_use?(k) }
end

#maximumObject

Maximum value for float and integer types, set by validation



260
261
262
# File 'lib/quby/questionnaires/entities/question.rb', line 260

def maximum
  validations.find { |i| i[:type] == :maximum }.try(:fetch, :value)
end

#minimumObject

Minimum value for float and integer types, set by validation



255
256
257
# File 'lib/quby/questionnaires/entities/question.rb', line 255

def minimum
  validations.find { |i| i[:type] == :minimum }.try(:fetch, :value)
end

#set_depends_on(keys) ⇒ Object

rubocop:disable AccessorMethodName



178
179
180
181
182
# File 'lib/quby/questionnaires/entities/question.rb', line 178

def set_depends_on(keys)
  return if keys.blank?
  keys = [keys] unless keys.is_a?(Array)
  @depends_on = keys
end

#show_values_in_mode?(mode) ⇒ Boolean

Returns:

  • (Boolean)


276
277
278
279
280
281
282
# File 'lib/quby/questionnaires/entities/question.rb', line 276

def show_values_in_mode?(mode)
  case show_values
  when :none then false
  when :all then true
  else show_values == mode
  end
end

#subquestion?Boolean

Returns:

  • (Boolean)


288
289
290
# File 'lib/quby/questionnaires/entities/question.rb', line 288

def subquestion?
  !parent_option_key.nil?
end

#subquestionsObject



284
285
286
# File 'lib/quby/questionnaires/entities/question.rb', line 284

def subquestions
  options.map { |opt| opt.questions }.flatten
end

#to_codebook(questionnaire, opts = {}) ⇒ Object



292
293
294
295
296
297
298
299
300
301
302
# File 'lib/quby/questionnaires/entities/question.rb', line 292

def to_codebook(questionnaire, opts = {})
  output = []
  question_key = codebook_key(key, questionnaire, opts)
  output << "#{question_key} #{codebook_output_type} #{codebook_output_range}#{' deprecated' if hidden}"
  output << "\"#{context_free_title}\"" unless context_free_title.blank?
  options_string = options.map do |option|
    option.to_codebook(questionnaire, opts)
  end.compact.join("\n")
  output << options_string unless options.blank?
  output.join("\n")
end

#variable_descriptionsObject



323
324
325
# File 'lib/quby/questionnaires/entities/question.rb', line 323

def variable_descriptions
  {key => context_free_title}.with_indifferent_access
end

#view_selectorObject



268
269
270
# File 'lib/quby/questionnaires/entities/question.rb', line 268

def view_selector
  table.blank? ? "#item_#{key}" : "[data-for=#{key}], #answer_#{key}_input"
end