Class: Arborist::Dependency
- Inherits:
-
Object
- Object
- Arborist::Dependency
- Extended by:
- Loggability
- Defined in:
- lib/arborist/dependency.rb
Overview
A inter-node dependency that is outside of the implicit ones expressed by the tree.
Instance Attribute Summary collapse
-
#behavior ⇒ Object
readonly
The behavior that determines if the dependency is met by any or all of the nodes.
-
#identifier_states ⇒ Object
readonly
The Hash of identifier states.
-
#subdeps ⇒ Object
readonly
The Array of sub-dependencies (instances of Dependency).
Class Method Summary collapse
-
.from_hash(hash) ⇒ Object
Construct a new instance using the specified
hash
, which should be in the same form as that generated by #to_h:. -
.on(behavior, *identifiers, prefixes: nil) ⇒ Object
Construct a new Dependency for the specified
behavior
on the givenidentifiers
withprefixes
.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Equality comparison operator – return true if the
other
dependency has the same behavior, identifiers, and sub-dependencies. -
#all_identifiers ⇒ Object
Return the Set of this Dependency’s identifiers as well as those of all of its sub-dependencies.
-
#down? ⇒ Boolean
Returns
true
if this dependency cannot be met. -
#down_identifiers ⇒ Object
Return a Set of identifiers which have been marked down in this dependency.
-
#down_primary_reasons ⇒ Object
Return an English description of why any first tier dependencies are not met, or
nil
if there are none. -
#down_reason ⇒ Object
Return an English description of why this dependency is not met.
-
#down_secondary_reasons ⇒ Object
Return an English description of why any subdependencies are not met, or
nil
if there are none. -
#down_subdeps ⇒ Object
Return any of this dependency’s sub-dependencies that are down.
-
#each_downed ⇒ Object
Yield each unique identifier and Time of downed nodes from both direct and sub-dependencies.
-
#earliest_down_time ⇒ Object
Returns the earliest Time a node was marked down.
-
#empty? ⇒ Boolean
Returns
true
if this dependency doesn’t contain any identifiers or sub-dependencies. -
#eql?(other) ⇒ Boolean
Returns true if
other
is the same object or if they both have the same identifiers, sub-dependencies, and identifier states. -
#identifiers ⇒ Object
Return a Set of identifiers belonging to this dependency.
-
#include?(*identifiers) ⇒ Boolean
Returns
true
if the receiver includes all of the givenidentifiers
. -
#initialize(behavior, *nodes_or_subdeps) ⇒ Dependency
constructor
Create a new Dependency on the specified
nodes_or_subdeps
with the givenbehavior
(one of :any or :all). -
#initialize_clone(original) ⇒ Object
Clone constructor – clone internal datastructures without ephemeral state on #clone.
-
#initialize_dup(original) ⇒ Object
Dup constructor – dup internal datastructures without ephemeral state on #dup.
-
#latest_down_time ⇒ Object
Returns the latest Time a node was marked down.
-
#mark_down(identifier, time = Time.now) ⇒ Object
Mark the specified
identifier
as being down and propagate it to any subdependencies. -
#mark_up(identifier) ⇒ Object
Mark the specified
identifier
as being up and propagate it to any subdependencies. -
#subdep_identifiers ⇒ Object
Return a Set of identifiers for all of this Dependency’s sub-dependencies.
-
#to_h ⇒ Object
Return the entire dependency tree as a nested Hash.
-
#up? ⇒ Boolean
Returns
true
if this dependency is met. -
#up_identifiers ⇒ Object
Return a Set of identifiers which have not been marked down in this dependency.
-
#up_subdeps ⇒ Object
Return any of this dependency’s sub-dependencies that are up.
Constructor Details
#initialize(behavior, *nodes_or_subdeps) ⇒ Dependency
Create a new Dependency on the specified nodes_or_subdeps
with the given behavior
(one of :any or :all)
55 56 57 58 59 60 |
# File 'lib/arborist/dependency.rb', line 55 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 |
Instance Attribute Details
#behavior ⇒ Object (readonly)
The behavior that determines if the dependency is met by any or all of the nodes.
84 85 86 |
# File 'lib/arborist/dependency.rb', line 84 def behavior @behavior end |
#identifier_states ⇒ Object (readonly)
The Hash of identifier states
88 89 90 |
# File 'lib/arborist/dependency.rb', line 88 def identifier_states @identifier_states end |
#subdeps ⇒ Object (readonly)
The Array of sub-dependencies (instances of Dependency).
92 93 94 |
# File 'lib/arborist/dependency.rb', line 92 def subdeps @subdeps end |
Class Method Details
.from_hash(hash) ⇒ Object
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>],
}
43 44 45 46 47 48 49 50 |
# File 'lib/arborist/dependency.rb', line 43 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 |
.on(behavior, *identifiers, prefixes: nil) ⇒ Object
Construct a new Dependency for the specified behavior
on the given identifiers
with prefixes
.
24 25 26 27 28 29 30 31 |
# File 'lib/arborist/dependency.rb', line 24 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 |
Instance Method Details
#==(other) ⇒ Object
Equality comparison operator – return true if the other
dependency has the same behavior, identifiers, and sub-dependencies. Does not consider identifier states.
296 297 298 299 300 301 302 303 |
# File 'lib/arborist/dependency.rb', line 296 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 |
#all_identifiers ⇒ Object
Return the Set of this Dependency’s identifiers as well as those of all of its sub-dependencies.
121 122 123 |
# File 'lib/arborist/dependency.rb', line 121 def all_identifiers return self.identifiers + self.subdep_identifiers end |
#down? ⇒ Boolean
Returns true
if this dependency cannot be met.
193 194 195 196 197 198 199 200 |
# File 'lib/arborist/dependency.rb', line 193 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 |
#down_identifiers ⇒ Object
Return a Set of identifiers which have been marked down in this dependency.
102 103 104 |
# File 'lib/arborist/dependency.rb', line 102 def down_identifiers return Set.new( self.identifier_states.select {|_, mark| mark }.map(&:first) ) end |
#down_primary_reasons ⇒ Object
Return an English description of why any first tier dependencies are not met, or nil
if there are none.
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/arborist/dependency.rb', line 237 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 |
#down_reason ⇒ Object
Return an English description of why this dependency is not met. If it is met, returns nil
.
223 224 225 226 227 228 229 230 231 232 |
# File 'lib/arborist/dependency.rb', line 223 def down_reason parts = [ self.down_primary_reasons, self.down_secondary_reasons ].compact return nil if parts.empty? return parts.join( '; ' ) end |
#down_secondary_reasons ⇒ Object
Return an English description of why any subdependencies are not met, or nil
if there are none.
265 266 267 268 269 270 |
# File 'lib/arborist/dependency.rb', line 265 def down_secondary_reasons subdeps = self.down_subdeps return nil if subdeps.empty? return subdeps.map( &:down_reason ).join( ' and ' ) end |
#down_subdeps ⇒ Object
Return any of this dependency’s sub-dependencies that are down.
127 128 129 |
# File 'lib/arborist/dependency.rb', line 127 def down_subdeps return self.subdeps.select( &:down? ) end |
#each_downed ⇒ Object
Yield each unique identifier and Time of downed nodes from both direct and sub-dependencies.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/arborist/dependency.rb', line 140 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 |
#earliest_down_time ⇒ Object
Returns the earliest Time a node was marked down.
210 211 212 |
# File 'lib/arborist/dependency.rb', line 210 def earliest_down_time return self.identifier_states.values.compact.min end |
#empty? ⇒ Boolean
Returns true
if this dependency doesn’t contain any identifiers or sub-dependencies.
169 170 171 |
# File 'lib/arborist/dependency.rb', line 169 def empty? return self.all_identifiers.empty? end |
#eql?(other) ⇒ Boolean
Returns true if other
is the same object or if they both have the same identifiers, sub-dependencies, and identifier states.
285 286 287 288 289 290 291 |
# File 'lib/arborist/dependency.rb', line 285 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 |
#identifiers ⇒ Object
Return a Set of identifiers belonging to this dependency.
96 97 98 |
# File 'lib/arborist/dependency.rb', line 96 def identifiers return Set.new( self.identifier_states.keys ) end |
#include?(*identifiers) ⇒ Boolean
Returns true
if the receiver includes all of the given identifiers
.
162 163 164 |
# File 'lib/arborist/dependency.rb', line 162 def include?( *identifiers ) return self.all_identifiers.include?( *identifiers ) end |
#initialize_clone(original) ⇒ Object
Clone constructor – clone internal datastructures without ephemeral state on #clone.
71 72 73 74 |
# File 'lib/arborist/dependency.rb', line 71 def initialize_clone( original ) # :nodoc: @subdeps = @subdeps.map( &:clone ) @identifier_states = @identifier_states.keys.product([ nil ]).to_h end |
#initialize_dup(original) ⇒ Object
Dup constructor – dup internal datastructures without ephemeral state on #dup.
64 65 66 67 |
# File 'lib/arborist/dependency.rb', line 64 def initialize_dup( original ) # :nodoc: @subdeps = @subdeps.map( &:dup ) @identifier_states = @identifier_states.keys.product([ nil ]).to_h end |
#latest_down_time ⇒ Object
Returns the latest Time a node was marked down.
216 217 218 |
# File 'lib/arborist/dependency.rb', line 216 def latest_down_time return self.identifier_states.values.compact.max end |
#mark_down(identifier, time = Time.now) ⇒ Object
Mark the specified identifier
as being down and propagate it to any subdependencies.
175 176 177 178 179 180 |
# File 'lib/arborist/dependency.rb', line 175 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_up(identifier) ⇒ Object
Mark the specified identifier
as being up and propagate it to any subdependencies.
184 185 186 187 188 189 |
# File 'lib/arborist/dependency.rb', line 184 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 |
#subdep_identifiers ⇒ Object
Return a Set of identifiers for all of this Dependency’s sub-dependencies.
114 115 116 |
# File 'lib/arborist/dependency.rb', line 114 def subdep_identifiers return self.subdeps.map( &:all_identifiers ).reduce( :+ ) || Set.new end |
#to_h ⇒ Object
Return the entire dependency tree as a nested Hash.
274 275 276 277 278 279 280 |
# File 'lib/arborist/dependency.rb', line 274 def to_h return { behavior: self.behavior, identifiers: self.identifier_states.keys, subdeps: self.subdeps.map( &:to_h ) } end |
#up? ⇒ Boolean
Returns true
if this dependency is met.
204 205 206 |
# File 'lib/arborist/dependency.rb', line 204 def up? return !self.down? end |
#up_identifiers ⇒ Object
Return a Set of identifiers which have not been marked down in this dependency.
108 109 110 |
# File 'lib/arborist/dependency.rb', line 108 def up_identifiers return Set.new( self.identifier_states.reject {|_, mark| mark }.map(&:first) ) end |
#up_subdeps ⇒ Object
Return any of this dependency’s sub-dependencies that are up.
133 134 135 |
# File 'lib/arborist/dependency.rb', line 133 def up_subdeps return self.subdeps.select( &:up? ) end |