module LineCache

module LineCache

A module to read and cache lines of a Ruby program.

Constants

LineCacheInfo
VERSION

Public Instance Methods

cache(file_or_script, reload_on_change=false) click to toggle source

Cache file name or script object if it’s not already cached. Return the expanded filename for it in the cache if a filename, or the script, or nil if we can’t find the file.

# File lib/linecache.rb, line 216
def cache(file_or_script, reload_on_change=false)
  if file_or_script.kind_of?(String)
    cache_file(file_or_script, reload_on_change)
  else
    cache_script(file_or_script)
  end
end
cache_file(filename, reload_on_change=false, opts={}) click to toggle source

Cache filename if it’s not already cached. Return the expanded filename for it in the cache or nil if we can’t find the file.

# File lib/linecache.rb, line 227
def cache_file(filename, reload_on_change=false, opts={})
  if @@file_cache.member?(filename)
    checkcache(filename) if reload_on_change
  else
    opts[:use_script_lines] = true
    update_cache(filename, opts)
  end
  if @@file_cache.member?(filename)
    @@file_cache[filename].path
  else
    nil
  end
end
cache_script(script, opts={}) click to toggle source

Cache script if it’s not already cached.

# File lib/linecache.rb, line 206
def cache_script(script, opts={})
  if !@@script_cache.member?(script)
    update_script_cache(script, opts)
  end
  script
end
cached?(file_or_script) click to toggle source

Return true if file_or_script is cached

# File lib/linecache.rb, line 259
def cached?(file_or_script)
  if file_or_script.kind_of?(String) 
    @@file_cache.member?(unmap_file(file_or_script))
  else 
    cached_script?(file_or_script)
  end
end
cached_files() click to toggle source

Return an array of cached file names

# File lib/linecache.rb, line 157
def cached_files()
  @@file_cache.keys
end
cached_script?(filename) click to toggle source
# File lib/linecache.rb, line 267
def cached_script?(filename)
  SCRIPT_LINES__.member?(unmap_file(filename))
end
checkcache(filename=nil, opts=false) click to toggle source

Discard cache entries that are out of date. If filename is nil all entries in the file cache +@@file_cache+ are checked. If we don’t have stat information about a file, which can happen if the file was read from __SCRIPT_LINES but no corresponding file is found, it will be kept. Return a list of invalidated filenames. nil is returned if a filename was given but not found cached.

# File lib/linecache.rb, line 167
def checkcache(filename=nil, opts=false)
  use_script_lines = 
    if opts.kind_of?(Hash)
      opts[:use_script_lines]
    else
      opts
    end
  
  if !filename
    filenames = @@file_cache.keys()
  elsif @@file_cache.member?(filename)
    filenames = [filename]
  else
    return nil
  end

  result = []
  for filename in filenames
    next unless @@file_cache.member?(filename)
    path = @@file_cache[filename].path
    if File.exist?(path)
      cache_info = @@file_cache[filename].stat
      stat = File.stat(path)
      if cache_info
        if stat && 
            (cache_info.size != stat.size or cache_info.mtime != stat.mtime)
          result << filename
          update_cache(filename, opts)
        end
      else
        result << filename
        update_cache(filename, opts)
      end
    end
  end
  return result
end
clear_file_cache(filename=nil) click to toggle source

Clear the file cache entirely.

# File lib/linecache.rb, line 113
def clear_file_cache(filename=nil)
  if filename 
    if @@file_cache[filename]
      @@file_cache.delete(filename)
    end
  else
    @@file_cache = {}
    @@file2file_remap = {}
    @@file2file_remap_lines = {}
  end
end
clear_file_format_cache() click to toggle source

Remove syntax-formatted lines in the cache. Use this when you change the CodeRay syntax or Token formatting and want to redo how files may have previously been syntax marked.

# File lib/linecache.rb, line 129
def clear_file_format_cache
  @@file_cache.each_pair do |fname, cache_info|
    cache_info.lines.each_pair do |format, lines|
      next if :plain == format
      @@file_cache[fname].lines[format] = nil
    end
  end
end
clear_script_cache() click to toggle source

Clear the script cache entirely.

# File lib/linecache.rb, line 152
def clear_script_cache()
  @@script_cache = {}
end
empty?(filename) click to toggle source
# File lib/linecache.rb, line 271
def empty?(filename)
  filename=unmap_file(filename)
  !!@@file_cache[filename].lines[:plain]
