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)
478 479 480 481 482 483 484 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 |
# File 'lib/rubylabs.rb', line 478 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)
600 601 602 603 604 605 606 |
# File 'lib/rubylabs.rb', line 600 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.…
614 615 616 617 618 619 620 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 |
# File 'lib/rubylabs.rb', line 614 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
687 688 689 690 691 692 693 694 695 696 697 698 |
# File 'lib/rubylabs.rb', line 687 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.
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
# File 'lib/rubylabs.rb', line 657 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)
451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/rubylabs.rb', line 451 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
517 518 519 520 521 522 |
# File 'lib/rubylabs.rb', line 517 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
552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/rubylabs.rb', line 552 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
583 584 585 586 587 588 589 590 591 |
# File 'lib/rubylabs.rb', line 583 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).
570 571 572 573 574 575 |
# File 'lib/rubylabs.rb', line 570 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 |