module LineCache
module LineCache¶ ↑
A module to read and cache lines of a Ruby program.
Constants
- LineCacheInfo
Public Class Methods
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/linecache19.rb, line 143 def cache(filename, reload_on_change=false) if @@file_cache.member?(filename) checkcache(filename) if reload_on_change else update_cache(filename, true) end if @@file_cache.member?(filename) @@file_cache[filename].path else nil end end
Return true if filename is cached
# File lib/linecache19.rb, line 158 def cached?(filename) @@file_cache.member?(unmap_file(filename)) end
Return an array of cached file names
# File lib/linecache19.rb, line 101 def cached_files() @@file_cache.keys end
# File lib/linecache19.rb, line 163 def cached_script?(filename) # In 1.8.6, the SCRIPT_LINES__ filename key can be unqualified # In 1.9.1 it's the fully qualified name if RUBY_VERSION < "1.9" SCRIPT_LINES__.member?(unmap_file(filename)) else SCRIPT_LINES__.member?(File.expand_path(unmap_file(filename))) end 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/linecache19.rb, line 112 def checkcache(filename=nil, use_script_lines=false) 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 stat && (cache_info.size != stat.size or cache_info.mtime != stat.mtime) result << filename update_cache(filename, use_script_lines) end end end return result end
Clear the file cache entirely.
# File lib/linecache19.rb, line 93 def clear_file_cache() @@file_cache = {} @@file2file_remap = {} @@file2file_remap_lines = {} end
# File lib/linecache19.rb, line 174 def empty?(filename) filename=unmap_file(filename) @@file_cache[filename].lines.empty? 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/linecache19.rb, line 191 def getline(filename, line_number, reload_on_change=true) filename = unmap_file(filename) filename, line_number = unmap_file_line(filename, line_number) lines = getlines(filename, reload_on_change) 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/linecache19.rb, line 206 def getlines(filename, reload_on_change=false) filename = unmap_file(filename) checkcache(filename) if reload_on_change if @@file_cache.member?(filename) return @@file_cache[filename].lines else update_cache(filename, true) return @@file_cache[filename].lines if @@file_cache.member?(filename) end end
Return full filename path for filename
# File lib/linecache19.rb, line 219 def path(filename) filename = unmap_file(filename) return nil unless @@file_cache.member?(filename) @@file_cache[filename].path end
# File lib/linecache19.rb, line 226 def remap_file(from_file, to_file) @@file2file_remap[to_file] = from_file end
# File lib/linecache19.rb, line 231 def remap_file_lines(from_file, to_file, range, start) range = (range..range) if range.is_a?(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 SHA1 of filename.
# File lib/linecache19.rb, line 245 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.each do |line| sha1 << line end @@file_cache[filename].sha1 = sha1 sha1.hexdigest end
Return the number of lines in filename
# File lib/linecache19.rb, line 260 def size(filename) filename = unmap_file(filename) return nil unless @@file_cache.member?(filename) @@file_cache[filename].lines.length end
Return File.stat in the cache for filename.
# File lib/linecache19.rb, line 268 def stat(filename) return nil unless @@file_cache.member?(filename) @@file_cache[filename].stat 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/linecache19.rb, line 278 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) e.line_numbers = false unless e.line_numbers end e.line_numbers end
# File lib/linecache19.rb, line 291 def unmap_file(file) @@file2file_remap[file] ? @@file2file_remap[file] : file end
# File lib/linecache19.rb, line 296 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/linecache19.rb, line 313 def update_cache(filename, use_script_lines=false) 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 lines = SCRIPT_LINES__[name] if "ruby19".respond_to?(:force_encoding) lines.each{|l| l.force_encoding(Encoding.default_external) } end @@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') lines = fp.readlines() fp.close() 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
Private Instance Methods
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/linecache19.rb, line 143 def cache(filename, reload_on_change=false) if @@file_cache.member?(filename) checkcache(filename) if reload_on_change else update_cache(filename, true) end if @@file_cache.member?(filename) @@file_cache[filename].path else nil end end
Return true if filename is cached
# File lib/linecache19.rb, line 158 def cached?(filename) @@file_cache.member?(unmap_file(filename)) end
Return an array of cached file names
# File lib/linecache19.rb, line 101 def cached_files() @@file_cache.keys end
# File lib/linecache19.rb, line 163 def cached_script?(filename) # In 1.8.6, the SCRIPT_LINES__ filename key can be unqualified # In 1.9.1 it's the fully qualified name if RUBY_VERSION < "1.9" SCRIPT_LINES__.member?(unmap_file(filename)) else SCRIPT_LINES__.member?(File.expand_path(unmap_file(filename))) end 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/linecache19.rb, line 112 def checkcache(filename=nil, use_script_lines=false) 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 stat && (cache_info.size != stat.size or cache_info.mtime != stat.mtime) result << filename update_cache(filename, use_script_lines) end end end return result end
Clear the file cache entirely.
# File lib/linecache19.rb, line 93 def clear_file_cache() @@file_cache = {} @@file2file_remap = {} @@file2file_remap_lines = {} end
# File lib/linecache19.rb, line 174 def empty?(filename) filename=unmap_file(filename) @@file_cache[filename].lines.empty? 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/linecache19.rb, line 191 def getline(filename, line_number, reload_on_change=true) filename = unmap_file(filename) filename, line_number = unmap_file_line(filename, line_number) lines = getlines(filename, reload_on_change) 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/linecache19.rb, line 206 def getlines(filename, reload_on_change=false) filename = unmap_file(filename) checkcache(filename) if reload_on_change if @@file_cache.member?(filename) return @@file_cache[filename].lines else update_cache(filename, true) return @@file_cache[filename].lines if @@file_cache.member?(filename) end end
Return full filename path for filename
# File lib/linecache19.rb, line 219 def path(filename) filename = unmap_file(filename) return nil unless @@file_cache.member?(filename) @@file_cache[filename].path end
# File lib/linecache19.rb, line 226 def remap_file(from_file, to_file) @@file2file_remap[to_file] = from_file end
# File lib/linecache19.rb, line 231 def remap_file_lines(from_file, to_file, range, start) range = (range..range) if range.is_a?(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 SHA1 of filename.
# File lib/linecache19.rb, line 245 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.each do |line| sha1 << line end @@file_cache[filename].sha1 = sha1 sha1.hexdigest end
Return the number of lines in filename
# File lib/linecache19.rb, line 260 def size(filename) filename = unmap_file(filename) return nil unless @@file_cache.member?(filename) @@file_cache[filename].lines.length end
Return File.stat in the cache for filename.
# File lib/linecache19.rb, line 268 def stat(filename) return nil unless @@file_cache.member?(filename) @@file_cache[filename].stat 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/linecache19.rb, line 278 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) e.line_numbers = false unless e.line_numbers end e.line_numbers end
# File lib/linecache19.rb, line 291 def unmap_file(file) @@file2file_remap[file] ? @@file2file_remap[file] : file end
# File lib/linecache19.rb, line 296 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/linecache19.rb, line 313 def update_cache(filename, use_script_lines=false) 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 lines = SCRIPT_LINES__[name] if "ruby19".respond_to?(:force_encoding) lines.each{|l| l.force_encoding(Encoding.default_external) } end @@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') lines = fp.readlines() fp.close() 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