Dependency

class
Superclass
Object
Extended With
Loggability

A inter-node dependency that is outside of the implicit ones expressed by the tree.

Attributes

behavior[R]

The behavior that determines if the dependency is met by any or all of the nodes.

identifier_states[R]

The Hash of identifier states

subdeps[R]

The Array of sub-dependencies (instances of Dependency).

Public Class Methods

anchor
from_hash( hash )

Construct a new instance using the specified hash, which should be in the same form as that generated by to_h:

{
  behavior: <string>,
  identifiers: [<identifier_1>, <identifier_n>],
  subdeps: [<dephash_1>, <dephash_n>],
}
# File lib/arborist/dependency.rb, line 42
def self::from_hash( hash )
        self.log.debug "Creating a new %p from a hash: %p" % [ self, hash ]

        hash[:subdeps] ||= []
        subdeps = hash[:subdeps].map {|subhash| self.from_hash(subhash) }

        return self.new( hash[:behavior], hash[:identifiers] + subdeps )
end
anchor
new( behavior, *nodes_or_subdeps )

Create a new Dependency on the specified nodes_or_subdeps with the given behavior (one of :any or :all)

# File lib/arborist/dependency.rb, line 54
def initialize( behavior, *nodes_or_subdeps )
        @behavior = behavior
        @subdeps, identifiers = nodes_or_subdeps.flatten.
                partition {|obj| obj.is_a?(self.class) }
        @identifier_states = identifiers.product([ nil ]).to_h
end
anchor
on( behavior, *identifiers, prefixes: nil )

Construct a new Dependency for the specified behavior on the given identifiers with prefixes.

# File lib/arborist/dependency.rb, line 23
def self::on( behavior, *identifiers, prefixes: nil )
        deps, identifiers = identifiers.flatten.uniq.partition {|obj| obj.is_a?(self.class) }
        prefixes = Array( prefixes ).uniq
        identifiers = prefixes.product( identifiers ).map {|pair| pair.join('-') } unless
                prefixes.empty?

        return self.new( behavior, identifiers + deps )
end

Public Instance Methods

anchor
==( other )

Equality comparison operator – return true if the other dependency has the same behavior, identifiers, and sub-dependencies. Does not consider identifier states.

# File lib/arborist/dependency.rb, line 295
def ==( other )
        return true if other.equal?( self )
        return false unless other.is_a?( self.class )

        return self.behavior == other.behavior &&
                self.identifiers == other.identifiers &&
                self.subdeps == other.subdeps
end
anchor
all_identifiers()

Return the Set of this Dependency's identifiers as well as those of all of its sub-dependencies.

# File lib/arborist/dependency.rb, line 120
def all_identifiers
        return self.identifiers + self.subdep_identifiers
end
anchor
down?()

Returns true if this dependency cannot be met.

# File lib/arborist/dependency.rb, line 192
def down?
        case self.behavior
        when :all
                self.identifier_states.values.any? || self.subdeps.any?( &:down? )
        when :any
                self.identifier_states.values.all? && self.subdeps.all?( &:down? )
        end
end
anchor
down_identifiers()

Return a Set of identifiers which have been marked down in this dependency.

# File lib/arborist/dependency.rb, line 101
def down_identifiers
        return Set.new( self.identifier_states.select {|_, mark| mark }.map(&:first) )
end
anchor
down_primary_reasons()

Return an English description of why any first tier dependencies are not met, or nil if there are none.

# File lib/arborist/dependency.rb, line 236
def down_primary_reasons
        ids = self.down_identifiers
        return nil if ids.empty?

        msg = nil
        case self.behavior
        when :all
                msg = ids.first.dup
                if ids.size == 1
                        msg << " is unavailable"
                else
                        msg << " (and %d other%s) are unavailable" % [ ids.size - 1, ids.size == 2 ? '' : 's' ]
                end

                msg << " as of %s" % [ self.earliest_down_time ]

        when :any
                msg = "%s are all unavailable" % [ ids.to_a.join(', ') ]
                msg << " as of %s" % [ self.latest_down_time ]

        else
                raise "Don't know how to build a description of down behavior for %p" % [ self.behavior ]
        end
end
anchor
down_reason()

Return an English description of why this dependency is not met. If it is met, returns nil.

# File lib/arborist/dependency.rb, line 222
def down_reason
        parts = [
                self.down_primary_reasons,
                self.down_secondary_reasons
        ].compact

        return nil if parts.empty?

        return parts.join( '; ' )
end
anchor
down_secondary_reasons()

