123456789_123456789_123456789_123456789_123456789_

Class: YARD::Parser::Ruby::TokenResolver

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

Overview

Supports #each enumeration over a source's tokens, yielding the token and a possible ::YARD::CodeObjects::Base associated with the constant or identifier token.

Class Method Summary

Instance Method Summary

::YARD::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(source, namespace = Registry.root) ⇒ TokenResolver

Creates a token resolver for given source.

Parameters:

  • source (String)

    the source code to tokenize

  • namespace (CodeObjects::Base) (defaults to: Registry.root)

    the object/namespace to resolve from

Raises:

[ GitHub ]

  
# File 'lib/yard/parser/ruby/token_resolver.rb', line 16

def initialize(source, namespace = Registry.root)
  @tokens = RubyParser.parse(source, '(tokenize)').tokens
  raise ParserSyntaxError if @tokens.empty? && !source.empty?
  @default_namespace = namespace
end

Class Method Details

.state_attr(*attrs)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/token_resolver.rb', line 92

def self.state_attr(*attrs)
  attrs.each do |attr|
    define_method(attr) { @states.last[attr.to_sym] }
    define_method("#{attr}=") {|v| @states.last[attr.to_sym] = v }
    protected attr, :"#{attr}="
  end
end

Instance Method Details

#each {|token, object| ... }

Iterates over each token, yielding the token and a possible code object that is associated with the token.

Examples:

Yielding code objects

r = TokenResolver.new("A::B::C")
r.each do |tok, obj|
  if obj
    puts "#{tok[0]} -> #{obj.path.inspect}"
  else
    puts "No object: #{tok.inspect}"
  end
end

# Prints:
# :const -> "A"
# No object: [:op, "::"]
# :const -> "A::B"
# No object: [:op, "::"]
# :const -> "A::B::C"

Yield Parameters:

  • token (Array(Symbol,String,Array(Integer,Integer)))

    the current token object being iterated

  • object (CodeObjects::Base, nil)

    the fully qualified code object associated with the current token, or nil if there is no object for the yielded token.

[ GitHub ]

  
# File 'lib/yard/parser/ruby/token_resolver.rb', line 46

def each
  @states = []
  push_state
  @tokens.each do |token|
    yield_obj = false

    if skip_group && [:const, :ident, :op, :period].include?(token[0])
      yield token, nil
      next
    else
      self.skip_group = false
    end

    case token[0]
    when :const
      lookup(token[0], token[1])
      yield_obj = true
      self.last_sep = nil
    when :ident
      lookup(token[0], token[1])
      yield_obj = true
      self.last_sep = nil
    when :op, :period
      self.last_sep = token[1]
      unless CodeObjects.types_for_separator(token[1])
        self.object = nil
        self.last_sep = nil
      end
    when :lparen
      push_state
    when :rparen
      pop_state
    else
      self.object = nil
    end

    yield token, (yield_obj ? object : nil)

    if next_object
      self.object = next_object
      self.next_object = nil
    end
    self.skip_group = true if yield_obj && object.nil?
  end
end

#lookup(toktype, name) (private)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/token_resolver.rb', line 112

def lookup(toktype, name)
  types = object_resolved_types
  return self.object = nil if types.empty?

  if toktype == :const
    types.any? do |type|
      prefix = type ? type.path : ""
      prefix += last_sep.to_s if separators.include?(last_sep.to_s)
      self.object = Registry.resolve(@default_namespace, "#{prefix}#{name}", true)
    end
  else # ident
    types.any? do |type|
      obj = Registry.resolve(type, name, true)
      if obj.nil? && name == "new"
        obj = Registry.resolve(object, "#initialize", true)
        self.next_object = object if obj.nil?
      end
      self.object = obj
    end
  end
end

#object_resolved_types(obj = object) (private)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/token_resolver.rb', line 134

def object_resolved_types(obj = object)
  return [obj] unless obj.is_a?(CodeObjects::MethodObject)

  resolved_types = []
  tags = obj.tags(:return)
  tags += obj.tags(:overload).map {|o| o.tags(:return) }.flatten
  tags.each do |tag|
    next if tag.types.nil?
    tag.types.each do |type|
      type = type.sub(/<.+>/, '')
      if type == "self"
        resolved_types << obj.parent
      else
        type_obj = Registry.resolve(obj, type, true)
        resolved_types << type_obj if type_obj
      end
    end
  end

  resolved_types
end

#pop_state (private)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/token_resolver.rb', line 106

def pop_state
  @states.pop
end

#push_state (private)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/token_resolver.rb', line 102

def push_state
  @states.push :object => nil, :skip_group => false, :last_sep => nil
end