class Yoda::Store::YardImporter

Attributes

patch[R]

@return [Objects::Patch]

root_path[R]

@return [String, nil]

Public Class Methods

import(file, root_path: nil) click to toggle source

@param file [String] @param root_path [String, nil] @return [Objects::Patch]

# File lib/yoda/store/yard_importer.rb, line 15
def self.import(file, root_path: nil)
  store = YARD::RegistryStore.new
  store.load(file)
  root_path ||= File.expand_path('..', file)
  new(file, root_path: root_path).import(store.values).patch
end
new(id, root_path: nil) click to toggle source

@param id [String]

# File lib/yoda/store/yard_importer.rb, line 23
def initialize(id, root_path: nil)
  @patch = Objects::Patch.new(id)
  @root_path = root_path
  @registered = Set.new
end

Public Instance Methods

import(values) click to toggle source

@param values [Array<YARD::CodeObjects::Base>] @return [self]

# File lib/yoda/store/yard_importer.rb, line 31
def import(values)
  values.each do |el|
    register(el)
  end
  self
end
register(code_object) click to toggle source

@param code_object [YARD::CodeObjects::Base]

# File lib/yoda/store/yard_importer.rb, line 39
def register(code_object)
  return if @registered.member?(code_object.path)
  @registered.add(code_object.path)
  register(code_object.parent) if code_object.parent

  new_objects = begin
    case code_object.type
    when :root
      convert_root_object(code_object)
    when :class
      convert_class_object(code_object)
    when :module
      convert_module_object(code_object)
    when :classvariable
      # convert_class_variable_object(code_object)
    when :method
      convert_method_object(code_object)
    when :macro
      # convert_macro_object(code_object)
    when :constant
      convert_constant_object(code_object)
    when :proxy
      create_proxy_module(code_object)
    else
      fail ArgumentError, 'Unsupported type code object'
    end
  end

  # In YARD, proxy module is undetermined its absolute path and its defined namespace is undetermined.
  # In Yoda, proxy module is assumed to be defined directory under parent namespace.
  register_to_parent(code_object) if code_object.parent && (code_object.type == :proxy || code_object.parent.type == :proxy)
  [new_objects].flatten.compact.each { |new_object| patch.register(new_object) }
end

Private Instance Methods

calc_path_to_store(object) click to toggle source

@param code_object [::YARD::CodeObjects::Base] @return [String] absolute object path to store.

# File lib/yoda/store/yard_importer.rb, line 277
def calc_path_to_store(object)
  return 'Object' if object.root?
  parent_path = path_to_store(object.parent)

  if object.type == :proxy || object.is_a?(YARD::CodeObjects::Proxy)
    # For now, we suppose the proxy object exists directly under its namespace.
    [path_to_store(object.parent), object.name].join('::')
  elsif object.parent.path == path_to_store(object.parent)
    object.path
  else
    [path_to_store(object.parent), object.name].join(object.sep)
  end.gsub(/^Object::/, '')
end
convert_class_object(code_object) click to toggle source

@param code_object [::YARD::CodeObjects::ClassObject] @return [Array<Objects::ClassObject, Objects::MetaClassObject>]

# File lib/yoda/store/yard_importer.rb, line 172
def convert_class_object(code_object)
  class_object = Objects::ClassObject.new(
    path: path_to_store(code_object),
    document: code_object.docstring.to_s,
    tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object)) },
    sources: code_object.files.map(&method(:convert_source)),
    primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
    instance_method_addresses: code_object.meths(included: false, scope: :instance).map { |meth| path_to_store(meth) },
    mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
    constant_addresses: code_object.children.select{ |child| %i(constant module class).include?(child.type) }.map { |constant| path_to_store(constant) },
    superclass_path: !code_object.superclass || code_object.superclass&.path == 'Qnil' ? nil : path_to_store(code_object.superclass),
  )

  meta_class_object = Objects::MetaClassObject.new(
    path: path_to_store(code_object),
    sources: code_object.files.map(&method(:convert_source)),
    primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
    instance_method_addresses: code_object.meths(included: false, scope: :class).map { |meth| path_to_store(meth) },
    mixin_addresses: code_object.class_mixins.map { |mixin| path_to_store(mixin) },
  )

  [class_object, meta_class_object]
