A set of ri data.

The store manages reading and writing ri data for a project (gem, path, etc.) and maintains a cache of methods, classes and ancestors in the store.

The store maintains a cache of its contents for faster lookup. After adding items to the store it must be flushed using save_cache. The cache contains the following structures:

@cache = {
  :class_methods    => {}, # class name => class methods
  :instance_methods => {}, # class name => instance methods
  :attributes       => {}, # class name => attributes
  :modules          => [], # classes and modules in this store
  :ancestors        => {}, # class name => ancestor names
}
Methods
A
C
F
I
L
M
N
S
Attributes
[R] cache

The contents of the Store

[RW] dry_run

If true this Store will not write any files

[RW] encoding

The encoding of the contents in the Store

[RW] path

Path this store reads or writes

[RW] type

Type of ri datastore this was loaded from. See RDoc::RI::Driver, RDoc::RI::Paths.

Class Public methods
new(path, type = nil)

Creates a new Store of type that will load or save to path

# File ../ruby/lib/rdoc/ri/store.rb, line 56
def initialize path, type = nil
  @dry_run  = false
  @type     = type
  @path     = path
  @encoding = nil

  @cache = {
    :ancestors        => {},
    :attributes       => {},
    :class_methods    => {},
    :encoding         => @encoding,
    :instance_methods => {},
    :modules          => [],
  }
end
Instance Public methods
ancestors()

Ancestors cache accessor. Maps a klass name to an Array of its ancestors in this store. If Foo in this store inherits from Object, Kernel won't be listed (it will be included from ruby's ri store).

# File ../ruby/lib/rdoc/ri/store.rb, line 77
def ancestors
  @cache[:ancestors]
end
attributes()

Attributes cache accessor. Maps a class to an Array of its attributes.

# File ../ruby/lib/rdoc/ri/store.rb, line 84
def attributes
  @cache[:attributes]
end
cache_path()

Path to the cache file

# File ../ruby/lib/rdoc/ri/store.rb, line 91
def cache_path
  File.join @path, 'cache.ri'
end
class_file(klass_name)

Path to the ri data for klass_name

# File ../ruby/lib/rdoc/ri/store.rb, line 98
def class_file klass_name
  name = klass_name.split('::').last
  File.join class_path(klass_name), "cdesc-#{name}.ri"
end
class_methods()

Class methods cache accessor. Maps a class to an Array of its class methods (not full name).

# File ../ruby/lib/rdoc/ri/store.rb, line 107
def class_methods
  @cache[:class_methods]
end
class_path(klass_name)

Path where data for klass_name will be stored (methods or class data)

# File ../ruby/lib/rdoc/ri/store.rb, line 114
def class_path klass_name
  File.join @path, *klass_name.split('::')
end
friendly_path()

Friendly rendition of path

# File ../ruby/lib/rdoc/ri/store.rb, line 137
def friendly_path
  case type
  when :gem    then
    sep = Regexp.union(*['/', File::ALT_SEPARATOR].compact)
    @path =~ /#{sep}doc#{sep}(.*?)#{sep}ri$/
    "gem #{$1}"
  when :home   then '~/.ri'
  when :site   then 'ruby site'
  when :system then 'ruby core'
  else @path
  end
end
instance_methods()

Instance methods cache accessor. Maps a class to an Array of its instance methods (not full name).

# File ../ruby/lib/rdoc/ri/store.rb, line 158
def instance_methods
  @cache[:instance_methods]
end
load_cache()

Loads cache file for this store

# File ../ruby/lib/rdoc/ri/store.rb, line 165
def load_cache
  #orig_enc = @encoding

  open cache_path, 'rb' do |io|
    @cache = Marshal.load io.read
  end

  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 diffent 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
rescue Errno::ENOENT
end
load_class(klass_name)

Loads ri data for klass_name

# File ../ruby/lib/rdoc/ri/store.rb, line 195
def load_class klass_name
  open class_file(klass_name), 'rb' do |io|
    Marshal.load io.read
  end
end
load_method(klass_name, method_name)

Loads ri data for method_name in klass_name

# File ../ruby/lib/rdoc/ri/store.rb, line 204
def load_method klass_name, method_name
  open method_file(klass_name, method_name), 'rb' do |io|
    Marshal.load io.read
  end
end
method_file(klass_name, method_name)

Path to the ri data for method_name in klass_name

# File ../ruby/lib/rdoc/ri/store.rb, line 213
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 = if ''.respond_to? :ord then
                  method_name.gsub(/\W/) { "%%%02x" % $&[0].ord }
                else
                  method_name.gsub(/\W/) { "%%%02x" % $&[0] }
                end

  File.join class_path(klass_name), "#{method_name}-#{method_type}.ri"
end
modules()

Modules cache accessor. An Array of all the modules (and classes) in the store.

# File ../ruby/lib/rdoc/ri/store.rb, line 232
def modules
  @cache[:modules]
end
save_cache()

Writes the cache file for this store

# File ../ruby/lib/rdoc/ri/store.rb, line 239
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[:encoding] = @encoding # this gets set twice due to assert_cache

  return if @dry_run

  marshal = Marshal.dump @cache

  open cache_path, 'wb' do |io|
    io.write marshal
  end
end
save_class(klass)

Writes the ri data for klass

# File ../ruby/lib/rdoc/ri/store.rb, line 261
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 Errno::ENOENT
  end

  # BasicObject has no ancestors
  ancestors = klass.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].push(*ancestors)

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

  unless attributes.empty? then
    @cache[:attributes][full_name] ||= []
    @cache[:attributes][full_name].push(*attributes)
  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 }

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

  marshal = Marshal.dump klass

  open path, 'wb' do |io|
    io.write marshal
  end
end
save_method(klass, method)

Writes the ri data for method on klass

# File ../ruby/lib/rdoc/ri/store.rb, line 335
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

  marshal = Marshal.dump method

  open method_file(full_name, method.full_name), 'wb' do |io|
    io.write marshal
  end
end