Module: RubyLabs::Source
- Defined in:
- lib/rubylabs.rb
Overview
Source
The Source module provides access the source code for a lab project. When IRB reads the modules from a file, the source is saved in a global array named SCRIPT_LINES__
. The methods defined in this module scan the source code to look for tags that mark the first and last lines of methods described in the book.
A method name can be passed either as a String or a Symbol. For example, to print a listing of the isort
method a user can call
Source.listing("isort")
or
Source.listing(:isort)
#– Code that will be accessed by methods in this module should be delimited by :begin and :end tags. See the definition of isort in iterationlab.rb for an example of how to name a method and its helper methods.
Constant Summary collapse
- @@probes =
Hash.new
- @@file =
Hash.new
- @@size =
Hash.new
- @@base =
Hash.new
- @@helpers =
Hash.new
- @@line =
nil
Class Method Summary collapse
-
.checkout(name, newfilename = nil) ⇒ Object
Save a copy of the source code for method
name
in a file. -
.clear(name = nil) ⇒ Object
Remove all the probes on a designated method, or if no method name is passed, remove all probes from all methods.
-
.find(name) ⇒ Object
Internal use only – locate the filename, starting line number, and length of method
name
, record the information for any methods that need it. -
.info(name) ⇒ Object
Internal use only – show info about method to verify it’s being found by Source.lines.
-
.lines(spec, id) ⇒ Object
Internal use only – make an array of line numbers to use for probing method
name
. -
.listing(name) ⇒ Object
Print a listing (source code along with line numbers) for method
name
. -
.print_source(f, id) ⇒ Object
Helper method called from Source.checkout – print the code for method
id
in the filef
. - .probe(name, spec, expr = :count) ⇒ Object
-
.probes ⇒ Object
Print a description of all the currently defined probes.
-
.probing(filename, method, line) ⇒ Object
– Method for internal use only – Return probes (if any) attached to the specified file, method, and line number.
-
.range_check(n, id) ⇒ Object
:nodoc:.
Class Method Details
.checkout(name, newfilename = nil) ⇒ Object
Save a copy of the source code for method name
in a file. If a file name is not specified, the output file name is the name of the method with “.rb” appended. Prompts the user before overwriting an existing file.
Example – Write the source for the method isort
to “isort.rb”:
Source.checkout("isort")
Example – Write the source for isort
to “mysort.rb”
Source.checkout("isort", "mysort.rb")
:call-seq:
Source.checkout(name)
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 |
# File 'lib/rubylabs.rb', line 485 def Source.checkout(name, newfilename = nil) begin id = Source.find(name) if newfilename.nil? newfilename = id.to_s end if newfilename[-1] == ?? || newfilename[1] == ?! newfilename.chop! end if newfilename !~ /\.rb$/ newfilename += ".rb" end if File.exists?(newfilename) print "Replace existing #{newfilename}? [yn] " if STDIN.gets[0] != ?y puts "File not written" return false end end File.open(newfilename, "w") do |f| f.puts "# #{name} method exported from #{File.basename(@@file[id])}" f.puts Source.print_source(f, id) @@helpers[id].each do |m| f.puts xid = Source.find(m) Source.print_source(f, xid) end end rescue Exception => e puts e end puts "Saved a copy of source in #{newfilename}" return true end |
.clear(name = nil) ⇒ Object
Remove all the probes on a designated method, or if no method name is passed, remove all probes from all methods.
:call-seq:
Source.clear(name)
607 608 609 610 611 612 613 |
# File 'lib/rubylabs.rb', line 607 def Source.clear(name = nil) @@probes.each do |id, plist| next if ! name.nil? && id != name plist.clear end return true end |
.find(name) ⇒ Object
Internal use only – locate the filename, starting line number, and length of method name
, record the information for any methods that need it. This information only needs to be found once, so it is recorded in a set of class variables. Revisit this decision if monitoring user-defined methods.…
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
# File 'lib/rubylabs.rb', line 621 def Source.find(name) # :nodoc: id = name.to_sym return id if @@file[id] # return if we looked for this source previously filename, base, size, helpers = nil, nil, nil, nil catch (:found) do SCRIPT_LINES__.each do |file, lines| line_num = 0 lines.each do |s| line_num += 1 if match = s.match(/:(begin|end)\s+(.*)/) verb = match[1] names = match[2].split.collect{|x| eval(x)} if names[0] == id if verb == "begin" filename = file base = line_num + 1 helpers = names[1..-1] else size = line_num - base throw :found end end end end end end raise "Can't find method named '#{name}'" if size.nil? @@file[id] = filename @@size[id] = size @@base[id] = base @@probes[id] = Hash.new @@helpers[id] = helpers return id end |
.info(name) ⇒ Object
Internal use only – show info about method to verify it’s being found by Source.lines
694 695 696 697 698 699 700 701 702 703 704 705 |
# File 'lib/rubylabs.rb', line 694 def Source.info(name) # :nodoc: unless id = Source.find(name) puts "Can't find method named '#{name}'" return end printf "file: %s\n", @@file[id] printf "size: %d\n", @@size[id] printf "base: %d\n", @@base[id] printf "helpers: %s\n", @@helpers[id].inspect printf "probes: %s\n", @@probes[id].inspect end |
.lines(spec, id) ⇒ Object
Internal use only – make an array of line numbers to use for probing method name
. Argument can be a single line number, an array of line numbers, or a pattern. Checks to make sure line numbers are valid.
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
# File 'lib/rubylabs.rb', line 664 def Source.lines(spec, id) # :nodoc: if spec.class == Fixnum && Source.range_check(spec, id) return [spec] elsif spec.class == Array res = Array.new spec.each do |line| raise "line number must be an integer" unless line.class == Fixnum res << line if Source.range_check(line, id) end return res elsif spec.class == String res = Array.new for i in @@base[id]..(@@base[id]+@@size[id]-1) line = SCRIPT_LINES__[@@file[id]][i-1].chomp res << i - @@base[id] + 1 if line.index(spec) end return res else raise "invalid spec: '#{spec}' (must be an integer, array of integers, or a pattern)" end end |
.listing(name) ⇒ Object
Print a listing (source code along with line numbers) for method name
.
:call-seq:
Source.listing(name)
458 459 460 461 462 463 464 465 466 467 468 469 |
# File 'lib/rubylabs.rb', line 458 def Source.listing(name) begin id = Source.find(name) for i in @@base[id]..(@@base[id]+@@size[id]-1) line = SCRIPT_LINES__[@@file[id]][i-1].chomp printf "%3d: %s\n", i - @@base[id] + 1, line.gsub(/\t/," ") end rescue Exception => e puts e end return true end |
.print_source(f, id) ⇒ Object
Helper method called from Source.checkout – print the code for method id
in the file f
524 525 526 527 528 529 |
# File 'lib/rubylabs.rb', line 524 def Source.print_source(f, id) # :nodoc: for i in @@base[id]..(@@base[id]+@@size[id]-1) line = SCRIPT_LINES__[@@file[id]][i-1].chomp f.puts line.gsub(/\t/," ") end end |
.probe(name, spec, expr = :count) ⇒ Object
559 560 561 562 563 564 565 566 567 568 569 570 |
# File 'lib/rubylabs.rb', line 559 def Source.probe(name, spec, expr = :count) begin id = Source.find(name) Source.lines(spec, id).each do |n| n += @@base[id] - 1 @@probes[id][n] = expr end rescue Exception => e puts e end return true end |
.probes ⇒ Object
590 591 592 593 594 595 596 597 598 |
# File 'lib/rubylabs.rb', line 590 def Source.probes @@probes.each do |name, plist| plist.each do |line, exprs| n = line - @@base[name] + 1 printf "%s %2d: %s\n", name, n, exprs end end return true end |
.probing(filename, method, line) ⇒ Object
– Method for internal use only –
Return probes (if any) attached to the specified file, method, and line number. Intended to be called from a trace func callback (which is why the file is one of the parameters).
577 578 579 580 581 582 |
# File 'lib/rubylabs.rb', line 577 def Source.probing(filename, method, line) # :nodoc: return nil if line == @@line @@line = line return nil unless @@probes[method] && @@file[method] == filename return @@probes[method][line] end |