end
convert_constant_object(code_object) click to toggle source

@param code_object [::YARD::CodeObjects::ConstantObject] @return [Objects::ValueObject]

# File lib/yoda/store/yard_importer.rb, line 100
def convert_constant_object(code_object)
  Objects::ValueObject.new(
    path: path_to_store(code_object),
    document: code_object.docstring.to_s,
    tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object.namespace)) },
    sources: code_object.files.map(&method(:convert_source)),
    primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
    value: code_object.value,
  )
end
convert_method_object(code_object) click to toggle source

@param code_object [::YARD::CodeObjects::MethodObject] @return [Objects::MethodObject, (Objects::MethodObject, Object::ClassObject)]

# File lib/yoda/store/yard_importer.rb, line 113
def convert_method_object(code_object)
  if code_object.namespace.root?
    # @todo Remove root oriented method path from Object namespace
    method_object = Objects::MethodObject.new(
      path: "Object#{code_object.sep}#{code_object.name}",
      document: code_object.docstring.to_s,
      tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object.namespace)) },
      overloads: code_object.tags(:overload).map { |tag| convert_overload_tag(tag, path_to_store(code_object.namespace)) },
      sources: code_object.files.map(&method(:convert_source)),
      primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
      parameters: code_object.parameters,
      visibility: :private,
    )
    object_object = Objects::ClassObject.new(
      path: 'Object',
      instance_method_addresses: ["Object#{code_object.sep}#{code_object.name}"],
    )
    [method_object, object_object]
  else
    Objects::MethodObject.new(
      path: path_to_store(code_object),
      document: code_object.docstring.to_s,
      tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object.namespace)) },
      overloads: code_object.tags(:overload).map { |tag| convert_overload_tag(tag, path_to_store(code_object.namespace)) },
      sources: code_object.files.map(&method(:convert_source)),
      primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
      parameters: code_object.parameters,
      visibility: code_object.visibility,
    )
  end
end
convert_module_object(code_object) click to toggle source

@param code_object [::YARD::CodeObjects::ModuleObject] @return [Array<Objects::ModuleObject, Objects::MetaClassObject>]

# File lib/yoda/store/yard_importer.rb, line 147
def convert_module_object(code_object)
  module_object = Objects::ModuleObject.new(
    path: path_to_store(code_object),
    document: code_object.docstring.to_s,
    tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object)) },
    sources: code_object.files.map(&method(:convert_source)),
    primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
    instance_method_addresses: code_object.meths(included: false, scope: :instance).map { |meth| path_to_store(meth) },
    mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
    constant_addresses: code_object.children.select{ |child| %i(constant module class).include?(child.type) }.map { |constant| constant.path },
  )

  meta_class_object = Objects::MetaClassObject.new(
    path: path_to_store(code_object),
    sources: code_object.files.map(&method(:convert_source)),
    primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
    instance_method_addresses: code_object.meths(included: false, scope: :class).map { |meth| path_to_store(meth) },
    mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
  )

  [module_object, meta_class_object]
end
convert_overload_tag(tag, namespace) click to toggle source

@param tag [::YARD::Tags::OverloadTag] @param namespace [String] @return [Objects::Tag]

# File lib/yoda/store/yard_importer.rb, line 206
def convert_overload_tag(tag, namespace)
  Objects::Overload.new(name: tag.name.to_s, tag_list: tag.tags.map { |tag| convert_tag(tag, namespace) }, document: tag.docstring.to_s, parameters: tag.parameters)
end
convert_root_object(code_object) click to toggle source

@param code_object [::YARD::CodeObjects::NamespaceObject] @return [Objects::ClassObject]

