linecache-tf 0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/NEWS ADDED
@@ -0,0 +1,31 @@
1
+ tf-0.44
2
+ Sept 13, 2010
3
+ - First 1.9.2 release via rb-threadframe
4
+
5
+ 0.43
6
+ 06-12-08
7
+ - tolerance for finding windows extension in lib rather than ext.
8
+
9
+ 0.41
10
+ - add test/data/* to gem.
11
+
12
+ 0.4
13
+ - Credit Ryan Davis and ParseTree.
14
+
15
+ 0.3
16
+ - Add tracelines: get line numbers that can be stopped at.
17
+
18
+ - Add routines to allow line-number
19
+ remapping and filename remapping.
20
+
21
+ - Add access methods to get the number of lines in a file.
22
+
23
+ 0.2
24
+ - Make this work with ruby-debug-base. Add reload-on-change parameters.
25
+ add checkcache, cache, cached? sha1, and stat methods.
26
+
27
+ - Use SCRIPT_LINES__.
28
+
29
+ 0.1
30
+
31
+ - Initial release of LineCache, a module for reading and caching lines.
data/README ADDED
@@ -0,0 +1,48 @@
1
+ = LineCache - A module to read and cache file information of a Ruby program.
2
+
3
+ == SYNOPSIS
4
+
5
+ The LineCache module allows one to get any line from any file, caching
6
+ the lines and file information on first access to the file. Although
7
+ the file may be any file, the common use is when the file is a Ruby
8
+ script since parsing of the file is done to figure out where the
9
+ statement boundaries are.
10
+
11
+ The routines here may be is useful when a small random sets of lines
12
+ are read from a single file, in particular in a debugger to show
13
+ source lines.
14
+
15
+ == Summary
16
+
17
+ require 'linecache'
18
+ lines = LineCache::getlines('/tmp/myruby.rb')
19
+ # The following lines have same effect as the above.
20
+ $: << '/tmp'
21
+ Dir.chdir('/tmp') {lines = LineCache::getlines('myruby.rb')
22
+
23
+ line = LineCache::getline('/tmp/myruby.rb', 6)
24
+ # Note lines[6] == line (if /tmp/myruby.rb has 6 lines)
25
+
26
+ LineCache::clear_file_cache
27
+ LineCache::clear_file_cache('/tmp/myruby.rb')
28
+ LineCache::update_cache # Check for modifications of all cached files.
29
+
30
+ == Credits
31
+
32
+ This is a port of the module of the same name from the Python distribution.
33
+
34
+ The idea for how TraceLineNumbers works, and some code was taken
35
+ from ParseTree by Ryan Davis.
36
+
37
+ == Other stuff
38
+
39
+ Author:: Rocky Bernstein <rockyb@rubyforge.net>
40
+ License:: Copyright (c) 2007, 2008, 2009 Rocky Bernstein
41
+ Released under the GNU GPL 2 license
42
+
43
+ == Warranty
44
+
45
+ This program is distributed in the hope that it will be useful,
46
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
47
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48
+ GNU General Public License for more details.
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env rake
2
+ # -*- Ruby -*-
3
+ require 'rubygems'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+
8
+ # ------- Default Package ----------
9
+ PKG_VERSION = open(File.join(File.dirname(__FILE__), 'VERSION')) do
10
+ |f| f.readlines[0].chomp
11
+ end
12
+ PKG_NAME = 'linecache'
13
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
+ RUBY_FORGE_PROJECT = 'rocky-hacks'
15
+ RUBY_FORGE_USER = 'rockyb'
16
+
17
+ FILES = FileList[
18
+ 'AUTHORS',
19
+ 'COPYING',
20
+ 'ChangeLog',
21
+ 'NEWS',
22
+ 'README',
23
+ 'Rakefile',
24
+ 'VERSION',
25
+ 'lib/*.rb',
26
+ 'test/*.rb',
27
+ 'test/data/*.rb',
28
+ 'test/short-file'
29
+ ]
30
+
31
+ desc "Test everything."
32
+ test_task = task :test => :lib do
33
+ Rake::TestTask.new(:test) do |t|
34
+ t.pattern = 'test/test-*.rb'
35
+ t.verbose = true
36
+ end
37
+ end
38
+
39
+ desc "Test everything - same as test."
40
+ task :check => :test
41
+
42
+ desc "Create a GNU-style ChangeLog via svn2cl"
43
+ task :ChangeLog do
44
+ system("svn2cl svn+ssh://rockyb@rubyforge.org/var/svn/rocky-hacks/linecache/branches/ruby-1.9 --authors=svn2cl_usermap")
45
+ end
46
+
47
+ # Base GEM Specification
48
+ default_spec = Gem::Specification.new do |spec|
49
+ spec.name = "linecache-tf"
50
+
51
+ spec.homepage = "http://rubyforge.org/projects/rocky-hacks/linecache"
52
+ spec.summary = "Read file with caching"
53
+ spec.description = <<-EOF
54
+ LineCache is a module for reading and caching lines. This may be useful for
55
+ example in a debugger where the same lines are shown many times.
56
+
57
+ This version works only with a patched version of Ruby 1.9.2 and rb-threadframe.
58
+ EOF
59
+
60
+ spec.version = "#{PKG_VERSION}"
61
+
62
+ spec.author = "R. Bernstein"
63
+ spec.email = "rockyb@rubyforge.net"
64
+ spec.platform = Gem::Platform::RUBY
65
+ spec.require_path = "lib"
66
+ spec.files = FILES.to_a
67
+
68
+ spec.required_ruby_version = '>= 1.9.2'
69
+ spec.date = Time.now
70
+ spec.add_dependency('rb-threadframe', '>= 0.32')
71
+ spec.rubyforge_project = 'rocky-hacks'
72
+
73
+ # rdoc
74
+ spec.has_rdoc = true
75
+ spec.extra_rdoc_files = %w(README lib/linecache.rb lib/tracelines.rb)
76
+
77
+ spec.test_files = FileList['test/*.rb']
78
+ end
79
+
80
+ # Rake task to build the default package
81
+ Rake::GemPackageTask.new(default_spec) do |pkg|
82
+ pkg.need_tar = true
83
+ end
84
+
85
+ task :default => [:test]
86
+
87
+ # desc "Publish linecache to RubyForge."
88
+ # task :publish do
89
+ # require 'rake/contrib/sshpublisher'
90
+
91
+ # # Get ruby-debug path.
92
+ # ruby_debug_path = File.expand_path(File.dirname(__FILE__))
93
+
94
+ # publisher = Rake::SshDirPublisher.new("rockyb@rubyforge.org",
95
+ # "/var/www/gforge-projects/rocky-hacks/linecache", ruby_debug_path)
96
+ # end
97
+
98
+ desc "Remove built files"
99
+ task :clean => [:clobber_package, :clobber_rdoc]
100
+
101
+ # --------- RDoc Documentation ------
102
+ desc "Generate rdoc documentation"
103
+ Rake::RDocTask.new("rdoc") do |rdoc|
104
+ rdoc.rdoc_dir = 'doc'
105
+ rdoc.title = "linecache"
106
+ # Show source inline with line numbers
107
+ rdoc.options << "--inline-source" << "--line-numbers"
108
+ # Make the readme file the start page for the generated html
109
+ rdoc.options << '--main' << 'README'
110
+ rdoc.rdoc_files.include(%w(lib/*.rb README COPYING))
111
+ end
112
+
113
+ # desc "Publish the release files to RubyForge."
114
+ # task :rubyforge_upload do
115
+ # `rubyforge login`
116
+ # release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
117
+ # puts release_command
118
+ # system(release_command)
119
+ # end
120
+
121
+ def install(spec, *opts)
122
+ args = ['gem', 'install', "pkg/#{spec.name}-#{spec.version}.gem"] + opts
123
+ system(*args)
124
+ end
125
+
126
+ desc 'Install locally'
127
+ task :install => :package do
128
+ Dir.chdir(File::dirname(__FILE__)) do
129
+ # ri and rdoc take lots of time
130
+ install(default_spec, '--no-ri', '--no-rdoc')
131
+ end
132
+ end
133
+
134
+ task :install_full => :package do
135
+ Dir.chdir(File::dirname(__FILE__)) do
136
+ install(default_spec)
137
+ end
138
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.44
@@ -0,0 +1,407 @@
1
+ #!/usr/bin/env ruby
2
+ # $Id: linecache.rb 184 2009-10-22 13:05:11Z rockyb $
3
+ #
4
+ # Copyright (C) 2007, 2008, 2009 Rocky Bernstein <rockyb@rubyforge.net>
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
+ # 02110-1301 USA.
20
+ #
21
+
22
+ # Author:: Rocky Bernstein (mailto:rockyb@rubyforge.net)
23
+ #
24
+ # = linecache
25
+ # A module to read and cache lines of a Ruby program.
26
+ # == Version
27
+ # :include:VERSION
28
+
29
+ # == SYNOPSIS
30
+ #
31
+ # The LineCache module allows one to get any line from any file,
32
+ # caching lines of the file on first access to the file. Although the
33
+ # file may be any file, the common use is when the file is a Ruby
34
+ # script since parsing of the file is done to figure out where the
35
+ # statement boundaries are.
36
+ #
37
+ # The routines here may be is useful when a small random sets of lines
38
+ # are read from a single file, in particular in a debugger to show
39
+ # source lines.
40
+ #
41
+ #
42
+ # require 'linecache'
43
+ # lines = LineCache::getlines('/tmp/myruby.rb')
44
+ # # The following lines have same effect as the above.
45
+ # $: << '/tmp'
46
+ # Dir.chdir('/tmp') {lines = LineCache::getlines('myruby.rb')
47
+ #
48
+ # line = LineCache::getline('/tmp/myruby.rb', 6)
49
+ # # Note lines[6] == line (if /tmp/myruby.rb has 6 lines)
50
+ #
51
+ # LineCache::clear_file_cache
52
+ # LineCache::clear_file_cache('/tmp/myruby.rb')
53
+ # LineCache::update_cache # Check for modifications of all cached files.
54
+ #
55
+ # Some parts of the interface is derived from the Python module of the
56
+ # same name.
57
+ #
58
+
59
+ # Defining SCRIPT_LINES__ causes Ruby to cache the lines of files
60
+ # it reads. The key the setting of __FILE__ at the time when Ruby does
61
+ # its read. LineCache keeps a separate copy of the lines elsewhere
62
+ # and never destroys SCRIPT_LINES__
63
+ SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
64
+
65
+ require 'digest/sha1'
66
+ require 'set'
67
+ require_relative 'tracelines'
68
+
69
+ # require 'ruby-debug' ; Debugger.start
70
+
71
+ # = module LineCache
72
+ # A module to read and cache lines of a Ruby program.
73
+ module LineCache
74
+ LineCacheInfo = Struct.new(:stat, :line_numbers, :lines, :path, :sha1) unless
75
+ defined?(LineCacheInfo)
76
+
77
+ # The file cache. The key is a name as would be given by Ruby for
78
+ # __FILE__. The value is a LineCacheInfo object.
79
+ @@file_cache = {}
80
+
81
+ # Maps a string filename (a String) to a key in @@file_cache (a
82
+ # String).
83
+ #
84
+ # One important use of @@file2file_remap is mapping the a full path
85
+ # of a file into the name stored in @@file_cache or given by Ruby's
86
+ # __FILE__. Applications such as those that get input from users,
87
+ # may want canonicalize a file name before looking it up. This map
88
+ # gives a way to do that.
89
+ #
90
+ # Another related use is when a template system is used. Here we'll
91
+ # probably want to remap not only the file name but also line
92
+ # ranges. Will probably use this for that, but I'm not sure.
93
+ @@file2file_remap = {}
94
+ @@file2file_remap_lines = {}
95
+
96
+ # Clear the file cache entirely.
97
+ def clear_file_cache()
98
+ @@file_cache = {}
99
+ @@file2file_remap = {}
100
+ @@file2file_remap_lines = {}
101
+ end
102
+ module_function :clear_file_cache
103
+
104
+ # Return an array of cached file names
105
+ def cached_files()
106
+ @@file_cache.keys
107
+ end
108
+ module_function :cached_files
109
+
110
+ # Discard cache entries that are out of date. If +filename+ is +nil+
111
+ # all entries in the file cache +@@file_cache+ are checked.
112
+ # If we don't have stat information about a file, which can happen
113
+ # if the file was read from __SCRIPT_LINES but no corresponding file
114
+ # is found, it will be kept. Return a list of invalidated filenames.
115
+ # nil is returned if a filename was given but not found cached.
116
+ def checkcache(filename=nil, use_script_lines=false)
117
+
118
+ if !filename
119
+ filenames = @@file_cache.keys()
120
+ elsif @@file_cache.member?(filename)
121
+ filenames = [filename]
122
+ else
123
+ return nil
124
+ end
125
+
126
+ result = []
127
+ for filename in filenames
128
+ next unless @@file_cache.member?(filename)
129
+ path = @@file_cache[filename].path
130
+ if File.exist?(path)
131
+ cache_info = @@file_cache[filename].stat
132
+ stat = File.stat(path)
133
+ if cache_info
134
+ if stat &&
135
+ (cache_info.size != stat.size or cache_info.mtime != stat.mtime)
136
+ result << filename
137
+ update_cache(filename, use_script_lines)
138
+ end
139
+ else
140
+ result << filename
141
+ update_cache(filename, use_script_lines)
142
+ end
143
+ end
144
+ end
145
+ return result
146
+ end
147
+ module_function :checkcache
148
+
149
+ # Cache filename if it's not already cached.
150
+ # Return the expanded filename for it in the cache
151
+ # or nil if we can't find the file.
152
+ def cache(filename, reload_on_change=false)
153
+ if @@file_cache.member?(filename)
154
+ checkcache(filename) if reload_on_change
155
+ else
156
+ update_cache(filename, true)
157
+ end
158
+ if @@file_cache.member?(filename)
159
+ @@file_cache[filename].path
160
+ else
161
+ nil
162
+ end
163
+ end
164
+ module_function :cache
165
+
166
+ # Return true if filename is cached
167
+ def cached?(filename)
168
+ @@file_cache.member?(map_file(filename))
169
+ end
170
+ module_function :cached?
171
+
172
+ def cached_script?(filename)
173
+ SCRIPT_LINES__.member?(map_file(filename))
174
+ end
175
+ module_function :cached_script?
176
+
177
+ def empty?(filename)
178
+ filename=map_file(filename)
179
+ @@file_cache[filename].lines.empty?
180
+ end
181
+ module_function :empty?
182
+
183
+ # Get line +line_number+ from file named +filename+. Return nil if
184
+ # there was a problem. If a file named filename is not found, the
185
+ # function will look for it in the $: array.
186
+ #
187
+ # Examples:
188
+ #
189
+ # lines = LineCache::getline('/tmp/myfile.rb')
190
+ # # Same as above
191
+ # $: << '/tmp'
192
+ # lines = LineCache.getlines('myfile.rb')
193
+ #
194
+ def getline(filename, line_number, reload_on_change=true)
195
+ filename = map_file(filename)
196
+ filename, line_number = map_file_line(filename, line_number)
197
+ lines = getlines(filename, reload_on_change)
198
+ if lines and (1..lines.size) === line_number
199
+ return lines[line_number-1]
200
+ else
201
+ return nil
202
+ end
203
+ end
204
+ module_function :getline
205
+
206
+ # Read lines of +filename+ and cache the results. However +filename+ was
207
+ # previously cached use the results from the cache. Return nil
208
+ # if we can't get lines
209
+ def getlines(filename, reload_on_change=false)
210
+ filename = map_file(filename)
211
+ checkcache(filename) if reload_on_change
212
+ if @@file_cache.member?(filename)
213
+ return @@file_cache[filename].lines
214
+ else
215
+ update_cache(filename, true)
216
+ return @@file_cache[filename].lines if @@file_cache.member?(filename)
217
+ end
218
+ end
219
+ module_function :getlines
220
+
221
+ # Return full filename path for filename
222
+ def path(filename)
223
+ filename = map_file(filename)
224
+ return nil unless @@file_cache.member?(filename)
225
+ @@file_cache[filename].path
226
+ end
227
+ module_function :path
228
+
229
+ def remap_file(to_file, from_file)
230
+ @@file2file_remap[to_file] = from_file
231
+ end
232
+ module_function :remap_file
233
+
234
+ def remap_file_lines(from_file, to_file, range, start)
235
+ range = (range..range) if range.is_a?(Fixnum)
236
+ to_file = from_file unless to_file
237
+ if @@file2file_remap_lines[to_file]
238
+ # FIXME: need to check for overwriting ranges: whether
239
+ # they intersect or one encompasses another.
240
+ @@file2file_remap_lines[to_file] << [from_file, range, start]
241
+ else
242
+ @@file2file_remap_lines[to_file] = [[from_file, range, start]]
243
+ end
244
+ end
245
+ module_function :remap_file_lines
246
+
247
+ # Return SHA1 of filename.
248
+ def sha1(filename)
249
+ filename = map_file(filename)
250
+ return nil unless @@file_cache.member?(filename)
251
+ return @@file_cache[filename].sha1.hexdigest if
252
+ @@file_cache[filename].sha1
253
+ sha1 = Digest::SHA1.new
254
+ @@file_cache[filename].lines.each do |line|
255
+ sha1 << line
256
+ end
257
+ @@file_cache[filename].sha1 = sha1
258
+ sha1.hexdigest
259
+ end
260
+ module_function :sha1
261
+
262
+ # Return the number of lines in filename
263
+ def size(filename)
264
+ filename = map_file(filename)
265
+ return nil unless @@file_cache.member?(filename)
266
+ @@file_cache[filename].lines.length
267
+ end
268
+ module_function :size
269
+
270
+ # Return File.stat in the cache for filename.
271
+ def stat(filename)
272
+ return nil unless @@file_cache.member?(filename)
273
+ @@file_cache[filename].stat
274
+ end
275
+ module_function :stat
276
+
277
+ # Return an Array of breakpoints in filename.
278
+ # The list will contain an entry for each distinct line event call
279
+ # so it is possible (and possibly useful) for a line number appear more
280
+ # than once.
281
+ def trace_line_numbers(filename, reload_on_change=false)
282
+ fullname = cache(filename, reload_on_change)
283
+ return nil unless fullname
284
+ e = @@file_cache[filename]
285
+ unless e.line_numbers
286
+ e.line_numbers =
287
+ TraceLineNumbers.lnums_for_str_array(e.lines)
288
+ e.line_numbers = false unless e.line_numbers
289
+ end
290
+ e.line_numbers
291
+ end
292
+ module_function :trace_line_numbers
293
+
294
+ def map_file(file)
295
+ @@file2file_remap[file] ? @@file2file_remap[file] : file
296
+ end
297
+ module_function :map_file
298
+
299
+ def map_file_line(file, line)
300
+ if @@file2file_remap_lines[file]
301
+ @@file2file_remap_lines[file].each do |from_file, range, start|
302
+ if range === line
303
+ from_file = from_file || file
304
+ return [from_file, start+line-range.begin]
305
+ end
306
+ end
307
+ end
308
+ return [map_file(file), line]
309
+ end
310
+ module_function :map_file_line
311
+
312
+ # Update a cache entry. If something's
313
+ # wrong, return nil. Return true if the cache was updated and false
314
+ # if not. If use_script_lines is true, use that as the source for the
315
+ # lines of the file
316
+ def update_cache(filename, use_script_lines=false)
317
+
318
+ return nil unless filename
319
+
320
+ @@file_cache.delete(filename)
321
+ path = File.expand_path(filename)
322
+
323
+ if use_script_lines
324
+ list = [filename]
325
+ list << @@file2file_remap[path] if @@file2file_remap[path]
326
+ list.each do |name|
327
+ if !SCRIPT_LINES__[name].nil? && SCRIPT_LINES__[name] != true
328
+ begin
329
+ stat = File.stat(name)
330
+ rescue
331
+ stat = nil
332
+ end
333
+ lines = SCRIPT_LINES__[name]
334
+ @@file_cache[filename] = LineCacheInfo.new(stat, nil, lines, path, nil)
335
+ @@file2file_remap[path] = filename
336
+ return true
337
+ end
338
+ end
339
+ end
340
+
341
+ if File.exist?(path)
342
+ stat = File.stat(path)
343
+ elsif File.basename(filename) == filename
344
+ # try looking through the search path.
345
+ stat = nil
346
+ for dirname in $:
347
+ path = File.join(dirname, filename)
348
+ if File.exist?(path)
349
+ stat = File.stat(path)
350
+ break
351
+ end
352
+ end
353
+ return false unless stat
354
+ end
355
+ begin
356
+ fp = File.open(path, 'r')
357
+ lines = fp.readlines()
358
+ fp.close()
359
+ rescue
360
+ ## print '*** cannot open', path, ':', msg
361
+ return nil
362
+ end
363
+ @@file_cache[filename] = LineCacheInfo.new(File.stat(path), nil, lines,
364
+ path, nil)
365
+ @@file2file_remap[path] = filename
366
+ return true
367
+ end
368
+
369
+ module_function :update_cache
370
+
371
+ end
372
+
373
+ # example usage
374
+ if __FILE__ == $0
375
+ def yes_no(var)
376
+ return var ? "" : "not "
377
+ end
378
+
379
+ lines = LineCache::getlines(__FILE__)
380
+ puts "#{__FILE__} has #{LineCache.size(__FILE__)} lines"
381
+ line = LineCache::getline(__FILE__, 6)
382
+ puts "The 6th line is\n#{line}"
383
+ line = LineCache::remap_file(__FILE__, 'another_name')
384
+ puts LineCache::getline('another_name', 7)
385
+
386
+ puts("Files cached: #{LineCache::cached_files.inspect}")
387
+ LineCache::update_cache(__FILE__)
388
+ LineCache::checkcache(__FILE__)
389
+ puts "#{__FILE__} has #{LineCache::size(__FILE__)} lines"
390
+ puts "#{__FILE__} trace line numbers:\n" +
391
+ "#{LineCache::trace_line_numbers(__FILE__).to_a.sort.inspect}"
392
+ puts("#{__FILE__} is %scached." %
393
+ yes_no(LineCache::cached?(__FILE__)))
394
+ puts LineCache::stat(__FILE__).inspect
395
+ puts "Full path: #{LineCache::path(__FILE__)}"
396
+ LineCache::checkcache # Check all files in the cache
397
+ LineCache::clear_file_cache
398
+ puts("#{__FILE__} is now %scached." %
399
+ yes_no(LineCache::cached?(__FILE__)))
400
+ digest = SCRIPT_LINES__.select{|k,v| k =~ /digest.rb$/}
401
+ puts digest.first[0] if digest
402
+ line = LineCache::getline(__FILE__, 7)
403
+ puts "The 7th line is\n#{line}"
404
+ LineCache::remap_file_lines(__FILE__, 'test2', (10..20), 6)
405
+ puts LineCache::getline('test2', 10)
406
+ puts "Remapped 10th line of test2 is\n#{line}"
407
+ end