Class: KVDAG::Vertex

Inherits:
Object
  • Object
show all
Includes:
Comparable, AttributeNode
Defined in:
lib/kvdag/vertex.rb

Overview

A vertex in a KVDAG

Instance Attribute Summary collapse

Attributes included from AttributeNode

#attrs

Instance Method Summary collapse

Methods included from AttributeNode

#[], #[]=, #fetch, #filter, #match?, #merge!, #to_hash

Constructor Details

#initialize(dag, attrs = {}) ⇒ Vertex

Returns a new instance of Vertex.



17
18
19
20
21
22
23
24
# File 'lib/kvdag/vertex.rb', line 17

def initialize(dag, attrs = {})
  @edges = Set.new
  @dag = dag
  @attrs = dag.hash_proxy_class.new(attrs)
  @child_cache = Set.new

  @dag.vertices << self
end

Instance Attribute Details

#dagObject (readonly)

Returns the value of attribute dag.



7
8
9
# File 'lib/kvdag/vertex.rb', line 7

def dag
  @dag
end

#edgesObject (readonly)

Returns the value of attribute edges.



8
9
10
# File 'lib/kvdag/vertex.rb', line 8

def edges
  @edges
end

Instance Method Details

#<=>(other) ⇒ Object

Comparable ordering for a DAG:

Reachable vertices are lesser. Unreachable vertices are equal.



143
144
145
146
147
# File 'lib/kvdag/vertex.rb', line 143

def <=>(other)
  return -1 if reachable?(other)
  return 1 if reachable_from?(other)
  return 0
end

#ancestors(filter = {}, &block) ⇒ Object

:call-seq:

vtx.ancestors                 -> all ancestors
vtx.ancestors(filter)         -> ancestors matching +filter+
vtx.ancestors {|anc| ... }    -> call block with each ancestor

Return the set of this object and all its parents, and their parents, recursively, possibly filtered by #match? expressions. If a block is given, call it with each ancestor.



103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/kvdag/vertex.rb', line 103

def ancestors(filter = {}, &block)
  result = Set.new
  result << self if match?(filter)

  parents.each { |p| result += p.ancestors(filter) }

  if block_given?
    result.each(&block)
  else
    result
  end
end

#children(filter = {}, &block) ⇒ Object

:call-seq:

vtx.children                 -> all children
vtx.children(filter)         -> children matching +filter+
vtx.children {|cld| ... }    -> call block with each child

Returns the set of all direct children, possibly filtered by #match? expressions. If a block is given, call it with each child.



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/kvdag/vertex.rb', line 62

def children(filter = {}, &block)
  result = @child_cache.select { |child|
             child.match?(filter)
           }

  if block_given?
    result.each(&block)
  else
    result
  end
end

#descendants(filter = {}, &block) ⇒ Object

:call-seq:

vtx.descendants                 -> all descendants
vtx.descendants(filter)         -> descendants matching +filter+
vtx.descendants {|desc| ... }   -> call block with each descendant

Return the set of this object and all its children, and their children, recursively, possibly filtered by #match? expressions. If a block is given, call it with each descendant.



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/kvdag/vertex.rb', line 125

def descendants(filter = {}, &block)
  result = Set.new
  result << self if match?(filter)

  children.each { |c| result += c.descendants(filter) }

  if block_given?
    result.each(&block)
  else
    result
  end
end

#edge(other, attrs = {}) ⇒ Object

Create an edge towards an other vertex, optionally loaded with key-values.

A KVDAG::VertexError is raised if vertices belong to different KVDAG.

A KVDAG::CyclicError is raised if the edge would cause a cycle in the KVDAG.

Raises:



158
159
160
161
162
163
164
165
166
167
# File 'lib/kvdag/vertex.rb', line 158

def edge(other, attrs = {})
  other = other.to_vertex unless other.is_a?(Vertex)
  raise VertexError.new('Not in the same DAG') if @dag != other.dag
  raise CyclicError.new('Would become cyclic') if other.reachable?(self)

  edge = Edge.new(@dag, other, attrs)
  @edges << edge
  other.add_child(self)
  edge
end

#inspectObject Also known as: to_s



26
27
28
# File 'lib/kvdag/vertex.rb', line 26

def inspect
  '#<%s @attr=%s @edges=%s>' % [self.class, @attrs.to_hash, @edges.to_a]
end

#parents(filter = {}, &block) ⇒ Object

:call-seq:

vtx.parents                 -> all parents
vtx.parents(filter)         -> parents matching +filter+
vtx.parents {|cld| ... }    -> call block with each parent

Returns the set of all direct parents, possibly filtered by #match? expressions. If a block is given, call it with each parent.



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/kvdag/vertex.rb', line 40

def parents(filter = {}, &block)
  result = Set.new(edges.map { |edge|
                     edge.to_vertex
                   }.select { |parent|
                     parent.match?(filter)
                   })

  if block_given?
    result.each(&block)
  else
    result
  end
end

#reachable?(other) ⇒ Boolean

Is other vertex reachable via any of my #edges?

A KVDAG::VertexError is raised if vertices belong to different KVDAG.

Returns:

  • (Boolean)

Raises:



79
80
81
82
83
# File 'lib/kvdag/vertex.rb', line 79

def reachable?(other)
  raise VertexError.new('Not in the same DAG') unless @dag.equal?(other.dag)

  equal?(other) || parents.any? { |parent| parent.reachable?(other) }
end

#reachable_from?(other) ⇒ Boolean

Am I reachable from other via any of its #edges?

A KVDAG::VertexError is raised if vertices belong to different KVDAG.

Returns:

  • (Boolean)


90
91
92
# File 'lib/kvdag/vertex.rb', line 90

def reachable_from?(other)
  other.reachable?(self)
end

#to_hash_proxyObject

Return the proxied key-value hash tree visible from this vertex via its edges and all its ancestors.

Calling #to_hash instead will return a regular hash tree, without any special properties, e.g. for serializing as YAML or JSON.



175
176
177
178
179
180
181
# File 'lib/kvdag/vertex.rb', line 175

def to_hash_proxy
  result = @dag.hash_proxy_class.new
  edges.each do |edge|
    result.merge!(edge.to_hash_proxy)
  end
  result.merge!(@attrs)
end