class RDoc::Store

单个项目(gem、路径等)的一组 rdoc 数据。

该存储器管理项目的 ri 数据的读取和写入,并在存储器中维护方法、类和祖先的缓存。

存储器维护其内容的缓存,以便更快地查找。将项目添加到存储器后,必须使用save_cache刷新它。缓存包含以下结构

@cache = {
  :ancestors        => {}, # class name => ancestor names
  :attributes       => {}, # class name => attributes
  :class_methods    => {}, # class name => class methods
  :instance_methods => {}, # class name => instance methods
  :modules          => [], # classes and modules in this store
  :pages            => [], # page names
}

常量

MarshalFilter

属性

c_class_variables[R]

将 C 变量映射到每个已解析的 C 文件的类或模块名称。

c_singleton_class_variables[R]

将 C 变量映射到每个已解析的 C 文件的单例类名称。

cache[R]

存储器的内容

dry_run[RW]

如果为 true,则此存储器将不写入任何文件

encoding[RW]

存储器中内容的编码

path[RW]

此存储器读取或写入的路径

rdoc[RW]

此解析树的RDoc::RDoc驱动程序。 这允许咨询文档树的类访问用户设置的选项,例如。

type[RW]

加载此 ri 数据存储的类型。 请参阅RDoc::RI::DriverRDoc::RI::Paths

unmatched_constant_alias[R]

惰性常量别名将在传递过程中被发现

公共类方法

new(path = nil, type = nil) 单击以切换源代码

创建 type 的新存储器,该存储器将加载或保存到 path

# File rdoc/store.rb, line 127
def initialize path = nil, type = nil
  @dry_run  = false
  @encoding = nil
  @path     = path
  @rdoc     = nil
  @type     = type

  @cache = {
    :ancestors                   => {},
    :attributes                  => {},
    :class_methods               => {},
    :c_class_variables           => {},
    :c_singleton_class_variables => {},
    :encoding                    => @encoding,
    :instance_methods            => {},
    :main                        => nil,
    :modules                     => [],
    :pages                       => [],
    :title                       => nil,
  }

  @classes_hash = {}
  @modules_hash = {}
  @files_hash   = {}
  @text_files_hash = {}

  @c_enclosure_classes = {}
  @c_enclosure_names   = {}

  @c_class_variables           = {}
  @c_singleton_class_variables = {}

  @unique_classes = nil
  @unique_modules = nil

  @unmatched_constant_alias = {}
end

公共实例方法

add_c_enclosure(variable, namespace) 单击以切换源代码

module 添加为给定 variable 的 C 文件的封闭(命名空间)。

# File rdoc/store.rb, line 169
def add_c_enclosure variable, namespace
  @c_enclosure_classes[variable] = namespace
end
add_c_variables(c_parser) 单击以切换源代码

RDoc::Parser::C添加 C 变量

# File rdoc/store.rb, line 176
def add_c_variables c_parser
  filename = c_parser.top_level.relative_name

  @c_class_variables[filename] = make_variable_map c_parser.classes

  @c_singleton_class_variables[filename] = c_parser.singleton_classes
end
add_file(absolute_name, relative_name: absolute_name, parser: nil) 单击以切换源代码

将具有 name 的文件作为RDoc::TopLevel添加到存储器。返回创建的RDoc::TopLevel

# File rdoc/store.rb, line 188
def add_file absolute_name, relative_name: absolute_name, parser: nil
  unless top_level = @files_hash[relative_name] then
    top_level = RDoc::TopLevel.new absolute_name, relative_name
    top_level.parser = parser if parser
    top_level.store = self
    @files_hash[relative_name] = top_level
    @text_files_hash[relative_name] = top_level if top_level.text?
  end

  top_level
end
all_classes() 单击以切换源代码

返回RDoc发现的所有类

# File rdoc/store.rb, line 224
def all_classes
  @classes_hash.values
end
all_classes_and_modules() 单击以切换源代码

返回RDoc发现的所有类和模块

# File rdoc/store.rb, line 231
def all_classes_and_modules
  @classes_hash.values + @modules_hash.values
end
all_files() 单击以切换源代码

