Linguistics 1.0.3
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/Artistic +127 -0
 - data/ChangeLog +444 -0
 - data/MANIFEST +19 -0
 - data/README +178 -0
 - data/README.english +245 -0
 - data/TODO +17 -0
 - data/experiments/randobjlist.rb +34 -0
 - data/install.rb +154 -0
 - data/lib/linguistics/en/infinitive.rb +1149 -0
 - data/lib/linguistics/en/linkparser.rb +142 -0
 - data/lib/linguistics/en/wordnet.rb +253 -0
 - data/lib/linguistics/en.rb +1694 -0
 - data/lib/linguistics/iso639.rb +456 -0
 - data/lib/linguistics.rb +368 -0
 - data/redist/crosscase.rb +298 -0
 - data/test.rb +110 -0
 - data/tests/en/conjunction.tests.rb +114 -0
 - data/tests/en/inflect.tests.rb +1378 -0
 - data/tests/lingtestcase.rb +239 -0
 - data/tests/use.tests.rb +99 -0
 - data/utils.rb +689 -0
 - metadata +58 -0
 
    
        data/utils.rb
    ADDED
    
    | 
         @@ -0,0 +1,689 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            #	Install/distribution utility functions
         
     | 
| 
      
 3 
     | 
    
         
            +
            #	$Id: utils.rb 8 2005-07-13 12:35:15Z ged $
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            #	Copyright (c) 2001-2005, The FaerieMUD Consortium.
         
     | 
| 
      
 6 
     | 
    
         
            +
            #
         
     | 
| 
      
 7 
     | 
    
         
            +
            #	This is free software. You may use, modify, and/or redistribute this
         
     | 
| 
      
 8 
     | 
    
         
            +
            #	software under the terms of the Perl Artistic License. (See
         
     | 
| 
      
 9 
     | 
    
         
            +
            #	http://language.perl.com/misc/Artistic.html)
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            BEGIN {
         
     | 
| 
      
 13 
     | 
    
         
            +
            	require 'rbconfig'
         
     | 
| 
      
 14 
     | 
    
         
            +
            	require 'uri'
         
     | 
| 
      
 15 
     | 
    
         
            +
            	require 'find'
         
     | 
| 
      
 16 
     | 
    
         
            +
            	require 'pp'
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            	begin
         
     | 
| 
      
 19 
     | 
    
         
            +
            		require 'readline'
         
     | 
| 
      
 20 
     | 
    
         
            +
            		include Readline
         
     | 
| 
      
 21 
     | 
    
         
            +
            	rescue LoadError => e
         
     | 
| 
      
 22 
     | 
    
         
            +
            		$stderr.puts "Faking readline..."
         
     | 
| 
      
 23 
     | 
    
         
            +
            		def readline( prompt )
         
     | 
| 
      
 24 
     | 
    
         
            +
            			$stderr.print prompt.chomp
         
     | 
| 
      
 25 
     | 
    
         
            +
            			return $stdin.gets.chomp
         
     | 
| 
      
 26 
     | 
    
         
            +
            		end
         
     | 
| 
      
 27 
     | 
    
         
            +
            	end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            	begin
         
     | 
| 
      
 30 
     | 
    
         
            +
            		require 'yaml'
         
     | 
| 
      
 31 
     | 
    
         
            +
            		$yaml = true
         
     | 
| 
      
 32 
     | 
    
         
            +
            	rescue LoadError => e
         
     | 
| 
      
 33 
     | 
    
         
            +
            		$stderr.puts "No YAML; try() will use PrettyPrint instead."
         
     | 
| 
      
 34 
     | 
    
         
            +
            		$yaml = false
         
     | 
| 
      
 35 
     | 
    
         
            +
            	end
         
     | 
| 
      
 36 
     | 
    
         
            +
            }
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            module UtilityFunctions
         
     | 
| 
      
 40 
     | 
    
         
            +
            	include Config
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            	# The list of regexen that eliminate files from the MANIFEST
         
     | 
| 
      
 43 
     | 
    
         
            +
            	ANTIMANIFEST = [
         
     | 
| 
      
 44 
     | 
    
         
            +
            		/makedist\.rb/,
         
     | 
| 
      
 45 
     | 
    
         
            +
            		/\bCVS\b/,
         
     | 
| 
      
 46 
     | 
    
         
            +
            		/~$/,
         
     | 
| 
      
 47 
     | 
    
         
            +
            		/^#/,
         
     | 
| 
      
 48 
     | 
    
         
            +
            		%r{docs/html},
         
     | 
| 
      
 49 
     | 
    
         
            +
            		%r{docs/man},
         
     | 
| 
      
 50 
     | 
    
         
            +
            		/\bTEMPLATE\.\w+\.tpl\b/,
         
     | 
| 
      
 51 
     | 
    
         
            +
            		/\.cvsignore/,
         
     | 
| 
      
 52 
     | 
    
         
            +
            		/\.s?o$/,
         
     | 
| 
      
 53 
     | 
    
         
            +
            	]
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            	# Set some ANSI escape code constants (Shamelessly stolen from Perl's
         
     | 
| 
      
 56 
     | 
    
         
            +
            	# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
         
     | 
| 
      
 57 
     | 
    
         
            +
            	AnsiAttributes = {
         
     | 
| 
      
 58 
     | 
    
         
            +
            		'clear'      => 0,
         
     | 
| 
      
 59 
     | 
    
         
            +
            		'reset'      => 0,
         
     | 
| 
      
 60 
     | 
    
         
            +
            		'bold'       => 1,
         
     | 
| 
      
 61 
     | 
    
         
            +
            		'dark'       => 2,
         
     | 
| 
      
 62 
     | 
    
         
            +
            		'underline'  => 4,
         
     | 
| 
      
 63 
     | 
    
         
            +
            		'underscore' => 4,
         
     | 
| 
      
 64 
     | 
    
         
            +
            		'blink'      => 5,
         
     | 
| 
      
 65 
     | 
    
         
            +
            		'reverse'    => 7,
         
     | 
| 
      
 66 
     | 
    
         
            +
            		'concealed'  => 8,
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            		'black'      => 30,   'on_black'   => 40, 
         
     | 
| 
      
 69 
     | 
    
         
            +
            		'red'        => 31,   'on_red'     => 41, 
         
     | 
| 
      
 70 
     | 
    
         
            +
            		'green'      => 32,   'on_green'   => 42, 
         
     | 
| 
      
 71 
     | 
    
         
            +
            		'yellow'     => 33,   'on_yellow'  => 43, 
         
     | 
| 
      
 72 
     | 
    
         
            +
            		'blue'       => 34,   'on_blue'    => 44, 
         
     | 
| 
      
 73 
     | 
    
         
            +
            		'magenta'    => 35,   'on_magenta' => 45, 
         
     | 
| 
      
 74 
     | 
    
         
            +
            		'cyan'       => 36,   'on_cyan'    => 46, 
         
     | 
| 
      
 75 
     | 
    
         
            +
            		'white'      => 37,   'on_white'   => 47
         
     | 
| 
      
 76 
     | 
    
         
            +
            	}
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            	ErasePreviousLine = "\033[A\033[K"
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            	ManifestHeader = (<<-"EOF").gsub( /^\t+/, '' )
         
     | 
| 
      
 81 
     | 
    
         
            +
            		#
         
     | 
| 
      
 82 
     | 
    
         
            +
            		# Distribution Manifest
         
     | 
| 
      
 83 
     | 
    
         
            +
            		# Created: #{Time::now.to_s}
         
     | 