end
getline(file_or_script, line_number, opts=true) click to toggle source

Get line line_number from file named filename. Return nil if there was a problem. If a file named filename is not found, the function will look for it in the $: array.

Examples:

lines = LineCache::getline('/tmp/myfile.rb')
# Same as above
$: << '/tmp'
lines = LineCache.getlines('myfile.rb')
# File lib/linecache.rb, line 287
def getline(file_or_script, line_number, opts=true)
  reload_on_change = 
    if opts.kind_of?(Hash)
      opts[:reload_on_change]
    else
      opts
    end
  lines = 
    if file_or_script.kind_of?(String)
      filename = unmap_file(file_or_script)
      filename, line_number = unmap_file_line(filename, line_number)
      getlines(filename, opts)
    else
      script_getlines(file_or_script)
    end
  if lines and (1..lines.size) === line_number
      return lines[line_number-1]
  else
      return nil
  end
end
getlines(filename, opts=false) click to toggle source

Read lines of filename and cache the results. However filename was previously cached use the results from the cache. Return nil if we can’t get lines

# File lib/linecache.rb, line 312
def getlines(filename, opts=false)
  if opts.kind_of?(Hash)
    reload_on_change, use_script_lines = 
      [opts[:reload_on_change], opts[:use_script_lines]]
  else
    reload_on_change, use_script_lines = [opts, false]
    opts = {:reload_on_change => reload_on_change}
  end
  checkcache(filename) if reload_on_change
  format = opts[:output] || :plain
  if @@file_cache.member?(filename)
    lines = @@file_cache[filename].lines
    if opts[:output] && !lines[format]
      lines[format] = 
        highlight_string(lines[:plain].join(''), format).split(%r\n/)
    end
    return lines[format]
  else
    opts[:use_script_lines] = true
    update_cache(filename, opts)
    if @@file_cache.member?(filename)
      return @@file_cache[filename].lines[format]
    else
      return nil
    end
  end
end
highlight_string(string, output_type) click to toggle source
# File lib/linecache.rb, line 340
def highlight_string(string, output_type)
  require 'rubygems'
  begin
    require 'coderay'
    require 'term/ansicolor'
  rescue LoadError
    return string
  end
  @@ruby_highlighter ||= CodeRay::Duo[:ruby, output_type]
  @@ruby_highlighter.encode(string)
end
map_file(file) click to toggle source
Alias for: unmap_file
path(filename) click to toggle source

Return full filename path for filename

# File lib/linecache.rb, line 353
def path(filename)
  return unless filename.kind_of?(String)
  filename = unmap_file(filename)
  return nil unless @@file_cache.member?(filename)
  @@file_cache[filename].path
end
remap_file(from_file, to_file) click to toggle source
# File lib/linecache.rb, line 360
def remap_file(from_file, to_file)
  @@file2file_remap[from_file] = to_file
  cache_file(to_file)
end
remove_script_temps() click to toggle source
# File lib/linecache.rb, line 104
def remove_script_temps
  @@script2file.values.each do |filename|
    File.unlink(filename) if File.exist?(filename)
  end
end
sha1(filename) click to toggle source

Return SHA1 of filename.

# File lib/linecache.rb, line 379
def sha1(filename)
  filename = unmap_file(filename)
  return nil unless @@file_cache.member?(filename)
  return @@file_cache[filename].sha1.hexdigest if 
    @@file_cache[filename].sha1
  sha1 = Digest::SHA1.new
  @@file_cache[filename].lines[:plain].each do |line|
    sha1 << line + "\n"
  end
  @@file_cache[filename].sha1 = sha1
  sha1.hexdigest
end
size(file_or_script) click to toggle source

Return the number of lines in filename

# File lib/linecache.rb, line 393
def size(file_or_script)
  cache(file_or_script)
  if file_or_script.kind_of?(String)
    file_or_script = unmap_file(file_or_script)
    return nil unless @@file_cache.member?(file_or_script)
    @@file_cache[file_or_script].lines[:plain].length
  else
    return nil unless @@script_cache.member?(file_or_script)
    @@script_cache[file_or_script].lines[:plain].length
  end
end
trace_line_numbers(filename, reload_on_change=false) click to toggle source

Return an Array of breakpoints in filename. The list will contain an entry for each distinct line event call so it is possible (and possibly useful) for a line number appear more than once.