RDoc已知的所有 TopLevel

# File rdoc/store.rb, line 238
def all_files
  @files_hash.values
end
all_modules() 单击以切换源代码

返回RDoc发现的所有模块

# File rdoc/store.rb, line 245
def all_modules
  modules_hash.values
end
ancestors() 单击以切换源代码

祖先缓存访问器。 将 klass 名称映射到此存储器中其祖先的数组。如果此存储器中的 Foo 继承自Object,则不会列出 Kernel(它将包含在 ruby 的 ri 存储器中)。

# File rdoc/store.rb, line 254
def ancestors
  @cache[:ancestors]
end
attributes() 单击以切换源代码

属性缓存访问器。 将一个类映射到其属性的数组。

# File rdoc/store.rb, line 261
def attributes
  @cache[:attributes]
end
cache_path() 单击以切换源代码

缓存文件的路径

# File rdoc/store.rb, line 268
def cache_path
  File.join @path, 'cache.ri'
end
class_file(klass_name) 单击以切换源代码

klass_name 的 ri 数据的路径

# File rdoc/store.rb, line 275
def class_file klass_name
  name = klass_name.split('::').last
  File.join class_path(klass_name), "cdesc-#{name}.ri"
end
class_methods() 单击以切换源代码

类方法缓存访问器。 将一个类映射到其类方法数组(不是全名)。

# File rdoc/store.rb, line 284
def class_methods
  @cache[:class_methods]
end
class_path(klass_name) 单击以切换源代码

将存储 klass_name 的数据(方法或类数据)的路径

# File rdoc/store.rb, line 291
def class_path klass_name
  File.join @path, *klass_name.split('::')
end
classes_hash() 单击以切换源代码

RDoc已知的所有类的哈希

# File rdoc/store.rb, line 298
def classes_hash
  @classes_hash
end
complete(min_visibility) 单击以切换源代码

准备RDoc代码对象树以供生成器使用。

它会查找定义的唯一类/模块,并用设置了RDoc::ClassModule#is_alias_for的副本替换作为另一个别名的类/模块。

它更新“真实”类或模块的RDoc::ClassModule#constant_aliases属性。

它还会完全删除应从文档中删除的类和模块,以及可见性低于 min_visibility 的方法,min_visibility--visibility 选项。

另请参阅RDoc::Context#remove_from_documentation?

# File rdoc/store.rb, line 334
def complete min_visibility
  fix_basic_object_inheritance

  # cache included modules before they are removed from the documentation
  all_classes_and_modules.each { |cm| cm.ancestors }

  unless min_visibility == :nodoc then
    remove_nodoc @classes_hash
    remove_nodoc @modules_hash
  end

  @unique_classes = find_unique @classes_hash
  @unique_modules = find_unique @modules_hash

  unique_classes_and_modules.each do |cm|
    cm.complete min_visibility
  end

  @files_hash.each_key do |file_name|
    tl = @files_hash[file_name]

    unless tl.text? then
      tl.modules_hash.clear
      tl.classes_hash.clear

      tl.classes_or_modules.each do |cm|
        name = cm.full_name
        if cm.type == 'class' then
          tl.classes_hash[name] = cm if @classes_hash[name]
        else
          tl.modules_hash[name] = cm if @modules_hash[name]
        end
      end
    end
  end
end
files_hash() 单击以切换源代码

RDoc已知的所有文件的哈希

# File rdoc/store.rb, line 374
def files_hash
  @files_hash
end
find_c_enclosure(variable) 单击以切换源代码

查找给定 C variable 的封闭(命名空间)。

# File rdoc/store.rb, line 381
def find_c_enclosure variable
  @c_enclosure_classes.fetch variable do
    break unless name = @c_enclosure_names[variable]

    mod = find_class_or_module name

    unless mod then
      loaded_mod = load_class_data name

      file = loaded_mod.in_files.first

      return unless file # legacy data source

      file.store = self

      mod = file.add_module RDoc::NormalModule, name
    end

    @c_enclosure_classes[variable] = mod
  end
end
find_class_named(name) 单击以切换源代码

