A module to read and cache lines of a Ruby program.
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 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 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
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
Return an array of cached file names
# File lib/linecache.rb, line 157 def cached_files() @@file_cache.keys end
# File lib/linecache.rb, line 267 def cached_script?(filename) SCRIPT_LINES__.member?(unmap_file(filename)) end
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 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
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 the script cache entirely.
# File lib/linecache.rb, line 152 def clear_script_cache() @@script_cache = {} end
# File lib/linecache.rb, line 271 def empty?(filename) filename=unmap_file(filename) !!@@file_cache[filename].lines[:plain] end
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
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
# 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
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
# File lib/linecache.rb, line 360 def remap_file(from_file, to_file) @@file2file_remap[from_file] = to_file cache_file(to_file) end
# File lib/linecache.rb, line 104 def remove_script_temps @@script2file.values.each do |filename| File.unlink(filename) if File.exist?(filename) end end
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
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
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
# File lib/linecache.rb, line 428 def unmap_file(file) @@file2file_remap[file] ? @@file2file_remap[file] : file end
# 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 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 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
# 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
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