linecache 0.41-mswin32

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/ext/trace_nums.h ADDED
@@ -0,0 +1,111 @@
1
+ /* Order is in C enum order. The below is correct for Ruby 1.8.6.
2
+ Possibly others, but there may need some adjustment here.
3
+ */
4
+ char *NODE2NAME[] =
5
+ {
6
+ "method",
7
+ "fbody",
8
+ "cfunc",
9
+ "scope",
10
+ "block",
11
+ "if",
12
+ "case",
13
+ "when",
14
+ "opt_n (-n)",
15
+ "while",
16
+ "until",
17
+ "iter",
18
+ "for",
19
+ "break",
20
+ "next",
21
+ "redo",
22
+ "retry",
23
+ "begin",
24
+ "rescue",
25
+ "resbody",
26
+ "ensure",
27
+ "and",
28
+ "or",
29
+ "not",
30
+ "masgn",
31
+ "lasgn (x=)",
32
+ "dasgn",
33
+ "dasgn_curr",
34
+ "gasgn",
35
+ "iasgn",
36
+ "cdecl",
37
+ "cvasgn",
38
+ "cvdecl",
39
+ "op_asgn1",
40
+ "op_asgn2",
41
+ "op_asgn_and",
42
+ "op_asgn_or",
43
+ "call",
44
+ "fcall",
45
+ "vcall",
46
+ "super",
47
+ "zsuper",
48
+ "array",
49
+ "zarray",
50
+ "hash",
51
+ "return",
52
+ "yield",
53
+ "lvar",
54
+ "dvar",
55
+ "gvar",
56
+ "ivar",
57
+ "const",
58
+ "cvar",
59
+ "nth_ref",
60
+ "back_ref",
61
+ "match",
62
+ "match2 (~=, !~)",
63
+ "match3 (~=, !~)",
64
+ "lit",
65
+ "str",
66
+ "dstr",
67
+ "xstr",
68
+ "dxstr",
69
+ "evstr",
70
+ "dregx",
71
+ "dregx_once",
72
+ "args",
73
+ "argscat",
74
+ "argspush",
75
+ "splat (*args)",
76
+ "to_ary",
77
+ "svalue",
78
+ "block_arg",
79
+ "block_pass",
80
+ "defn",
81
+ "defs",
82
+ "alias",
83
+ "valias",
84
+ "undef",
85
+ "class",
86
+ "module",
87
+ "sclass",
88
+ "colon2 (::)",
89
+ "colon3",
90
+ "cref",
91
+ "dot2 (..)",
92
+ "dot3 (...)",
93
+ "flip2",
94
+ "flip3",
95
+ "attrset",
96
+ "self",
97
+ "nil",
98
+ "true",
99
+ "false",
100
+ "defined?",
101
+ "newline (; or \\n)",
102
+ "postexe",
103
+ "alloca",
104
+ "dmethod",
105
+ "bmethod",
106
+ "memo",
107
+ "ifunc",
108
+ "dsym",
109
+ "attrasgn",
110
+ "last"
111
+ };
data/lib/linecache.rb ADDED
@@ -0,0 +1,399 @@
1
+ #!/usr/bin/env ruby
2
+ # $Id: linecache.rb 69 2008-03-09 23:24:25Z rockyb $
3
+ #
4
+ # Copyright (C) 2007, 2008 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
+ # Module to read and cache lines of a file
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. The may be is
33
+ # useful when a small random sets of lines are read from a single
34
+ # file, in particular in a debugger to show source lines.
35
+ #
36
+ # require 'linecache'
37
+ # lines = LineCache::getlines('/tmp/myruby.rb')
38
+ # # The following lines have same effect as the above.
39
+ # $: << '/tmp'
40
+ # Dir.chdir('/tmp') {lines = LineCache::getlines('myruby.rb')
41
+ #
42
+ # line = LineCache::getline('/tmp/myruby.rb', 6)
43
+ # # Note lines[6] == line (if /tmp/myruby.rb has 6 lines)
44
+ #
45
+ # LineCache::clear_file_cache
46
+ # LineCache::clear_file_cache('/tmp/myruby.rb')
47
+ # LineCache::update_cache # Check for modifications of all cached files.
48
+ #
49
+ # Some parts of the interface is derived from the Python module of the
50
+ # same name.
51
+ #
52
+
53
+ # Defining SCRIPT_LINES__ causes Ruby to cache the lines of files
54
+ # it reads. The key the setting of __FILE__ at the time when Ruby does
55
+ # its read. LineCache keeps a separate copy of the lines elsewhere
56
+ # and never destroys SCRIPT_LINES__
57
+ SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
58
+
59
+ require 'digest/sha1'
60
+ require 'set'
61
+
62
+ begin require 'rubygems' rescue LoadError end
63
+ require 'tracelines'
64
+ # require 'ruby-debug' ; Debugger.start
65
+
66
+ # = module LineCache
67
+ # Module caching lines of a file
68
+ module LineCache
69
+ LineCacheInfo = Struct.new(:stat, :line_numbers, :lines, :path, :sha1) unless
70
+ defined?(LineCacheInfo)
71
+
72
+ # The file cache. The key is a name as would be given by Ruby for
73
+ # __FILE__. The value is a LineCacheInfo object.
74
+ @@file_cache = {}
75
+
76
+ # Maps a string filename (a String) to a key in @@file_cache (a
77
+ # String).
78
+ #
79
+ # One important use of @@file2file_remap is mapping the a full path
80
+ # of a file into the name stored in @@file_cache or given by Ruby's
81
+ # __FILE__. Applications such as those that get input from users,
82
+ # may want canonicalize a file name before looking it up. This map
83
+ # gives a way to do that.
84
+ #
85
+ # Another related use is when a template system is used. Here we'll
86
+ # probably want to remap not only the file name but also line
87
+ # ranges. Will probably use this for that, but I'm not sure.
88
+ @@file2file_remap = {}
89
+ @@file2file_remap_lines = {}
90
+
91
+ # Clear the file cache entirely.
92
+ def clear_file_cache()
93
+ @@file_cache = {}
94
+ @@file2file_remap = {}
95
+ @@file2file_remap_lines = {}
96
+ end
97
+ module_function :clear_file_cache
98
+
99
+ # Return an array of cached file names
100
+ def cached_files()
101
+ @@file_cache.keys
102
+ end
103
+ module_function :cached_files
104
+
105
+ # Discard cache entries that are out of date. If +filename+ is +nil+
106
+ # all entries in the file cache +@@file_cache+ are checked.
107
+ # If we don't have stat information about a file which can happen
108
+ # if the file was read from __SCRIPT_LINES but no corresponding file
109
+ # is found, it will be kept. Return a list of invalidated filenames.
110
+ # nil is returned if a filename was given but not found cached.
111
+ def checkcache(filename=nil, use_script_lines=false)
112
+
113
+ if !filename
114
+ filenames = @@file_cache.keys()
115
+ elsif @@file_cache.member?(filename)
116
+ filenames = [filename]
117
+ else
118
+ return nil
119
+ end
120
+
121
+ result = []
122
+ for filename in filenames
123
+ next unless @@file_cache.member?(filename)
124
+ path = @@file_cache[filename].path
125
+ if File.exist?(path)
126
+ cache_info = @@file_cache[filename]
127
+ stat = File.stat(path)
128
+ if stat &&
129
+ (cache_info.size != stat.size or cache_info.mtime != stat.mtime)
130
+ result << filename
131
+ update_cache(filename, use_script_lines)
132
+ end
133
+ end
134
+ end
135
+ return result
136
+ end
137
+ module_function :checkcache
138
+
139
+ # Cache filename if it's not already cached.
140
+ # Return the expanded filename for it in the cache
141
+ # or nil if we can't find the file.
142
+ def cache(filename, reload_on_change=false)
143
+ if @@file_cache.member?(filename)
144
+ checkcache(filename) if reload_on_change
145
+ else
146
+ update_cache(filename, true)
147
+ end
148
+ if @@file_cache.member?(filename)
149
+ @@file_cache[filename].path
150
+ else
151
+ nil
152
+ end
153
+ end
154
+ module_function :cache
155
+
156
+ # Return true if filename is cached
157
+ def cached?(filename)
158
+ @@file_cache.member?(unmap_file(filename))
159
+ end
160
+ module_function :cached?
161
+
162
+ def cached_script?(filename)
163
+ SCRIPT_LINES__.member?(unmap_file(filename))
164
+ end
165
+ module_function :cached_script?
166
+
167
+ def empty?(filename)
168
+ filename=unmap_file(filename)
169
+ @@file_cache[filename].lines.empty?
170
+ end
171
+ module_function :empty?
172
+
173
+ # Get line +line_number+ from file named +filename+. Return nil if
174
+ # there was a problem. If a file named filename is not found, the
175
+ # function will look for it in the $: path array.
176
+ #
177
+ # Examples:
178
+ #
179
+ # lines = LineCache::getline('/tmp/myfile.rb)
180
+ # # Same as above
181
+ # $: << '/tmp'
182
+ # lines = Dir.chdir('/tmp') do
183
+ # lines = LineCache::getlines ('myfile.rb')
184
+ # end
185
+ #
186
+ def getline(filename, line_number, reload_on_change=true)
187
+ filename = unmap_file(filename)
188
+ filename, line_number = unmap_file_line(filename, line_number)
189
+ lines = getlines(filename, reload_on_change)
190
+ if lines and (1..lines.size) === line_number
191
+ return lines[line_number-1]
192
+ else
193
+ return nil
194
+ end
195
+ end
196
+ module_function :getline
197
+
198
+ # Read lines of +filename+ and cache the results. However +filename+ was
199
+ # previously cached use the results from the cache. Return nil
200
+ # if we can't get lines
201
+ def getlines(filename, reload_on_change=false)
202
+ filename = unmap_file(filename)
203
+ checkcache(filename) if reload_on_change
204
+ if @@file_cache.member?(filename)
205
+ return @@file_cache[filename].lines
206
+ else
207
+ update_cache(filename, true)
208
+ return @@file_cache[filename].lines if @@file_cache.member?(filename)
209
+ end
210
+ end
211
+ module_function :getlines
212
+
213
+ # Return full filename path for filename
214
+ def path(filename)
215
+ filename = unmap_file(filename)
216
+ return nil unless @@file_cache.member?(filename)
217
+ @@file_cache[filename].path
218
+ end
219
+ module_function :path
220
+
221
+ def remap_file(from_file, to_file)
222
+ @@file2file_remap[to_file] = from_file
223
+ end
224
+ module_function :remap_file
225
+
226
+ def remap_file_lines(from_file, to_file, range, start)
227
+ range = (range..range) if range.is_a?(Fixnum)
228
+ to_file = from_file unless to_file
229
+ if @@file2file_remap_lines[to_file]
230
+ # FIXME: need to check for overwriting ranges: whether
231
+ # they intersect or one encompasses another.
232
+ @@file2file_remap_lines[to_file] << [from_file, range, start]
233
+ else
234
+ @@file2file_remap_lines[to_file] = [[from_file, range, start]]
235
+ end
236
+ end
237
+ module_function :remap_file_lines
238
+
239
+ # Return SHA1 of filename.
240
+ def sha1(filename)
241
+ filename = unmap_file(filename)
242
+ return nil unless @@file_cache.member?(filename)
243
+ return @@file_cache[filename].sha1.hexdigest if
244
+ @@file_cache[filename].sha1
245
+ sha1 = Digest::SHA1.new
246
+ @@file_cache[filename].lines.each do |line|
247
+ sha1 << line
248
+ end
249
+ @@file_cache[filename].sha1 = sha1
250
+ sha1.hexdigest
251
+ end
252
+ module_function :sha1
253
+
254
+ # Return the number of lines in filename
255
+ def size(filename)
256
+ filename = unmap_file(filename)
257
+ return nil unless @@file_cache.member?(filename)
258
+ @@file_cache[filename].lines.length
259
+ end
260
+ module_function :size
261
+
262
+ # Return File.stat in the cache for filename.
263
+ def stat(filename)
264
+ return nil unless @@file_cache.member?(filename)
265
+ @@file_cache[filename].stat
266
+ end
267
+ module_function :stat
268
+
269
+ # Return an Array of breakpoints in filename.
270
+ # The list will contain an entry for each distinct line event call
271
+ # so it is possible (and possibly useful) for a line number appear more
272
+ # than once.
273
+ def trace_line_numbers(filename, reload_on_change=false)
274
+ fullname = cache(filename, reload_on_change)
275
+ return nil unless fullname
276
+ e = @@file_cache[filename]
277
+ unless e.line_numbers
278
+ e.line_numbers =
279
+ TraceLineNumbers.lnums_for_str_array(e.lines)
280
+ e.line_numbers = false unless e.line_numbers
281
+ end
282
+ e.line_numbers
283
+ end
284
+ module_function :trace_line_numbers
285
+
286
+ def unmap_file(file)
287
+ @@file2file_remap[file] ? @@file2file_remap[file] : file
288
+ end
289
+ module_function :unmap_file
290
+
291
+ def unmap_file_line(file, line)
292
+ if @@file2file_remap_lines[file]
293
+ @@file2file_remap_lines[file].each do |from_file, range, start|
294
+ if range === line
295
+ from_file = from_file || file
296
+ return [from_file, start+line-range.begin]
297
+ end
298
+ end
299
+ end
300
+ return [file, line]
301
+ end
302
+ module_function :unmap_file_line
303
+
304
+ # Update a cache entry. If something's
305
+ # wrong, return nil. Return true if the cache was updated and false
306
+ # if not. If use_script_lines is true, use that as the source for the
307
+ # lines of the file
308
+ def update_cache(filename, use_script_lines=false)
309
+
310
+ return nil unless filename
311
+
312
+ @@file_cache.delete(filename)
313
+ path = File.expand_path(filename)
314
+
315
+ if use_script_lines
316
+ list = [filename]
317
+ list << @@file2file_remap[path] if @@file2file_remap[path]
318
+ list.each do |name|
319
+ if !SCRIPT_LINES__[name].nil? && SCRIPT_LINES__[name] != true
320
+ begin
321
+ stat = File.stat(name)
322
+ rescue
323
+ stat = nil
324
+ end
325
+ lines = SCRIPT_LINES__[name]
326
+ @@file_cache[filename] = LineCacheInfo.new(stat, nil, lines, path, nil)
327
+ @@file2file_remap[path] = filename
328
+ return true
329
+ end
330
+ end
331
+ end
332
+
333
+ if File.exist?(path)
334
+ stat = File.stat(path)
335
+ elsif File.basename(filename) == filename
336
+ # try looking through the search path.
337
+ stat = nil
338
+ for dirname in $:
339
+ path = File.join(dirname, filename)
340
+ if File.exist?(path)
341
+ stat = File.stat(path)
342
+ break
343
+ end
344
+ end
345
+ return false unless stat
346
+ end
347
+ begin
348
+ fp = File.open(path, 'r')
349
+ lines = fp.readlines()
350
+ fp.close()
351
+ rescue
352
+ ## print '*** cannot open', path, ':', msg
353
+ return nil
354
+ end
355
+ @@file_cache[filename] = LineCacheInfo.new(File.stat(path), nil, lines,
356
+ path, nil)
357
+ @@file2file_remap[path] = filename
358
+ return true
359
+ end
360
+
361
+ module_function :update_cache
362
+
363
+ end
364
+
365
+ # example usage
366
+ if __FILE__ == $0
367
+ def yes_no(var)
368
+ return var ? "" : "not "
369
+ end
370
+
371
+ lines = LineCache::getlines(__FILE__)
372
+ puts "#{__FILE__} has #{LineCache.size(__FILE__)} lines"
373
+ line = LineCache::getline(__FILE__, 6)
374
+ puts "The 6th line is\n#{line}"
375
+ line = LineCache::remap_file(__FILE__, 'another_name')
376
+ puts LineCache::getline('another_name', 7)
377
+
378
+ puts("Files cached: #{LineCache::cached_files.inspect}")
379
+ LineCache::update_cache(__FILE__)
380
+ LineCache::checkcache(__FILE__)
381
+ puts "#{__FILE__} has #{LineCache::size(__FILE__)} lines"
382
+ puts "#{__FILE__} trace line numbers:\n" +
383
+ "#{LineCache::trace_line_numbers(__FILE__).to_a.sort.inspect}"
384
+ puts("#{__FILE__} is %scached." %
385
+ yes_no(LineCache::cached?(__FILE__)))
386
+ puts LineCache::stat(__FILE__).inspect
387
+ puts "Full path: #{LineCache::path(__FILE__)}"
388
+ LineCache::checkcache # Check all files in the cache
389
+ LineCache::clear_file_cache
390
+ puts("#{__FILE__} is now %scached." %
391
+ yes_no(LineCache::cached?(__FILE__)))
392
+ digest = SCRIPT_LINES__.select{|k,v| k =~ /digest.rb$/}
393
+ puts digest.first[0] if digest
394
+ line = LineCache::getline(__FILE__, 7)
395
+ puts "The 7th line is\n#{line}"
396
+ LineCache::remap_file_lines(__FILE__, 'test2', (10..20), 6)
397
+ puts LineCache::getline('test2', 10)
398
+ puts "Remapped 10th line of test2 is\n#{line}"
399
+ end