查找所有已发现的类中具有 name 的类

# File rdoc/store.rb, line 406
def find_class_named name
  @classes_hash[name]
end
find_class_named_from(name, from) 单击以切换源代码

查找从命名空间 from 开始的具有 name 的类

# File rdoc/store.rb, line 413
def find_class_named_from name, from
  from = find_class_named from unless RDoc::Context === from

  until RDoc::TopLevel === from do
    return nil unless from

    klass = from.find_class_named name
    return klass if klass

    from = from.parent
  end

  find_class_named name
end
find_class_or_module(name) 单击以切换源代码

查找具有 name 的类或模块

# File rdoc/store.rb, line 431
def find_class_or_module name
  name = $' if name =~ /^::/
  @classes_hash[name] || @modules_hash[name]
end
find_file_named(name) 单击以切换源代码

查找所有已发现的文件中具有 name 的文件

# File rdoc/store.rb, line 439
def find_file_named name
  @files_hash[name]
end
find_module_named(name) 单击以切换源代码

查找所有已发现的模块中具有 name 的模块

# File rdoc/store.rb, line 446
def find_module_named name
  @modules_hash[name]
end
find_text_page(file_name) 单击以切换源代码

返回作为文本文件并具有给定 file_nameRDoc::TopLevel

# File rdoc/store.rb, line 454
def find_text_page file_name
  @text_files_hash.each_value.find do |file|
    file.full_name == file_name
  end
end
find_unique(all_hash) 单击以切换源代码

查找 all_hash 中定义的唯一类/模块,并将它们作为数组返回。在 all_hash 中执行别名更新:请参阅 ::complete。

# File rdoc/store.rb, line 467
def find_unique all_hash
  unique = []

  all_hash.each_pair do |full_name, cm|
    unique << cm if full_name == cm.full_name
  end

  unique
end
fix_basic_object_inheritance() 单击以切换源代码

修复 1.9 中的错误 BasicObject < Object

因为我们假设所有没有声明超类的类都继承自Object,所以我们有上述错误的继承。

如果我们在 Ruby 版本 >= 1.9 中运行,我们会立即修复 BasicObject。

# File rdoc/store.rb, line 486
def fix_basic_object_inheritance
  basic = classes_hash['BasicObject']
  return unless basic
  basic.superclass = nil
end
friendly_path() 单击以切换源代码

path的友好表示

# File rdoc/store.rb, line 495
def friendly_path
  case type
  when :gem    then
    parent = File.expand_path '..', @path
    "gem #{File.basename parent}"
  when :home   then RDoc.home
  when :site   then 'ruby site'
  when :system then 'ruby core'
  else @path
  end
end
instance_methods() 单击以切换源代码

实例方法缓存访问器。 将一个类映射到其实例方法的数组(不是全名)。

# File rdoc/store.rb, line 515
def instance_methods
  @cache[:instance_methods]
end
load_all() 单击以切换源代码

将此存储器中的所有项加载到内存中。这将重新创建供生成器使用的文档树

# File rdoc/store.rb, line 523
def load_all
  load_cache

  module_names.each do |module_name|
    mod = find_class_or_module(module_name) || load_class(module_name)

    # load method documentation since the loaded class/module does not have
    # it
    loaded_methods = mod.method_list.map do |method|
      load_method module_name, method.full_name
    end

    mod.method_list.replace loaded_methods

    loaded_attributes = mod.attributes.map do |attribute|
      load_method module_name, attribute.full_name
    end

    mod.attributes.replace loaded_attributes
  end

  all_classes_and_modules.each do |mod|
    descendent_re = /^#{mod.full_name}::[^:]+$/

    module_names.each do |name|
      next unless name =~ descendent_re

      descendent = find_class_or_module name

      case descendent
      when RDoc::NormalClass then
        mod.classes_hash[name] = descendent
      when RDoc::NormalModule then
        mod.modules_hash[name] = descendent
      end
    end
  end

  @cache[:pages].each do |page_name|
    page = load_page page_name
    @files_hash[page_name] = page
    @text_files_hash[page_name] = page if page.text?
  end
end
load_cache() 单击以切换源代码