| 
      
 84 
     | 
    
         
            +
            		# 
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            	EOF
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            	###############
         
     | 
| 
      
 89 
     | 
    
         
            +
            	module_function
         
     | 
| 
      
 90 
     | 
    
         
            +
            	###############
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            	# Create a string that contains the ANSI codes specified and return it
         
     | 
| 
      
 93 
     | 
    
         
            +
            	def ansiCode( *attributes )
         
     | 
| 
      
 94 
     | 
    
         
            +
            		return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
         
     | 
| 
      
 95 
     | 
    
         
            +
            		attr = attributes.collect {|a| AnsiAttributes[a] ? AnsiAttributes[a] : nil}.compact.join(';')
         
     | 
| 
      
 96 
     | 
    
         
            +
            		if attr.empty? 
         
     | 
| 
      
 97 
     | 
    
         
            +
            			return ''
         
     | 
| 
      
 98 
     | 
    
         
            +
            		else
         
     | 
| 
      
 99 
     | 
    
         
            +
            			return "\e[%sm" % attr
         
     | 
| 
      
 100 
     | 
    
         
            +
            		end
         
     | 
| 
      
 101 
     | 
    
         
            +
            	end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            	# Test for the presence of the specified <tt>library</tt>, and output a
         
     | 
| 
      
 104 
     | 
    
         
            +
            	# message describing the test using <tt>nicename</tt>. If <tt>nicename</tt>
         
     | 
| 
      
 105 
     | 
    
         
            +
            	# is <tt>nil</tt>, the value in <tt>library</tt> is used to build a default.
         
     | 
| 
      
 106 
     | 
    
         
            +
            	def testForLibrary( library, nicename=nil, progress=false )
         
     | 
| 
      
 107 
     | 
    
         
            +
            		nicename ||= library
         
     | 
| 
      
 108 
     | 
    
         
            +
            		message( "Testing for the #{nicename} library..." ) if progress
         
     | 
| 
      
 109 
     | 
    
         
            +
            		if $LOAD_PATH.detect {|dir|
         
     | 
| 
      
 110 
     | 
    
         
            +
            				File.exists?(File.join(dir,"#{library}.rb")) ||
         
     | 
| 
      
 111 
     | 
    
         
            +
            				File.exists?(File.join(dir,"#{library}.#{CONFIG['DLEXT']}"))
         
     | 
| 
      
 112 
     | 
    
         
            +
            			}
         
     | 
| 
      
 113 
     | 
    
         
            +
            			message( "found.\n" ) if progress
         
     | 
| 
      
 114 
     | 
    
         
            +
            			return true
         
     | 
| 
      
 115 
     | 
    
         
            +
            		else
         
     | 
| 
      
 116 
     | 
    
         
            +
            			message( "not found.\n" ) if progress
         
     | 
| 
      
 117 
     | 
    
         
            +
            			return false
         
     | 
| 
      
 118 
     | 
    
         
            +
            		end
         
     | 
| 
      
 119 
     | 
    
         
            +
            	end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            	# Test for the presence of the specified <tt>library</tt>, and output a
         
     | 
| 
      
 122 
     | 
    
         
            +
            	# message describing the problem using <tt>nicename</tt>. If
         
     | 
| 
      
 123 
     | 
    
         
            +
            	# <tt>nicename</tt> is <tt>nil</tt>, the value in <tt>library</tt> is used
         
     | 
| 
      
 124 
     | 
    
         
            +
            	# to build a default. If <tt>raaUrl</tt> and/or <tt>downloadUrl</tt> are
         
     | 
| 
      
 125 
     | 
    
         
            +
            	# specified, they are also use to build a message describing how to find the
         
     | 
| 
      
 126 
     | 
    
         
            +
            	# required library. If <tt>fatal</tt> is <tt>true</tt>, a missing library
         
     | 
| 
      
 127 
     | 
    
         
            +
            	# will cause the program to abort.
         
     | 
| 
      
 128 
     | 
    
         
            +
            	def testForRequiredLibrary( library, nicename=nil, raaUrl=nil, downloadUrl=nil, fatal=true )
         
     | 
| 
      
 129 
     | 
    
         
            +
            		nicename ||= library
         
     | 
| 
      
 130 
     | 
    
         
            +
            		unless testForLibrary( library, nicename )
         
     | 
| 
      
 131 
     | 
    
         
            +
            			msgs = [ "You are missing the required #{nicename} library.\n" ]
         
     | 
| 
      
 132 
     | 
    
         
            +
            			msgs << "RAA: #{raaUrl}\n" if raaUrl
         
     | 
| 
      
 133 
     | 
    
         
            +
            			msgs << "Download: #{downloadUrl}\n" if downloadUrl
         
     | 
| 
      
 134 
     | 
    
         
            +
            			if fatal
         
     | 
| 
      
 135 
     | 
    
         
            +
            				abort msgs.join('')
         
     | 
| 
      
 136 
     | 
    
         
            +
            			else
         
     | 
| 
      
 137 
     | 
    
         
            +
            				errorMessage msgs.join('')
         
     | 
| 
      
 138 
     | 
    
         
            +
            			end
         
     | 
| 
      
 139 
     | 
    
         
            +
            		end
         
     | 
| 
      
 140 
     | 
    
         
            +
            		return true
         
     | 
| 
      
 141 
     | 
    
         
            +
            	end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
            	### Output <tt>msg</tt> as a ANSI-colored program/section header (white on
         
     | 
| 
      
 144 
     | 
    
         
            +
            	### blue).
         
     | 
| 
      
 145 
     | 
    
         
            +
            	def header( msg )
         
     | 
| 
      
 146 
     | 
    
         
            +
            		msg.chomp!
         
     | 
| 
      
 147 
     | 
    
         
            +
            		$stderr.puts ansiCode( 'bold', 'white', 'on_blue' ) + msg + ansiCode( 'reset' )
         
     | 
| 
      
 148 
     | 
    
         
            +
            		$stderr.flush
         
     | 
| 
      
 149 
     | 
    
         
            +
            	end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
            	### Output <tt>msg</tt> to STDERR and flush it.
         
     | 
| 
      
 152 
     | 
    
         
            +
            	def message( *msgs )
         
     | 
| 
      
 153 
     | 
    
         
            +
            		$stderr.print( msgs.join("\n") )
         
     | 
| 
      
 154 
     | 
    
         
            +
            		$stderr.flush
         
     | 
| 
      
 155 
     | 
    
         
            +
            	end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
            	### Output +msg+ to STDERR and flush it if $VERBOSE is true.
         
     | 
| 
      
 158 
     | 
    
         
            +
            	def verboseMsg( msg )
         
     | 
| 
      
 159 
     | 
    
         
            +
            		msg.chomp!
         
     | 
| 
      
 160 
     | 
    
         
            +
            		message( msg + "\n" ) if $VERBOSE
         
     | 
| 
      
 161 
     | 
    
         
            +
            	end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
            	### Output the specified <tt>msg</tt> as an ANSI-colored error message
         
     | 
| 
      
 164 
     | 
    
         
            +
            	### (white on red).
         
     | 
| 
      
 165 
     | 
    
         
            +
            	def errorMessage( msg )
         
     | 
| 
      
 166 
     | 
    
         
            +
            		message ansiCode( 'bold', 'white', 'on_red' ) + msg + ansiCode( 'reset' )
         
     | 
| 
      
 167 
     | 
    
         
            +
            	end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            	### Output the specified <tt>msg</tt> as an ANSI-colored debugging message
         
     | 
| 
      
 170 
     | 
    
         
            +
            	### (yellow on blue).
         
     | 
