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.



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

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.



174
175
176
# File 'lib/inspec/input.rb', line 174

def description
  @description
end

#eventsObject (readonly)

Returns the value of attribute events.



174
175
176
# File 'lib/inspec/input.rb', line 174

def events
  @events
end

#identifierObject (readonly)

Returns the value of attribute identifier.



174
175
176
# File 'lib/inspec/input.rb', line 174

def identifier
  @identifier
end

#nameObject (readonly)

Returns the value of attribute name.



174
175
176
# File 'lib/inspec/input.rb', line 174

def name
  @name
end

#requiredObject (readonly)

Returns the value of attribute required.



174
175
176
# File 'lib/inspec/input.rb', line 174

def required
  @required
end

#sensitiveObject (readonly)

Returns the value of attribute sensitive.



174
175
176
# File 'lib/inspec/input.rb', line 174

def sensitive
  @sensitive
end

#titleObject (readonly)

Returns the value of attribute title.



174
175
176
# File 'lib/inspec/input.rb', line 174

def title
  @title
end

#typeObject (readonly)

Returns the value of attribute type.



174
175
176
# File 'lib/inspec/input.rb', line 174

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)



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

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



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

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

#has_value?Boolean

Returns:

  • (Boolean)


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

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?



197
198
199
# File 'lib/inspec/input.rb', line 197

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

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



337
338
339
# File 'lib/inspec/input.rb', line 337

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

#update(options) ⇒ Object

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

Managing Value

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



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

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



313
314
315
316
# File 'lib/inspec/input.rb', line 313

def value
  enforce_required_validation!
  current_value
end

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



299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/inspec/input.rb', line 299

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