Class: Inspec::Input

Inherits:
Object
  • Object
show all
Defined in:
lib/inspec/objects/input.rb,
lib/inspec/input.rb

Overview

NOTE: due to namespacing, this reopens and extends the existing Inspec::Input. This should be under Inspec::Objects but that ship has sailed.

Defined Under Namespace

Classes: Error, Event, NO_VALUE_SET, RequiredError, TypeError, ValidationError

Constant Summary collapse

VALID_TYPES =

Validation types for input values

%w{
  String
  Numeric
  Regexp
  Array
  Hash
  Boolean
  Any
}.freeze
DEFAULT_PRIORITY_FOR_DSL_ATTRIBUTES =

TODO: this is not used anywhere? If you call ‘input` in a control file, the input will receive this priority. You can override that with a :priority option.

20
DEFAULT_PRIORITY_FOR_UNKNOWN_CALLER =

If you somehow manage to initialize an Input outside of the DSL, AND you don’t provide an Input::Event, this is the priority you get.

10
DEFAULT_PRIORITY_FOR_VALUE_SET =

If you directly call value=, this is the priority assigned. This is the highest priority within InSpec core; though plugins are free to go higher.

60

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, options = {}) ⇒ Input

Returns a new instance of Input.



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/inspec/input.rb', line 179

def initialize(name, options = {})
  @name = name
  @opts = options
  if @opts.key?(:default)
    Inspec.deprecate(:attrs_value_replaces_default, "input name: '#{name}'")
    if @opts.key?(:value)
      Inspec::Log.warn "Input #{@name} created using both :default and :value options - ignoring :default"
      @opts.delete(:default)
    end
  end

  # Array of Input::Event objects.  These compete with one another to determine
  # the value of the input when value() is called, as well as providing a
  # debugging record of when and how the value changed.
  @events = []
  events.push make_creation_event(options)

  update(options)
end

Instance Attribute Details

#descriptionObject (readonly)

Returns the value of attribute description.



177
178
179
# File 'lib/inspec/input.rb', line 177

def description
  @description
end

#eventsObject (readonly)

Returns the value of attribute events.



177
178
179
# File 'lib/inspec/input.rb', line 177

def events
  @events
end

#identifierObject (readonly)

Returns the value of attribute identifier.



177
178
179
# File 'lib/inspec/input.rb', line 177

def identifier
  @identifier
end

#nameObject (readonly)

Returns the value of attribute name.



177
178
179
# File 'lib/inspec/input.rb', line 177

def name
  @name
end

#requiredObject (readonly)

Returns the value of attribute required.



177
178
179
# File 'lib/inspec/input.rb', line 177

def required
  @required
end

#sensitiveObject (readonly)

Returns the value of attribute sensitive.



177
178
179
# File 'lib/inspec/input.rb', line 177

def sensitive
  @sensitive
end

#titleObject (readonly)

Returns the value of attribute title.



177
178
179
# File 'lib/inspec/input.rb', line 177

def title
  @title
end

#typeObject (readonly)

Returns the value of attribute type.



177
178
179
# File 'lib/inspec/input.rb', line 177

def type
  @type
end

Class Method Details

.infer_event(options) ⇒ Object

We can determine a value:

  1. By event.value (preferred)

  2. By options

  3. By options (deprecated)



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/inspec/input.rb', line 236

def self.infer_event(options)
  # Don't rely on this working; you really should be passing a proper Input::Event
  # with the context information you have.
  location = Input::Event.probe_stack
  event = Input::Event.new(
    action: :set,
    provider: options[:provider] || :unknown,
    priority: options[:priority] || Inspec::Input::DEFAULT_PRIORITY_FOR_UNKNOWN_CALLER,
    file: location.path,
    line: location.lineno
  )

  if options.key?(:default)
    Inspec.deprecate(:attrs_value_replaces_default, "attribute name: '#{name}'")
    if options.key?(:value)
      Inspec::Log.warn "Input #{@name} created using both :default and :value options - ignoring :default"
      options.delete(:default)
    else
      options[:value] = options.delete(:default)
    end
  end
  event.value = options[:value] if options.key?(:value)
  options[:event] = event
end

Instance Method Details

#diagnostic_stringObject



204
205
206
207
# File 'lib/inspec/input.rb', line 204

def diagnostic_string
  "Input #{name}, with history:\n" +
    events.map(&:diagnostic_string).map { |line| "  #{line}" }.join("\n")
end

#has_value?Boolean

Returns:

  • (Boolean)


321
322
323
# File 'lib/inspec/input.rb', line 321

def has_value?
  !current_value(false).is_a? NO_VALUE_SET
end

#ruby_var_identifierObject



32
33
34
# File 'lib/inspec/objects/input.rb', line 32

def ruby_var_identifier
  identifier || "attr_" + name.downcase.strip.gsub(/\s+/, "-").gsub(/[^\w-]/, "")
end

#set_eventsObject

TODO: is this here just for testing?



200
201
202
# File 'lib/inspec/input.rb', line 200

def set_events
  events.select { |e| e.action == :set }
end

#to_hashObject

————————————————————————–#

Marshalling

————————————————————————–#



21
22
23
24
25
26
27
28
29
30
# File 'lib/inspec/objects/input.rb', line 21

def to_hash
  as_hash = { name: name, options: {} }
  %i{description title identifier type required value sensitive}.each do |field|
    val = send(field)
    next if val.nil?

    as_hash[:options][field] = val
  end
  as_hash
end

#to_rubyObject



36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/inspec/objects/input.rb', line 36

def to_ruby
  res = ["#{ruby_var_identifier} = attribute('#{name}',{"]
  res.push "  title: '#{title}'," unless title.to_s.empty?
  res.push "  value: #{value.inspect}," unless value.to_s.empty?
  # to_ruby may generate code that is to be used by older versions of inspec.
  # Anything older than 3.4 will not recognize the value: option, so
  # send the default: option as well. See #3759
  res.push "  default: #{value.inspect}," unless value.to_s.empty?
  res.push "  description: '#{description}'," unless description.to_s.empty?
  res.push "})"
  res.join("\n")
end

#to_sObject

————————————————————————–#

Value Type Coercion

————————————————————————–#



340
341
342
# File 'lib/inspec/input.rb', line 340

def to_s
  "Input #{name} with value " + (sensitive ? "*** (senstive)" : "#{current_value}")
end

#update(options) ⇒ Object

————————————————————————–#

Managing Value

————————————————————————–#



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/inspec/input.rb', line 213

def update(options)
  (options)
  normalize_type_restriction!

  # Values are set by passing events in; but we can also infer an event.
  if options.key?(:value) || options.key?(:default)
    if options.key?(:event)
      if options.key?(:value) || options.key?(:default)
        Inspec::Log.warn "Do not provide both an Event and a value as an option to attribute('#{name}') - using value from event"
      end
    else
      self.class.infer_event(options) # Sets options[:event]
    end
  end
  events << options[:event] if options.key? :event

  enforce_type_restriction!
end

#valueObject



316
317
318
319
# File 'lib/inspec/input.rb', line 316

def value
  enforce_required_validation!
  current_value
end

#value=(new_value, priority = DEFAULT_PRIORITY_FOR_VALUE_SET) ⇒ Object



302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/inspec/input.rb', line 302

def value=(new_value, priority = DEFAULT_PRIORITY_FOR_VALUE_SET)
  # Inject a new Event with the new value.
  location = Event.probe_stack
  events << Event.new(
    action: :set,
    provider: :value_setter,
    priority: priority,
    value: new_value,
    file: location.path,
    line: location.lineno
  )
  enforce_type_restriction!
end