linecache 0.46-java

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS ADDED
@@ -0,0 +1,39 @@
1
+ 0.46
2
+ 06-12-19
3
+ - A require_relative dependency snuck in.
4
+ Add a rbx-require-relative to handle this.
5
+
6
+ 0.45
7
+ 06-12-11
8
+ - Support for syntax highlighting and caching eval strings. The former
9
+ is used in rb8-trepanning.
10
+
11
+ 0.43
12
+ 06-12-08
13
+ - tolerance for finding windows extension in lib rather than ext.
14
+
15
+ 0.41
16
+ - add test/data/* to gem.
17
+
18
+ 0.4
19
+ - Credit Ryan Davis and ParseTree.
20
+
21
+ 0.3
22
+ - Add tracelines: get line numbers that can be stopped at.
23
+
24
+ - Add routines to allow line-number
25
+ remapping and filename remapping.
26
+
27
+ - Add access methods to get the number of lines in a file.
28
+
29
+ 0.2
30
+ - Make this work with ruby-debug-base. Add reload-on-change parameters.
31
+ add checkcache, cache, cached? sha1, and stat methods.
32
+
33
+ - Use SCRIPT_LINES__.
34
+
35
+ 0.1
36
+
37
+ - Initial release of LineCache, a module for reading and caching lines.
38
+
39
+ $Id$
data/README ADDED
@@ -0,0 +1,50 @@
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 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.
49
+
50
+ $Id$
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env rake
2
+ # -*- Ruby -*-
3
+ require 'rubygems'
4
+ require 'rubygems/package_task'
5
+ require 'rdoc/task'
6
+ require 'rake/testtask'
7
+
8
+ SO_NAME = 'trace_nums.so'
9
+
10
+ ROOT_DIR = File.dirname(__FILE__)
11
+ load File.join %W(#{ROOT_DIR} lib linecache version.rb)
12
+
13
+ PKG_VERSION = LineCache::VERSION
14
+ PKG_NAME = 'linecache'
15
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
16
+ RUBY_FORGE_PROJECT = 'rocky-hacks'
17
+ RUBY_FORGE_USER = 'rockyb'
18
+
19
+ FILES = FileList[
20
+ 'AUTHORS',
21
+ 'COPYING',
22
+ 'ChangeLog',
23
+ 'NEWS',
24
+ 'README',
25
+ 'Rakefile',
26
+ 'ext/linecache/trace_nums.c',
27
+ 'ext/linecache/trace_nums.h',
28
+ 'ext/linecache/extconf.rb',
29
+ 'lib/**/*.rb',
30
+ 'test/*.rb',
31
+ 'test/data/*.rb',
32
+ 'test/short-file'
33
+ ]
34
+
35
+ desc 'Test everything'
36
+ Rake::TestTask.new(:test) do |t|
37
+ t.libs << 'ext'
38
+ t.pattern = 'test/test-*.rb'
39
+ t.options = '--verbose' if $VERBOSE
40
+ end
41
+ task :test => :lib
42
+
43
+ desc 'Create the core ruby-debug shared library extension'
44
+ task :lib do
45
+ Dir.chdir('ext/linecache') do
46
+ system("#{Gem.ruby} extconf.rb && make")
47
+ end
48
+ end
49
+
50
+
51
+ desc 'Test everything - same as test.'
52
+ task :check => :test
53
+
54
+ desc 'Create a GNU-style ChangeLog via svn2cl'
55
+ task :ChangeLog do
56
+ system('git log --pretty --numstat --summary | git2cl > ChangeLog')
57
+ end
58
+
59
+ gem_file = nil
60
+
61
+ # Base GEM Specification
62
+ default_spec = Gem::Specification.new do |spec|
63
+ spec.name = 'linecache'
64
+
65
+ spec.homepage = 'http://rubyforge.org/projects/rocky-hacks/linecache'
66
+ spec.summary = 'Read file with caching'
67
+ spec.description = <<-EOF
68
+ LineCache is a module for reading and caching lines. This may be useful for
69
+ example in a debugger where the same lines are shown many times.
70
+ EOF
71
+
72
+ spec.version = PKG_VERSION
73
+
74
+ spec.author = 'R. Bernstein'
75
+ spec.email = 'rockyb@rubyforge.net'
76
+ spec.platform = Gem::Platform::RUBY
77
+ spec.require_path = 'lib'
78
+ spec.files = FILES.to_a
79
+ spec.extensions = ['ext/linecache/extconf.rb']
80
+
81
+ spec.required_ruby_version = '>= 1.8.7'
82
+ spec.date = Time.now
83
+ spec.rubyforge_project = 'rocky-hacks'
84
+
85
+ # rdoc
86
+ spec.has_rdoc = true
87
+ spec.extra_rdoc_files = ['README', 'lib/linecache.rb', 'lib/linecache/tracelines.rb']
88
+
89
+ spec.test_files = FileList['test/*.rb']
90
+ gem_file = "#{spec.name}-#{spec.version}.gem"
91
+
92
+ end
93
+
94
+ # Rake task to build the default package
95
+ Gem::PackageTask.new(default_spec) do |pkg|
96
+ pkg.need_tar = true
97
+ end
98
+
99
+ task :default => [:test]
100
+
101
+ # Windows specification
102
+ win_spec = default_spec.clone
103
+ win_spec.extensions = []
104
+ ## win_spec.platform = Gem::Platform::WIN32 # deprecated
105
+ win_spec.platform = 'mswin32'
106
+ win_spec.files += ["lib/#{SO_NAME}"]
107
+
108
+ desc 'Create Windows Gem'
109
+ task :win32_gem do
110
+ # Copy the win32 extension the top level directory.
111
+ current_dir = File.expand_path(File.dirname(__FILE__))
112
+ source = File.join(current_dir, 'ext', 'win32', SO_NAME)
113
+ target = File.join(current_dir, 'lib', SO_NAME)
114
+ cp(source, target)
115
+
116
+ # Create the gem, then move it to pkg.
117
+ Gem::Builder.new(win_spec).build
118
+ gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
119
+ mv(gem_file, "pkg/#{gem_file}")
120
+
121
+ # Remove win extension from top level directory.
122
+ rm(target)
123
+ end
124
+
125
+ desc 'Publish linecache to RubyForge.'
126
+ task :publish do
127
+ require 'rake/contrib/sshpublisher'
128
+
129
+ # Get ruby-debug path.
130
+ ruby_debug_path = File.expand_path(File.dirname(__FILE__))
131
+
132
+ publisher = Rake::SshDirPublisher.new('rockyb@rubyforge.org',
133
+ '/var/www/gforge-projects/rocky-hacks/linecache', ruby_debug_path)
134
+ end
135
+
136
+ desc 'Remove residue from running patch'
137
+ task :rm_patch_residue do
138
+ FileUtils.rm_rf Dir.glob('**/*.{rej,orig}'), :verbose => true
139
+ end
140
+
141
+ desc 'Remove ~ backup files'
142
+ task :rm_tilde_backups do
143
+ FileUtils.rm_rf Dir.glob('**/*~'), :verbose => true
144
+ end
145
+
146
+ desc 'Remove built files'
147
+ task :clean => [:clobber_package, :clobber_rdoc, :rm_patch_residue,
148
+ :rm_tilde_backups] do
149
+ cd 'ext' do
150
+ if File.exists?('Makefile')
151
+ sh 'make clean'
152
+ rm 'Makefile'
153
+ end
154
+ derived_files = Dir.glob('.o') + Dir.glob('*.so')
155
+ rm derived_files unless derived_files.empty?
156
+ end
157
+ end
158
+
159
+ # --------- RDoc Documentation ------
160
+ desc 'Generate rdoc documentation'
161
+ RDoc::Task.new('rdoc') do |rdoc|
162
+ rdoc.rdoc_dir = 'doc'
163
+ rdoc.title = "linecache #{LineCache::VERSION} Documentation"
164
+ rdoc.options << '--main' << 'README'
165
+ rdoc.rdoc_files.include('ext/**/*.c',
166
+ 'lib/*.rb',
167
+ 'README',
168
+ 'COPYING')
169
+ end
170
+
171
+ desc 'Publish the release files to RubyForge.'
172
+ task :rubyforge_upload do
173
+ `rubyforge login`
174
+ release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
175
+ puts release_command
176
+ system(release_command)
177
+ end
178
+
179
+ desc 'Install the gem locally'
180
+ task :install => :gem do
181
+ Dir.chdir(ROOT_DIR) do
182
+ sh %{gem install --local pkg/#{gem_file}}
183
+ end
184
+ end
185
+
186
+ task :install_jruby => :gem do
187
+ namespace :jruby do
188
+ jruby_spec = default_spec.clone
189
+ jruby_spec.platform = "java"
190
+ jruby_spec.files = jruby_spec.files.reject {|f| f =~ /^ext/ }
191
+ jruby_spec.extensions = []
192
+
193
+ Gem::PackageTask.new(jruby_spec) {}
194
+ end
195
+ end
@@ -0,0 +1,565 @@
1
+ #!/usr/bin/env ruby
2
+ # $Id$
3
+ #
4
+ # Copyright (C) 2007, 2008, 2010, 2011 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
+
27
+ # == SYNOPSIS
28
+ #
29
+ # The LineCache module allows one to get any line from any file,
30
+ # caching lines of the file on first access to the file. Although the
31
+ # file may be any file, the common use is when the file is a Ruby
32
+ # script since parsing of the file is done to figure out where the
33
+ # statement boundaries are.
34
+ #
35
+ # The routines here may be is useful when a small random sets of lines
36
+ # are read from a single file, in particular in a debugger to show
37
+ # source lines.
38
+ #
39
+ #
40
+ # require 'linecache'
41
+ # lines = LineCache::getlines('/tmp/myruby.rb')
42
+ # # The following lines have same effect as the above.
43
+ # $: << '/tmp'
44
+ # Dir.chdir('/tmp') {lines = LineCache::getlines('myruby.rb')
45
+ #
46
+ # line = LineCache::getline('/tmp/myruby.rb', 6)
47
+ # # Note lines[6] == line (if /tmp/myruby.rb has 6 lines)
48
+ #
49
+ # LineCache::clear_file_cache
50
+ # LineCache::update_cache # Check for modifications of all cached files.
51
+ #
52
+ # Some parts of the interface is derived from the Python module of the
53
+ # same name.
54
+ #
55
+
56
+ # Defining SCRIPT_LINES__ causes Ruby to cache the lines of files
57
+ # it reads. The key the setting of __FILE__ at the time when Ruby does
58
+ # its read. LineCache keeps a separate copy of the lines elsewhere
59
+ # and never destroys SCRIPT_LINES__
60
+ SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
61
+
62
+ require 'digest/sha1'
63
+ require 'set'
64
+
65
+ require 'linecache/tracelines'
66
+ require 'linecache/version'
67
+ # require 'ruby-debug' ; Debugger.start
68
+
69
+ # = module LineCache
70
+ # A module to read and cache lines of a Ruby program.
71
+ module LineCache
72
+ LineCacheInfo = Struct.new(:stat, :line_numbers, :lines, :path, :sha1) unless
73
+ defined?(LineCacheInfo)
74
+
75
+ # The file cache. The key is a name as would be given by Ruby for
76
+ # __FILE__. The value is a LineCacheInfo object.
77
+ @@file_cache = {}
78
+ @@script_cache = {}
79
+
80
+
81
+ # Used for CodeRay syntax highlighting
82
+ @@ruby_highlighter = nil
83
+
84
+ # Maps a string filename (a String) to a key in @@file_cache (a
85
+ # String).
86
+ #
87
+ # One important use of @@file2file_remap is mapping the a full path
88
+ # of a file into the name stored in @@file_cache or given by Ruby's
89
+ # __FILE__. Applications such as those that get input from users,
90
+ # may want canonicalize a file name before looking it up. This map
91
+ # gives a way to do that.
92
+ #
93
+ # Another related use is when a template system is used. Here we'll
94
+ # probably want to remap not only the file name but also line
95
+ # ranges. Will probably use this for that, but I'm not sure.
96
+ @@file2file_remap = {}
97
+ @@file2file_remap_lines = {}
98
+ @@script2file = {}
99
+
100
+ module_function
101
+
102
+ def remove_script_temps
103
+ @@script2file.values.each do |filename|
104
+ File.unlink(filename) if File.exist?(filename)
105
+ end
106
+ end
107
+ at_exit { remove_script_temps }
108
+
109
+
110
+ # Clear the file cache entirely.
111
+ def clear_file_cache(filename=nil)
112
+ if filename
113
+ if @@file_cache[filename]
114
+ @@file_cache.delete(filename)
115
+ end
116
+ else
117
+ @@file_cache = {}
118
+ @@file2file_remap = {}
119
+ @@file2file_remap_lines = {}
120
+ end
121
+ end
122
+
123
+ # Remove syntax-formatted lines in the cache. Use this
124
+ # when you change the CodeRay syntax or Token formatting
125
+ # and want to redo how files may have previously been
126
+ # syntax marked.
127
+ def clear_file_format_cache
128
+ @@file_cache.each_pair do |fname, cache_info|
129
+ cache_info.lines.each_pair do |format, lines|
130
+ next if :plain == format
131
+ @@file_cache[fname].lines[format] = nil
132
+ end
133
+ end
134
+ end
135
+
136
+ # Remove syntax-formatted lines in the cache. Use this
137
+ # when you change the CodeRay syntax or Token formatting
138
+ # and want to redo how files may have previously been
139
+ # syntax marked.
140
+ def clear_file_format_cache
141
+ @@file_cache.each_pair do |fname, cache_info|
142
+ cache_info.lines.each_pair do |format, lines|
143
+ next if :plain == format
144
+ @@file_cache[fname].lines[format] = nil
145
+ end
146
+ end
147
+ end
148
+
149
+ # Clear the script cache entirely.
150
+ def clear_script_cache()
151
+ @@script_cache = {}
152
+ end
153
+
154
+ # Return an array of cached file names
155
+ def cached_files()
156
+ @@file_cache.keys
157
+ end
158
+
159
+ # Discard cache entries that are out of date. If +filename+ is +nil+
160
+ # all entries in the file cache +@@file_cache+ are checked.
161
+ # If we don't have stat information about a file, which can happen
162
+ # if the file was read from __SCRIPT_LINES but no corresponding file
163
+ # is found, it will be kept. Return a list of invalidated filenames.
164
+ # nil is returned if a filename was given but not found cached.
165
+ def checkcache(filename=nil, opts=false)
166
+ use_script_lines =
167
+ if opts.kind_of?(Hash)
168
+ opts[:use_script_lines]
169
+ else
170
+ opts
171
+ end
172
+
173
+ if !filename
174
+ filenames = @@file_cache.keys()
175
+ elsif @@file_cache.member?(filename)
176
+ filenames = [filename]
177
+ else
178
+ return nil
179
+ end
180
+
181
+ result = []
182
+ for filename in filenames
183
+ next unless @@file_cache.member?(filename)
184
+ path = @@file_cache[filename].path
185
+ if File.exist?(path)
186
+ cache_info = @@file_cache[filename].stat
187
+ stat = File.stat(path)
188
+ if cache_info
189
+ if stat &&
190
+ (cache_info.size != stat.size or cache_info.mtime != stat.mtime)
191
+ result << filename
192
+ update_cache(filename, opts)
193
+ end
194
+ else
195
+ result << filename
196
+ update_cache(filename, opts)
197
+ end
198
+ end
199
+ end
200
+ return result
201
+ end
202
+
203
+ # Cache script if it's not already cached.
204
+ def cache_script(script, opts={})
205
+ if !@@script_cache.member?(script)
206
+ update_script_cache(script, opts)
207
+ end
208
+ script
209
+ end
210
+
211
+ # Cache file name or script object if it's not already cached.
212
+ # Return the expanded filename for it in the cache if a filename,
213
+ # or the script, or nil if we can't find the file.
214
+ def cache(file_or_script, reload_on_change=false)
215
+ if file_or_script.kind_of?(String)
216
+ cache_file(file_or_script, reload_on_change)
217
+ else
218
+ cache_script(file_or_script)
219
+ end
220
+ end
221
+
222
+ # Cache filename if it's not already cached.
223
+ # Return the expanded filename for it in the cache
224
+ # or nil if we can't find the file.
225
+ def cache_file(filename, reload_on_change=false, opts={})
226
+ if @@file_cache.member?(filename)
227
+ checkcache(filename) if reload_on_change
228
+ else
229
+ opts[:use_script_lines] = true
230
+ update_cache(filename, opts)
231
+ end
232
+ if @@file_cache.member?(filename)
233
+ @@file_cache[filename].path
234
+ else
235
+ nil
236
+ end
237
+ end
238
+
239
+ # Older routine - for compability.
240
+ # Cache filename if it's not already cached.
241
+ # Return the expanded filename for it in the cache
242
+ # or nil if we can't find the file.
243
+ def cache(filename, reload_on_change=false)
244
+ if @@file_cache.member?(filename)
245
+ checkcache(filename) if reload_on_change
246
+ else
247
+ update_cache(filename, true)
248
+ end
249
+ if @@file_cache.member?(filename)
250
+ @@file_cache[filename].path
251
+ else
252
+ nil
253
+ end
254
+ end
255
+
256
+ # Return true if file_or_script is cached
257
+ def cached?(file_or_script)
258
+ if file_or_script.kind_of?(String)
259
+ @@file_cache.member?(unmap_file(file_or_script))
260
+ else
261
+ cached_script?(file_or_script)
262
+ end
263
+ end
264
+
265
+ def cached_script?(filename)
266
+ SCRIPT_LINES__.member?(unmap_file(filename))
267
+ end
268
+
269
+ def empty?(filename)
270
+ filename=unmap_file(filename)
271
+ !!@@file_cache[filename].lines[:plain]
272
+ end
273
+
274
+ # Get line +line_number+ from file named +filename+. Return nil if
275
+ # there was a problem. If a file named filename is not found, the
276
+ # function will look for it in the $: array.
277
+ #
278
+ # Examples:
279
+ #
280
+ # lines = LineCache::getline('/tmp/myfile.rb')
281
+ # # Same as above
282
+ # $: << '/tmp'
283
+ # lines = LineCache.getlines('myfile.rb')
284
+ #
285
+ def getline(file_or_script, line_number, opts=true)
286
+ reload_on_change =
287
+ if opts.kind_of?(Hash)
288
+ opts[:reload_on_change]
289
+ else
290
+ opts
291
+ end
292
+ lines =
293
+ if file_or_script.kind_of?(String)
294
+ filename = unmap_file(file_or_script)
295
+ filename, line_number = unmap_file_line(filename, line_number)
296
+ getlines(filename, opts)
297
+ else
298
+ script_getlines(file_or_script)
299
+ end
300
+ if lines and (1..lines.size) === line_number
301
+ return lines[line_number-1]
302
+ else
303
+ return nil
304
+ end
305
+ end
306
+
307
+ # Read lines of +filename+ and cache the results. However +filename+ was
308
+ # previously cached use the results from the cache. Return nil
309
+ # if we can't get lines
310
+ def getlines(filename, opts=false)
311
+ if opts.kind_of?(Hash)
312
+ reload_on_change, use_script_lines =
313
+ [opts[:reload_on_change], opts[:use_script_lines]]
314
+ else
315
+ reload_on_change, use_script_lines = [opts, false]
316
+ opts = {:reload_on_change => reload_on_change}
317
+ end
318
+ checkcache(filename) if reload_on_change
319
+ format = opts[:output] || :plain
320
+ if @@file_cache.member?(filename)
321
+ lines = @@file_cache[filename].lines
322
+ if opts[:output] && !lines[format]
323
+ lines[format] =
324
+ highlight_string(lines[:plain].join(''), format).split(/\n/)
325
+ end
326
+ return lines[format]
327
+ else
328
+ opts[:use_script_lines] = true
329
+ update_cache(filename, opts)
330
+ if @@file_cache.member?(filename)
331
+ return @@file_cache[filename].lines[format]
332
+ else
333
+ return nil
334
+ end
335
+ end
336
+ end
337
+
338
+ def highlight_string(string, output_type)
339
+ require 'rubygems'
340
+ begin
341
+ require 'coderay'
342
+ require 'term/ansicolor'
343
+ rescue LoadError
344
+ return string
345
+ end
346
+ @@ruby_highlighter ||= CodeRay::Duo[:ruby, output_type]
347
+ @@ruby_highlighter.encode(string)
348
+ end
349
+
350
+ # Return full filename path for filename
351
+ def path(filename)
352
+ return unless filename.kind_of?(String)
353
+ filename = unmap_file(filename)
354
+ return nil unless @@file_cache.member?(filename)
355
+ @@file_cache[filename].path
356
+ end
357
+
358
+ def remap_file(from_file, to_file)
359
+ @@file2file_remap[from_file] = to_file
360
+ cache_file(to_file)
361
+ end
362
+
363
+ def remap_file_lines(from_file, to_file, range, start)
364
+ range = (range..range) if range.kind_of?(Fixnum)
365
+ to_file = from_file unless to_file
366
+ if @@file2file_remap_lines[to_file]
367
+ # FIXME: need to check for overwriting ranges: whether
368
+ # they intersect or one encompasses another.
369
+ @@file2file_remap_lines[to_file] << [from_file, range, start]
370
+ else
371
+ @@file2file_remap_lines[to_file] = [[from_file, range, start]]
372
+ end
373
+ end
374
+ module_function :remap_file_lines
375
+
376
+ # Return SHA1 of filename.
377
+ def sha1(filename)
378
+ filename = unmap_file(filename)
379
+ return nil unless @@file_cache.member?(filename)
380
+ return @@file_cache[filename].sha1.hexdigest if
381
+ @@file_cache[filename].sha1
382
+ sha1 = Digest::SHA1.new
383
+ @@file_cache[filename].lines[:plain].each do |line|
384
+ sha1 << line + "\n"
385
+ end
386
+ @@file_cache[filename].sha1 = sha1
387
+ sha1.hexdigest
388
+ end
389
+
390
+ # Return the number of lines in filename
391
+ def size(file_or_script)
392
+ cache(file_or_script)
393
+ if file_or_script.kind_of?(String)
394
+ file_or_script = unmap_file(file_or_script)
395
+ return nil unless @@file_cache.member?(file_or_script)
396
+ @@file_cache[file_or_script].lines[:plain].length
397
+ else
398
+ return nil unless @@script_cache.member?(file_or_script)
399
+ @@script_cache[file_or_script].lines[:plain].length
400
+ end
401
+ end
402
+
403
+ # Return File.stat in the cache for filename.
404
+ def stat(filename)
405
+ return nil unless @@file_cache.member?(filename)
406
+ @@file_cache[filename].stat
407
+ end
408
+ module_function :stat
409
+
410
+ # Return an Array of breakpoints in filename.
411
+ # The list will contain an entry for each distinct line event call
412
+ # so it is possible (and possibly useful) for a line number appear more
413
+ # than once.
414
+ def trace_line_numbers(filename, reload_on_change=false)
415
+ fullname = cache(filename, reload_on_change)
416
+ return nil unless fullname
417
+ e = @@file_cache[filename]
418
+ unless e.line_numbers
419
+ e.line_numbers =
420
+ TraceLineNumbers.lnums_for_str_array(e.lines[:plain])
421
+ e.line_numbers = false unless e.line_numbers
422
+ end
423
+ e.line_numbers
424
+ end
425
+
426
+ def unmap_file(file)
427
+ @@file2file_remap[file] ? @@file2file_remap[file] : file
428
+ end
429
+ alias :map_file :unmap_file
430
+
431
+ def unmap_file_line(file, line)
432
+ if @@file2file_remap_lines[file]
433
+ @@file2file_remap_lines[file].each do |from_file, range, start|
434
+ if range === line
435
+ from_file = from_file || file
436
+ return [from_file, start+line-range.begin]
437
+ end
438
+ end
439
+ end
440
+ return [file, line]
441
+ end
442
+
443
+ # Update a cache entry. If something is wrong, return nil. Return
444
+ # true if the cache was updated and false if not.
445
+ def update_script_cache(script, opts)
446
+ # return false unless script_is_eval?(script)
447
+ # string = opts[:string] || script.eval_source
448
+ lines = {:plain => string.split(/\n/)}
449
+ lines[opts[:output]] = highlight_string(string, opts[:output]) if
450
+ opts[:output]
451
+ @@script_cache[script] =
452
+ LineCacheInfo.new(nil, nil, lines, nil, opts[:sha1],
453
+ opts[:compiled_method])
454
+ return true
455
+ end
456
+
457
+ # Update a cache entry. If something's
458
+ # wrong, return nil. Return true if the cache was updated and false
459
+ # if not. If use_script_lines is true, use that as the source for the
460
+ # lines of the file
461
+ def update_cache(filename, opts=false)
462
+ if opts.kind_of?(Hash)
463
+ use_script_lines = opts[:use_script_lines]
464
+ else
465
+ use_script_lines = opts
466
+ opts = {:use_script_lines => use_script_lines}
467
+ end
468
+
469
+ return nil unless filename
470
+
471
+ @@file_cache.delete(filename)
472
+ path = File.expand_path(filename)
473
+
474
+ if use_script_lines
475
+ list = [filename]
476
+ list << @@file2file_remap[path] if @@file2file_remap[path]
477
+ list.each do |name|
478
+ if !SCRIPT_LINES__[name].nil? && SCRIPT_LINES__[name] != true
479
+ begin
480
+ stat = File.stat(name)
481
+ rescue
482
+ stat = nil
483
+ end
484
+ raw_lines = SCRIPT_LINES__[name]
485
+ lines = {:plain => raw_lines}
486
+ lines[opts[:output]] =
487
+ highlight_string(raw_lines.join, opts[:output]).split(/\n/) if
488
+ opts[:output]
489
+ @@file_cache[filename] = LineCacheInfo.new(stat, nil, lines, path, nil)
490
+ @@file2file_remap[path] = filename
491
+ return true
492
+ end
493
+ end
494
+ end
495
+
496
+ if File.exist?(path)
497
+ stat = File.stat(path)
498
+ elsif File.basename(filename) == filename
499
+ # try looking through the search path.
500
+ stat = nil
501
+ for dirname in $:
502
+ path = File.join(dirname, filename)
503
+ if File.exist?(path)
504
+ stat = File.stat(path)
505
+ break
506
+ end
507
+ end
508
+ return false unless stat
509
+ end
510
+ begin
511
+ fp = File.open(path, 'r')
512
+ raw_string = fp.read
513
+ fp.rewind
514
+ lines = {:plain => fp.readlines}
515
+ fp.close()
516
+ lines[opts[:output]] =
517
+ highlight_string(raw_string, opts[:output]).split(/\n/) if
518
+ opts[:output]
519
+ rescue
520
+ ## print '*** cannot open', path, ':', msg
521
+ return nil
522
+ end
523
+ @@file_cache[filename] = LineCacheInfo.new(File.stat(path), nil, lines,
524
+ path, nil)
525
+ @@file2file_remap[path] = filename
526
+ return true
527
+ end
528
+
529
+ end
530
+
531
+ # example usage
532
+ if __FILE__ == $0
533
+ def yes_no(var)
534
+ return var ? "" : "not "
535
+ end
536
+
537
+ lines = LineCache::getlines(__FILE__)
538
+ puts "#{__FILE__} has #{LineCache.size(__FILE__)} lines"
539
+ line = LineCache::getline(__FILE__, 6)
540
+ puts "The 6th line is\n#{line}"
541
+ line = LineCache::remap_file(__FILE__, 'another_name')
542
+ puts LineCache::getline('another_name', 7)
543
+
544
+ puts("Files cached: #{LineCache::cached_files.inspect}")
545
+ LineCache::update_cache(__FILE__)
546
+ LineCache::checkcache(__FILE__)
547
+ puts "#{__FILE__} has #{LineCache::size(__FILE__)} lines"
548
+ puts "#{__FILE__} trace line numbers:\n" +
549
+ "#{LineCache::trace_line_numbers(__FILE__).to_a.sort.inspect}"
550
+ puts("#{__FILE__} is %scached." %
551
+ yes_no(LineCache::cached?(__FILE__)))
552
+ puts LineCache::stat(__FILE__).inspect
553
+ puts "Full path: #{LineCache::path(__FILE__)}"
554
+ LineCache::checkcache # Check all files in the cache
555
+ LineCache::clear_file_cache
556
+ puts("#{__FILE__} is now %scached." %
557
+ yes_no(LineCache::cached?(__FILE__)))
558
+ digest = SCRIPT_LINES__.select{|k,v| k =~ /digest.rb$/}
559
+ puts digest.first[0] if digest
560
+ line = LineCache::getline(__FILE__, 7)
561
+ puts "The 7th line is\n#{line}"
562
+ LineCache::remap_file_lines(__FILE__, 'test2', (10..20), 6)
563
+ puts LineCache::getline('test2', 10)
564
+ puts "Remapped 10th line of test2 is\n#{line}"
565
+ end