为此存储器加载缓存文件

# File rdoc/store.rb, line 571
def load_cache
  #orig_enc = @encoding

  @cache = marshal_load(cache_path)

  load_enc = @cache[:encoding]

  # TODO this feature will be time-consuming to add:
  # a) Encodings may be incompatible but transcodeable
  # b) Need to warn in the appropriate spots, wherever they may be
  # c) Need to handle cross-cache differences in encodings
  # d) Need to warn when generating into a cache with different encodings
  #
  #if orig_enc and load_enc != orig_enc then
  #  warn "Cached encoding #{load_enc} is incompatible with #{orig_enc}\n" \
  #       "from #{path}/cache.ri" unless
  #    Encoding.compatible? orig_enc, load_enc
  #end

  @encoding = load_enc unless @encoding

  @cache[:pages]                       ||= []
  @cache[:main]                        ||= nil
  @cache[:c_class_variables]           ||= {}
  @cache[:c_singleton_class_variables] ||= {}

  @cache[:c_class_variables].each do |_, map|
    map.each do |variable, name|
      @c_enclosure_names[variable] = name
    end
  end

  @cache
rescue Errno::ENOENT
end
load_class(klass_name) 单击以切换源代码

加载 klass_name 的 ri 数据,并将其连接到此存储器。

# File rdoc/store.rb, line 610
def load_class klass_name
  obj = load_class_data klass_name

  obj.store = self

  case obj
  when RDoc::NormalClass then
    @classes_hash[klass_name] = obj
  when RDoc::SingleClass then
    @classes_hash[klass_name] = obj
  when RDoc::NormalModule then
    @modules_hash[klass_name] = obj
  end
end
load_class_data(klass_name) 单击以切换源代码

加载 klass_name 的 ri 数据

# File rdoc/store.rb, line 628
def load_class_data klass_name
  file = class_file klass_name

  marshal_load(file)
rescue Errno::ENOENT => e
  error = MissingFileError.new(self, file, klass_name)
  error.set_backtrace e.backtrace
  raise error
end
load_method(klass_name, method_name) 单击以切换源代码

klass_name 中加载 method_name 的 ri 数据

# File rdoc/store.rb, line 641
def load_method klass_name, method_name
  file = method_file klass_name, method_name

  obj = marshal_load(file)
  obj.store = self
  obj.parent ||= find_class_or_module(klass_name) || load_class(klass_name)
  obj
rescue Errno::ENOENT => e
  error = MissingFileError.new(self, file, klass_name + method_name)
  error.set_backtrace e.backtrace
  raise error
end
load_page(page_name) 单击以切换源代码

加载 page_name 的 ri 数据

# File rdoc/store.rb, line 657
def load_page page_name
  file = page_file page_name

  obj = marshal_load(file)
  obj.store = self
  obj
rescue Errno::ENOENT => e
  error = MissingFileError.new(self, file, page_name)
  error.set_backtrace e.backtrace
  raise error
end
main() 单击以切换源代码

获取此RDoc存储器的主要页面。 此页面用作RDoc服务器的根目录。

# File rdoc/store.rb, line 673
def main
  @cache[:main]
end
main=(page) 单击以切换源代码

设置此RDoc存储器的主要页面。

# File rdoc/store.rb, line 680
def main= page
  @cache[:main] = page
end
make_variable_map(variables) 单击以切换源代码

将 C 解析器中的变量 => ClassModule 映射 variables 转换为变量 => 类名称映射。

# File rdoc/store.rb, line 688
def make_variable_map variables
  map = {}

  variables.each { |variable, class_module|
    map[variable] = class_module.full_name
  }

  map
end
method_file(klass_name, method_name) 单击以切换源代码

klass_namemethod_name 的 ri 数据的路径

# File rdoc/store.rb, line 701
def method_file klass_name, method_name
  method_name = method_name.split('::').last
  method_name =~ /#(.*)/
  method_type = $1 ? 'i' : 'c'
  method_name = $1 if $1
  method_name = method_name.gsub(/\W/) { "%%%02x" % $&[0].ord }

  File.join class_path(klass_name), "#{method_name}-#{method_type}.ri"