| 
      
 171 
     | 
    
         
            +
            	def debugMsg( msg )
         
     | 
| 
      
 172 
     | 
    
         
            +
            		return unless $DEBUG
         
     | 
| 
      
 173 
     | 
    
         
            +
            		msg.chomp!
         
     | 
| 
      
 174 
     | 
    
         
            +
            		$stderr.puts ansiCode( 'bold', 'yellow', 'on_blue' ) + ">>> #{msg}" + ansiCode( 'reset' )
         
     | 
| 
      
 175 
     | 
    
         
            +
            		$stderr.flush
         
     | 
| 
      
 176 
     | 
    
         
            +
            	end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
            	### Erase the previous line (if supported by your terminal) and output the
         
     | 
| 
      
 179 
     | 
    
         
            +
            	### specified <tt>msg</tt> instead.
         
     | 
| 
      
 180 
     | 
    
         
            +
            	def replaceMessage( msg )
         
     | 
| 
      
 181 
     | 
    
         
            +
            		$stderr.print ErasePreviousLine
         
     | 
| 
      
 182 
     | 
    
         
            +
            		message( msg )
         
     | 
| 
      
 183 
     | 
    
         
            +
            	end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
            	### Output a divider made up of <tt>length</tt> hyphen characters.
         
     | 
| 
      
 186 
     | 
    
         
            +
            	def divider( length=75 )
         
     | 
| 
      
 187 
     | 
    
         
            +
            		$stderr.puts "\r" + ("-" * length )
         
     | 
| 
      
 188 
     | 
    
         
            +
            	end
         
     | 
| 
      
 189 
     | 
    
         
            +
            	alias :writeLine :divider
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
            	### Output the specified <tt>msg</tt> colored in ANSI red and exit with a
         
     | 
| 
      
 193 
     | 
    
         
            +
            	### status of 1.
         
     | 
| 
      
 194 
     | 
    
         
            +
            	def abort( msg )
         
     | 
| 
      
 195 
     | 
    
         
            +
            		print ansiCode( 'bold', 'red' ) + "Aborted: " + msg.chomp + ansiCode( 'reset' ) + "\n\n"
         
     | 
| 
      
 196 
     | 
    
         
            +
            		Kernel.exit!( 1 )
         
     | 
| 
      
 197 
     | 
    
         
            +
            	end
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
            	### Output the specified <tt>promptString</tt> as a prompt (in green) and
         
     | 
| 
      
 201 
     | 
    
         
            +
            	### return the user's input with leading and trailing spaces removed.  If a
         
     | 
| 
      
 202 
     | 
    
         
            +
            	### test is provided, the prompt will repeat until the test returns true.
         
     | 
| 
      
 203 
     | 
    
         
            +
            	### An optional failure message can also be passed in.
         
     | 
| 
      
 204 
     | 
    
         
            +
            	def prompt( promptString, failure_msg="Try again." ) # :yields: response
         
     | 
| 
      
 205 
     | 
    
         
            +
            		promptString.chomp!
         
     | 
| 
      
 206 
     | 
    
         
            +
            		response = nil
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            		begin
         
     | 
| 
      
 209 
     | 
    
         
            +
            			response = readline( ansiCode('bold', 'green') +
         
     | 
| 
      
 210 
     | 
    
         
            +
            				"#{promptString}: " + ansiCode('reset') ).strip
         
     | 
| 
      
 211 
     | 
    
         
            +
            			if block_given? && ! yield( response ) 
         
     | 
| 
      
 212 
     | 
    
         
            +
            				errorMessage( failure_msg + "\n\n" )
         
     | 
| 
      
 213 
     | 
    
         
            +
            				response = nil
         
     | 
| 
      
 214 
     | 
    
         
            +
            			end
         
     | 
| 
      
 215 
     | 
    
         
            +
            		end until response
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
            		return response
         
     | 
| 
      
 218 
     | 
    
         
            +
            	end
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
            	### Prompt the user with the given <tt>promptString</tt> via #prompt,
         
     | 
| 
      
 222 
     | 
    
         
            +
            	### substituting the given <tt>default</tt> if the user doesn't input
         
     | 
| 
      
 223 
     | 
    
         
            +
            	### anything.  If a test is provided, the prompt will repeat until the test
         
     | 
| 
      
 224 
     | 
    
         
            +
            	### returns true.  An optional failure message can also be passed in.
         
     | 
| 
      
 225 
     | 
    
         
            +
            	def promptWithDefault( promptString, default, failure_msg="Try again." )
         
     | 
| 
      
 226 
     | 
    
         
            +
            		response = nil
         
     | 
| 
      
 227 
     | 
    
         
            +
            		
         
     | 
| 
      
 228 
     | 
    
         
            +
            		begin
         
     | 
| 
      
 229 
     | 
    
         
            +
            			response = prompt( "%s [%s]" % [ promptString, default ] )
         
     | 
| 
      
 230 
     | 
    
         
            +
            			response = default if response.empty?
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
            			if block_given? && ! yield( response ) 
         
     | 
| 
      
 233 
     | 
    
         
            +
            				errorMessage( failure_msg + "\n\n" )
         
     | 
| 
      
 234 
     | 
    
         
            +
            				response = nil
         
     | 
| 
      
 235 
     | 
    
         
            +
            			end
         
     | 
| 
      
 236 
     | 
    
         
            +
            		end until response
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
            		return response
         
     | 
| 
      
 239 
     | 
    
         
            +
            	end
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
            	$programs = {}
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
            	### Search for the program specified by the given <tt>progname</tt> in the
         
     | 
| 
      
 245 
     | 
    
         
            +
            	### user's <tt>PATH</tt>, and return the full path to it, or <tt>nil</tt> if
         
     | 
| 
      
 246 
     | 
    
         
            +
            	### no such program is in the path.
         
     | 
| 
      
 247 
     | 
    
         
            +
            	def findProgram( progname )
         
     | 
| 
      
 248 
     | 
    
         
            +
            		unless $programs.key?( progname )
         
     | 
| 
      
 249 
     | 
    
         
            +
            			ENV['PATH'].split(File::PATH_SEPARATOR).each {|d|
         
     | 
| 
      
 250 
     | 
    
         
            +
            				file = File.join( d, progname )
         
     | 
| 
      
 251 
     | 
    
         
            +
            				if File.executable?( file )
         
     | 
| 
      
 252 
     | 
    
         
            +
            					$programs[ progname ] = file 
         
     | 
| 
      
 253 
     | 
    
         
            +
            					break
         
     | 
| 
      
 254 
     | 
    
         
            +
            				end
         
     | 
| 
      
 255 
     | 
    
         
            +
            			}
         
     | 
| 
      
 256 
     | 
    
         
            +
            		end
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
            		return $programs[ progname ]
         
     | 
| 
      
 259 
     | 
    
         
            +
            	end
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
            	### Search for the release version for the project in the specified
         
     | 
| 
      
 263 
     | 
    
         
            +
            	### +directory+.
         
     | 
| 
      
 264 
     | 
    
         
            +
            	def extractVersion( directory='.' )
         
     | 
| 
      
 265 
     | 
    
         
            +
            		release = nil
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
            		Dir::chdir( directory ) do
         
     | 
| 
      
 268 
     | 
    
         
            +
            			if File::directory?( "CVS" )
         
     | 
| 
      
 269 
     | 
    
         
            +
            				verboseMsg( "Project is versioned via CVS. Searching for RELEASE_*_* tags..." )
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
            				if (( cvs = findProgram('cvs') ))
         
     | 
