class Facter::Core::Aggregate

Attributes

confines[R]

@!attribute [r] confines

@return [Array<LegacyFacter::Core::Confine>] An array of confines restricting

this to a specific platform

@api private

deps[R]

@!attribute [r] deps

@return [LegacyFacter::Core::DirectedGraph]

@api private

fact[R]

@!attribute [r] fact

@return [Facter::Util::Fact]

@api private

fact_type[R]

@!attribute [r] fact_type

@return [Symbol] The fact type of the aggregate resolution

@api private

last_evaluated[R]

@!attribute [r] last_evaluated

@return [String]

@api public

name[R]

@!attribute [r] name

@return [Symbol] The name of the aggregate resolution

@api public

Public Class Methods

new(name, fact) click to toggle source

Create a new aggregated resolution mechanism.

@param name [String] The name of the resolution. @param fact [Facter::Fact] The fact to which this

resolution will be added.

@return [Facter::Util::Resolution] The created resolution

@api private

# File lib/facter/custom_facts/core/aggregate.rb, line 72
def initialize(name, fact)
  @name = name
  @fact = fact

  @confines = []
  @chunks = {}

  @aggregate = nil
  @deps = LegacyFacter::Core::DirectedGraph.new
end

Public Instance Methods

<=>(other) click to toggle source

Compares the weight of two aggregate facts

@return [bool] Weight comparison result

@api private

# File lib/facter/custom_facts/core/aggregate.rb, line 88
def <=>(other)
  weight <=> other.weight
end
aggregate(&block) click to toggle source

Define how all chunks should be combined

@example Merge all chunks

aggregate.aggregate do |chunks|
  final_result = {}
  chunks.each_value do |chunk|
    final_result.deep_merge(chunk)
  end
  final_result
end

@example Sum all chunks

aggregate.aggregate do |chunks|
  total = 0
  chunks.each_value do |chunk|
    total += chunk
  end
  total
end

@yield [Hash<Symbol, Object>] A hash containing chunk names and

chunk values

@return [Facter::Core::Aggregate] The aggregate fact

@api public

# File lib/facter/custom_facts/core/aggregate.rb, line 182
def aggregate(&block)
  raise ArgumentError, "#{self.class.name}#aggregate requires a block" unless block_given?

  @aggregate = block
  self
end
chunk(name, opts = {}, &block) click to toggle source

Define a new chunk for the given aggregate

@example Defining a chunk with no dependencies

aggregate.chunk(:mountpoints) do
  # generate mountpoint information
end

@example Defining an chunk to add mount options

aggregate.chunk(:mount_options, :require => [:mountpoints]) do |mountpoints|
  # `mountpoints` is the result of the previous chunk
  # generate mount option information based on the mountpoints
end

@param name [Symbol] A name unique to this aggregate describing the chunk

@param opts [Hash] Hash with options for the aggregate fact

@return [Facter::Core::Aggregate] The aggregate object

@api public

# File lib/facter/custom_facts/core/aggregate.rb, line 142
def chunk(name, opts = {}, &block)
  evaluate_params(name, &block)

  deps = Array(opts.delete(:require))

  unless opts.empty?
    raise ArgumentError, "Unexpected options passed to #{self.class.name}#chunk: #{opts.keys.inspect}"
  end

  @deps[name] = deps
  @chunks[name] = block
  self
end
evaluate(&block) click to toggle source

Evaluates the given block

@return [String] Result of the block’s evaluation

@api private

# File lib/facter/custom_facts/core/aggregate.rb, line 110
def evaluate(&block)
  if @last_evaluated
    msg = +"Already evaluated #{@name}"
    msg << " at #{@last_evaluated}" if msg.is_a? String
    msg << ', reevaluating anyways'
    log.warn msg
  end
  instance_eval(&block)

  @last_evaluated = block.source_location.join(':')
end
options(options) click to toggle source

Sets options for the aggregate fact

@return [nil]

@api private

# File lib/facter/custom_facts/core/aggregate.rb, line 97
def options(options)
  accepted_options = %i[name timeout weight fact_type]
  accepted_options.each do |option_name|
    instance_variable_set("@#{option_name}", options.delete(option_name)) if options.key?(option_name)
  end
  raise ArgumentError, "Invalid aggregate options #{options.keys.inspect}" unless options.keys.empty?
end
resolution_type() click to toggle source

Returns the fact’s resolution type

@return [Symbol] The fact’s type

@api private

# File lib/facter/custom_facts/core/aggregate.rb, line 194
def resolution_type
  :aggregate
end

Private Instance Methods

aggregate_results(results) click to toggle source

Process the results of all chunks with the aggregate block and return the results. If no aggregate block has been specified, fall back to deep merging the given data structure

@param results [Hash<Symbol, Object>] A hash of chunk names and the output

of that chunk.

@return [Object]

# File lib/facter/custom_facts/core/aggregate.rb, line 242
def aggregate_results(results)
  if @aggregate
    @aggregate.call(results)
  else
    default_aggregate(results)
  end
end
default_aggregate(results) click to toggle source
# File lib/facter/custom_facts/core/aggregate.rb, line 250
def default_aggregate(results)
  results.values.inject do |result, current|
    LegacyFacter::Util::Values.deep_merge(result, current)
  end
rescue LegacyFacter::Util::Values::DeepMergeError => e
  raise ArgumentError, 'Could not deep merge all chunks (Original error: ' \
                   "#{e.message}), ensure that chunks return either an Array or Hash or " \
                   'override the aggregate block', e.backtrace
end
evaluate_params(name) click to toggle source
# File lib/facter/custom_facts/core/aggregate.rb, line 204
def evaluate_params(name)
  raise ArgumentError, "#{self.class.name}#chunk requires a block" unless block_given?
  raise ArgumentError, "#{self.class.name}#expected chunk name to be a Symbol" unless name.is_a? Symbol
end
log() click to toggle source
# File lib/facter/custom_facts/core/aggregate.rb, line 200
def log
  @log ||= Facter::Log.new(self)
end
order_chunks() click to toggle source

Order chunks based on their dependencies

@return [Array<Symbol, Proc>] A list of chunk names and blocks in evaluation order.

# File lib/facter/custom_facts/core/aggregate.rb, line 263
def order_chunks
  unless @deps.acyclic?
    raise DependencyError,
          "Could not order chunks; found the following dependency cycles: #{@deps.cycles.inspect}"
  end

  sorted_names = @deps.tsort

  sorted_names.map do |name|
    [name, @chunks[name]]
  end
end
resolve_value() click to toggle source

Evaluate the results of this aggregate.

@see Facter::Core::Resolvable#value @return [Object]

# File lib/facter/custom_facts/core/aggregate.rb, line 213
def resolve_value
  chunk_results = run_chunks
  aggregate_results(chunk_results)
end
run_chunks() click to toggle source

Order all chunks based on their dependencies and evaluate each one, passing dependent chunks as needed.

@return [Hash<Symbol, Object>] A hash containing the chunk that

generated value and the related value.
# File lib/facter/custom_facts/core/aggregate.rb, line 223
def run_chunks
  results = {}
  order_chunks.each do |(name, block)|
    input = @deps[name].map { |dep_name| results[dep_name] }

    output = block.call(*input)
    results[name] = LegacyFacter::Util::Values.deep_freeze(output)
  end

  results
end