Return an English description of why any subdependencies are not met, or nil if there are none.

# File lib/arborist/dependency.rb, line 264
def down_secondary_reasons
        subdeps = self.down_subdeps
        return nil if subdeps.empty?

        return subdeps.map( &:down_reason ).join( ' and ' )
end
anchor
down_subdeps()

Return any of this dependency's sub-dependencies that are down.

# File lib/arborist/dependency.rb, line 126
def down_subdeps
        return self.subdeps.select( &:down? )
end
anchor
each_downed() { |ident, time| ... }

Yield each unique identifier and Time of downed nodes from both direct and sub-dependencies.

# File lib/arborist/dependency.rb, line 139
def each_downed
        return enum_for( __method__ ) unless block_given?

        yielded = Set.new
        self.identifier_states.each do |ident, time|
                if time
                        yield( ident, time ) unless yielded.include?( ident )
                        yielded.add( ident )
                end
        end
        self.subdeps.each do |subdep|
                subdep.each_downed do |ident, time|
                        if time
                                yield( ident, time ) unless yielded.include?( ident )
                                yielded.add( ident )
                        end
                end
        end
end
anchor
earliest_down_time()

Returns the earliest Time a node was marked down.

# File lib/arborist/dependency.rb, line 209
def earliest_down_time
        return self.identifier_states.values.compact.min
end
anchor
empty?()

Returns true if this dependency doesn't contain any identifiers or sub-dependencies.

# File lib/arborist/dependency.rb, line 168
def empty?
        return self.all_identifiers.empty?
end
anchor
eql?( other )

Returns true if other is the same object or if they both have the same identifiers, sub-dependencies, and identifier states.

# File lib/arborist/dependency.rb, line 284
def eql?( other )
        self.log.debug "Comparing %p to %p (with states)" % [ self, other ]
        return true if other.equal?( self )
        return self == other &&
                self.identifier_states.eql?( other.identifier_states ) &&
                self.subdeps.eql?( other.subdeps )
end
anchor
identifiers()

Return a Set of identifiers belonging to this dependency.

# File lib/arborist/dependency.rb, line 95
def identifiers
        return Set.new( self.identifier_states.keys )
end
anchor
include?( *identifiers )

Returns true if the receiver includes all of the given identifiers.

# File lib/arborist/dependency.rb, line 161
def include?( *identifiers )
        return self.all_identifiers.include?( *identifiers )
end
anchor
latest_down_time()

Returns the latest Time a node was marked down.

# File lib/arborist/dependency.rb, line 215
def latest_down_time
        return self.identifier_states.values.compact.max
end
anchor
mark_down( identifier, time=Time.now )

Mark the specified identifier as being down and propagate it to any subdependencies.

# File lib/arborist/dependency.rb, line 174
def mark_down( identifier, time=Time.now )
        self.identifier_states[ identifier ] = time if self.identifier_states.key?( identifier )
        self.subdeps.each do |dep|
                dep.mark_down( identifier, time )
        end
end
anchor
mark_up( identifier )

Mark the specified identifier as being up and propagate it to any subdependencies.

# File lib/arborist/dependency.rb, line 183
def mark_up( identifier )
        self.subdeps.each do |dep|
                dep.mark_up( identifier )
        end
        self.identifier_states[ identifier ] = nil if self.identifier_states.key?( identifier )
end
anchor
subdep_identifiers()

Return a Set of identifiers for all of this Dependency's sub-dependencies.

# File lib/arborist/dependency.rb, line 113
def subdep_identifiers
        return self.subdeps.map( &:all_identifiers ).reduce( :+ ) || Set.new
end
anchor
to_h()

Return the entire dependency tree as a nested Hash.

# File lib/arborist/dependency.rb, line 273
def to_h
        return {
                behavior: self.behavior,
                identifiers: self.identifier_states.keys,
                subdeps: self.subdeps.map( &:to_h )
        }
end
anchor
up?()

Returns true if this dependency is met.

# File lib/arborist/dependency.rb, line 203
def up?
        return !self.down?
end
anchor
up_identifiers()

Return a Set of identifiers which have not been marked down in this dependency.

# File lib/arborist/dependency.rb, line 107
def up_identifiers
        return Set.new( self.identifier_states.reject {|_, mark| mark }.map(&:first) )
end
anchor
up_subdeps()

Return any of this dependency's sub-dependencies that are up.

# File lib/arborist/dependency.rb, line 132
def up_subdeps
        return self.subdeps.select( &:up? )
end