Class: Inferno::Entities::Input

Inherits:
Object
  • Object
show all
Includes:
Attributes
Defined in:
lib/inferno/entities/input.rb

Overview

This class represents an Input for a runnable.

Constant Summary collapse

ATTRIBUTES =
[
  :name,
  :title,
  :description,
  :type,
  :default,
  :optional,
  :options,
  :locked,
  :hidden,
  :value
].freeze
UNINHERITABLE_ATTRIBUTES =

These attributes require special handling when merging input definitions.

[
  # Locking or hiding an input only has meaning at the level it is applied.
  # Consider:
  # - ParentGroup
  #   - Group 1, input :a
  #   - Group 2, input :a, locked: true, hidden: true, optional: true
  # The input 'a' should only be locked or hidden when running Group 2 in isolation.
  # It should not be locked or hidden when running Group 1 or the ParentGroup.
  :locked,
  :hidden,
  # Input type is sometimes only a UI concern (e.g. text vs. textarea), so
  # it is common to not redeclare the type everywhere it's used and needs
  # special handling to avoid clobbering the type with the default (text)
  # type.
  :type
].freeze
INHERITABLE_ATTRIBUTES =

These are the attributes that can be directly copied when merging a runnable’s input with the input of one of its children.

(ATTRIBUTES - UNINHERITABLE_ATTRIBUTES).freeze
MERGEABLE_ATTRIBUTES =

These are the attributes that can be directly copied when merging a runnable’s input with an input configuration.

(ATTRIBUTES - [:type, :options]).freeze

Instance Method Summary collapse

Methods included from Attributes

included

Constructor Details

#initialize(**params) ⇒ Input

Returns a new instance of Input.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/inferno/entities/input.rb', line 49

def initialize(**params)
  bad_params = params.keys - ATTRIBUTES

  raise Exceptions::UnknownAttributeException.new(bad_params, self.class) if bad_params.present?

  if params[:hidden] && !params[:optional] && !params[:locked]
    raise Exceptions::InvalidAttributeException.new(
      :hidden,
      self.class,
      "Input '#{params[:name]}' cannot be hidden unless it is optional or locked."
    )
  end

  params
    .compact
    .each { |key, value| send("#{key}=", value) }

  self.name = name.to_s if params[:name].present?
end

Instance Method Details

#==(other) ⇒ Object



184
185
186
187
188
# File 'lib/inferno/entities/input.rb', line 184

def ==(other)
  return false unless other.is_a? Input

  ATTRIBUTES.all? { |attribute| send(attribute) == other.send(attribute) }
end

#merge(other_input, merge_all: false) ⇒ Object

Merge this input with an input from a configuration. Fields defined in the configuration take precedence over those defined on this input.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/inferno/entities/input.rb', line 89

def merge(other_input, merge_all: false)
  return self if other_input.nil?

  attributes_to_merge = merge_all ? ATTRIBUTES : MERGEABLE_ATTRIBUTES

  attributes_to_merge.each do |attribute|
    merge_attribute(attribute, primary_source: other_input, secondary_source: self)
  end

  self.type = other_input.type if other_input.type.present? && other_input.type != 'text'

  merge_options(primary_source: other_input, secondary_source: self)

  self
end

#merge_attribute(attribute, primary_source:, secondary_source:) ⇒ Object

Merge an individual attribute. If the primary source contains the attribute, that value will be used. Otherwise the value from the secondary source will be used.

Parameters:

  • attribute (Symbol)
  • primary_source (Input)
  • secondary_source (Input)


112
113
114
115
116
117
118
119
# File 'lib/inferno/entities/input.rb', line 112

def merge_attribute(attribute, primary_source:, secondary_source:)
  value = primary_source.send(attribute)
  value = secondary_source.send(attribute) if value.nil?

  return if value.nil?

  send("#{attribute}=", value)
end

#merge_components(primary_components:, secondary_components:) ⇒ Object

Merge component hashes.

Parameters:



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
# File 'lib/inferno/entities/input.rb', line 145

def merge_components(primary_components:, secondary_components:) # rubocop:disable Metrics/CyclomaticComplexity
  primary_components
    .each { |component| component[:name] = component[:name].to_sym }
  secondary_components
    .each { |component| component[:name] = component[:name].to_sym }

  return if primary_components.blank? && secondary_components.blank?

  component_keys =
    (primary_components + secondary_components)
      .map { |component| component[:name] }
      .uniq

  merged_components = component_keys.map do |key|
    primary_component = primary_components.find { |component| component[:name] == key }
    secondary_component = secondary_components.find { |component| component[:name] == key }

    next secondary_component if primary_component.blank?

    next primary_component if secondary_component.blank?

    Input.new(**secondary_component).merge(Input.new(**primary_component), merge_all: true).to_hash
  end

  merged_components.each { |component| component[:name] = component[:name].to_sym }

  self.options ||= {}
  self.options[:components] = merged_components
end

#merge_options(primary_source:, secondary_source:) ⇒ Object

Merge input options. This performs a normal merge for all options except for the “components” field, the members of which are individually merged by ‘merge_components`

Parameters:



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/inferno/entities/input.rb', line 127

def merge_options(primary_source:, secondary_source:)
  primary_options = primary_source.options.dup || {}
  secondary_options = secondary_source.options.dup || {}

  return if primary_options.blank? && secondary_options.blank?

  primary_components = primary_options.delete(:components) || []
  secondary_components = secondary_options.delete(:components) || []

  send('options=', secondary_options.merge(primary_options))

  merge_components(primary_components:, secondary_components:)
end

#merge_with_child(child_input) ⇒ Object

Merge this input with an input belonging to a child. Fields defined on this input take precedence over those defined on the child input.



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/inferno/entities/input.rb', line 72

def merge_with_child(child_input)
  return self if child_input.nil?

  INHERITABLE_ATTRIBUTES.each do |attribute|
    merge_attribute(attribute, primary_source: self, secondary_source: child_input)
  end

  self.type = child_input.type if child_input.present? && child_input.type != 'text'

  merge_options(primary_source: self, secondary_source: child_input)

  self
end

#to_hashObject



175
176
177
178
179
180
181
182
# File 'lib/inferno/entities/input.rb', line 175

def to_hash
  ATTRIBUTES.each_with_object({}) do |attribute, hash|
    value = send(attribute)
    next if value.nil?

    hash[attribute] = value
  end
end