linecache 0.41-mswin32

Sign up to get free protection for your applications and to get access to all the features.
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