Method: Object#transitive_closure

Defined in:
lib/jinx/helpers/transitive_closure.rb

#transitive_closure(method = nil) {|node| ... } ⇒ Object

Returns the transitive closure over a method or block. This method returns an array partially ordered by the children method or block, i.e. each node occurs before all other nodes referenced directly or indirectly by the children.

If a method symbol or name is provided, then that method is called. Otherwise, the block is called. In either case, the call is expected to return an object or Enumerable of objects which also respond to the method or block.

Examples:

class Node
  attr_reader :parent, :children
  def initialize(name, parent=nil)
    super()
    @name = name
    @parent = parent
    @children = []
    parent.children << self if parent
  end
end
a = Node.new('a'); b = Node.new('b', a), c = Node.new('c', a); d = Node.new('d', c)
a.transitive_closure { |node| node.children }.to_a.join(", ") #=> a, b, c, d
a.transitive_closure(:children).to_a.join(", ") #=> a, b, c, d

Parameters:

  • method (Symbol, nil) (defaults to: nil)

    the child reference, or nil if a block is given

Yields:

  • (node)

    the parent node’s children

Yield Parameters:

  • node

    the parent node

Raises:

  • (ArgumentError)


29
30
31
32
33
34
35
36
37
38
# File 'lib/jinx/helpers/transitive_closure.rb', line 29

def transitive_closure(method=nil)
  raise ArgumentError.new("Missing both a method argument and a block") if method.nil? and not block_given?
  # If there is a method argument, then the transitive closure is based on that method.
  # Otherwise, visit the closure in reverse depth-first order.
  if method then
    transitive_closure() { |node| node.send(method) }
  else
    Jinx::Visitor.new(:depth_first) { |node| yield node }.to_enum(self).to_a.reverse
  end
end