# File lib/yoda/store/yard_importer.rb, line 77
def convert_root_object(code_object)
  object_class = Objects::ClassObject.new(
    path: path_to_store(code_object),
    document: code_object.docstring.to_s,
    tag_list: code_object.tags.map { |tag| convert_tag(tag, '') },
    sources: code_object.files.map(&method(:convert_source)),
    primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
    instance_method_addresses: code_object.meths(included: false, scope: :instance).map { |meth| path_to_store(meth) },
    mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
    constant_addresses: (code_object.children.select{ |child| %i(constant module class).include?(child.type) }.map { |constant| constant.path } + ['Object']).uniq,
  )
  object_meta_class = Objects::MetaClassObject.new(
    path: path_to_store(code_object),
    sources: code_object.files.map(&method(:convert_source)),
    primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
    instance_method_addresses: code_object.meths(included: false, scope: :class).map { |meth| path_to_store(meth) },
    mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
  )
  [object_class, object_meta_class]
end
convert_source(source) click to toggle source

@param source [(String, Integer)] @return [(String, Integer, Integer)]

# File lib/yoda/store/yard_importer.rb, line 263
def convert_source(source)
  file, line = source
  [root_path ? File.expand_path(file, root_path) : file, line, 0]
end
convert_tag(tag, namespace) click to toggle source

@param tag [::YARD::Tags::Tag] @param namespace [String] @return [Objects::Tag]

# File lib/yoda/store/yard_importer.rb, line 199
def convert_tag(tag, namespace)
  Objects::Tag.new(tag_name: tag.tag_name, name: tag.name, yard_types: tag.types, text: tag.text, lexical_scope: convert_to_lexical_scope(namespace))
end
convert_to_lexical_scope(namespace) click to toggle source

@param namespace [String] @return [Array<String>]

# File lib/yoda/store/yard_importer.rb, line 212
def convert_to_lexical_scope(namespace)
  path = Model::Path.new(namespace)
  ((path.to_s.empty? ? [] : [path]) + path.parent_paths).map(&:to_s)
end
convert_yard_object_type(type) click to toggle source

@param symbol [Symbol] @return [Symbol]

# File lib/yoda/store/yard_importer.rb, line 219
def convert_yard_object_type(type)
  case type
  when :constant
    :value
  else
    type
  end
end
create_proxy_module(code_object) click to toggle source

@param code_object [::YARD::CodeObjects::Proxy] @return [Array<Objects::ModuleObject>]

# File lib/yoda/store/yard_importer.rb, line 230
def create_proxy_module(code_object)
  module_object = Objects::ModuleObject.new(
    path: path_to_store(code_object),
    document: '',
    tag_list: [],
    sources: [],
    primary_source: nil,
    instance_method_addresses: [],
    mixin_addresses: [],
    constant_addresses: [],
  )

  meta_class_object = Objects::MetaClassObject.new(
    path: path_to_store(code_object),
    sources: [],
    primary_source: nil,
    instance_method_addresses: [],
    mixin_addresses: [],
  )

  [module_object, meta_class_object]
end
path_to_store(object) click to toggle source

@param code_object [::YARD::CodeObjects::Base] @return [String]

# File lib/yoda/store/yard_importer.rb, line 270
def path_to_store(object)
  @paths_to_store ||= {}
  @paths_to_store[[object.type, object.path]] ||= calc_path_to_store(object)
end
register_to_parent(code_object) click to toggle source

@param code_object [::YARD::CodeObjects::Base] @return [vaid]

# File lib/yoda/store/yard_importer.rb, line 255
def register_to_parent(code_object)
  parent_module = patch.find(path_to_store(code_object.parent))
  parent_module.instance_method_addresses.push(path_to_store(code_object)) if code_object.type == :method
  parent_module.constant_addresses.push(path_to_store(code_object)) if [:class, :module, :proxy].include?(code_object.type)
end