123456789_123456789_123456789_123456789_123456789_

Class: YARD::RegistryResolver

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: lib/yard/registry_resolver.rb

Overview

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

See Also:

Since:

  • 0.9.1

Class Method Summary

Instance Method Summary

CodeObjects::NamespaceMapper - Included

#clear_separators

Clears the map of separators.

#default_separator

Gets or sets the default separator value to use when no separator for the namespace can be determined.

#register_separator

Registers a separator with an optional set of valid types that must follow the separator lexically.

#separators, #separators_for_type, #separators_match, #types_for_separator,
#unregister_separator_by_type

Unregisters a separator by a type.

Constructor Details

.new(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

[ GitHub ]

  
# 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

#collect_namespaces(object) (private)

Collects and returns all inherited namespaces for a given object

Since:

  • 0.9.1

[ GitHub ]

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

def collect_namespaces(object)
  return [] unless object.respond_to?(:inheritance_tree)

  nss = object.inheritance_tree(true)
  if object.respond_to?(:superclass)
    nss |= [P('Object')] if object.superclass != P('BasicObject')
    nss |= [P('BasicObject')]
  end

  nss
end

#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, 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

[ GitHub ]

  
# 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)
    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

#lookup_path_direct(namespace, path, type) (private)

Performs a lexical lookup from a namespace for a path and a type hint.

Since:

  • 0.9.1

[ GitHub ]

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

def lookup_path_direct(namespace, path, type)
  result = namespace.root? && validate(@registry.at(path), type)
  return result if result

  if path =~ starts_with_separator_match
    return validate(@registry.at(namespace.path + path), type)
  end

  separators.each do |sep|
    result = validate(@registry.at("#{namespace.path}#{sep}#{path}"), type)
    return result if result
  end

  nil
end

#lookup_path_inherited(namespace, path, type) (private)

Performs a lookup through the inheritance chain on a path with a type hint.

Since:

  • 0.9.1

[ GitHub ]

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

def lookup_path_inherited(namespace, path, type)
  resolved = nil
  last_obj = namespace
  scopes = []
  last_sep = nil
  pos = 0

  if path =~ starts_with_separator_match
    last_sep = $1
    path = $'
  end

  path.scan(split_on_separators_match).each do |part, sep|
    cur_obj = nil
    pos += part.length
    pos += sep.length
    parsed_end = pos == path.length

    if !last_obj || (!parsed_end && !last_obj.is_a?(CodeObjects::NamespaceObject))
      break # can't continue
    end

    collect_namespaces(last_obj).each do |ns|
      next if ns.is_a?(CodeObjects::Proxy)

      found = nil
      search_seps = []
      scopes.each do |scope|
        search_seps += separators_for_type(scope)
      end

      if search_seps.empty?
        search_seps =
          if ns.type == :root
            [""]
          elsif last_sep.nil?
            separators
          else
            [@default_sep]
          end
      end

      ([last_sep] | search_seps).compact.each do |search_sep|
        found = @registry.at(ns.path + search_sep.to_s + part)
        break if found
      end

      break cur_obj = found if found
    end

    last_sep = sep
    scopes = types_for_separator(sep) || []
    last_obj = cur_obj
    resolved = cur_obj if parsed_end && cur_obj && (type.nil? || type == cur_obj.type)
  end

  resolved
end

#split_on_separators_matchRegexp (private)

Returns:

  • (Regexp)

    the regexp that can be used to split a string on all occurrences of separator tokens

Since:

  • 0.9.1

[ GitHub ]

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

def split_on_separators_match
  @@split_on_separators_match ||= /(.+?)(#{separators_match}|$)/
end

#starts_with_default_separator_matchRegexp (private)

Returns:

  • (Regexp)

    the regexp match of the default separator

Since:

  • 0.9.1

[ GitHub ]

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

def starts_with_default_separator_match
  @@starts_with_default_separator_match ||= /\A#{default_separator}/
end

#starts_with_separator_matchRegexp (private)

Returns:

  • (Regexp)

    the regexp that matches strings starting with a separator

Since:

  • 0.9.1

[ GitHub ]

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

def starts_with_separator_match
  @@starts_with_separator_match ||= /\A(#{separators_match})/
end

#validate(obj, type) (private)

return [Boolean] if the obj's type matches the provided type.

Since:

  • 0.9.1

[ GitHub ]

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

def validate(obj, type)
  !type || (obj && obj.type == type) ? obj : nil
end