class Arborist::Dependency
A inter-node dependency that is outside of the implicit ones expressed by the tree.
Attributes
The behavior that determines if the dependency is met by any or all of the nodes.
The Hash of identifier states
The Array of sub-dependencies (instances of Dependency
).
Public Class Methods
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Returns true
if this dependency is met.
# File lib/arborist/dependency.rb, line 203 def up? return !self.down? end
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
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