class FilterTable::Table
Attributes
criteria_string[R]
raw_data[R]
resource_instance[R]
Public Class Methods
new(resource_instance, raw_data, criteria_string)
click to toggle source
# File lib/inspec/utils/filter.rb, line 92 def initialize(resource_instance, raw_data, criteria_string) @resource_instance = resource_instance @raw_data = raw_data @raw_data = [] if @raw_data.nil? @criteria_string = criteria_string @populated_lazy_columns = {} end
Public Instance Methods
callback_for_lazy_field(field_name)
click to toggle source
# File lib/inspec/utils/filter.rb, line 220 def callback_for_lazy_field(field_name) return unless is_field_lazy?(field_name) custom_properties_schema.values.find do |property_struct| property_struct.field_name == field_name end.opts[:lazy] end
create_eval_context_for_row(*_)
click to toggle source
# File lib/inspec/utils/filter.rb, line 146 def create_eval_context_for_row(*_) raise "#{self.class} must not be used on its own. It must be inherited "\ "and the #create_eval_context_for_row method must be implemented. This is an internal "\ "error and should not happen." end
entries()
click to toggle source
# File lib/inspec/utils/filter.rb, line 161 def entries row_criteria_string = resource.to_s + criteria_string + " one entry" raw_data.map do |row| create_eval_context_for_row(row, row_criteria_string) end end
field?(proposed_field)
click to toggle source
# File lib/inspec/utils/filter.rb, line 180 def field?(proposed_field) # Currently we only know about a field if it is present in a at least one row of the raw data. # If we have no rows in the raw data, assume all fields are acceptable (and rely on failing to match on value, nil) return true if raw_data.empty? # Most resources have Symbol keys in their raw data. Some have Strings (looking at you, `shadow`). is_field = false is_field ||= list_fields.include?(proposed_field.to_s) is_field ||= list_fields.include?(proposed_field.to_sym) is_field ||= is_field_lazy?(proposed_field.to_s) is_field ||= is_field_lazy?(proposed_field.to_sym) is_field end
field_populated?(field_name)
click to toggle source
# File lib/inspec/utils/filter.rb, line 228 def field_populated?(field_name) @populated_lazy_columns[field_name] end
get_column_values(field)
click to toggle source
# File lib/inspec/utils/filter.rb, line 168 def get_column_values(field) raw_data.map do |row| row[field] end end
is_field_lazy?(sought_field_name)
click to toggle source
# File lib/inspec/utils/filter.rb, line 213 def is_field_lazy?(sought_field_name) custom_properties_schema.values.any? do |property_struct| sought_field_name == property_struct.field_name && \ property_struct.opts[:lazy] end end
list_fields()
click to toggle source
# File lib/inspec/utils/filter.rb, line 174 def list_fields @__fields_in_raw_data ||= raw_data.reduce([]) do |fields, row| fields.concat(row.keys).uniq end end
mark_lazy_field_populated(field_name)
click to toggle source
# File lib/inspec/utils/filter.rb, line 232 def mark_lazy_field_populated(field_name) @populated_lazy_columns[field_name] = true end
params()
click to toggle source
# File lib/inspec/utils/filter.rb, line 156 def params # TODO: consider deprecating raw_data end
populate_lazy_field(field_name, criterion)
click to toggle source
# File lib/inspec/utils/filter.rb, line 201 def populate_lazy_field(field_name, criterion) return unless is_field_lazy?(field_name) return if field_populated?(field_name) raw_data.each do |row| next if row.key?(field_name) # skip row if pre-existing data is present callback_for_lazy_field(field_name).call(row, criterion, self) end mark_lazy_field_populated(field_name) end
resource()
click to toggle source
# File lib/inspec/utils/filter.rb, line 152 def resource resource_instance end
to_s()
click to toggle source
# File lib/inspec/utils/filter.rb, line 195 def to_s resource.to_s + criteria_string end
Also aliased as: inspect
where(conditions = {}, &block)
click to toggle source
Filter the raw data based on criteria (as method params) or by evaling a block; then construct a new Table
of the same class as ourselves, wrapping the filtered data, and return it.
# File lib/inspec/utils/filter.rb, line 103 def where(conditions = {}, &block) return self unless conditions.is_a?(Hash) return self if conditions.empty? && !block_given? # Initialize the details of the new Table. new_criteria_string = criteria_string filtered_raw_data = raw_data # If we were provided params, interpret them as criteria to be evaluated # against the raw data. Criteria are assumed to be hash keys. conditions.each do |raw_field_name, desired_value| raise(ArgumentError, "'#{decorate_symbols(raw_field_name)}' is not a recognized criterion - expected one of #{decorate_symbols(list_fields).join(", ")}'") unless field?(raw_field_name) populate_lazy_field(raw_field_name, desired_value) if is_field_lazy?(raw_field_name) new_criteria_string += " #{raw_field_name} == #{desired_value.inspect}" filtered_raw_data = filter_raw_data(filtered_raw_data, raw_field_name, desired_value) end # If we were given a block, make a special Struct for each row, that has an accessor # for each field declared using `register_custom_property`, then instance-eval the block # against the struct. if block_given? # Perform the filtering. filtered_raw_data = filtered_raw_data.find_all { |row_as_hash| create_eval_context_for_row(row_as_hash, "").instance_eval(&block) } # Try to interpret the block for updating the stringification. src = Trace.new # Swallow any exceptions raised here. # See https://github.com/chef/inspec/issues/2929 begin src.instance_eval(&block) rescue # rubocop: disable Lint/HandleExceptions # Yes, robocop, ignoring all exceptions is normally # a bad idea. Here, an exception just means we don't # understand what was in a `where` block, so we can't # meaningfully sytringify it. We still have a decent # default stringification. end new_criteria_string += Trace.to_ruby(src) end self.class.new(resource, filtered_raw_data, new_criteria_string) end
Private Instance Methods
decorate_symbols(thing)
click to toggle source
# File lib/inspec/utils/filter.rb, line 282 def decorate_symbols(thing) return thing.map { |t| decorate_symbols(t) } if thing.is_a?(Array) return ":" + thing.to_s if thing.is_a? Symbol return thing + " (String)" if thing.is_a? String thing end
filter_raw_data(current_raw_data, field, desired_value)
click to toggle source
# File lib/inspec/utils/filter.rb, line 262 def filter_raw_data(current_raw_data, field, desired_value) return [] if current_raw_data.empty? method_ref = case desired_value when Float then :matches_float when Integer then :matches_int when Regexp then :matches_regex else :matches end assume_symbolic_keyed_data = current_raw_data.first.keys.first.is_a? Symbol field = assume_symbolic_keyed_data ? field.to_sym : field.to_s current_raw_data.find_all do |row| next unless row.key?(field) send(method_ref, row[field], desired_value) end end
matches(x, y)
click to toggle source
# File lib/inspec/utils/filter.rb, line 258 def matches(x, y) y === x # rubocop:disable Style/CaseEquality end
matches_float(x, y)
click to toggle source
# File lib/inspec/utils/filter.rb, line 238 def matches_float(x, y) return false if x.nil? return false if !x.is_a?(Float) && (x =~ /\A[-+]?(\d+\.?\d*|\.\d+)\z/).nil? x.to_f == y end
matches_int(x, y)
click to toggle source
# File lib/inspec/utils/filter.rb, line 245 def matches_int(x, y) return false if x.nil? return false if !x.is_a?(Integer) && (x =~ /\A[-+]?\d+\z/).nil? x.to_i == y end
matches_regex(x, y)
click to toggle source
# File lib/inspec/utils/filter.rb, line 252 def matches_regex(x, y) return x == y if x.is_a?(Regexp) !x.to_s.match(y).nil? end