end
module_names() 单击以切换源代码

模块缓存访问器。 存储器中所有模块(和类)名称的数组。

# File rdoc/store.rb, line 715
def module_names
  @cache[:modules]
end
modules_hash() 单击以切换源代码

RDoc已知的所有模块的哈希

# File rdoc/store.rb, line 722
def modules_hash
  @modules_hash
end
page(name) 单击以切换源代码

返回作为文本文件并具有给定 nameRDoc::TopLevel

# File rdoc/store.rb, line 729
def page name
  @text_files_hash.each_value.find do |file|
    file.page_name == name or file.base_name == name
  end
end
page_file(page_name) 单击以切换源代码

page_name 的 ri 数据的路径

# File rdoc/store.rb, line 738
def page_file page_name
  file_name = File.basename(page_name).gsub('.', '_')

  File.join @path, File.dirname(page_name), "page-#{file_name}.ri"
end
remove_nodoc(all_hash) 单击以切换源代码

all_hash 中移除那些标记为 nodoc 或没有内容的上下文。

请参阅 RDoc::Context#remove_from_documentation?

# File rdoc/store.rb, line 749
def remove_nodoc all_hash
  all_hash.keys.each do |name|
    context = all_hash[name]
    all_hash.delete(name) if context.remove_from_documentation?
  end
end
resolve_c_superclasses() 点击以切换源代码

确保对 C 变量名的任何引用都被解析为对应的类。

# File rdoc/store.rb, line 204
def resolve_c_superclasses
  @classes_hash.each_value do |klass|
    if klass.superclass.is_a?(String) && (candidate = find_c_enclosure(klass.superclass))
      klass.superclass = candidate
    end
  end
end
save() 点击以切换源代码

保存存储中的所有条目

# File rdoc/store.rb, line 759
def save
  load_cache

  all_classes_and_modules.each do |klass|
    save_class klass

    klass.each_method do |method|
      save_method klass, method
    end

    klass.each_attribute do |attribute|
      save_method klass, attribute
    end
  end

  all_files.each do |file|
    save_page file
  end

  save_cache
end
save_cache() 点击以切换源代码

为这个存储写入缓存文件

# File rdoc/store.rb, line 784
def save_cache
  clean_cache_collection @cache[:ancestors]
  clean_cache_collection @cache[:attributes]
  clean_cache_collection @cache[:class_methods]
  clean_cache_collection @cache[:instance_methods]

  @cache[:modules].uniq!
  @cache[:modules].sort!

  @cache[:pages].uniq!
  @cache[:pages].sort!

  @cache[:encoding] = @encoding # this gets set twice due to assert_cache

  @cache[:c_class_variables].merge!           @c_class_variables
  @cache[:c_singleton_class_variables].merge! @c_singleton_class_variables

  return if @dry_run

  File.open cache_path, 'wb' do |io|
    Marshal.dump @cache, io
  end
end
save_class(klass) 点击以切换源代码

klass (或模块) 写入 ri 数据

# File rdoc/store.rb, line 811
def save_class klass
  full_name = klass.full_name

  FileUtils.mkdir_p class_path(full_name) unless @dry_run

  @cache[:modules] << full_name

  path = class_file full_name

  begin
    disk_klass = load_class full_name

    klass = disk_klass.merge klass
  rescue MissingFileError
  end

  # BasicObject has no ancestors
  ancestors = klass.direct_ancestors.compact.map do |ancestor|
    # HACK for classes we don't know about (class X < RuntimeError)
    String === ancestor ? ancestor : ancestor.full_name
  end

  @cache[:ancestors][full_name] ||= []
  @cache[:ancestors][full_name].concat ancestors

  attribute_definitions = klass.attributes.map do |attribute|
    "#{attribute.definition} #{attribute.name}"
  end

  unless attribute_definitions.empty? then
    @cache[:attributes][full_name] ||= []
    @cache[:attributes][full_name].concat attribute_definitions
  end

  to_delete = []

  unless klass.method_list.empty? then
    @cache[:class_methods][full_name]    ||= []
    @cache[:instance_methods][full_name] ||= []

    class_methods, instance_methods =
      klass.method_list.partition { |meth| meth.singleton }

    class_methods    = class_methods.   map { |method| method.name }
    instance_methods = instance_methods.map { |method| method.name }
    attribute_names  = klass.attributes.map { |attr|   attr.name }

    old = @cache[:class_methods][full_name] - class_methods
    to_delete.concat old.map { |method|
      method_file full_name, "#{full_name}::#{method}"
    }

    old = @cache[:instance_methods][full_name] -
      instance_methods - attribute_names
    to_delete.concat old.map { |method|
      method_file full_name, "#{full_name}##{method}"
    }

    @cache[:class_methods][full_name]    = class_methods
    @cache[:instance_methods][full_name] = instance_methods
  end

  return if @dry_run

  FileUtils.rm_f to_delete

  File.open path, 'wb' do |io|
    Marshal.dump klass, io
  end
