class YARD::Parser::Ruby::TokenResolver

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

Public Class Methods

new(source, namespace = Registry.root) click to toggle source

Creates a token resolver for given source.

@param source [String] the source code to tokenize @param namespace [CodeObjects::Base] the object/namespace to resolve from

# 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
state_attr(*attrs) click to toggle source
# 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

Public Instance Methods

each() { |token, nil| ... } click to toggle source

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

@yieldparam token [Array(Symbol,String,Array(Integer,Integer))] the

current token object being iterated

@yieldparam 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.

@example 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"
# 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

Private Instance Methods

lookup(toktype, name) click to toggle source
# 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) click to toggle source
# 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() click to toggle source
# File lib/yard/parser/ruby/token_resolver.rb, line 106
def pop_state
  @states.pop
end
push_state() click to toggle source
# File lib/yard/parser/ruby/token_resolver.rb, line 102
def push_state
  @states.push :object => nil, :skip_group => false, :last_sep => nil
end