Class: Parlour::ConflictResolver

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/parlour/conflict_resolver.rb

Overview

Responsible for resolving conflicts (that is, multiple definitions with the same name) between objects defined in the same namespace.

Instance Method Summary collapse

Instance Method Details

#resolve_conflicts(namespace) {|message, candidates| ... } ⇒ void

This method returns an undefined value.

Given a namespace, attempts to automatically resolve conflicts in the namespace’s definitions. (A conflict occurs when multiple objects share the same name.)

All children of the given namespace which are also namespaces are processed recursively, so passing RbiGenerator#root will eliminate all conflicts in the entire object tree.

If automatic resolution is not possible, the block passed to this method is invoked and passed two arguments: a message on what the conflict is, and an array of candidate objects. The block should return one of these candidate objects, which will be kept, and all other definitions are deleted. Alternatively, the block may return nil, which will delete all definitions. The block may be invoked many times from one call to #resolve_conflicts, one for each unresolvable conflict.

Parameters:

Yield Parameters:

  • message (String)

    A descriptional message on what the conflict is.

  • candidates (Array<RbiGenerator::RbiObject>)

    The objects for which there is a conflict.

Yield Returns:



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/parlour/conflict_resolver.rb', line 41

def resolve_conflicts(namespace, &resolver)
  # Check for multiple definitions with the same name
  grouped_by_name_children = namespace.children.group_by(&:name)

  grouped_by_name_children.each do |name, children|
    if children.length > 1
      # We found a conflict!
      # Start by removing all the conflicting items
      children.each do |c|
        namespace.children.delete(c)
      end

      # We can only try to resolve automatically if they're all the same 
      # type of object, so check that first
      children_type = single_type_of_array(children)
      unless children_type
        # The types aren't the same, so ask the resovler what to do, and
        # insert that (if not nil)
        choice = resolver.call("Different kinds of definition for the same name", children)
        namespace.children << choice if choice
        next
      end

      # Can the children merge themselves automatically? If so, let them
      first, *rest = children
      first, rest = T.must(first), T.must(rest)
      if T.must(first).mergeable?(T.must(rest))
        first.merge_into_self(rest)
        namespace.children << first
        next
      end

      # I give up! Let it be resolved manually somehow
      choice = resolver.call("Can't automatically resolve", children)
      namespace.children << choice if choice
    end
  end

  # Recurse to child namespaces
  namespace.children.each do |child|
    resolve_conflicts(child, &resolver) if RbiGenerator::Namespace === child
  end
end