end
save_method(klass, method) 点击以切换源代码

klass 上的 method 写入 ri 数据

# File rdoc/store.rb, line 885
def save_method klass, method
  full_name = klass.full_name

  FileUtils.mkdir_p class_path(full_name) unless @dry_run

  cache = if method.singleton then
            @cache[:class_methods]
          else
            @cache[:instance_methods]
          end
  cache[full_name] ||= []
  cache[full_name] << method.name

  return if @dry_run

  File.open method_file(full_name, method.full_name), 'wb' do |io|
    Marshal.dump method, io
  end
end
save_page(page) 点击以切换源代码

page 写入 ri 数据

# File rdoc/store.rb, line 908
def save_page page
  return unless page.text?

  path = page_file page.full_name

  FileUtils.mkdir_p File.dirname(path) unless @dry_run

  cache[:pages] ||= []
  cache[:pages] << page.full_name

  return if @dry_run

  File.open path, 'wb' do |io|
    Marshal.dump page, io
  end
end
source() 点击以切换源代码

此存储内容来源。

对于来自 gem 的存储,来源是 gem 的名称。 对于来自主目录的存储,来源是 “home”。 对于系统 ri 存储(标准库文档),来源是 “ruby”。 对于来自站点 ri 目录的存储,存储的来源是 “site”。 对于其他存储,来源是 path

# File rdoc/store.rb, line 934
def source
  case type
  when :gem    then File.basename File.expand_path '..', @path
  when :home   then 'home'
  when :site   then 'site'
  when :system then 'ruby'
  else @path
  end
end
title() 点击以切换源代码

获取此 RDoc 存储的标题。 这将用作 RDoc 服务器上每个页面的标题。

# File rdoc/store.rb, line 948
def title
  @cache[:title]
end
title=(title) 点击以切换源代码

为此 RDoc 存储设置标题页面。

# File rdoc/store.rb, line 955
def title= title
  @cache[:title] = title
end
unique_classes() 点击以切换源代码

返回 RDoc 发现的唯一类。

::complete 必须在使用此方法之前被调用。

# File rdoc/store.rb, line 964
def unique_classes
  @unique_classes
end
unique_classes_and_modules() 点击以切换源代码

返回 RDoc 发现的唯一类和模块。 ::complete 必须在使用此方法之前被调用。

# File rdoc/store.rb, line 972
def unique_classes_and_modules
  @unique_classes + @unique_modules
end
unique_modules() 点击以切换源代码

返回 RDoc 发现的唯一模块。 ::complete 必须在使用此方法之前被调用。

# File rdoc/store.rb, line 980
def unique_modules
  @unique_modules
end
update_parser_of_file(absolute_name, parser) 点击以切换源代码

设置 absolute_name 的解析器,除非它来自源代码文件。

# File rdoc/store.rb, line 215
def update_parser_of_file(absolute_name, parser)
  if top_level = @files_hash[absolute_name] then
    @text_files_hash[absolute_name] = top_level if top_level.text?
  end
end

私有实例方法

marshal_load(file) 点击以切换源代码
# File rdoc/store.rb, line 985
def marshal_load(file)
  File.open(file, 'rb') {|io| Marshal.load(io, MarshalFilter)}
end