| 
      
 272 
     | 
    
         
            +
            					revs = []
         
     | 
| 
      
 273 
     | 
    
         
            +
            					output = %x{cvs log}
         
     | 
| 
      
 274 
     | 
    
         
            +
            					output.scan( /RELEASE_(\d+(?:_\d\w+)*)/ ) {|match|
         
     | 
| 
      
 275 
     | 
    
         
            +
            						rev = $1.split(/_/).collect {|s| Integer(s) rescue 0}
         
     | 
| 
      
 276 
     | 
    
         
            +
            						verboseMsg( "Found %s...\n" % rev.join('.') )
         
     | 
| 
      
 277 
     | 
    
         
            +
            						revs << rev
         
     | 
| 
      
 278 
     | 
    
         
            +
            					}
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
            					release = revs.sort.last
         
     | 
| 
      
 281 
     | 
    
         
            +
            				end
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
            			elsif File::directory?( '.svn' )
         
     | 
| 
      
 284 
     | 
    
         
            +
            				verboseMsg( "Project is versioned via Subversion" )
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
            				if (( svn = findProgram('svn') ))
         
     | 
| 
      
 287 
     | 
    
         
            +
            					output = %x{svn pg project-version}.chomp
         
     | 
| 
      
 288 
     | 
    
         
            +
            					unless output.empty?
         
     | 
| 
      
 289 
     | 
    
         
            +
            						verboseMsg( "Using 'project-version' property: %p" % output )
         
     | 
| 
      
 290 
     | 
    
         
            +
            						release = output.split( /[._]/ ).collect {|s| Integer(s) rescue 0}
         
     | 
| 
      
 291 
     | 
    
         
            +
            					end
         
     | 
| 
      
 292 
     | 
    
         
            +
            				end
         
     | 
| 
      
 293 
     | 
    
         
            +
            			end
         
     | 
| 
      
 294 
     | 
    
         
            +
            		end
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
            		return release
         
     | 
| 
      
 297 
     | 
    
         
            +
            	end
         
     | 
| 
      
 298 
     | 
    
         
            +
             
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
      
 300 
     | 
    
         
            +
            	### Find the current release version for the project in the specified
         
     | 
| 
      
 301 
     | 
    
         
            +
            	### +directory+ and return its successor.
         
     | 
| 
      
 302 
     | 
    
         
            +
            	def extractNextVersion( directory='.' )
         
     | 
| 
      
 303 
     | 
    
         
            +
            		version = extractVersion( directory ) || [0,0,0]
         
     | 
| 
      
 304 
     | 
    
         
            +
            		version.compact!
         
     | 
| 
      
 305 
     | 
    
         
            +
            		version[-1] += 1
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
            		return version
         
     | 
| 
      
 308 
     | 
    
         
            +
            	end
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
             
     | 
| 
      
 311 
     | 
    
         
            +
            	# Pattern for extracting the name of the project from a Subversion URL
         
     | 
| 
      
 312 
     | 
    
         
            +
            	SVNUrlPath = %r{
         
     | 
| 
      
 313 
     | 
    
         
            +
            		.*/						# Skip all but the last bit
         
     | 
| 
      
 314 
     | 
    
         
            +
            		(\w+)					# $1 = project name
         
     | 
| 
      
 315 
     | 
    
         
            +
            		/						# Followed by / +
         
     | 
| 
      
 316 
     | 
    
         
            +
            		(?:
         
     | 
| 
      
 317 
     | 
    
         
            +
            			trunk |				# 'trunk'
         
     | 
| 
      
 318 
     | 
    
         
            +
            			(
         
     | 
| 
      
 319 
     | 
    
         
            +
            				branches |		# ...or branches/branch-name
         
     | 
| 
      
 320 
     | 
    
         
            +
            				tags			# ...or tags/tag-name
         
     | 
| 
      
 321 
     | 
    
         
            +
            			)/\w	
         
     | 
| 
      
 322 
     | 
    
         
            +
            		)
         
     | 
| 
      
 323 
     | 
    
         
            +
            		$						# bound to the end
         
     | 
| 
      
 324 
     | 
    
         
            +
            	}ix
         
     | 
| 
      
 325 
     | 
    
         
            +
             
     | 
| 
      
 326 
     | 
    
         
            +
            	### Extract the project name (CVS Repository name) for the given +directory+.
         
     | 
| 
      
 327 
     | 
    
         
            +
            	def extractProjectName( directory='.' )
         
     | 
| 
      
 328 
     | 
    
         
            +
            		name = nil
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
            		Dir::chdir( directory ) do
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
            			# CVS-controlled
         
     | 
| 
      
 333 
     | 
    
         
            +
            			if File::directory?( "CVS" )
         
     | 
| 
      
 334 
     | 
    
         
            +
            				verboseMsg( "Project is versioned via CVS. Using repository name." )
         
     | 
| 
      
 335 
     | 
    
         
            +
            				name = File.open( "CVS/Repository", "r").readline.chomp
         
     | 
| 
      
 336 
     | 
    
         
            +
            				name.sub!( %r{.*/}, '' )
         
     | 
| 
      
 337 
     | 
    
         
            +
             
     | 
| 
      
 338 
     | 
    
         
            +
            			# Subversion-controlled
         
     | 
| 
      
 339 
     | 
    
         
            +
            			elsif File::directory?( '.svn' )
         
     | 
| 
      
 340 
     | 
    
         
            +
            				verboseMsg( "Project is versioned via Subversion" )
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
            				# If the machine has the svn tool, try to get the project name
         
     | 
| 
      
 343 
     | 
    
         
            +
            				if (( svn = findProgram( 'svn' ) ))
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
            					# First try an explicit property
         
     | 
| 
      
 346 
     | 
    
         
            +
            					output = shellCommand( svn, 'pg', 'project-name' )
         
     | 
| 
      
 347 
     | 
    
         
            +
            					if !output.empty?
         
     | 
| 
      
 348 
     | 
    
         
            +
            						verboseMsg( "Using 'project-name' property: %p" % output )
         
     | 
| 
      
 349 
     | 
    
         
            +
            						name = output.first.chomp
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
            					# If that doesn't work, try to figure it out from the URL
         
     | 
| 
      
 352 
     | 
    
         
            +
            					elsif (( uri = getSvnUri() ))
         
     | 
| 
      
 353 
     | 
    
         
            +
            						name = uri.path.sub( SVNUrlPath ) { $1 }
         
     | 
| 
      
 354 
     | 
    
         
            +
            					end
         
     | 
| 
      
 355 
     | 
    
         
            +
            				end
         
     | 
| 
      
 356 
     | 
    
         
            +
            			end
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
            			# Fall back to guessing based on the directory name
         
     | 
| 
      
 359 
     | 
    
         
            +
            			unless name
         
     | 
| 
      
 360 
     | 
    
         
            +
            				name = File::basename(File::dirname( File::expand_path(__FILE__) ))
         
     | 
| 
      
 361 
     | 
    
         
            +
            			end
         
     | 
| 
      
 362 
     | 
    
         
            +
            		end
         
     | 
| 
      
 363 
     | 
    
         
            +
             
     | 
| 
      
 364 
     | 
    
         
            +
            		return name
         
     | 
| 
      
 365 
     | 
    
         
            +
            	end
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
             
     | 
| 
      
 368 
     | 
    
         
            +
            	### Extract the Subversion URL from the specified directory and return it as
         
     | 
| 
      
 369 
     | 
    
         
            +
            	### a URI object.
         
     | 
| 
      
 370 
     | 
    
         
            +
            	def getSvnUri( directory='.' )
         
     | 
