# Class: YARD::RegistryResolver

Inherits:
  Object
  - Object
  - YARD::RegistryResolver
  show all

Includes:
  CodeObjects::NamespaceMapper

Defined in:
  lib/yard/registry_resolver.rb

## Overview

Handles all logic for complex lexical and inherited object resolution. Used by YARD::Registry.resolve, so there is no need to use this class directly.

See Also:

- YARD::Registry.resolve

Since:

- 0.9.1

## Instance Method Summary collapse

- #initialize(registry = Registry) ⇒ RegistryResolver constructor

  Creates a new resolver object for a registry.

- #lookup_by_path(path, opts = {}) ⇒ CodeObjects::Base, ...

  Performs a lookup on a given path in the registry.

### Methods included from CodeObjects::NamespaceMapper

#clear_separators, #default_separator, on_invalidate, #register_separator, #separators, #separators_for_type, #separators_match, #types_for_separator, #unregister_separator_by_type

## Constructor Details

### #initialize(registry = Registry) ⇒ `RegistryResolver`

Creates a new resolver object for a registry.

Parameters:

- registry (`Registry`) (defaults to: `Registry`) —

  only set this if customizing the registry object

Since:

- 0.9.1

    16
    17
    18
    19
    20
    21
    22

    # File 'lib/yard/registry_resolver.rb', line 16

    def initialize(registry = Registry)
      @registry = registry
      @default_sep = nil

      # Preload all code objects for separator declarations
      YARD::CodeObjects.constants.map {|t| YARD::CodeObjects.const_get(t) }
    end

## Instance Method Details

### #lookup_by_path(path, opts = {}) ⇒ `CodeObjects::Base`, ...

Performs a lookup on a given path in the registry. Resolution will occur in a similar way to standard Ruby identifier resolution, doing lexical lookup, as well as (optionally) through the inheritance chain. A proxy object can be returned if the lookup fails for future resolution. The proxy will be type hinted with the `type` used in the original lookup.

#### Examples:

#####

A lookup from root

    resolver.lookup_by_path("A::B::C")

#####

A lookup from the A::B namespace

    resolver.lookup_by_path("C", namespace: P("A::B"))

#####

A lookup on a method through the inheritance tree

    resolver.lookup_by_math("A::B#foo", inheritance: true)

Parameters:

- opts (`Hash`) (defaults to: `{}`) —

  a customizable set of options

Options Hash (`opts`):

- namespace (`CodeObjects::Base`, `:root`, `nil`) — default: `nil` —

  the namespace object to start searching from. If root or nil is provided, YARD::Registry.root is assumed.

- inheritance (`Boolean`) — default: `false` —

  whether to perform lookups through the inheritance chain (includes mixins)

- proxy_fallback (`Boolean`) — default: `false` —

  when true, a proxy is returned if no match is found

- type (`Symbol`) — default: `nil` —

  an optional type hint for the resolver to consider when performing a lookup. If a type is provided and the resolved object’s type does not match the hint, the object is discarded.

Returns:

- (`CodeObjects::Base`, `CodeObjects::Proxy`, `nil`) —

  the first object that matches the path lookup. If proxy_fallback is provided, a proxy object will be returned in the event of no match, otherwise nil will be returned.

Since:

- 0.9.1

    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
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101

    # File 'lib/yard/registry_resolver.rb', line 50

    def lookup_by_path(path, opts = {})
      path = path.to_s
      namespace = opts[:namespace]
      inheritance = opts[:inheritance] || false
      proxy_fallback = opts[:proxy_fallback] || false
      type = opts[:type]

      if namespace.is_a?(CodeObjects::Proxy)
        return proxy_fallback ? CodeObjects::Proxy.new(namespace, path, type) : nil
      end

      if namespace == :root || !namespace
        namespace = @registry.root
      else
        namespace = namespace.parent until namespace.is_a?(CodeObjects::NamespaceObject)
      end
      orignamespace = namespace

      if path =~ starts_with_default_separator_match
        path = $'
        namespace = @registry.root
        orignamespace = @registry.root
      end

      resolved = nil
      lexical_lookup = 0
      while namespace && !resolved
        resolved = lookup_path_direct(namespace, path, type)
        # Prevent a bare name from resolving back to the namespace we started
        # from when searching through a parent namespace. For example,
        # `include Enumerable` inside `A::Enumerable` would walk up to namespace
        # `A` and match `A::Enumerable`, creating a false self-referential mixin.
        # Only skip when we have already moved to a parent (namespace != orignamespace).
        # See https://github.com/lsegal/yard/issues/1116
        resolved = nil if resolved.equal?(orignamespace) && !namespace.equal?(orignamespace)
        resolved ||= lookup_path_inherited(namespace, path, type) if inheritance
        break if resolved
        namespace = namespace.parent
        lexical_lookup += 1
      end

      # method objects cannot be resolved through lexical lookup by more than 1 ns
      if lexical_lookup > 1 && resolved.is_a?(CodeObjects::MethodObject)
        resolved = nil
      end

      if proxy_fallback
        resolved ||= CodeObjects::Proxy.new(orignamespace, path, type)
      end

      resolved
    end