# File lib/linecache.rb, line 416
def trace_line_numbers(filename, reload_on_change=false)
  fullname = cache(filename, reload_on_change)
  return nil unless fullname
  e = @@file_cache[filename]
  unless e.line_numbers
    e.line_numbers = 
      TraceLineNumbers.lnums_for_str_array(e.lines[:plain])
    e.line_numbers = false unless e.line_numbers
  end
  e.line_numbers
end
unmap_file(file) click to toggle source
# File lib/linecache.rb, line 428
def unmap_file(file)
  @@file2file_remap[file] ? @@file2file_remap[file] : file
end
Also aliased as: map_file
unmap_file_line(file, line) click to toggle source
# File lib/linecache.rb, line 433
def unmap_file_line(file, line)
  if @@file2file_remap_lines[file]
    @@file2file_remap_lines[file].each do |from_file, range, start|
      if range === line
        from_file = from_file || file 
        return [from_file, start+line-range.begin] 
      end
    end
  end
  return [file, line]
end
update_cache(filename, opts=false) click to toggle source

Update a cache entry. If something’s wrong, return nil. Return true if the cache was updated and false if not. If use_script_lines is true, use that as the source for the lines of the file

# File lib/linecache.rb, line 463
def update_cache(filename, opts=false)
    if opts.kind_of?(Hash)
      use_script_lines = opts[:use_script_lines]
    else
      use_script_lines = opts
      opts = {:use_script_lines => use_script_lines}
    end

  return nil unless filename

  @@file_cache.delete(filename)
  path = File.expand_path(filename)
  
  if use_script_lines
    list = [filename]
    list << @@file2file_remap[path] if @@file2file_remap[path]
    list.each do |name| 
      if !SCRIPT_LINES__[name].nil? && SCRIPT_LINES__[name] != true
        begin 
          stat = File.stat(name)
        rescue
          stat = nil
        end
        raw_lines = SCRIPT_LINES__[name]
        lines = {:plain => raw_lines}
        lines[opts[:output]] =
          highlight_string(raw_lines.join, opts[:output]).split(%r\n/) if 
          opts[:output]
        @@file_cache[filename] = LineCacheInfo.new(stat, nil, lines, path, nil)
        @@file2file_remap[path] = filename
        return true
      end
    end
  end
    
  if File.exist?(path)
    stat = File.stat(path)
  elsif File.basename(filename) == filename
    # try looking through the search path.
    stat = nil
    for dirname in $:
      path = File.join(dirname, filename)
      if File.exist?(path)
          stat = File.stat(path)
          break
      end
    end
    return false unless stat
  end
  begin
    fp = File.open(path, 'r')
    raw_string = fp.read
    fp.rewind
    lines = {:plain => fp.readlines}
    fp.close()
    lines[opts[:output]] = 
      highlight_string(raw_string, opts[:output]).split(%r\n/) if 
      opts[:output]
  rescue 
    ##  print '*** cannot open', path, ':', msg
    return nil
  end
  @@file_cache[filename] = LineCacheInfo.new(File.stat(path), nil, lines,
                                             path, nil)
  @@file2file_remap[path] = filename
  return true
end
update_script_cache(script, opts) click to toggle source

Update a cache entry. If something is wrong, return nil. Return true if the cache was updated and false if not.

# File lib/linecache.rb, line 447
def update_script_cache(script, opts)
  # return false unless script_is_eval?(script)
  # string = opts[:string] || script.eval_source
  lines = {:plain => string.split(%r\n/)}
  lines[opts[:output]] = highlight_string(string, opts[:output]) if
    opts[:output]
  @@script_cache[script] = 
    LineCacheInfo.new(nil, nil, lines, nil, opts[:sha1], 
                      opts[:compiled_method])
  return true
end

Public Class Methods

remap_file_lines(from_file, to_file, range, start) click to toggle source
# File lib/linecache.rb, line 365
def remap_file_lines(from_file, to_file, range, start)
  range = (range..range) if range.kind_of?(Fixnum)
  to_file = from_file unless to_file
  if @@file2file_remap_lines[to_file] 
    # FIXME: need to check for overwriting ranges: whether
    # they intersect or one encompasses another.
    @@file2file_remap_lines[to_file] << [from_file, range, start]
  else
    @@file2file_remap_lines[to_file]  = [[from_file, range, start]]
  end
end
stat(filename) click to toggle source

Return File.stat in the cache for filename.

# File lib/linecache.rb, line 406
def stat(filename)
  return nil unless @@file_cache.member?(filename)
  @@file_cache[filename].stat
end