| 
      
 371 
     | 
    
         
            +
            		uri = nil
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
            		Dir::chdir( directory ) do
         
     | 
| 
      
 374 
     | 
    
         
            +
            			output = %x{svn info}
         
     | 
| 
      
 375 
     | 
    
         
            +
            			debugMsg( "Using info: %p" % output )
         
     | 
| 
      
 376 
     | 
    
         
            +
             
     | 
| 
      
 377 
     | 
    
         
            +
            			if /^URL: \s* ( .* )/xi.match( output )
         
     | 
| 
      
 378 
     | 
    
         
            +
            				uri = URI::parse( $1 )
         
     | 
| 
      
 379 
     | 
    
         
            +
            			end
         
     | 
| 
      
 380 
     | 
    
         
            +
            		end
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
            		return uri
         
     | 
| 
      
 383 
     | 
    
         
            +
            	end
         
     | 
| 
      
 384 
     | 
    
         
            +
             
     | 
| 
      
 385 
     | 
    
         
            +
             
     | 
| 
      
 386 
     | 
    
         
            +
            	### (Re)make a manifest file in the specified +path+.
         
     | 
| 
      
 387 
     | 
    
         
            +
            	def makeManifest( path="MANIFEST" )
         
     | 
| 
      
 388 
     | 
    
         
            +
            		if File::exists?( path )
         
     | 
| 
      
 389 
     | 
    
         
            +
            			reply = promptWithDefault( "Replace current '#{path}'? [yN]", "n" )
         
     | 
| 
      
 390 
     | 
    
         
            +
            			return false unless /^y/i.match( reply )
         
     | 
| 
      
 391 
     | 
    
         
            +
             
     | 
| 
      
 392 
     | 
    
         
            +
            			verboseMsg "Replacing manifest at '#{path}'"
         
     | 
| 
      
 393 
     | 
    
         
            +
            		else
         
     | 
| 
      
 394 
     | 
    
         
            +
            			verboseMsg "Creating new manifest at '#{path}'"
         
     | 
| 
      
 395 
     | 
    
         
            +
            		end
         
     | 
| 
      
 396 
     | 
    
         
            +
             
     | 
| 
      
 397 
     | 
    
         
            +
            		files = []
         
     | 
| 
      
 398 
     | 
    
         
            +
            		verboseMsg( "Finding files...\n" )
         
     | 
| 
      
 399 
     | 
    
         
            +
            		Find::find( Dir::pwd ) do |f|
         
     | 
| 
      
 400 
     | 
    
         
            +
            			Find::prune if File::directory?( f ) &&
         
     | 
| 
      
 401 
     | 
    
         
            +
            				/^\./.match( File::basename(f) )
         
     | 
| 
      
 402 
     | 
    
         
            +
            			verboseMsg( "  found: #{f}\n" )
         
     | 
| 
      
 403 
     | 
    
         
            +
            			files << f.sub( %r{^#{Dir::pwd}/?}, '' )
         
     | 
| 
      
 404 
     | 
    
         
            +
            		end
         
     | 
| 
      
 405 
     | 
    
         
            +
            		files = vetManifest( files )
         
     | 
| 
      
 406 
     | 
    
         
            +
            		
         
     | 
| 
      
 407 
     | 
    
         
            +
            		verboseMsg( "Writing new manifest to #{path}..." )
         
     | 
| 
      
 408 
     | 
    
         
            +
            		File::open( path, File::WRONLY|File::CREAT|File::TRUNC ) do |ofh|
         
     | 
| 
      
 409 
     | 
    
         
            +
            			ofh.puts( ManifestHeader )
         
     | 
| 
      
 410 
     | 
    
         
            +
            			ofh.puts( files )
         
     | 
| 
      
 411 
     | 
    
         
            +
            		end
         
     | 
| 
      
 412 
     | 
    
         
            +
            		verboseMsg( "done." )
         
     | 
| 
      
 413 
     | 
    
         
            +
            	end
         
     | 
| 
      
 414 
     | 
    
         
            +
             
     | 
| 
      
 415 
     | 
    
         
            +
             
     | 
| 
      
 416 
     | 
    
         
            +
            	### Read the specified <tt>manifestFile</tt>, which is a text file
         
     | 
| 
      
 417 
     | 
    
         
            +
            	### describing which files to package up for a distribution. The manifest
         
     | 
| 
      
 418 
     | 
    
         
            +
            	### should consist of one or more lines, each containing one filename or
         
     | 
| 
      
 419 
     | 
    
         
            +
            	### shell glob pattern.
         
     | 
| 
      
 420 
     | 
    
         
            +
            	def readManifest( manifestFile="MANIFEST" )
         
     | 
| 
      
 421 
     | 
    
         
            +
            		verboseMsg "Building manifest..."
         
     | 
| 
      
 422 
     | 
    
         
            +
            		raise "Missing #{manifestFile}, please remake it" unless File.exists? manifestFile
         
     | 
| 
      
 423 
     | 
    
         
            +
             
     | 
| 
      
 424 
     | 
    
         
            +
            		manifest = IO::readlines( manifestFile ).collect {|line|
         
     | 
| 
      
 425 
     | 
    
         
            +
            			line.chomp
         
     | 
| 
      
 426 
     | 
    
         
            +
            		}.select {|line|
         
     | 
| 
      
 427 
     | 
    
         
            +
            			line !~ /^(\s*(#.*)?)?$/
         
     | 
| 
      
 428 
     | 
    
         
            +
            		}
         
     | 
| 
      
 429 
     | 
    
         
            +
             
     | 
| 
      
 430 
     | 
    
         
            +
            		filelist = []
         
     | 
| 
      
 431 
     | 
    
         
            +
            		for pat in manifest
         
     | 
| 
      
 432 
     | 
    
         
            +
            			verboseMsg "Adding files that match '#{pat}' to the file list"
         
     | 
| 
      
 433 
     | 
    
         
            +
            			filelist |= Dir.glob( pat ).find_all {|f| FileTest.file?(f)}
         
     | 
| 
      
 434 
     | 
    
         
            +
            		end
         
     | 
| 
      
 435 
     | 
    
         
            +
             
     | 
| 
      
 436 
     | 
    
         
            +
            		verboseMsg "found #{filelist.length} files.\n"
         
     | 
| 
      
 437 
     | 
    
         
            +
            		return filelist
         
     | 
| 
      
 438 
     | 
    
         
            +
            	end
         
     | 
| 
      
 439 
     | 
    
         
            +
             
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
            	### Given a <tt>filelist</tt> like that returned by #readManifest, remove
         
     | 
| 
      
 442 
     | 
    
         
            +
            	### the entries therein which match the Regexp objects in the given
         
     | 
| 
      
 443 
     | 
    
         
            +
            	### <tt>antimanifest</tt> and return the resultant Array.
         
     | 
| 
      
 444 
     | 
    
         
            +
            	def vetManifest( filelist, antimanifest=ANTIMANIFEST )
         
     | 
| 
      
 445 
     | 
    
         
            +
            		origLength = filelist.length
         
     | 
| 
      
 446 
     | 
    
         
            +
            		verboseMsg "Vetting manifest..."
         
     | 
| 
      
 447 
     | 
    
         
            +
             
     | 
| 
      
 448 
     | 
    
         
            +
            		for regex in antimanifest
         
     | 
| 
      
 449 
     | 
    
         
            +
            			verboseMsg "\n\tPattern /#{regex.source}/ removed: " +
         
     | 
| 
      
 450 
     | 
    
         
            +
            				filelist.find_all {|file| regex.match(file)}.join(', ')
         
     | 
| 
      
 451 
     | 
    
         
            +
            			filelist.delete_if {|file| regex.match(file)}
         
     | 
| 
      
 452 
     | 
    
         
            +
            		end
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
            		verboseMsg "removed #{origLength - filelist.length} files from the list.\n"
         
     | 
| 
      
 455 
     | 
    
         
            +
            		return filelist
         
     | 
| 
      
 456 
     | 
    
         
            +
            	end
         
     | 
| 
      
 457 
     | 
    
         
            +
             
     | 
| 
      
 458 
     | 
    
         
            +
             
     | 
| 
      
 459 
     | 
    
         
            +
            	### Combine a call to #readManifest with one to #vetManifest.
         
     | 
| 
      
 460 
     | 
    
         
            +
            	def getVettedManifest( manifestFile="MANIFEST", antimanifest=ANTIMANIFEST )
         
     | 
| 
      
 461 
     | 
    
         
            +
            		vetManifest( readManifest(manifestFile), antimanifest )
         
     | 
| 
      
 462 
     | 
    
         
            +
            	end
         
     | 
| 
      
 463 
     | 
    
         
            +
             
     | 
| 
      
 464 
     | 
    
         
            +
             
     | 
| 
      
 465 
     | 
    
         
            +
            	### Given a documentation <tt>catalogFile</tt>, extract the title, if
         
     | 
| 
      
 466 
     | 
    
         
            +
            	### available, and return it. Otherwise generate a title from the name of
         
     | 
| 
      
 467 
     | 
    
         
            +
            	### the CVS module.
         
     | 
| 
      
 468 
     | 
    
         
            +
            	def findRdocTitle( catalogFile="docs/CATALOG" )
         
     | 
| 
      
 469 
     | 
    
         
            +
             
     | 
| 
      
 470 
     | 
    
         
            +
            		# Try extracting it from the CATALOG file from a line that looks like:
         
     | 
| 
      
 471 
     | 
    
         
            +
            		# Title: Foo Bar Module
         
     | 
| 
      
 472 
     | 
    
         
            +
            		title = findCatalogKeyword( 'title', catalogFile )
         
     | 
| 
      
 473 
     | 
    
         
            +
             
     | 
| 
      
 474 
     | 
    
         
            +
            		# If that doesn't work for some reason, use the name of the project.
         
     | 
| 
      
 475 
     | 
    
         
            +
            		title = extractProjectName()
         
     | 
| 
      
 476 
     | 
    
         
            +
             
     | 
| 
      
 477 
     | 
    
         
            +
            		return title
         
     | 
| 
      
 478 
     | 
    
         
            +
            	end
         
     | 
| 
      
 479 
     | 
    
         
            +
             
     | 
| 
      
 480 
     | 
    
         
            +
             
     | 
| 
      
 481 
     | 
    
         
            +
            	### Given a documentation <tt>catalogFile</tt>, extract the name of the file
         
     | 
| 
      
 482 
     | 
    
         
            +
            	### to use as the initally displayed page. If extraction fails, the
         
     | 
| 
      
 483 
     | 
    
         
            +
            	### +default+ will be used if it exists. Returns +nil+ if there is no main
         
     | 
| 
      
 484 
     | 
    
         
            +
            	### file to be found.
         
     | 
| 
      
 485 
     | 
    
         
            +
            	def findRdocMain( catalogFile="docs/CATALOG", default="README" )
         
     | 
| 
      
 486 
     | 
    
         
            +
             
     | 
| 
      
 487 
     | 
    
         
            +
            		# Try extracting it from the CATALOG file from a line that looks like:
         
     | 
| 
      
 488 
     | 
    
         
            +
            		# Main: Foo Bar Module
         
     | 
| 
      
 489 
     | 
    
         
            +
            		main = findCatalogKeyword( 'main', catalogFile )
         
     | 
| 
      
 490 
     | 
    
         
            +
             
     | 
| 
      
 491 
     | 
    
         
            +
            		# Try to make some educated guesses if that doesn't work
         
     | 
| 
      
 492 
     | 
    
         
            +
            		if main.nil?
         
     | 
| 
      
 493 
     | 
    
         
            +
            			basedir = File::dirname( __FILE__ )
         
     | 
| 
      
 494 
     | 
    
         
            +
            			basedir = File::dirname( basedir ) if /docs$/ =~ basedir
         
     | 
| 
      
 495 
     | 
    
         
            +
            			
         
     | 
| 
      
 496 
     | 
    
         
            +
            			if File::exists?( File::join(basedir, default) )
         
     | 
| 
      
 497 
     | 
    
         
            +
            				main = default
         
     | 
| 
      
 498 
     | 
    
         
            +
            			end
         
     | 
| 
      
 499 
     | 
    
         
            +
            		end
         
     | 
| 
      
 500 
     | 
    
         
            +
             
     | 
| 
      
 501 
     | 
    
         
            +
            		return main
         
     | 
| 
      
 502 
     | 
    
         
            +
            	end
         
     | 
| 
      
 503 
     | 
    
         
            +
             
     | 
| 
      
 504 
     | 
    
         
            +
             
     | 
| 
      
 505 
     | 
    
         
            +
            	### Given a documentation <tt>catalogFile</tt>, extract an upload URL for
         
     | 
| 
      
 506 
     | 
    
         
            +
            	### RDoc.
         
     | 
| 
      
 507 
     | 
    
         
            +
            	def findRdocUpload( catalogFile="docs/CATALOG" )
         
     | 
| 
      
 508 
     | 
    
         
            +
            		findCatalogKeyword( 'upload', catalogFile )
         
     | 
| 
      
 509 
     | 
    
         
            +
            	end
         
     | 
| 
      
 510 
     | 
    
         
            +
             
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
      
 512 
     | 
    
         
            +
            	### Given a documentation <tt>catalogFile</tt>, extract a CVS web frontend
         
     | 
| 
      
 513 
     | 
    
         
            +
            	### URL for RDoc.
         
     | 
| 
      
 514 
     | 
    
         
            +
            	def findRdocCvsURL( catalogFile="docs/CATALOG" )
         
     | 
| 
      
 515 
     | 
    
         
            +
            		findCatalogKeyword( 'webcvs', catalogFile )
         
     | 
| 
      
 516 
     | 
    
         
            +
            	end
         
     | 
| 
      
 517 
     | 
    
         
            +
             
     | 
| 
      
 518 
     | 
    
         
            +
             
     | 
| 
      
 519 
     | 
    
         
            +
            	### Given a documentation <tt>catalogFile</tt>, try extracting the given
         
     | 
| 
      
 520 
     | 
    
         
            +
            	### +keyword+'s value from it. Keywords are lines that look like:
         
     | 
| 
      
 521 
     | 
    
         
            +
            	###   # <keyword>: <value>
         
     | 
| 
      
 522 
     | 
    
         
            +
            	### Returns +nil+ if the catalog file was unreadable or didn't contain the
         
     | 
| 
      
 523 
     | 
    
         
            +
            	### specified +keyword+.
         
     | 
| 
      
 524 
     | 
    
         
            +
            	def findCatalogKeyword( keyword, catalogFile="docs/CATALOG" )
         
     | 
| 
      
 525 
     | 
    
         
            +
            		val = nil
         
     | 
| 
      
 526 
     | 
    
         
            +
             
     | 
| 
      
 527 
     | 
    
         
            +
            		if File::exists? catalogFile
         
     | 
| 
      
 528 
     | 
    
         
            +
            			verboseMsg "Extracting '#{keyword}' from CATALOG file (%s).\n" % catalogFile
         
     | 
| 
      
 529 
     | 
    
         
            +
            			File::foreach( catalogFile ) {|line|
         
     | 
| 
      
 530 
     | 
    
         
            +
            				debugMsg( "Examining line #{line.inspect}..." )
         
     | 
| 
      
 531 
     | 
    
         
            +
            				val = $1.strip and break if /^#\s*#{keyword}:\s*(.*)$/i =~ line
         
     | 
| 
      
 532 
     | 
    
         
            +
            			}
         
     | 
| 
      
 533 
     | 
    
         
            +
            		end
         
     | 
| 
      
 534 
     | 
    
         
            +
             
     | 
| 
      
 535 
     | 
    
         
            +
            		return val
         
     | 
| 
      
 536 
     | 
    
         
            +
            	end
         
     | 
| 
      
 537 
     | 
    
         
            +
             
     | 
| 
      
 538 
     | 
    
         
            +
             
     | 
| 
      
 539 
     | 
    
         
            +
            	### Given a documentation <tt>catalogFile</tt>, which is in the same format
         
     | 
| 
      
 540 
     | 
    
         
            +
            	### as that described by #readManifest, read and expand it, and then return
         
     | 
| 
      
 541 
     | 
    
         
            +
            	### a list of those files which appear to have RDoc documentation in
         
     | 
| 
      
 542 
     | 
    
         
            +
            	### them. If <tt>catalogFile</tt> is nil or does not exist, the MANIFEST
         
     | 
| 
      
 543 
     | 
    
         
            +
            	### file is used instead.
         
     | 
| 
      
 544 
     | 
    
         
            +
            	def findRdocableFiles( catalogFile="docs/CATALOG" )
         
     | 
| 
      
 545 
     | 
    
         
            +
            		startlist = []
         
     | 
| 
      
 546 
     | 
    
         
            +
            		if File.exists? catalogFile
         
     | 
| 
      
 547 
     | 
    
         
            +
            			verboseMsg "Using CATALOG file (%s).\n" % catalogFile
         
     | 
| 
      
 548 
     | 
    
         
            +
            			startlist = getVettedManifest( catalogFile )
         
     | 
| 
      
 549 
     | 
    
         
            +
            		else
         
     | 
| 
      
 550 
     | 
    
         
            +
            			verboseMsg "Using default MANIFEST\n"
         
     | 
| 
      
 551 
     | 
    
         
            +
            			startlist = getVettedManifest()
         
     | 
| 
      
 552 
     | 
    
         
            +
            		end
         
     | 
| 
      
 553 
     | 
    
         
            +
             
     | 
| 
      
 554 
     | 
    
         
            +
            		verboseMsg "Looking for RDoc comments in:\n"
         
     | 
| 
      
 555 
     | 
    
         
            +
            		startlist.select {|fn|
         
     | 
| 
      
 556 
     | 
    
         
            +
            			verboseMsg "  #{fn}: "
         
     | 
| 
      
 557 
     | 
    
         
            +
            			found = false
         
     | 
| 
      
 558 
     | 
    
         
            +
            			File::open( fn, "r" ) {|fh|
         
     | 
| 
      
 559 
     | 
    
         
            +
            				fh.each {|line|
         
     | 
| 
      
 560 
     | 
    
         
            +
            					if line =~ /^(\s*#)?\s*=/ || line =~ /:\w+:/ || line =~ %r{/\*}
         
     | 
| 
      
 561 
     | 
    
         
            +
            						found = true
         
     | 
| 
      
 562 
     | 
    
         
            +
            						break
         
     | 
| 
      
 563 
     | 
    
         
            +
            					end
         
     | 
| 
      
 564 
     | 
    
         
            +
            				}
         
     | 
| 
      
 565 
     | 
    
         
            +
            			}
         
     | 
| 
      
 566 
     | 
    
         
            +
             
     | 
| 
      
 567 
     | 
    
         
            +
            			verboseMsg( (found ? "yes" : "no") + "\n" )
         
     | 
| 
      
 568 
     | 
    
         
            +
            			found
         
     | 
| 
      
 569 
     | 
    
         
            +
            		}
         
     | 
| 
      
 570 
     | 
    
         
            +
            	end
         
     | 
| 
      
 571 
     | 
    
         
            +
             
     | 
| 
      
 572 
     | 
    
         
            +
            	### Open a file and filter each of its lines through the given block a
         
     | 
| 
      
 573 
     | 
    
         
            +
            	### <tt>line</tt> at a time. The return value of the block is used as the
         
     | 
| 
      
 574 
     | 
    
         
            +
            	### new line, or omitted if the block returns <tt>nil</tt> or
         
     | 
| 
      
 575 
     | 
    
         
            +
            	### <tt>false</tt>.
         
     | 
| 
      
 576 
     | 
    
         
            +
            	def editInPlace( file, testMode=false ) # :yields: line
         
     | 
| 
      
 577 
     | 
    
         
            +
            		raise "No block specified for editing operation" unless block_given?
         
     | 
| 
      
 578 
     | 
    
         
            +
             
     | 
| 
      
 579 
     | 
    
         
            +
            		tempName = "#{file}.#{$$}"
         
     | 
| 
      
 580 
     | 
    
         
            +
            		File::open( tempName, File::RDWR|File::CREAT, 0600 ) {|tempfile|
         
     | 
| 
      
 581 
     | 
    
         
            +
            			File::open( file, File::RDONLY ) {|fh|
         
     | 
| 
      
 582 
     | 
    
         
            +
            				fh.each {|line|
         
     | 
| 
      
 583 
     | 
    
         
            +
            					newline = yield( line ) or next
         
     | 
| 
      
 584 
     | 
    
         
            +
            					tempfile.print( newline )
         
     | 
| 
      
 585 
     | 
    
         
            +
            					$deferr.puts "%p -> %p" % [ line, newline ] if
         
     | 
| 
      
 586 
     | 
    
         
            +
            						line != newline
         
     | 
| 
      
 587 
     | 
    
         
            +
            				}
         
     | 
| 
      
 588 
     | 
    
         
            +
            			}
         
     | 
| 
      
 589 
     | 
    
         
            +
            		}
         
     | 
| 
      
 590 
     | 
    
         
            +
             
     | 
| 
      
 591 
     | 
    
         
            +
            		if testMode
         
     | 
| 
      
 592 
     | 
    
         
            +
            			File::unlink( tempName )
         
     | 
| 
      
 593 
     | 
    
         
            +
            		else
         
     | 
| 
      
 594 
     | 
    
         
            +
            			File::rename( tempName, file )
         
     | 
| 
      
 595 
     | 
    
         
            +
            		end
         
     | 
| 
      
 596 
     | 
    
         
            +
            	end
         
     | 
| 
      
 597 
     | 
    
         
            +
             
     | 
| 
      
 598 
     | 
    
         
            +
            	### Execute the specified shell <tt>command</tt>, read the results, and
         
     | 
| 
      
 599 
     | 
    
         
            +
            	### return them. Like a %x{} that returns an Array instead of a String.
         
     | 
| 
      
 600 
     | 
    
         
            +
            	def shellCommand( *command )
         
     | 
| 
      
 601 
     | 
    
         
            +
            		raise "Empty command" if command.empty?
         
     | 
| 
      
 602 
     | 
    
         
            +
             
     | 
| 
      
 603 
     | 
    
         
            +
            		cmdpipe = IO::popen( command.join(' '), 'r' )
         
     | 
| 
      
 604 
     | 
    
         
            +
            		return cmdpipe.readlines
         
     | 
| 
      
 605 
     | 
    
         
            +
            	end
         
     | 
| 
      
 606 
     | 
    
         
            +
             
     | 
| 
      
 607 
     | 
    
         
            +
            	### Execute a block with $VERBOSE set to +false+, restoring it to its
         
     | 
| 
      
 608 
     | 
    
         
            +
            	### previous value before returning.
         
     | 
| 
      
 609 
     | 
    
         
            +
            	def verboseOff
         
     | 
| 
      
 610 
     | 
    
         
            +
            		raise LocalJumpError, "No block given" unless block_given?
         
     | 
| 
      
 611 
     | 
    
         
            +
             
     | 
| 
      
 612 
     | 
    
         
            +
            		thrcrit = Thread.critical
         
     | 
| 
      
 613 
     | 
    
         
            +
            		oldverbose = $VERBOSE
         
     | 
| 
      
 614 
     | 
    
         
            +
            		begin
         
     | 
| 
      
 615 
     | 
    
         
            +
            			Thread.critical = true
         
     | 
| 
      
 616 
     | 
    
         
            +
            			$VERBOSE = false
         
     | 
| 
      
 617 
     | 
    
         
            +
            			yield
         
     | 
| 
      
 618 
     | 
    
         
            +
            		ensure
         
     | 
| 
      
 619 
     | 
    
         
            +
            			$VERBOSE = oldverbose
         
     | 
| 
      
 620 
     | 
    
         
            +
            			Thread.critical = false
         
     | 
| 
      
 621 
     | 
    
         
            +
            		end
         
     | 
| 
      
 622 
     | 
    
         
            +
            	end
         
     | 
| 
      
 623 
     | 
    
         
            +
             
     | 
| 
      
 624 
     | 
    
         
            +
             
     | 
| 
      
 625 
     | 
    
         
            +
            	### Try the specified code block, printing the given 
         
     | 
| 
      
 626 
     | 
    
         
            +
            	def try( msg, bind=nil )
         
     | 
| 
      
 627 
     | 
    
         
            +
            		result = ''
         
     | 
| 
      
 628 
     | 
    
         
            +
            		if msg =~ /^to\s/
         
     | 
| 
      
 629 
     | 
    
         
            +
            			message = "Trying #{msg}..."
         
     | 
| 
      
 630 
     | 
    
         
            +
            		else
         
     | 
| 
      
 631 
     | 
    
         
            +
            			message = msg
         
     | 
| 
      
 632 
     | 
    
         
            +
            		end
         
     | 
| 
      
 633 
     | 
    
         
            +
            			
         
     | 
| 
      
 634 
     | 
    
         
            +
            		begin
         
     | 
| 
      
 635 
     | 
    
         
            +
            			rval = nil
         
     | 
| 
      
 636 
     | 
    
         
            +
            			if block_given?
         
     | 
| 
      
 637 
     | 
    
         
            +
            				rval = yield
         
     | 
| 
      
 638 
     | 
    
         
            +
            			else
         
     | 
| 
      
 639 
     | 
    
         
            +
            				file, line = caller(1)[0].split(/:/,2)
         
     | 
| 
      
 640 
     | 
    
         
            +
            				rval = eval( msg, bind, file, line.to_i )
         
     | 
| 
      
 641 
     | 
    
         
            +
            			end
         
     | 
| 
      
 642 
     | 
    
         
            +
             
     | 
| 
      
 643 
     | 
    
         
            +
            			if $yaml
         
     | 
| 
      
 644 
     | 
    
         
            +
            				result = rval.to_yaml
         
     | 
| 
      
 645 
     | 
    
         
            +
            			else
         
     | 
| 
      
 646 
     | 
    
         
            +
            				PP.pp( rval, result )
         
     | 
| 
      
 647 
     | 
    
         
            +
            			end
         
     | 
| 
      
 648 
     | 
    
         
            +
             
     | 
| 
      
 649 
     | 
    
         
            +
            		rescue Exception => err
         
     | 
| 
      
 650 
     | 
    
         
            +
            			if err.backtrace
         
     | 
| 
      
 651 
     | 
    
         
            +
            				nicetrace = err.backtrace.delete_if {|frame|
         
     | 
| 
      
 652 
     | 
    
         
            +
            					/in `(try|eval)'/ =~ frame
         
     | 
| 
      
 653 
     | 
    
         
            +
            				}.join("\n\t")
         
     | 
| 
      
 654 
     | 
    
         
            +
            			else
         
     | 
| 
      
 655 
     | 
    
         
            +
            				nicetrace = "Exception had no backtrace"
         
     | 
| 
      
 656 
     | 
    
         
            +
            			end
         
     | 
| 
      
 657 
     | 
    
         
            +
             
     | 
| 
      
 658 
     | 
    
         
            +
            			result = err.message + "\n\t" + nicetrace
         
     | 
| 
      
 659 
     | 
    
         
            +
            		ensure
         
     | 
| 
      
 660 
     | 
    
         
            +
            			divider
         
     | 
| 
      
 661 
     | 
    
         
            +
            			message result + "\n"
         
     | 
| 
      
 662 
     | 
    
         
            +
            			divider
         
     | 
| 
      
 663 
     | 
    
         
            +
            			$deferr.puts
         
     | 
| 
      
 664 
     | 
    
         
            +
            		end
         
     | 
| 
      
 665 
     | 
    
         
            +
            	end
         
     | 
| 
      
 666 
     | 
    
         
            +
            end
         
     | 
| 
      
 667 
     | 
    
         
            +
             
     | 
| 
      
 668 
     | 
    
         
            +
             
     | 
| 
      
 669 
     | 
    
         
            +
            if __FILE__ == $0
         
     | 
| 
      
 670 
     | 
    
         
            +
            	# $DEBUG = true
         
     | 
| 
      
 671 
     | 
    
         
            +
            	include UtilityFunctions
         
     | 
| 
      
 672 
     | 
    
         
            +
             
     | 
| 
      
 673 
     | 
    
         
            +
            	projname = extractProjectName()
         
     | 
| 
      
 674 
     | 
    
         
            +
            	header "Project: #{projname}"
         
     | 
| 
      
 675 
     | 
    
         
            +
             
     | 
| 
      
 676 
     | 
    
         
            +
            	ver = extractVersion() || [0,0,1]
         
     | 
| 
      
 677 
     | 
    
         
            +
            	puts "Version: %s\n" % ver.join('.')
         
     | 
| 
      
 678 
     | 
    
         
            +
             
     | 
| 
      
 679 
     | 
    
         
            +
            	if File::directory?( "docs" )
         
     | 
| 
      
 680 
     | 
    
         
            +
            		puts "Rdoc:",
         
     | 
| 
      
 681 
     | 
    
         
            +
            			"  Title: " + findRdocTitle(),
         
     | 
| 
      
 682 
     | 
    
         
            +
            			"  Main: " + findRdocMain(),
         
     | 
| 
      
 683 
     | 
    
         
            +
            			"  Upload: " + findRdocUpload(),
         
     | 
| 
      
 684 
     | 
    
         
            +
            			"  SCCS URL: " + findRdocCvsURL()
         
     | 
| 
      
 685 
     | 
    
         
            +
            	end
         
     | 
| 
      
 686 
     | 
    
         
            +
             
     | 
| 
      
 687 
     | 
    
         
            +
            	puts "Manifest:",
         
     | 
| 
      
 688 
     | 
    
         
            +
            		"  " + getVettedManifest().join("\n  ")
         
     | 
| 
      
 689 
     | 
    
         
            +
            end
         
     |