OSDN Git Service

Password mask
authorAkihiro Ono <a-ono@users.sourceforge.jp>
Sat, 5 Feb 2011 17:56:44 +0000 (02:56 +0900)
committerAkihiro Ono <a-ono@users.sourceforge.jp>
Sat, 5 Feb 2011 17:56:44 +0000 (02:56 +0900)
33 files changed:
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/CHANGELOG [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/INSTALL [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/LICENSE [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/README [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/Rakefile [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/TODO [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/ansi_colors.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/asking_for_arrays.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/basic_usage.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/color_scheme.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/limit.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/menus.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/overwrite.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/page_and_wrap.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/password.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/trapping_eof.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/using_readline.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/color_scheme.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/compatibility.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/import.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/menu.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/question.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/system_extensions.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/setup.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_color_scheme.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_highline.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_import.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_menu.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/ts_all.rb [new file with mode: 0644]
ruby/lib/ruby/gems/1.8/specifications/highline-1.6.1.gemspec [new file with mode: 0644]
script/install
script/service.bat

diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/CHANGELOG b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/CHANGELOG
new file mode 100644 (file)
index 0000000..4e11477
--- /dev/null
@@ -0,0 +1,244 @@
+= Change Log
+
+Below is a complete listing of changes for each revision of HighLine.
+
+== 1.6.1
+
+* Fixed raw_no_echo_mode so that it uses stty -icanon rather than cbreak
+  as cbreak does not appear to be the posixly correct argument. It fails
+  on Solaris if cbreak is used.
+* Fixed an issue that kept Menu from showing the correct choices for 
+  disambiguation.
+* Removed a circular require that kept Ruby 1.9.2 from loading HighLine.
+* Fixed a bug that caused infinite looping when wrapping text without spaces.
+* Fixed it so that :auto paging accounts for the two lines it adds.
+* On JRuby, improved error message about ffi-ncurses.  Before 1.5.3, 
+  HighLine was silently swallowing error messages when ffi-ncurses gem
+  was installed without ncurses present on the system.
+* Reverted Aaron Simmons's patch to allow redirecting STDIN on Windows.  This
+  is the only way we could find to restore HighLine's character reading to
+  working order.
+
+== 1.5.2
+
+* Added support for using the ffi-ncurses gem which is supported in JRuby.
+* Added gem build instructions.
+
+== 1.5.1
+
+* Fixed the long standing echo true bug.
+  (reported by Lauri Tuominen)
+* Improved Windows API calls to support the redirection of STDIN.
+  (patch by Aaron Simmons)
+* Updated gem specification to avoid a deprecated call.
+* Made a minor documentation clarification about character mode support.
+* Worked around some API changes in Ruby's standard library in Ruby 1.9.
+  (patch by Jake Benilov)
+
+== 1.5.0
+
+* Fixed a bug that would prevent Readline from showing all completions.
+  (reported by Yaohan Chen)
+* Added the ability to pass a block to HighLine#agree().
+  (patch by Yaohan Chen)
+
+== 1.4.0
+
+* Made the code grabbing terminal size a little more cross-platform by
+  adding support for Solaris.  (patch by Ronald Braswell and Coey Minear)
+
+== 1.2.9
+
+* Additional work on the backspacing issue. (patch by Jeremy Hinegardner)
+* Fixed Readline prompt bug. (patch by Jeremy Hinegardner)
+
+== 1.2.8
+
+* Fixed backspacing past the prompt and interrupting a prompt bugs.
+  (patch by Jeremy Hinegardner)
+
+== 1.2.7
+
+* Fixed the stty indent bug.
+* Fixed the echo backspace bug.
+* Added HighLine::track_eof=() setting to work are threaded eof?() calls.
+
+== 1.2.6
+
+Patch by Jeremy Hinegardner:
+
+* Added ColorScheme support.
+* Added HighLine::Question.overwrite mode.
+* Various documentation fixes.
+
+== 1.2.5
+
+* Really fixed the bug I tried to fix in 1.2.4.
+
+== 1.2.4
+
+* Fixed a crash causing bug when using menus, reported by Patrick Hof.
+
+== 1.2.3
+
+* Treat Cygwin like a Posix OS, instead of a native Windows environment.
+
+== 1.2.2
+
+* Minor documentation corrections.
+* Applied Thomas Werschleiln's patch to fix termio buffering on Solaris.
+* Applied Justin Bailey's patch to allow canceling paged output.
+* Fixed a documentation bug in the description of character case settings.
+* Added a notice about termios in HighLine::Question#echo.
+* Finally working around the infamous "fast typing" bug
+
+== 1.2.1
+
+* Applied Justin Bailey's fix for the page_print() infinite loop bug.
+* Made a SystemExtensions module to expose OS level functionality other
+  libraries may want to access.
+* Publicly exposed the get_character() method, per user requests.
+* Added terminal_size(), output_cols(), and output_rows() methods.
+* Added :auto setting for warp_at=() and page_at=().
+
+== 1.2.0
+
+* Improved RubyForge and gem spec project descriptions.
+* Added basic examples to README.
+* Added a VERSION constant.
+* Added support for hidden menu commands.
+* Added Object.or_ask() when using highline/import.
+
+== 1.0.4
+
+* Moved the HighLine project to Subversion.
+* HighLine's color escapes can now be disabled.
+* Fixed EOF bug introduced in the last release.
+* Updated HighLine web page.
+* Moved to a forked development/stable version numbering.
+
+== 1.0.2
+
+* Removed old and broken help tests.
+* Fixed test case typo found by David A. Black.
+* Added ERb escapes processing to lists, for coloring list items.  Color escapes
+  do not add to list element size.
+* HighLine now throws EOFError when input is exhausted.
+
+== 1.0.1
+
+* Minor bug fix:  Moved help initialization to before response building, so help
+  would show up in the default responses.
+
+== 1.0.0
+
+* Fixed documentation typo pointed out by Gavin Kistner.
+* Added <tt>gather = ...</tt> option to question for fetching entire Arrays or
+  Hashes filled with answers.  You can set +gather+ to a count of answers to
+  collect, a String or Regexp matching the end of input, or a Hash where each
+  key can be used in a new question.
+* Added File support to HighLine.ask().  You can specify a _directory_ and a
+  _glob_ pattern that combine into a list of file choices the user can select
+  from.  You can choose to receive the user's answer as an open filehandle or as
+  a Pathname object.
+* Added Readline support for history and editing.
+* Added tab completion for menu  and file selection selection (requires
+  Readline).
+* Added an optional character limit for input.
+* Added a complete help system to HighLine's shell menu creation tools.
+
+== 0.6.1
+
+* Removed termios dependancy in gem, to fix Windows' install.
+
+== 0.6.0
+
+* Implemented HighLine.choose() for menu handling.
+  * Provided shortcut <tt>choose(item1, item2, ...)</tt> for simple menus.
+  * Allowed Ruby code to be attached to each menu item, to create a complete
+    menu solution.
+  * Provided for total customization of the menu layout.
+  * Allowed for menu selection by index, name or both.
+  * Added a _shell_ mode to allow menu selection with additional details
+    following the name.
+* Added a list() utility method that can be invoked just like color().  It can
+  layout Arrays for you in any output in the modes <tt>:columns_across</tt>,
+  <tt>:columns_down</tt>, <tt>:inline</tt> and <tt>:rows</tt>
+* Added support for <tt>echo = "*"</tt> style settings.  User code can now
+  choose the echo character this way.
+* Modified HighLine to user the "termios" library for character input, if
+  available.  Will return to old behavior (using "stty"), if "termios" cannot be
+  loaded.
+* Improved "stty" state restoring code.
+* Fixed "stty" code to handle interrupt signals.
+* Improved the default auto-complete error message and exposed this message
+  through the +responses+ interface as <tt>:no_completion</tt>.
+
+== 0.5.0
+
+* Implemented <tt>echo = false</tt> for HighLine::Question objects, primarily to
+  make fetching passwords trivial.
+* Fixed an auto-complete bug that could cause a crash when the user gave an
+  answer that didn't complete to any valid choice.
+* Implemented +case+ for HighLine::Question objects to provide character case 
+  conversions on given answers.  Can be set to <tt>:up</tt>, <tt>:down</tt>, or
+  <tt>:capitalize</tt>.
+* Exposed <tt>@answer</tt> to the response system, to allow response that are
+  aware of incorrect input.
+* Implemented +confirm+ for HighLine::Question objects to allow for verification
+  for sensitive user choices.  If set to +true+, user will have to answer an
+  "Are you sure?  " question.  Can also be set to the question to confirm with
+  the user.
+
+== 0.4.0
+
+* Added <tt>@wrap_at</tt> and <tt>@page_at</tt> settings and accessors to
+  HighLine, to control text flow.
+* Implemented line wrapping with adjustable limit.
+* Implemented paged printing with adjustable limit.
+
+== 0.3.0
+
+* Added support for installing with setup.rb.
+* All output is now treated as an ERb sequence, allowing Ruby code to be
+  embedded in output strings.
+* Added support for ANSI color sequences in say().  (And everything else
+  by extension.)
+* Added whitespace handling for answers.  Can be set to <tt>:strip</tt>,
+  <tt>:chomp</tt>, <tt>:collapse</tt>, <tt>:strip_and_collapse</tt>,
+  <tt>:chomp_and_collapse</tt>, <tt>:remove</tt>, or <tt>:none</tt>.
+* Exposed question details to ERb completion through @question, to allow for
+  intelligent responses.
+* Simplified HighLine internals using @question.
+* Added support for fetching single character input either with getc() or
+  HighLine's own cross-platform terminal input routine.
+* Improved type conversion to handle user defined classes.
+
+== 0.2.0
+
+* Added Unit Tests to cover an already fixed output bug in the future.
+* Added Rakefile and setup test action (default).
+* Renamed HighLine::Answer to HighLine::Question to better illustrate its role.
+* Renamed fetch_line() to get_response() to better define its goal.
+* Simplified explain_error in terms of the Question object.
+* Renamed accept?() to in_range?() to better define purpose.
+* Reworked valid?() into valid_answer?() to better fit Question object.
+* Reworked <tt>@member</tt> into <tt>@in</tt>, to make it easier to remember and
+  switched implementation to include?().
+* Added range checks for @above and @below.
+* Fixed the bug causing ask() to swallow NoMethodErrors.
+* Rolled ask_on_error() into responses.
+* Redirected imports to Kernel from Object.
+* Added support for <tt>validate = lambda { ... }</tt>.
+* Added default answer support.
+* Fixed bug that caused ask() to die with an empty question.
+* Added complete documentation.
+* Improve the implemetation of agree() to be the intended "yes" or "no" only
+  question.
+* Added Rake tasks for documentation and packaging.
+* Moved project to RubyForge.
+
+== 0.1.0
+
+* Initial release as the solution to
+  {Ruby Quiz #29}[http://www.rubyquiz.com/quiz29.html].
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/INSTALL b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/INSTALL
new file mode 100644 (file)
index 0000000..5da0281
--- /dev/null
@@ -0,0 +1,55 @@
+= Installing HighLine
+
+RubyGems is the preferred easy install method for HighLine.  However, you can
+install HighLine manually as described below.
+
+== Installing the Gem
+
+HighLine is intended to be installed via the
+RubyGems[http://rubyforge.org/projects/rubygems/] system.  To get the latest
+version, simply enter the following into your command prompt:
+
+       $ sudo gem install highline
+
+You must have RubyGems[http://rubyforge.org/projects/rubygems/] installed for
+the above to work.
+
+If you want to build the gem locally, make sure you have
+Rake[http://rubyforge.org/projects/rake/] installed then run the following
+command:
+
+  $ rake package
+
+== Installing Manually
+
+Download the latest version of HighLine from the
+{RubyForge project page}[http://rubyforge.org/frs/?group_id=683].  Navigate to
+the root project directory and enter:
+
+       $ sudo ruby setup.rb
+
+== Installing HighLine on JRuby
+
+If you are using HighLine on JRuby, many features will not work properly
+without a working ncurses installation.  First, ensure that you have
+ncurses installed and then install the ffi-ncurses gem.
+
+If ffi-ncurses fails to find your ncurses library, you may need to set the
+RUBY_FFI_NCURSES envirionment variable, i.e:  
+
+  RUBY_FFI_NCURSES_LIB=ncursesw ruby examples/hello.rb
+
+For details, see the ffi-ncurses documentation at:
+http://github.com/seanohalpin/ffi-ncurses
+
+== Using termios
+
+While not a requirement, HighLine will take advantage of the termios library if
+installed (on Unix).  This slightly improves HighLine's character reading
+capabilities and thus is recommended for all Unix users.
+
+If using the HighLine gem, you should be able to add termios as easily as:
+
+       $ sudo gem install termios
+
+For manual installs, consult the termios documentation.
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/LICENSE b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/LICENSE
new file mode 100644 (file)
index 0000000..ff6f232
--- /dev/null
@@ -0,0 +1,7 @@
+= License Terms
+
+Distributed under the user's choice of the {GPL Version 2}[http://www.gnu.org/licenses/old-licenses/gpl-2.0.html] (see COPYING for details) or the
+{Ruby software license}[http://www.ruby-lang.org/en/LICENSE.txt] by
+James Edward Gray II and Greg Brown.
+
+Please email James[mailto:james@grayproductions.net] with any questions.
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/README b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/README
new file mode 100644 (file)
index 0000000..f28478b
--- /dev/null
@@ -0,0 +1,63 @@
+= Read Me
+
+by James Edward Gray II
+
+== Description
+
+Welcome to HighLine.
+
+HighLine was designed to ease the tedious tasks of doing console input and
+output with low-level methods like gets() and puts().  HighLine provides a
+robust system for requesting data from a user, without needing to code all the
+error checking and validation rules and without needing to convert the typed
+Strings into what your program really needs.  Just tell HighLine what you're
+after, and let it do all the work.
+
+== Documentation
+
+See HighLine and HighLine::Question for documentation.
+
+== Examples
+
+Basic usage:
+
+  ask("Company?  ") { |q| q.default = "none" }
+
+Validation:
+
+  ask("Age?  ", Integer) { |q| q.in = 0..105 }
+  ask("Name?  (last, first)  ") { |q| q.validate = /\A\w+, ?\w+\Z/ }
+
+Type conversion for answers:
+
+  ask("Birthday?  ", Date)
+  ask("Interests?  (comma sep list)  ", lambda { |str| str.split(/,\s*/) })
+
+Reading passwords:
+
+  ask("Enter your password:  ") { |q| q.echo = false }
+  ask("Enter your password:  ") { |q| q.echo = "x" }
+
+ERb based output (with HighLine's ANSI color tools):
+
+  say("This should be <%= color('bold', BOLD) %>!")
+
+Menus:
+
+  choose do |menu|
+    menu.prompt = "Please choose your favorite programming language?  "
+  
+    menu.choice(:ruby) { say("Good choice!") }
+    menu.choices(:python, :perl) { say("Not from around here, are you?") }
+  end
+  
+For more examples see the examples/ directory of this project.
+
+== Installing
+
+See the INSTALL file for instructions.
+
+== Questions and/or Comments
+
+Feel free to email {James Edward Gray II}[mailto:james@grayproductions.net] or
+{Gregory Brown}[mailto:gregory.t.brown@gmail.com] with any questions.
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/Rakefile b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/Rakefile
new file mode 100644 (file)
index 0000000..5c74b16
--- /dev/null
@@ -0,0 +1,82 @@
+require "rake/rdoctask"
+require "rake/testtask"
+require "rake/gempackagetask"
+
+require "rubygems"
+
+dir     = File.dirname(__FILE__)
+lib     = File.join(dir, "lib", "highline.rb")
+version = File.read(lib)[/^\s*VERSION\s*=\s*(['"])(\d\.\d\.\d)\1/, 2]
+
+task :default => [:test]
+
+Rake::TestTask.new do |test|
+  test.libs       << "test"
+  test.test_files =  [ "test/ts_all.rb" ]
+  test.verbose    =  true
+end
+
+Rake::RDocTask.new do |rdoc|
+  rdoc.rdoc_files.include( "README", "INSTALL",
+                           "TODO", "CHANGELOG",
+                           "AUTHORS", "COPYING",
+                           "LICENSE", "lib/" )
+  rdoc.main     = "README"
+  rdoc.rdoc_dir = "doc/html"
+  rdoc.title    = "HighLine Documentation"
+end
+
+desc "Upload current documentation to Rubyforge"
+task :upload_docs => [:rdoc] do
+  sh "scp -r doc/html/* " +
+     "bbazzarrakk@rubyforge.org:/var/www/gforge-projects/highline/doc/"
+  sh "scp -r site/* " +
+     "bbazzarrakk@rubyforge.org:/var/www/gforge-projects/highline/"
+end
+
+spec = Gem::Specification.new do |spec|
+  spec.name     = "highline"
+  spec.version  = version
+  spec.platform = Gem::Platform::RUBY
+  spec.summary  = "HighLine is a high-level command-line IO library."
+  spec.files    = Dir.glob("{examples,lib,test}/**/*.rb").
+                      delete_if { |item| item.include?("CVS") } +
+                      ["Rakefile", "setup.rb"]
+
+  spec.test_files       =  "test/ts_all.rb"
+  spec.has_rdoc         =  true
+  spec.extra_rdoc_files =  %w{README INSTALL TODO CHANGELOG LICENSE}
+  spec.rdoc_options     << '--title' << 'HighLine Documentation' <<
+                           '--main'  << 'README'
+
+  spec.require_path      = 'lib'
+
+  spec.author            = "James Edward Gray II"
+  spec.email             = "james@grayproductions.net"
+  spec.rubyforge_project = "highline"
+  spec.homepage          = "http://highline.rubyforge.org"
+  spec.description       = <<END_DESC
+A high-level IO library that provides validation, type conversion, and more for
+command-line interfaces. HighLine also includes a complete menu system that can
+crank out anything from simple list selection to complete shells with just
+minutes of work.
+END_DESC
+end
+
+Rake::GemPackageTask.new(spec) do |pkg|
+  pkg.need_zip = true
+  pkg.need_tar = true
+end
+
+desc "Show library's code statistics"
+task :stats do
+  require 'code_statistics'
+  CodeStatistics.new( ["HighLine", "lib"], 
+                      ["Functionals", "examples"], 
+                      ["Units", "test"] ).to_s
+end
+
+desc "Add new files to Subversion"
+task :add_to_svn do
+  sh %Q{svn status | ruby -nae 'system "svn add \#{$F[1]}" if $F[0] == "?"' }
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/TODO b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/TODO
new file mode 100644 (file)
index 0000000..89c5306
--- /dev/null
@@ -0,0 +1,6 @@
+= To Do List
+
+The following is a list of planned expansions for HighLine, in no particular
+order.
+
+* Rent this space.
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/ansi_colors.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/ansi_colors.rb
new file mode 100644 (file)
index 0000000..79735f4
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/local/bin/ruby -w
+
+# ansi_colors.rb
+#
+#  Created by James Edward Gray II on 2005-05-03.
+#  Copyright 2005 Gray Productions. All rights reserved.
+
+require "rubygems"
+require "highline/import"
+
+# Supported color sequences.
+colors = %w{black red green yellow blue magenta cyan white}
+
+# Using color() with symbols.
+colors.each_with_index do |c, i|
+  say("This should be <%= color('#{c}', :#{c}) %>!")
+  if i == 0
+    say( "This should be " +
+         "<%= color('white on #{c}', :white, :on_#{c}) %>!")
+  else
+    say( "This should be " +
+         "<%= color( '#{colors[i - 1]} on #{c}',
+                     :#{colors[i - 1]}, :on_#{c} ) %>!")
+  end
+end
+
+# Using color with constants.
+say("This should be <%= color('bold', BOLD) %>!")
+say("This should be <%= color('underlined', UNDERLINE) %>!")
+
+# Using constants only.
+say("This might even <%= BLINK %>blink<%= CLEAR %>!")
+
+# It even works with list wrapping.
+erb_digits = %w{Zero One Two Three Four}      +
+             ["<%= color('Five', :blue) %%>"] +
+             %w{Six Seven Eight Nine}
+say("<%= list(#{erb_digits.inspect}, :columns_down, 3) %>")
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/asking_for_arrays.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/asking_for_arrays.rb
new file mode 100644 (file)
index 0000000..6c62a0e
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/local/bin/ruby -w
+
+# asking_for_arrays.rb
+#
+#  Created by James Edward Gray II on 2005-07-05.
+#  Copyright 2005 Gray Productions. All rights reserved.
+
+require "rubygems"
+require "highline/import"
+require "pp"
+
+grades = ask( "Enter test scores (or a blank line to quit):",
+              lambda { |ans| ans =~ /^-?\d+$/ ? Integer(ans) : ans} ) do |q|
+  q.gather = ""
+end
+
+say("Grades:")
+pp grades
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/basic_usage.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/basic_usage.rb
new file mode 100644 (file)
index 0000000..60ecdc1
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/local/bin/ruby -w
+
+# basic_usage.rb
+#
+#  Created by James Edward Gray II on 2005-04-28.
+#  Copyright 2005 Gray Productions. All rights reserved.
+
+require "rubygems"
+require "highline/import"
+require "yaml"
+
+contacts = [ ]
+
+class NameClass
+  def self.parse( string )
+    if string =~ /^\s*(\w+),\s*(\w+)\s*$/
+      self.new($2, $1)
+    else
+      raise ArgumentError, "Invalid name format."
+    end
+  end
+
+  def initialize(first, last)
+    @first, @last = first, last
+  end
+  
+  attr_reader :first, :last
+end
+
+begin
+  entry = Hash.new
+  
+  # basic output
+  say("Enter a contact:")
+
+  # basic input
+  entry[:name]        = ask("Name?  (last, first)  ", NameClass) do |q|
+    q.validate = /\A\w+, ?\w+\Z/
+  end
+  entry[:company]     = ask("Company?  ") { |q| q.default = "none" }
+  entry[:address]     = ask("Address?  ")
+  entry[:city]        = ask("City?  ")
+  entry[:state]       = ask("State?  ") do |q|
+    q.case     = :up
+    q.validate = /\A[A-Z]{2}\Z/
+  end
+  entry[:zip]         = ask("Zip?  ") do |q|
+    q.validate = /\A\d{5}(?:-?\d{4})?\Z/
+  end
+  entry[:phone]       = ask( "Phone?  ",
+                             lambda { |p| p.delete("^0-9").
+                                            sub(/\A(\d{3})/, '(\1) ').
+                                            sub(/(\d{4})\Z/, '-\1') } ) do |q|
+    q.validate              = lambda { |p| p.delete("^0-9").length == 10 }
+    q.responses[:not_valid] = "Enter a phone numer with area code."
+  end
+  entry[:age]         = ask("Age?  ", Integer) { |q| q.in = 0..105 }
+  entry[:birthday]    = ask("Birthday?  ", Date)
+  entry[:interests]   = ask( "Interests?  (comma separated list)  ",
+                             lambda { |str| str.split(/,\s*/) } )
+  entry[:description] = ask("Enter a description for this contact.") do |q|
+    q.whitespace = :strip_and_collapse
+  end
+
+  contacts << entry
+# shortcut for yes and no questions
+end while agree("Enter another contact?  ", true)
+
+if agree("Save these contacts?  ", true)
+  file_name = ask("Enter a file name:  ") do |q|
+    q.validate = /\A\w+\Z/
+    q.confirm  = true
+  end
+  File.open("#{file_name}.yaml", "w") { |file| YAML.dump(contacts, file) }
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/color_scheme.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/color_scheme.rb
new file mode 100644 (file)
index 0000000..6d1e0a7
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/env ruby -w
+
+# color_scheme.rb
+# 
+#  Created by Jeremy Hinegardner on 2007-01-24
+#  Copyright 2007 Jeremy Hinegardner.  All rights reserved 
+
+require 'rubygems'
+require 'highline/import'
+
+# Create a color scheme, naming color patterns with symbol names.
+ft = HighLine::ColorScheme.new do |cs|
+        cs[:headline]        = [ :bold, :yellow, :on_black ]
+        cs[:horizontal_line] = [ :bold, :white, :on_blue]
+        cs[:even_row]        = [ :green ]
+        cs[:odd_row]         = [ :magenta ]
+     end
+
+# Assign that color scheme to HighLine...
+HighLine.color_scheme = ft
+
+# ...and use it.
+say("<%= color('Headline', :headline) %>")
+say("<%= color('-'*20, :horizontal_line) %>")
+
+# Setup a toggle for rows.
+i = true
+("A".."D").each do |row|
+    row_color = i ? :even_row : :odd_row
+    say("<%= color('#{row}', '#{row_color}') %>")
+    i = !i
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/limit.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/limit.rb
new file mode 100644 (file)
index 0000000..a3813e5
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby -w
+
+# limit.rb
+# 
+#  Created by James Edward Gray II on 2008-11-12.
+#  Copyright 2008 Gray Productions. All rights reserved.
+
+require "rubygems"
+require "highline/import"
+
+text = ask("Enter text (max 10 chars): ") { |q| q.limit = 10 }
+puts "You entered: #{text}!"
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/menus.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/menus.rb
new file mode 100644 (file)
index 0000000..e31c11d
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/local/bin/ruby -w
+
+require "rubygems"
+require "highline/import"
+
+# The old way, using ask() and say()...
+choices = %w{ruby python perl}
+say("This is the old way using ask() and say()...")
+say("Please choose your favorite programming language:")
+say(choices.map { |c| "  #{c}\n" }.join)
+
+case ask("?  ", choices)
+when "ruby"
+  say("Good choice!")
+else
+  say("Not from around here, are you?")
+end
+
+# The new and improved choose()...
+say("\nThis is the new mode (default)...")
+choose do |menu|
+  menu.prompt = "Please choose your favorite programming language?  "
+
+  menu.choice :ruby do say("Good choice!") end
+  menu.choices(:python, :perl) do say("Not from around here, are you?") end
+end
+
+say("\nThis is letter indexing...")
+choose do |menu|
+  menu.index        = :letter
+  menu.index_suffix = ") "
+
+  menu.prompt = "Please choose your favorite programming language?  "
+
+  menu.choice :ruby do say("Good choice!") end
+  menu.choices(:python, :perl) do say("Not from around here, are you?") end
+end
+
+say("\nThis is with a different layout...")
+choose do |menu|
+  menu.layout = :one_line
+
+  menu.header = "Languages"
+  menu.prompt = "Favorite?  "
+
+  menu.choice :ruby do say("Good choice!") end
+  menu.choices(:python, :perl) do say("Not from around here, are you?") end
+end
+
+say("\nYou can even build shells...")
+loop do
+  choose do |menu|
+    menu.layout = :menu_only
+  
+    menu.shell  = true
+  
+    menu.choice(:load, "Load a file.") do |command, details|
+      say("Loading file with options:  #{details}...")
+    end
+    menu.choice(:save, "Save a file.") do |command, details|
+      say("Saving file with options:  #{details}...")
+    end
+    menu.choice(:quit, "Exit program.") { exit }
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/overwrite.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/overwrite.rb
new file mode 100644 (file)
index 0000000..1ca2db5
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/local/bin/ruby -w
+
+# overwrite.rb
+# 
+#  Created by Jeremy Hinegardner on 2007-01-24
+#  Copyright 2007 Jeremy Hinegardner.  All rights reserved 
+
+require 'rubygems'
+require 'highline/import'
+
+prompt = "here is your password:"
+ask(
+  "#{prompt} <%= color('mypassword', RED, BOLD) %> (Press Any Key to blank) "
+) do |q|
+    q.overwrite = true
+    q.echo      = false  # overwrite works best when echo is false.
+    q.character = true   # if this is set to :getc then overwrite does not work
+end
+say("<%= color('Look! blanked out!', GREEN) %>")
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/page_and_wrap.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/page_and_wrap.rb
new file mode 100644 (file)
index 0000000..3209a4a
--- /dev/null
@@ -0,0 +1,322 @@
+#!/usr/local/bin/ruby -w
+
+# page_and_wrap.rb
+#
+#  Created by James Edward Gray II on 2005-05-07.
+#  Copyright 2005 Gray Productions. All rights reserved.
+
+require "rubygems"
+require "highline/import"
+
+$terminal.wrap_at = 80
+$terminal.page_at = 22
+
+say(<<END)
+THE UNITED STATES CONSTITUTION
+
+We the People of the United States, in Order to form a more perfect Union, establish Justice, insure domestic Tranquility, provide for the common defence, promote the general Welfare, and secure the Blessings of Liberty to ourselves and our Posterity, do ordain and establish this Constitution for the United States of America.
+
+Article. I.
+
+Section 1.
+
+All legislative Powers herein granted shall be vested in a Congress of the United States, which shall consist of a Senate and House of Representatives.
+
+Section. 2.
+
+Clause 1: The House of Representatives shall be composed of Members chosen every second Year by the People of the several States, and the Electors in each State shall have the Qualifications requisite for Electors of the most numerous Branch of the State Legislature.
+
+Clause 2: No Person shall be a Representative who shall not have attained to the Age of twenty five Years, and been seven Years a Citizen of the United States, and who shall not, when elected, be an Inhabitant of that State in which he shall be chosen.
+
+Clause 3: Representatives and direct Taxes shall be apportioned among the several States which may be included within this Union, according to their respective Numbers, which shall be determined by adding to the whole Number of free Persons, including those bound to Service for a Term of Years, and excluding Indians not taxed, three fifths of all other Persons. (See Note 2) The actual Enumeration shall be made within three Years after the first Meeting of the Congress of the United States, and within every subsequent Term of ten Years, in such Manner as they shall by Law direct. The Number of Representatives shall not exceed one for every thirty Thousand, but each State shall have at Least one Representative; and until such enumeration shall be made, the State of New Hampshire shall be entitled to chuse three, Massachusetts eight, Rhode-Island and Providence Plantations one, Connecticut five, New-York six, New Jersey four, Pennsylvania eight, Delaware one, Maryland six, Virginia ten, North Carolina five, South Carolina five, and Georgia three.
+
+Clause 4: When vacancies happen in the Representation from any State, the Executive Authority thereof shall issue Writs of Election to fill such Vacancies.
+
+Clause 5: The House of Representatives shall chuse their Speaker and other Officers; and shall have the sole Power of Impeachment.
+
+Section. 3.
+
+Clause 1: The Senate of the United States shall be composed of two Senators from each State, chosen by the Legislature thereof, (See Note 3) for six Years; and each Senator shall have one Vote.
+
+Clause 2: Immediately after they shall be assembled in Consequence of the first Election, they shall be divided as equally as may be into three Classes. The Seats of the Senators of the first Class shall be vacated at the Expiration of the second Year, of the second Class at the Expiration of the fourth Year, and of the third Class at the Expiration of the sixth Year, so that one third may be chosen every second Year; and if Vacancies happen by Resignation, or otherwise, during the Recess of the Legislature of any State, the Executive thereof may make temporary Appointments until the next Meeting of the Legislature, which shall then fill such Vacancies. (See Note 4)
+
+Clause 3: No Person shall be a Senator who shall not have attained to the Age of thirty Years, and been nine Years a Citizen of the United States, and who shall not, when elected, be an Inhabitant of that State for which he shall be chosen.
+
+Clause 4: The Vice President of the United States shall be President of the Senate, but shall have no Vote, unless they be equally divided.
+
+Clause 5: The Senate shall chuse their other Officers, and also a President pro tempore, in the Absence of the Vice President, or when he shall exercise the Office of President of the United States.
+
+Clause 6: The Senate shall have the sole Power to try all Impeachments. When sitting for that Purpose, they shall be on Oath or Affirmation. When the President of the United States is tried, the Chief Justice shall preside: And no Person shall be convicted without the Concurrence of two thirds of the Members present.
+
+Clause 7: Judgment in Cases of Impeachment shall not extend further than to removal from Office, and disqualification to hold and enjoy any Office of honor, Trust or Profit under the United States: but the Party convicted shall nevertheless be liable and subject to Indictment, Trial, Judgment and Punishment, according to Law.
+
+Section. 4.
+
+Clause 1: The Times, Places and Manner of holding Elections for Senators and Representatives, shall be prescribed in each State by the Legislature thereof; but the Congress may at any time by Law make or alter such Regulations, except as to the Places of chusing Senators.
+
+Clause 2: The Congress shall assemble at least once in every Year, and such Meeting shall be on the first Monday in December, (See Note 5) unless they shall by Law appoint a different Day.
+
+Section. 5.
+
+Clause 1: Each House shall be the Judge of the Elections, Returns and Qualifications of its own Members, and a Majority of each shall constitute a Quorum to do Business; but a smaller Number may adjourn from day to day, and may be authorized to compel the Attendance of absent Members, in such Manner, and under such Penalties as each House may provide.
+
+Clause 2: Each House may determine the Rules of its Proceedings, punish its Members for disorderly Behaviour, and, with the Concurrence of two thirds, expel a Member.
+
+Clause 3: Each House shall keep a Journal of its Proceedings, and from time to time publish the same, excepting such Parts as may in their Judgment require Secrecy; and the Yeas and Nays of the Members of either House on any question shall, at the Desire of one fifth of those Present, be entered on the Journal.
+
+Clause 4: Neither House, during the Session of Congress, shall, without the Consent of the other, adjourn for more than three days, nor to any other Place than that in which the two Houses shall be sitting.
+
+Section. 6.
+
+Clause 1: The Senators and Representatives shall receive a Compensation for their Services, to be ascertained by Law, and paid out of the Treasury of the United States. (See Note 6) They shall in all Cases, except Treason, Felony and Breach of the Peace, beprivileged from Arrest during their Attendance at the Session of their respective Houses, and in going to and returning from the same; and for any Speech or Debate in either House, they shall not be questioned in any other Place.
+
+Clause 2: No Senator or Representative shall, during the Time for which he was elected, be appointed to any civil Office under the Authority of the United States, which shall have been created, or the Emoluments whereof shall have been encreased during such time; and no Person holding any Office under the United States, shall be a Member of either House during his Continuance in Office.
+
+Section. 7.
+
+Clause 1: All Bills for raising Revenue shall originate in the House of Representatives; but the Senate may propose or concur with Amendments as on other Bills.
+
+Clause 2: Every Bill which shall have passed the House of Representatives and the Senate, shall, before it become a Law, be presented to the President of the United States; If he approve he shall sign it, but if not he shall return it, with his Objections to that House in which it shall have originated, who shall enter the Objections at large on their Journal, and proceed to reconsider it. If after such Reconsideration two thirds of that House shall agree to pass the Bill, it shall be sent, together with the Objections, to the other House, by which it shall likewise be reconsidered, and if approved by two thirds of that House, it shall become a Law. But in all such Cases the Votes of both Houses shall be determined by yeas and Nays, and the Names of the Persons voting for and against the Bill shall be entered on the Journal of each House respectively. If any Bill shall not be returned by the President within ten Days (Sundays excepted) after it shall have been presented to him, the Same shall be a Law, in like Manner as if he had signed it, unless the Congress by their Adjournment prevent its Return, in which Case it shall not be a Law.
+
+Clause 3: Every Order, Resolution, or Vote to which the Concurrence of the Senate and House of Representatives may be necessary (except on a question of Adjournment) shall be presented to the President of the United States; and before the Same shall take Effect, shall be approved by him, or being disapproved by him, shall be repassed by two thirds of the Senate and House of Representatives, according to the Rules and Limitations prescribed in the Case of a Bill.
+
+Section. 8.
+
+Clause 1: The Congress shall have Power To lay and collect Taxes, Duties, Imposts and Excises, to pay the Debts and provide for the common Defence and general Welfare of the United States; but all Duties, Imposts and Excises shall be uniform throughout the United States;
+
+Clause 2: To borrow Money on the credit of the United States;
+
+Clause 3: To regulate Commerce with foreign Nations, and among the several States, and with the Indian Tribes;
+
+Clause 4: To establish an uniform Rule of Naturalization, and uniform Laws on the subject of Bankruptcies throughout the United States;
+
+Clause 5: To coin Money, regulate the Value thereof, and of foreign Coin, and fix the Standard of Weights and Measures;
+
+Clause 6: To provide for the Punishment of counterfeiting the Securities and current Coin of the United States;
+
+Clause 7: To establish Post Offices and post Roads;
+
+Clause 8: To promote the Progress of Science and useful Arts, by securing for limited Times to Authors and Inventors the exclusive Right to their respective Writings and Discoveries;
+
+Clause 9: To constitute Tribunals inferior to the supreme Court;
+
+Clause 10: To define and punish Piracies and Felonies committed on the high Seas, and Offences against the Law of Nations;
+
+Clause 11: To declare War, grant Letters of Marque and Reprisal, and make Rules concerning Captures on Land and Water;
+
+Clause 12: To raise and support Armies, but no Appropriation of Money to that Use shall be for a longer Term than two Years;
+
+Clause 13: To provide and maintain a Navy;
+
+Clause 14: To make Rules for the Government and Regulation of the land and naval Forces;
+
+Clause 15: To provide for calling forth the Militia to execute the Laws of the Union, suppress Insurrections and repel Invasions;
+
+Clause 16: To provide for organizing, arming, and disciplining, the Militia, and for governing such Part of them as may be employed in the Service of the United States, reserving to the States respectively, the Appointment of the Officers, and the Authority of training the Militia according to the discipline prescribed by Congress;
+
+Clause 17: To exercise exclusive Legislation in all Cases whatsoever, over such District (not exceeding ten Miles square) as may, byCession of particular States, and the Acceptance of Congress, become the Seat of the Government of the United States, and to exercise like Authority over all Places purchased by the Consent of the Legislature of the State in which the Same shall be, for the Erection of Forts, Magazines, Arsenals, dock-Yards, and other needful Buildings;--And
+
+Clause 18: To make all Laws which shall be necessary and proper for carrying into Execution the foregoing Powers, and all other Powers vested by this Constitution in the Government of the United States, or in any Department or Officer thereof.
+
+Section. 9.
+
+Clause 1: The Migration or Importation of such Persons as any of the States now existing shall think proper to admit, shall not be prohibited by the Congress prior to the Year one thousand eight hundred and eight, but a Tax or duty may be imposed on such Importation, not exceeding ten dollars for each Person.
+
+Clause 2: The Privilege of the Writ of Habeas Corpus shall not be suspended, unless when in Cases of Rebellion or Invasion the public Safety may require it.
+
+Clause 3: No Bill of Attainder or ex post facto Law shall be passed.
+
+Clause 4: No Capitation, or other direct, Tax shall be laid, unless in Proportion to the Census or Enumeration herein before directed to be taken. (See Note 7)
+
+Clause 5: No Tax or Duty shall be laid on Articles exported from any State.
+
+Clause 6: No Preference shall be given by any Regulation of Commerce or Revenue to the Ports of one State over those of another: nor shall Vessels bound to, or from, one State, be obliged to enter, clear, or pay Duties in another.
+
+Clause 7: No Money shall be drawn from the Treasury, but in Consequence of Appropriations made by Law; and a regular Statement and Account of the Receipts and Expenditures of all public Money shall be published from time to time.
+
+Clause 8: No Title of Nobility shall be granted by the United States: And no Person holding any Office of Profit or Trust under them, shall, without the Consent of the Congress, accept of any present, Emolument, Office, or Title, of any kind whatever, from any King, Prince, or foreign State.
+
+Section. 10.
+
+Clause 1: No State shall enter into any Treaty, Alliance, or Confederation; grant Letters of Marque and Reprisal; coin Money; emit Bills of Credit; make any Thing but gold and silver Coin a Tender in Payment of Debts; pass any Bill of Attainder, ex post facto Law, or Law impairing the Obligation of Contracts, or grant any Title of Nobility.
+
+Clause 2: No State shall, without the Consent of the Congress, lay any Imposts or Duties on Imports or Exports, except what may be absolutely necessary for executing it's inspection Laws: and the net Produce of all Duties and Imposts, laid by any State on Imports or Exports, shall be for the Use of the Treasury of the United States; and all such Laws shall be subject to the Revision and Controul of the Congress.
+
+Clause 3: No State shall, without the Consent of Congress, lay any Duty of Tonnage, keep Troops, or Ships of War in time of Peace, enter into any Agreement or Compact with another State, or with a foreign Power, or engage in War, unless actually invaded, or in such imminent Danger as will not admit of delay.
+
+Article. II.
+
+Section. 1.
+
+Clause 1: The executive Power shall be vested in a President of the United States of America. He shall hold his Office during the Term of four Years, and, together with the Vice President, chosen for the same Term, be elected, as follows
+
+Clause 2: Each State shall appoint, in such Manner as the Legislature thereof may direct, a Number of Electors, equal to the whole Number of Senators and Representatives to which the State may be entitled in the Congress: but no Senator or Representative, or Person holding an Office of Trust or Profit under the United States, shall be appointed an Elector.
+
+Clause 3: The Electors shall meet in their respective States, and vote by Ballot for two Persons, of whom one at least shall not be an Inhabitant of the same State with themselves. And they shall make a List of all the Persons voted for, and of the Number of Votes for each; which List they shall sign and certify, and transmit sealed to the Seat of the Government of the United States, directed to the President of the Senate. The President of the Senate shall, in the Presence of the Senate and House of Representatives, open all the Certificates, and the Votes shall then be counted. The Person having the greatest Number of Votes shall be the President, if such Number be a Majority of the whole Number of Electors appointed; and if there be more than one who have such Majority, and have an equal Number of Votes, then the House of Representatives shall immediately chuse by Ballot one of them for President; and if no Person have a Majority, then from the five highest on the List the said House shall in like Manner chuse the President. But in chusing the President, the Votes shall be taken by States, the Representation from each State having one Vote; A quorum for this Purpose shall consist of a Member or Members from two thirds of the States, and a Majority of all the States shall be necessary to a Choice. In every Case, after the Choice of the President, the Person having the greatest Number of Votes of the Electors shall be the Vice President. But if there should remain two or more who have equal Votes, the Senate shall chuse from them by Ballot the Vice President. (See Note 8)
+
+Clause 4: The Congress may determine the Time of chusing the Electors, and the Day on which they shall give their Votes; which Day shall be the same throughout the United States.
+
+Clause 5: No Person except a natural born Citizen, or a Citizen of the United States, at the time of the Adoption of this Constitution, shall be eligible to the Office of President; neither shall any Person be eligible to that Office who shall not have attained to the Age of thirty five Years, and been fourteen Years a Resident within the United States.
+
+Clause 6: In Case of the Removal of the President from Office, or of his Death, Resignation, or Inability to discharge the Powers and Duties of the said Office, (See Note 9) the Same shall devolve on the VicePresident, and the Congress may by Law provide for the Case of Removal, Death, Resignation or Inability, both of the President and Vice President, declaring what Officer shall then act as President, and such Officer shall act accordingly, until the Disability be removed, or a President shall be elected.
+
+Clause 7: The President shall, at stated Times, receive for his Services, a Compensation, which shall neither be encreased nor diminished during the Period for which he shall have been elected, and he shall not receive within that Period any other Emolument from the United States, or any of them.
+
+Clause 8: Before he enter on the Execution of his Office, he shall take the following Oath or Affirmation:--"I do solemnly swear (or affirm) that I will faithfully execute the Office of President of the United States, and will to the best of my Ability, preserve, protect and defend the Constitution of the United States."
+
+Section. 2.
+
+Clause 1: The President shall be Commander in Chief of the Army and Navy of the United States, and of the Militia of the several States, when called into the actual Service of the United States; he may require the Opinion, in writing, of the principal Officer in each of the executive Departments, upon any Subject relating to the Duties of their respective Offices, and he shall have Power to grant Reprieves and Pardons for Offences against the United States, except in Cases of Impeachment.
+
+Clause 2: He shall have Power, by and with the Advice and Consent of the Senate, to make Treaties, provided two thirds of the Senators present concur; and he shall nominate, and by and with the Advice and Consent of the Senate, shall appoint Ambassadors, other public Ministers and Consuls, Judges of the supreme Court, and all other Officers of the United States, whose Appointments are not herein otherwise provided for, and which shall be established by Law: but the Congress may by Law vest the Appointment of such inferior Officers, as they think proper, in the President alone, in the Courts of Law, or in the Heads of Departments.
+
+Clause 3: The President shall have Power to fill up all Vacancies that may happen during the Recess of the Senate, by granting Commissions which shall expire at the End of their next Session.
+
+Section. 3.
+
+He shall from time to time give to the Congress Information of the State of the Union, and recommend to their Consideration such Measures as he shall judge necessary and expedient; he may, on extraordinary Occasions, convene both Houses, or either of them, and in Case of Disagreement between them, with Respect to the Time of Adjournment, he may adjourn them to such Time as he shall think proper; he shall receive Ambassadors and other public Ministers; he shall take Care that the Laws be faithfully executed, and shall Commission all the Officers of the United States.
+
+Section. 4.
+
+The President, Vice President and all civil Officers of the United States, shall be removed from Office on Impeachment for, and Conviction of, Treason, Bribery, or other high Crimes and Misdemeanors.
+
+Article. III.
+
+Section. 1.
+
+The judicial Power of the United States, shall be vested in one supreme Court, and in such inferior Courts as the Congress may from time to time ordain and establish. The Judges, both of the supreme and inferior Courts, shall hold their Offices during good Behaviour, and shall, at stated Times, receive for their Services, a Compensation, which shall not be diminished during their Continuance in Office.
+
+Section. 2.
+
+Clause 1: The judicial Power shall extend to all Cases, in Law and Equity, arising under this Constitution, the Laws of the United States, and Treaties made, or which shall be made, under their Authority;--to all Cases affecting Ambassadors, other public Ministers and Consuls;--to all Cases of admiralty and maritime Jurisdiction;--to Controversies to which the United States shall be a Party;--to Controversies between two or more States;--between a State and Citizens of another State; (See Note 10)--between Citizens of different States, --between Citizens of the same State claiming Lands under Grants of different States, and between a State, or the Citizens thereof, and foreign States, Citizens or Subjects.
+
+Clause 2: In all Cases affecting Ambassadors, other public Ministers and Consuls, and those in which a State shall be Party, the supreme Court shall have original Jurisdiction. In all the other Cases before mentioned, the supreme Court shall have appellate Jurisdiction, both as to Law and Fact, with such Exceptions, and under such Regulations as the Congress shall make.
+
+Clause 3: The Trial of all Crimes, except in Cases of Impeachment, shall be by Jury; and such Trial shall be held in the State where the said Crimes shall have been committed; but when not committed within any State, the Trial shall be at such Place or Places as the Congress may by Law have directed.
+
+Section. 3.
+
+Clause 1: Treason against the United States, shall consist only in levying War against them, or in adhering to their Enemies, giving them Aid and Comfort. No Person shall be convicted of Treason unless on the Testimony of two Witnesses to the same overt Act, or on Confession in open Court.
+
+Clause 2: The Congress shall have Power to declare the Punishment of Treason, but no Attainder of Treason shall work Corruption of Blood, or Forfeiture except during the Life of the Person attainted.
+
+Article. IV.
+
+Section. 1.
+
+Full Faith and Credit shall be given in each State to the public Acts, Records, and judicial Proceedings of every other State. And the Congress may by general Laws prescribe the Manner in which such Acts, Records and Proceedings shall be proved, and the Effect thereof.
+
+Section. 2.
+
+Clause 1: The Citizens of each State shall be entitled to all Privileges and Immunities of Citizens in the several States.
+
+Clause 2: A Person charged in any State with Treason, Felony, or other Crime, who shall flee from Justice, and be found in another State, shall on Demand of the executive Authority of the State from which he fled, be delivered up, to be removed to the State having Jurisdiction of the Crime.
+
+Clause 3: No Person held to Service or Labour in one State, under the Laws thereof, escaping into another, shall, in Consequence of any Law or Regulation therein, be discharged from such Service or Labour, but shall be delivered up on Claim of the Party to whom such Service or Labour may be due. (See Note 11)
+
+Section. 3.
+
+Clause 1: New States may be admitted by the Congress into this Union; but no new State shall be formed or erected within the Jurisdiction of any other State; nor any State be formed by the Junction of two or more States, or Parts of States, without the Consent of the Legislatures of the States concerned as well as of the Congress.
+
+Clause 2: The Congress shall have Power to dispose of and make all needful Rules and Regulations respecting the Territory or other Property belonging to the United States; and nothing in this Constitution shall be so construed as to Prejudice any Claims of the United States, or of any particular State.
+
+Section. 4.
+
+The United States shall guarantee to every State in this Union a Republican Form of Government, and shall protect each of them against Invasion; and on Application of the Legislature, or of the Executive (when the Legislature cannot be convened) against domestic Violence.
+
+Article. V.
+
+The Congress, whenever two thirds of both Houses shall deem it necessary, shall propose Amendments to this Constitution, or, on the Application of the Legislatures of two thirds of the several States, shall call a Convention for proposing Amendments, which, in either Case, shall be valid to all Intents and Purposes, as Part of this Constitution, when ratified by the Legislatures of three fourths of the several States, or by Conventions in three fourths thereof, as the one or the other Mode of Ratification may be proposed by the Congress; Provided that no Amendment which may be made prior to the Year One thousand eight hundred and eight shall in any Manner affect the first and fourth Clauses in the Ninth Section of the first Article; and that no State, without its Consent, shall be deprived of its equal Suffrage in the Senate.
+
+Article. VI.
+
+Clause 1: All Debts contracted and Engagements entered into, before the Adoption of this Constitution, shall be as valid against the United States under this Constitution, as under the Confederation.
+
+Clause 2: This Constitution, and the Laws of the United States which shall be made in Pursuance thereof; and all Treaties made, or which shall be made, under the Authority of the United States, shall be the supreme Law of the Land; and the Judges in every State shall be bound thereby, any Thing in the Constitution or Laws of any State to the Contrary notwithstanding.
+
+Clause 3: The Senators and Representatives before mentioned, and the Members of the several State Legislatures, and all executive and judicial Officers, both of the United States and of the several States, shall be bound by Oath or Affirmation, to support this Constitution; but no religious Test shall ever be required as a Qualification to any Office or public Trust under the United States.
+
+Article. VII.
+
+The Ratification of the Conventions of nine States, shall be sufficient for the Establishment of this Constitution between the States so ratifying the Same.
+done in Convention by the Unanimous Consent of the States present the Seventeenth Day of September in the Year of our Lord one thousand seven hundred and Eighty seven and of the Independence of the United States of America the Twelfth In witness whereof We have hereunto subscribed our Names,
+
+GO WASHINGTON--Presidt. and deputy from Virginia
+
+[Signed also by the deputies of twelve States.]
+
+Delaware
+
+Geo: Read
+Gunning Bedford jun
+John Dickinson 
+Richard Bassett 
+Jaco: Broom 
+
+Maryland
+
+James MCHenry
+Dan of ST ThoS. Jenifer 
+DanL Carroll.
+
+Virginia
+
+John Blair--
+James Madison Jr.
+
+North Carolina
+
+WM Blount
+RichD. Dobbs Spaight.
+Hu Williamson 
+
+South Carolina
+
+J. Rutledge
+Charles 1ACotesworth Pinckney
+Charles Pinckney
+Pierce Butler.
+
+Georgia
+
+William Few
+Abr Baldwin
+
+New Hampshire
+
+John Langdon
+Nicholas Gilman
+
+Massachusetts
+
+Nathaniel Gorham
+Rufus King 
+
+Connecticut
+WM. SamL. Johnson
+Roger Sherman
+
+New York
+
+Alexander Hamilton
+
+New Jersey
+
+Wil: Livingston
+David Brearley.
+WM. Paterson. 
+Jona: Dayton 
+
+Pennsylvania
+
+B Franklin
+Thomas Mifflin
+RobT Morris
+Geo. Clymer
+ThoS. FitzSimons 
+Jared Ingersoll 
+James Wilson. 
+Gouv Morris
+
+Attest William Jackson Secretary
+END
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/password.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/password.rb
new file mode 100644 (file)
index 0000000..9b46f36
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/local/bin/ruby -w
+
+require "rubygems"
+require "highline/import"
+
+pass = ask("Enter your password:  ") { |q| q.echo = false }
+puts "Your password is #{pass}!"
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/trapping_eof.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/trapping_eof.rb
new file mode 100644 (file)
index 0000000..6646a80
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/local/bin/ruby -w
+
+# trapping_eof.rb
+#
+#  Created by James Edward Gray II on 2006-02-20.
+#  Copyright 2006 Gray Productions. All rights reserved.
+
+require "rubygems"
+require "highline/import"
+
+loop do
+  begin
+    name = ask("What's your name?")
+    break if name == "exit"
+    puts "Hello, #{name}!"
+  rescue EOFError  # HighLine throws this if @input.eof?
+    break
+  end
+end
+
+puts "Goodbye, dear friend."
+exit
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/using_readline.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/examples/using_readline.rb
new file mode 100644 (file)
index 0000000..a84fd7d
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/local/bin/ruby -w
+
+# using_readline.rb
+#
+#  Created by James Edward Gray II on 2005-07-06.
+#  Copyright 2005 Gray Productions. All rights reserved.
+
+require "rubygems"
+require "highline/import"
+
+loop do
+  cmd = ask("Enter command:  ", %w{save sample load reset quit}) do |q|
+    q.readline = true
+  end
+  say("Executing \"#{cmd}\"...")
+  break if cmd == "quit"
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline.rb
new file mode 100644 (file)
index 0000000..0ac2b71
--- /dev/null
@@ -0,0 +1,756 @@
+#!/usr/local/bin/ruby -w
+
+# highline.rb
+#
+#  Created by James Edward Gray II on 2005-04-26.
+#  Copyright 2005 Gray Productions. All rights reserved.
+#
+# See HighLine for documentation.
+#
+# This is Free Software.  See LICENSE and COPYING for details.
+
+require "erb"
+require "optparse"
+require "stringio"
+require "abbrev"
+require "highline/system_extensions"
+require "highline/question"
+require "highline/menu"
+require "highline/color_scheme"
+
+#
+# A HighLine object is a "high-level line oriented" shell over an input and an 
+# output stream.  HighLine simplifies common console interaction, effectively
+# replacing puts() and gets().  User code can simply specify the question to ask
+# and any details about user interaction, then leave the rest of the work to
+# HighLine.  When HighLine.ask() returns, you'll have the answer you requested,
+# even if HighLine had to ask many times, validate results, perform range
+# checking, convert types, etc.
+#
+class HighLine
+  # The version of the installed library.
+  VERSION = "1.6.1".freeze
+  
+  # An internal HighLine error.  User code does not need to trap this.
+  class QuestionError < StandardError
+    # do nothing, just creating a unique error type
+  end
+  
+  # The setting used to disable color output.
+  @@use_color = true
+  
+  # Pass +false+ to _setting_ to turn off HighLine's color escapes.
+  def self.use_color=( setting )
+    @@use_color = setting
+  end
+  
+  # Returns true if HighLine is currently using color escapes.
+  def self.use_color?
+    @@use_color
+  end
+  
+  # The setting used to disable EOF tracking.
+  @@track_eof = true
+  
+  # Pass +false+ to _setting_ to turn off HighLine's EOF tracking.
+  def self.track_eof=( setting )
+    @@track_eof = setting
+  end
+  
+  # Returns true if HighLine is currently tracking EOF for input.
+  def self.track_eof?
+    @@track_eof
+  end
+
+  # The setting used to control color schemes.
+  @@color_scheme = nil
+
+  # Pass ColorScheme to _setting_ to turn set a HighLine color scheme.
+  def self.color_scheme=( setting )
+    @@color_scheme = setting
+  end
+
+  # Returns the current color scheme.
+  def self.color_scheme
+    @@color_scheme
+  end
+
+  # Returns +true+ if HighLine is currently using a color scheme.
+  def self.using_color_scheme?
+    not @@color_scheme.nil?
+  end
+
+  #
+  # Embed in a String to clear all previous ANSI sequences.  This *MUST* be 
+  # done before the program exits!
+  # 
+  CLEAR      = "\e[0m"
+  # An alias for CLEAR.
+  RESET      = CLEAR
+  # Erase the current line of terminal output.
+  ERASE_LINE = "\e[K"
+  # Erase the character under the cursor.
+  ERASE_CHAR = "\e[P"
+  # The start of an ANSI bold sequence.
+  BOLD       = "\e[1m"
+  # The start of an ANSI dark sequence.  (Terminal support uncommon.)
+  DARK       = "\e[2m"
+  # The start of an ANSI underline sequence.
+  UNDERLINE  = "\e[4m"
+  # An alias for UNDERLINE.
+  UNDERSCORE = UNDERLINE
+  # The start of an ANSI blink sequence.  (Terminal support uncommon.)
+  BLINK      = "\e[5m"
+  # The start of an ANSI reverse sequence.
+  REVERSE    = "\e[7m"
+  # The start of an ANSI concealed sequence.  (Terminal support uncommon.)
+  CONCEALED  = "\e[8m"
+
+  # Set the terminal's foreground ANSI color to black.
+  BLACK      = "\e[30m"
+  # Set the terminal's foreground ANSI color to red.
+  RED        = "\e[31m"
+  # Set the terminal's foreground ANSI color to green.
+  GREEN      = "\e[32m"
+  # Set the terminal's foreground ANSI color to yellow.
+  YELLOW     = "\e[33m"
+  # Set the terminal's foreground ANSI color to blue.
+  BLUE       = "\e[34m"
+  # Set the terminal's foreground ANSI color to magenta.
+  MAGENTA    = "\e[35m"
+  # Set the terminal's foreground ANSI color to cyan.
+  CYAN       = "\e[36m"
+  # Set the terminal's foreground ANSI color to white.
+  WHITE      = "\e[37m"
+
+  # Set the terminal's background ANSI color to black.
+  ON_BLACK   = "\e[40m"
+  # Set the terminal's background ANSI color to red.
+  ON_RED     = "\e[41m"
+  # Set the terminal's background ANSI color to green.
+  ON_GREEN   = "\e[42m"
+  # Set the terminal's background ANSI color to yellow.
+  ON_YELLOW  = "\e[43m"
+  # Set the terminal's background ANSI color to blue.
+  ON_BLUE    = "\e[44m"
+  # Set the terminal's background ANSI color to magenta.
+  ON_MAGENTA = "\e[45m"
+  # Set the terminal's background ANSI color to cyan.
+  ON_CYAN    = "\e[46m"
+  # Set the terminal's background ANSI color to white.
+  ON_WHITE   = "\e[47m"
+
+  #
+  # Create an instance of HighLine, connected to the streams _input_
+  # and _output_.
+  #
+  def initialize( input = $stdin, output = $stdout,
+                  wrap_at = nil, page_at = nil )
+    @input   = input
+    @output  = output
+    
+    self.wrap_at = wrap_at
+    self.page_at = page_at
+    
+    @question = nil
+    @answer   = nil
+    @menu     = nil
+    @header   = nil
+    @prompt   = nil
+    @gather   = nil
+    @answers  = nil
+    @key      = nil
+  end
+  
+  include HighLine::SystemExtensions
+  
+  # The current column setting for wrapping output.
+  attr_reader :wrap_at
+  # The current row setting for paging output.
+  attr_reader :page_at
+  
+  #
+  # A shortcut to HighLine.ask() a question that only accepts "yes" or "no"
+  # answers ("y" and "n" are allowed) and returns +true+ or +false+
+  # (+true+ for "yes").  If provided a +true+ value, _character_ will cause
+  # HighLine to fetch a single character response. A block can be provided
+  # to further configure the question as in HighLine.ask()
+  # 
+  # Raises EOFError if input is exhausted.
+  #
+  def agree( yes_or_no_question, character = nil )
+    ask(yes_or_no_question, lambda { |yn| yn.downcase[0] == ?y}) do |q|
+      q.validate                 = /\Ay(?:es)?|no?\Z/i
+      q.responses[:not_valid]    = 'Please enter "yes" or "no".'
+      q.responses[:ask_on_error] = :question
+      q.character                = character
+      
+      yield q if block_given?
+    end
+  end
+  
+  #
+  # This method is the primary interface for user input.  Just provide a
+  # _question_ to ask the user, the _answer_type_ you want returned, and
+  # optionally a code block setting up details of how you want the question
+  # handled.  See HighLine.say() for details on the format of _question_, and
+  # HighLine::Question for more information about _answer_type_ and what's
+  # valid in the code block.
+  # 
+  # If <tt>@question</tt> is set before ask() is called, parameters are
+  # ignored and that object (must be a HighLine::Question) is used to drive
+  # the process instead.
+  # 
+  # Raises EOFError if input is exhausted.
+  #
+  def ask( question, answer_type = String, &details ) # :yields: question
+    @question ||= Question.new(question, answer_type, &details)
+    
+    return gather if @question.gather
+  
+    # readline() needs to handle it's own output, but readline only supports 
+    # full line reading.  Therefore if @question.echo is anything but true, 
+    # the prompt will not be issued. And we have to account for that now.
+    say(@question) unless (@question.readline and @question.echo == true)
+    begin
+      @answer = @question.answer_or_default(get_response)
+      unless @question.valid_answer?(@answer)
+        explain_error(:not_valid)
+        raise QuestionError
+      end
+      
+      @answer = @question.convert(@answer)
+      
+      if @question.in_range?(@answer)
+        if @question.confirm
+          # need to add a layer of scope to ask a question inside a
+          # question, without destroying instance data
+          context_change = self.class.new(@input, @output, @wrap_at, @page_at)
+          if @question.confirm == true
+            confirm_question = "Are you sure?  "
+          else
+            # evaluate ERb under initial scope, so it will have
+            # access to @question and @answer
+            template  = ERB.new(@question.confirm, nil, "%")
+            confirm_question = template.result(binding)
+          end
+          unless context_change.agree(confirm_question)
+            explain_error(nil)
+            raise QuestionError
+          end
+        end
+        
+        @answer
+      else
+        explain_error(:not_in_range)
+        raise QuestionError
+      end
+    rescue QuestionError
+      retry
+    rescue ArgumentError, NameError => error
+      raise if error.is_a?(NoMethodError)
+      if error.message =~ /ambiguous/
+        # the assumption here is that OptionParser::Completion#complete
+        # (used for ambiguity resolution) throws exceptions containing 
+        # the word 'ambiguous' whenever resolution fails
+        explain_error(:ambiguous_completion)
+      else
+        explain_error(:invalid_type)
+      end
+      retry
+    rescue Question::NoAutoCompleteMatch
+      explain_error(:no_completion)
+      retry
+    ensure
+      @question = nil    # Reset Question object.
+    end
+  end
+
+  #
+  # This method is HighLine's menu handler.  For simple usage, you can just
+  # pass all the menu items you wish to display.  At that point, choose() will
+  # build and display a menu, walk the user through selection, and return
+  # their choice amoung the provided items.  You might use this in a case
+  # statement for quick and dirty menus.
+  # 
+  # However, choose() is capable of much more.  If provided, a block will be
+  # passed a HighLine::Menu object to configure.  Using this method, you can
+  # customize all the details of menu handling from index display, to building
+  # a complete shell-like menuing system.  See HighLine::Menu for all the
+  # methods it responds to.
+  # 
+  # Raises EOFError if input is exhausted.
+  # 
+  def choose( *items, &details )
+    @menu = @question = Menu.new(&details)
+    @menu.choices(*items) unless items.empty?
+    
+    # Set _answer_type_ so we can double as the Question for ask().
+    @menu.answer_type = if @menu.shell
+      lambda do |command|    # shell-style selection
+        first_word = command.to_s.split.first || ""
+
+        options = @menu.options
+        options.extend(OptionParser::Completion)
+        answer = options.complete(first_word)
+
+        if answer.nil?
+          raise Question::NoAutoCompleteMatch
+        end
+
+        [answer.last, command.sub(/^\s*#{first_word}\s*/, "")]
+      end
+    else
+      @menu.options          # normal menu selection, by index or name
+    end
+    
+    # Provide hooks for ERb layouts.
+    @header   = @menu.header
+    @prompt   = @menu.prompt
+    
+    if @menu.shell
+      selected = ask("Ignored", @menu.answer_type)
+      @menu.select(self, *selected)
+    else
+      selected = ask("Ignored", @menu.answer_type)
+      @menu.select(self, selected)
+    end
+  end
+
+  #
+  # This method provides easy access to ANSI color sequences, without the user
+  # needing to remember to CLEAR at the end of each sequence.  Just pass the
+  # _string_ to color, followed by a list of _colors_ you would like it to be
+  # affected by.  The _colors_ can be HighLine class constants, or symbols 
+  # (:blue for BLUE, for example).  A CLEAR will automatically be embedded to
+  # the end of the returned String.
+  # 
+  # This method returns the original _string_ unchanged if HighLine::use_color? 
+  # is +false+.
+  #
+  def color( string, *colors )
+    return string unless self.class.use_color?
+    
+    colors.map! do |c|
+      if self.class.using_color_scheme? and self.class.color_scheme.include? c
+        self.class.color_scheme[c]
+      elsif c.is_a? Symbol
+        self.class.const_get(c.to_s.upcase)
+      else
+        c
+      end
+    end
+    "#{colors.flatten.join}#{string}#{CLEAR}"
+  end
+  
+  # 
+  # This method is a utility for quickly and easily laying out lists.  It can
+  # be accessed within ERb replacements of any text that will be sent to the
+  # user.
+  #
+  # The only required parameter is _items_, which should be the Array of items
+  # to list.  A specified _mode_ controls how that list is formed and _option_
+  # has different effects, depending on the _mode_.  Recognized modes are:
+  #
+  # <tt>:columns_across</tt>::  _items_ will be placed in columns, flowing
+  #                             from left to right.  If given, _option_ is the
+  #                             number of columns to be used.  When absent, 
+  #                             columns will be determined based on _wrap_at_
+  #                             or a default of 80 characters.
+  # <tt>:columns_down</tt>::    Identical to <tt>:columns_across</tt>, save
+  #                             flow goes down.
+  # <tt>:inline</tt>::          All _items_ are placed on a single line.  The
+  #                             last two _items_ are separated by _option_ or
+  #                             a default of " or ".  All other _items_ are
+  #                             separated by ", ".
+  # <tt>:rows</tt>::            The default mode.  Each of the _items_ is
+  #                             placed on it's own line.  The _option_
+  #                             parameter is ignored in this mode.
+  # 
+  # Each member of the _items_ Array is passed through ERb and thus can contain
+  # their own expansions.  Color escape expansions do not contribute to the 
+  # final field width.
+  # 
+  def list( items, mode = :rows, option = nil )
+    items = items.to_ary.map do |item|
+      ERB.new(item, nil, "%").result(binding)
+    end
+    
+    case mode
+    when :inline
+      option = " or " if option.nil?
+      
+      case items.size
+      when 0
+        ""
+      when 1
+        items.first
+      when 2
+        "#{items.first}#{option}#{items.last}"
+      else
+        items[0..-2].join(", ") + "#{option}#{items.last}"
+      end
+    when :columns_across, :columns_down
+      max_length = actual_length(
+        items.max { |a, b| actual_length(a) <=> actual_length(b) }
+      )
+
+      if option.nil?
+        limit  = @wrap_at || 80
+        option = (limit + 2) / (max_length + 2)
+      end
+
+      items     = items.map do |item|
+        pad = max_length + (item.length - actual_length(item))
+        "%-#{pad}s" % item
+      end
+      row_count = (items.size / option.to_f).ceil
+      
+      if mode == :columns_across
+        rows = Array.new(row_count) { Array.new }
+        items.each_with_index do |item, index|
+          rows[index / option] << item
+        end
+
+        rows.map { |row| row.join("  ") + "\n" }.join
+      else
+        columns = Array.new(option) { Array.new }
+        items.each_with_index do |item, index|
+          columns[index / row_count] << item
+        end
+      
+        list = ""
+        columns.first.size.times do |index|
+          list << columns.map { |column| column[index] }.
+                          compact.join("  ") + "\n"
+        end
+        list
+      end
+    else
+      items.map { |i| "#{i}\n" }.join
+    end
+  end
+  
+  #
+  # The basic output method for HighLine objects.  If the provided _statement_
+  # ends with a space or tab character, a newline will not be appended (output
+  # will be flush()ed).  All other cases are passed straight to Kernel.puts().
+  #
+  # The _statement_ parameter is processed as an ERb template, supporting
+  # embedded Ruby code.  The template is evaluated with a binding inside 
+  # the HighLine instance, providing easy access to the ANSI color constants
+  # and the HighLine.color() method.
+  #
+  def say( statement )
+    statement = statement.to_str
+    return unless statement.length > 0
+    
+    template  = ERB.new(statement, nil, "%")
+    statement = template.result(binding)
+    
+    statement = wrap(statement) unless @wrap_at.nil?
+    statement = page_print(statement) unless @page_at.nil?
+    
+    if statement[-1, 1] == " " or statement[-1, 1] == "\t"
+      @output.print(statement)
+      @output.flush  
+    else
+      @output.puts(statement)
+    end
+  end
+  
+  #
+  # Set to an integer value to cause HighLine to wrap output lines at the
+  # indicated character limit.  When +nil+, the default, no wrapping occurs.  If
+  # set to <tt>:auto</tt>, HighLine will attempt to determing the columns
+  # available for the <tt>@output</tt> or use a sensible default.
+  #
+  def wrap_at=( setting )
+    @wrap_at = setting == :auto ? output_cols : setting
+  end
+  
+  #
+  # Set to an integer value to cause HighLine to page output lines over the
+  # indicated line limit.  When +nil+, the default, no paging occurs.  If
+  # set to <tt>:auto</tt>, HighLine will attempt to determing the rows available
+  # for the <tt>@output</tt> or use a sensible default.
+  #
+  def page_at=( setting )
+    @page_at = setting == :auto ? output_rows - 2 : setting
+  end
+  
+  # 
+  # Returns the number of columns for the console, or a default it they cannot
+  # be determined.
+  # 
+  def output_cols
+    return 80 unless @output.tty?
+    terminal_size.first
+  rescue
+    return 80
+  end
+  
+  # 
+  # Returns the number of rows for the console, or a default if they cannot be
+  # determined.
+  # 
+  def output_rows
+    return 24 unless @output.tty?
+    terminal_size.last
+  rescue
+    return 24
+  end
+  
+  private
+  
+  #
+  # A helper method for sending the output stream and error and repeat
+  # of the question.
+  #
+  def explain_error( error )
+    say(@question.responses[error]) unless error.nil?
+    if @question.responses[:ask_on_error] == :question
+      say(@question)
+    elsif @question.responses[:ask_on_error]
+      say(@question.responses[:ask_on_error])
+    end
+  end
+  
+  #
+  # Collects an Array/Hash full of answers as described in 
+  # HighLine::Question.gather().
+  # 
+  # Raises EOFError if input is exhausted.
+  # 
+  def gather(  )
+    @gather           = @question.gather
+    @answers          = [ ]
+    original_question = @question
+    
+    @question.gather = false
+    
+    case @gather
+    when Integer
+      @answers << ask(@question)
+      @gather  -= 1
+
+      original_question.question = ""
+      until @gather.zero?
+        @question =  original_question
+        @answers  << ask(@question)
+        @gather   -= 1
+      end
+    when String, Regexp
+      @answers << ask(@question)
+
+      original_question.question = ""
+      until (@gather.is_a?(String) and @answers.last.to_s == @gather) or
+            (@gather.is_a?(Regexp) and @answers.last.to_s =~ @gather)
+        @question =  original_question
+        @answers  << ask(@question)
+      end
+      
+      @answers.pop
+    when Hash
+      @answers = { }
+      @gather.keys.sort.each do |key|
+        @question     = original_question
+        @key          = key
+        @answers[key] = ask(@question)
+      end
+    end
+    
+    @answers
+  end
+
+  #
+  # Read a line of input from the input stream and process whitespace as
+  # requested by the Question object.
+  # 
+  # If Question's _readline_ property is set, that library will be used to
+  # fetch input.  *WARNING*:  This ignores the currently set input stream.
+  # 
+  # Raises EOFError if input is exhausted.
+  #
+  def get_line(  )
+    if @question.readline
+      require "readline"    # load only if needed
+
+      # capture say()'s work in a String to feed to readline()
+      old_output = @output
+      @output    = StringIO.new
+      say(@question)
+      question = @output.string
+      @output  = old_output
+      
+      # prep auto-completion
+      Readline.completion_proc = lambda do |string|
+        @question.selection.grep(/\A#{Regexp.escape(string)}/)
+      end
+      
+      # work-around ugly readline() warnings
+      old_verbose = $VERBOSE
+      $VERBOSE    = nil
+      answer      = @question.change_case(
+                        @question.remove_whitespace(
+                            Readline.readline(question, true) ) )
+      $VERBOSE    = old_verbose
+
+      answer
+    else
+      raise EOFError, "The input stream is exhausted." if @@track_eof and
+                                                          @input.eof?
+
+      @question.change_case(@question.remove_whitespace(@input.gets))
+    end
+  end
+  
+  #
+  # Return a line or character of input, as requested for this question.
+  # Character input will be returned as a single character String,
+  # not an Integer.
+  # 
+  # This question's _first_answer_ will be returned instead of input, if set.
+  # 
+  # Raises EOFError if input is exhausted.
+  #
+  def get_response(  )
+    return @question.first_answer if @question.first_answer?
+    
+    if @question.character.nil?
+      if @question.echo == true and @question.limit.nil?
+        get_line
+      else
+        raw_no_echo_mode if stty = CHARACTER_MODE == "stty"
+        
+        line            = ""
+        backspace_limit = 0
+        begin
+
+          while character = (stty ? @input.getbyte : get_character(@input))
+            # honor backspace and delete
+            if character == 127 or character == 8
+              line.slice!(-1, 1)
+              backspace_limit -= 1
+            else
+              line << character.chr
+              backspace_limit = line.size
+            end
+            # looking for carriage return (decimal 13) or
+            # newline (decimal 10) in raw input
+            break if character == 13 or character == 10 or
+                     (@question.limit and line.size == @question.limit)
+            if @question.echo != false
+              if character == 127 or character == 8 
+                  # only backspace if we have characters on the line to
+                  # eliminate, otherwise we'll tromp over the prompt
+                  if backspace_limit >= 0 then
+                    @output.print("\b#{ERASE_CHAR}")
+                  else 
+                      # do nothing
+                  end
+              else
+                if @question.echo == true
+                  @output.print(character.chr)
+                else
+                  @output.print(@question.echo)
+                end
+              end
+              @output.flush
+            end
+          end
+        ensure
+          restore_mode if stty
+        end
+        if @question.overwrite
+          @output.print("\r#{ERASE_LINE}")
+          @output.flush
+        else
+          say("\n")
+        end
+        
+        @question.change_case(@question.remove_whitespace(line))
+      end
+    elsif @question.character == :getc
+      @question.change_case(@input.getbyte.chr)
+    else
+      response = get_character(@input).chr
+      if @question.overwrite
+        @output.print("\r#{ERASE_LINE}")
+        @output.flush
+      else
+        echo = if @question.echo == true
+          response
+        elsif @question.echo != false
+          @question.echo
+        else
+          ""
+        end
+        say("#{echo}\n")
+      end
+      @question.change_case(response)
+    end
+  end
+  
+  # 
+  # Page print a series of at most _page_at_ lines for _output_.  After each
+  # page is printed, HighLine will pause until the user presses enter/return
+  # then display the next page of data.
+  #
+  # Note that the final page of _output_ is *not* printed, but returned
+  # instead.  This is to support any special handling for the final sequence.
+  # 
+  def page_print( output )
+    lines = output.scan(/[^\n]*\n?/)
+    while lines.size > @page_at
+      @output.puts lines.slice!(0...@page_at).join
+      @output.puts
+      # Return last line if user wants to abort paging
+      return (["...\n"] + lines.slice(-2,1)).join unless continue_paging?
+    end
+    return lines.join
+  end
+  # 
+  # Ask user if they wish to continue paging output. Allows them to type "q" to
+  # cancel the paging process.
+  # 
+  def continue_paging?
+    command = HighLine.new(@input, @output).ask(
+      "-- press enter/return to continue or q to stop -- "
+    ) { |q| q.character = true }
+    command !~ /\A[qQ]\Z/  # Only continue paging if Q was not hit.
+  end
+    
+  #
+  # Wrap a sequence of _lines_ at _wrap_at_ characters per line.  Existing
+  # newlines will not be affected by this process, but additional newlines
+  # may be added.
+  #
+  def wrap( text )
+    wrapped = [ ]
+    text.each_line do |line|
+      while line =~ /([^\n]{#{@wrap_at + 1},})/
+        search  = $1.dup
+        replace = $1.dup
+        if index = replace.rindex(" ", @wrap_at)
+          replace[index, 1] = "\n"
+          replace.sub!(/\n[ \t]+/, "\n")
+          line.sub!(search, replace)
+        else
+          line[$~.begin(1) + @wrap_at, 0] = "\n"
+        end
+      end
+      wrapped << line
+    end
+    return wrapped.join
+  end
+  
+  # 
+  # Returns the length of the passed +string_with_escapes+, minus and color
+  # sequence escapes.
+  # 
+  def actual_length( string_with_escapes )
+    string_with_escapes.gsub(/\e\[\d{1,2}m/, "").length
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/color_scheme.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/color_scheme.rb
new file mode 100644 (file)
index 0000000..23754a5
--- /dev/null
@@ -0,0 +1,118 @@
+#!/usr/local/bin/ruby -w
+
+# color_scheme.rb
+#
+# Created by Jeremy Hinegardner on 2007-01-24
+# Copyright 2007.  All rights reserved
+#
+# This is Free Software.  See LICENSE and COPYING for details
+
+class HighLine
+  #
+  # ColorScheme objects encapsulate a named set of colors to be used in the
+  # HighLine.colors() method call.  For example, by applying a ColorScheme that
+  # has a <tt>:warning</tt> color then the following could be used:
+  #
+  #   colors("This is a warning", :warning)
+  #
+  # A ColorScheme contains named sets of HighLine color constants. 
+  #
+  # Example: Instantiating a color scheme, applying it to HighLine,
+  #          and using it:
+  #
+  #   ft = HighLine::ColorScheme.new do |cs|
+  #          cs[:headline]        = [ :bold, :yellow, :on_black ]
+  #          cs[:horizontal_line] = [ :bold, :white ]
+  #          cs[:even_row]        = [ :green ]
+  #          cs[:odd_row]         = [ :magenta ]
+  #        end 
+  #
+  #   HighLine.color_scheme = ft
+  #   say("<%= color('Headline', :headline) %>")
+  #   say("<%= color('-'*20, :horizontal_line) %>")
+  #   i = true
+  #   ("A".."D").each do |row|
+  #      if i then
+  #        say("<%= color('#{row}', :even_row ) %>")
+  #      else
+  #        say("<%= color('#{row}', :odd_row) %>")
+  #      end 
+  #      i = !i
+  #   end
+  #
+  #
+  class ColorScheme 
+    #
+    # Create an instance of HighLine::ColorScheme. The customization can
+    # happen as a passed in Hash or via the yielded block.  Key's are
+    # converted to <tt>:symbols</tt> and values are converted to HighLine
+    # constants.
+    #
+    def initialize( h = nil )
+      @scheme = Hash.new
+      load_from_hash(h) unless h.nil?
+      yield self if block_given?
+    end
+
+    # Load multiple colors from key/value pairs.
+    def load_from_hash( h )
+      h.each_pair do |color_tag, constants|
+        self[color_tag] = constants
+      end
+    end
+
+    # Does this color scheme include the given tag name?
+    def include?( color_tag )
+      @scheme.keys.include?(to_symbol(color_tag))
+    end
+
+    # Allow the scheme to be accessed like a Hash.
+    def []( color_tag )
+      @scheme[to_symbol(color_tag)]
+    end
+
+    # Allow the scheme to be set like a Hash.
+    def []=( color_tag, constants )
+      @scheme[to_symbol(color_tag)] = constants.map { |c| to_constant(c) }
+    end
+
+    private
+
+    # Return a normalized representation of a color name.
+    def to_symbol( t )
+      t.to_s.downcase
+    end
+
+    # Return a normalized representation of a color setting.
+    def to_constant( v )
+      v = v.to_s if v.is_a?(Symbol)
+      if v.is_a?(String) then
+        HighLine.const_get(v.upcase)
+      else
+        v
+      end
+    end
+  end
+
+  # A sample ColorScheme.
+  class SampleColorScheme < ColorScheme
+    # 
+    # Builds the sample scheme with settings for <tt>:critical</tt>,
+    # <tt>:error</tt>, <tt>:warning</tt>, <tt>:notice</tt>, <tt>:info</tt>,
+    # <tt>:debug</tt>, <tt>:row_even</tt>, and <tt>:row_odd</tt> colors.
+    # 
+    def initialize( h = nil )
+      scheme = {
+        :critical => [ :yellow, :on_red  ],
+        :error    => [ :bold,   :red     ],
+        :warning  => [ :bold,   :yellow  ],
+        :notice   => [ :bold,   :magenta ],
+        :info     => [ :bold,   :cyan    ],
+        :debug    => [ :bold,   :green   ],
+        :row_even => [ :cyan    ],
+        :row_odd  => [ :magenta ]
+      }
+      super(scheme)
+    end
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/compatibility.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/compatibility.rb
new file mode 100644 (file)
index 0000000..7a99819
--- /dev/null
@@ -0,0 +1,16 @@
+unless STDIN.respond_to? :getbyte
+  class IO
+    alias_method :getbyte, :getc
+  end
+
+  class StringIO
+    alias_method :getbyte, :getc
+  end
+end
+
+unless "".respond_to? :each_line
+  # Not a perfect translation, but sufficient for our needs.
+  class String
+    alias_method :each_line, :each
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/import.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/import.rb
new file mode 100644 (file)
index 0000000..579a973
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/local/bin/ruby -w
+
+# import.rb
+#
+#  Created by James Edward Gray II on 2005-04-26.
+#  Copyright 2005 Gray Productions. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+
+require "highline"
+require "forwardable"
+
+$terminal = HighLine.new
+
+#
+# <tt>require "highline/import"</tt> adds shortcut methods to Kernel, making
+# agree(), ask(), choose() and say() globally available.  This is handy for
+# quick and dirty input and output.  These methods use the HighLine object in
+# the global variable <tt>$terminal</tt>, which is initialized to used
+# <tt>$stdin</tt> and <tt>$stdout</tt> (you are free to change this).
+# Otherwise, these methods are identical to their HighLine counterparts, see that
+# class for detailed explanations.
+#
+module Kernel
+  extend Forwardable
+  def_delegators :$terminal, :agree, :ask, :choose, :say
+end
+
+class Object
+  # 
+  # Tries this object as a _first_answer_ for a HighLine::Question.  See that
+  # attribute for details.
+  # 
+  # *Warning*:  This Object will be passed to String() before set.
+  # 
+  def or_ask( *args, &details )
+    ask(*args) do |question|
+      question.first_answer = String(self) unless nil?
+      
+      details.call(question) unless details.nil?
+    end
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/menu.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/menu.rb
new file mode 100644 (file)
index 0000000..890af45
--- /dev/null
@@ -0,0 +1,397 @@
+#!/usr/local/bin/ruby -w
+
+# menu.rb
+#
+#  Created by Gregory Thomas Brown on 2005-05-10.
+#  Copyright 2005. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+
+require "highline/question"
+
+class HighLine
+  # 
+  # Menu objects encapsulate all the details of a call to HighLine.choose().
+  # Using the accessors and Menu.choice() and Menu.choices(), the block passed
+  # to HighLine.choose() can detail all aspects of menu display and control.
+  # 
+  class Menu < Question
+    #
+    # Create an instance of HighLine::Menu.  All customization is done
+    # through the passed block, which should call accessors and choice() and
+    # choices() as needed to define the Menu.  Note that Menus are also
+    # Questions, so all that functionality is available to the block as
+    # well.
+    # 
+    def initialize(  )
+      #
+      # Initialize Question objects with ignored values, we'll
+      # adjust ours as needed.
+      # 
+      super("Ignored", [ ], &nil)    # avoiding passing the block along
+      
+      @items           = [ ]
+      @hidden_items    = [ ]
+      @help            = Hash.new("There's no help for that topic.")
+
+      @index           = :number
+      @index_suffix    = ". "
+      @select_by       = :index_or_name
+      @flow            = :rows
+      @list_option     = nil
+      @header          = nil
+      @prompt          = "?  "
+      @layout          = :list
+      @shell           = false
+      @nil_on_handled  = false
+      
+      # Override Questions responses, we'll set our own.
+      @responses       = { }
+      # Context for action code.
+      @highline        = nil
+      
+      yield self if block_given?
+
+      init_help if @shell and not @help.empty?
+    end
+
+    #
+    # An _index_ to append to each menu item in display.  See
+    # Menu.index=() for details.
+    # 
+    attr_reader   :index
+    #
+    # The String placed between an _index_ and a menu item.  Defaults to
+    # ". ".  Switches to " ", when _index_ is set to a String (like "-").
+    #
+    attr_accessor :index_suffix
+    # 
+    # The _select_by_ attribute controls how the user is allowed to pick a 
+    # menu item.  The available choices are:
+    # 
+    # <tt>:index</tt>::          The user is allowed to type the numerical
+    #                            or alphetical index for their selection.
+    # <tt>:index_or_name</tt>::  Allows both methods from the
+    #                            <tt>:index</tt> option and the
+    #                            <tt>:name</tt> option.
+    # <tt>:name</tt>::           Menu items are selected by typing a portion
+    #                            of the item name that will be
+    #                            auto-completed.
+    # 
+    attr_accessor :select_by
+    # 
+    # This attribute is passed directly on as the mode to HighLine.list() by
+    # all the preset layouts.  See that method for appropriate settings.
+    # 
+    attr_accessor :flow
+    #
+    # This setting is passed on as the third parameter to HighLine.list()
+    # by all the preset layouts.  See that method for details of its
+    # effects.  Defaults to +nil+.
+    # 
+    attr_accessor :list_option
+    #
+    # Used by all the preset layouts to display title and/or introductory
+    # information, when set.  Defaults to +nil+.
+    # 
+    attr_accessor :header
+    #
+    # Used by all the preset layouts to ask the actual question to fetch a
+    # menu selection from the user.  Defaults to "?  ".
+    # 
+    attr_accessor :prompt
+    #
+    # An ERb _layout_ to use when displaying this Menu object.  See
+    # Menu.layout=() for details.
+    # 
+    attr_reader   :layout
+    #
+    # When set to +true+, responses are allowed to be an entire line of
+    # input, including details beyond the command itself.  Only the first
+    # "word" of input will be matched against the menu choices, but both the
+    # command selected and the rest of the line will be passed to provided
+    # action blocks.  Defaults to +false+.
+    # 
+    attr_accessor :shell
+    #
+    # When +true+, any selected item handled by provided action code, will
+    # return +nil+, instead of the results to the action code.  This may
+    # prove handy when dealing with mixed menus where only the names of
+    # items without any code (and +nil+, of course) will be returned.
+    # Defaults to +false+.
+    # 
+    attr_accessor :nil_on_handled
+    
+    #
+    # Adds _name_ to the list of available menu items.  Menu items will be
+    # displayed in the order they are added.
+    # 
+    # An optional _action_ can be associated with this name and if provided,
+    # it will be called if the item is selected.  The result of the method
+    # will be returned, unless _nil_on_handled_ is set (when you would get
+    # +nil+ instead).  In _shell_ mode, a provided block will be passed the
+    # command chosen and any details that followed the command.  Otherwise,
+    # just the command is passed.  The <tt>@highline</tt> variable is set to
+    # the current HighLine context before the action code is called and can
+    # thus be used for adding output and the like.
+    # 
+    def choice( name, help = nil, &action )
+      @items << [name, action]
+      
+      @help[name.to_s.downcase] = help unless help.nil?
+      update_responses  # rebuild responses based on our settings
+    end
+    
+    #
+    # A shortcut for multiple calls to the sister method choice().  <b>Be
+    # warned:</b>  An _action_ set here will apply to *all* provided
+    # _names_.  This is considered to be a feature, so you can easily
+    # hand-off interface processing to a different chunk of code.
+    # 
+    def choices( *names, &action )
+      names.each { |n| choice(n, &action) }
+    end
+
+    # Identical to choice(), but the item will not be listed for the user.
+    def hidden( name, help = nil, &action )
+      @hidden_items << [name, action]
+      
+      @help[name.to_s.downcase] = help unless help.nil?
+    end
+    
+    # 
+    # Sets the indexing style for this Menu object.  Indexes are appended to
+    # menu items, when displayed in list form.  The available settings are:
+    # 
+    # <tt>:number</tt>::   Menu items will be indexed numerically, starting
+    #                      with 1.  This is the default method of indexing.
+    # <tt>:letter</tt>::   Items will be indexed alphabetically, starting
+    #                      with a.
+    # <tt>:none</tt>::     No index will be appended to menu items.
+    # <i>any String</i>::  Will be used as the literal _index_.
+    # 
+    # Setting the _index_ to <tt>:none</tt> a literal String, also adjusts
+    # _index_suffix_ to a single space and _select_by_ to <tt>:none</tt>. 
+    # Because of this, you should make a habit of setting the _index_ first.
+    # 
+    def index=( style )
+      @index = style
+      
+      # Default settings.
+      if @index == :none or @index.is_a?(String)
+        @index_suffix = " "
+        @select_by    = :name
+      end
+    end
+    
+    # 
+    # Initializes the help system by adding a <tt>:help</tt> choice, some
+    # action code, and the default help listing.
+    # 
+    def init_help(  )
+      return if @items.include?(:help)
+      
+      topics    = @help.keys.sort
+      help_help = @help.include?("help") ? @help["help"] :
+                  "This command will display helpful messages about " +
+                  "functionality, like this one.  To see the help for " +
+                  "a specific topic enter:\n\thelp [TOPIC]\nTry asking " +
+                  "for help on any of the following:\n\n" +
+                  "<%= list(#{topics.inspect}, :columns_across) %>"
+      choice(:help, help_help) do |command, topic|
+        topic.strip!
+        topic.downcase!
+        if topic.empty?
+          @highline.say(@help["help"])
+        else
+          @highline.say("= #{topic}\n\n#{@help[topic]}")
+        end
+      end
+    end
+    
+    #
+    # Used to set help for arbitrary topics.  Use the topic <tt>"help"</tt>
+    # to override the default message.
+    # 
+    def help( topic, help )
+      @help[topic] = help
+    end
+    
+    # 
+    # Setting a _layout_ with this method also adjusts some other attributes
+    # of the Menu object, to ideal defaults for the chosen _layout_.  To
+    # account for that, you probably want to set a _layout_ first in your
+    # configuration block, if needed.
+    # 
+    # Accepted settings for _layout_ are:
+    #
+    # <tt>:list</tt>::         The default _layout_.  The _header_ if set
+    #                          will appear at the top on its own line with
+    #                          a trailing colon.  Then the list of menu
+    #                          items will follow.  Finally, the _prompt_
+    #                          will be used as the ask()-like question.
+    # <tt>:one_line</tt>::     A shorter _layout_ that fits on one line.  
+    #                          The _header_ comes first followed by a
+    #                          colon and spaces, then the _prompt_ with menu
+    #                          items between trailing parenthesis.
+    # <tt>:menu_only</tt>::    Just the menu items, followed up by a likely
+    #                          short _prompt_.
+    # <i>any ERb String</i>::  Will be taken as the literal _layout_.  This
+    #                          String can access <tt>@header</tt>, 
+    #                          <tt>@menu</tt> and <tt>@prompt</tt>, but is
+    #                          otherwise evaluated in the typical HighLine
+    #                          context, to provide access to utilities like
+    #                          HighLine.list() primarily.
+    # 
+    # If set to either <tt>:one_line</tt>, or <tt>:menu_only</tt>, _index_
+    # will default to <tt>:none</tt> and _flow_ will default to
+    # <tt>:inline</tt>.
+    # 
+    def layout=( new_layout )
+      @layout = new_layout
+      
+      # Default settings.
+      case @layout
+      when :one_line, :menu_only
+        self.index = :none
+        @flow  = :inline
+      end
+    end
+
+    #
+    # This method returns all possible options for auto-completion, based
+    # on the settings of _index_ and _select_by_.
+    # 
+    def options(  )
+      # add in any hidden menu commands
+      @items.concat(@hidden_items)
+      
+      by_index = if @index == :letter
+        l_index = "`"
+        @items.map { "#{l_index.succ!}" }
+      else
+        (1 .. @items.size).collect { |s| String(s) }
+      end
+      by_name = @items.collect { |c| c.first }
+
+      case @select_by
+      when :index then
+        by_index
+      when :name
+        by_name
+      else
+        by_index + by_name
+      end
+    ensure
+      # make sure the hidden items are removed, before we return
+      @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
+    end
+
+    #
+    # This method processes the auto-completed user selection, based on the
+    # rules for this Menu object.  If an action was provided for the 
+    # selection, it will be executed as described in Menu.choice().
+    # 
+    def select( highline_context, selection, details = nil )
+      # add in any hidden menu commands
+      @items.concat(@hidden_items)
+      
+      # Find the selected action.
+      name, action = if selection =~ /^\d+$/
+        @items[selection.to_i - 1]
+      else
+        l_index = "`"
+        index = @items.map { "#{l_index.succ!}" }.index(selection)
+        @items.find { |c| c.first == selection } or @items[index]
+      end
+      
+      # Run or return it.
+      if not @nil_on_handled and not action.nil?
+        @highline = highline_context
+        if @shell
+          action.call(name, details)
+        else
+          action.call(name)
+        end
+      elsif action.nil?
+        name
+      else
+        nil
+      end
+    ensure
+      # make sure the hidden items are removed, before we return
+      @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
+    end
+    
+    #
+    # Allows Menu objects to pass as Arrays, for use with HighLine.list().
+    # This method returns all menu items to be displayed, complete with
+    # indexes.
+    # 
+    def to_ary(  )
+      case @index
+      when :number
+        @items.map { |c| "#{@items.index(c) + 1}#{@index_suffix}#{c.first}" }
+      when :letter
+        l_index = "`"
+        @items.map { |c| "#{l_index.succ!}#{@index_suffix}#{c.first}" }
+      when :none
+        @items.map { |c| "#{c.first}" }
+      else
+        @items.map { |c| "#{index}#{@index_suffix}#{c.first}" }
+      end
+    end
+    
+    #
+    # Allows Menu to behave as a String, just like Question.  Returns the
+    # _layout_ to be rendered, which is used by HighLine.say().
+    # 
+    def to_str(  )
+      case @layout
+      when :list
+        '<%= if @header.nil? then '' else "#{@header}:\n" end %>' +
+        "<%= list( @menu, #{@flow.inspect},
+                          #{@list_option.inspect} ) %>" +
+        "<%= @prompt %>"
+      when :one_line
+        '<%= if @header.nil? then '' else "#{@header}:  " end %>' +
+        "<%= @prompt %>" +
+        "(<%= list( @menu, #{@flow.inspect},
+                           #{@list_option.inspect} ) %>)" +
+        "<%= @prompt[/\s*$/] %>"
+      when :menu_only
+        "<%= list( @menu, #{@flow.inspect},
+                          #{@list_option.inspect} ) %><%= @prompt %>"
+      else
+        @layout
+      end
+    end      
+
+    #
+    # This method will update the intelligent responses to account for
+    # Menu specific differences.  This overrides the work done by 
+    # Question.build_responses().
+    # 
+    def update_responses(  )
+      append_default unless default.nil?
+      @responses = @responses.merge(
+                     :ambiguous_completion =>
+                       "Ambiguous choice.  " +
+                       "Please choose one of #{options.inspect}.",
+                     :ask_on_error         =>
+                       "?  ",
+                     :invalid_type         =>
+                       "You must enter a valid #{options}.",
+                     :no_completion        =>
+                       "You must choose one of " +
+                       "#{options.inspect}.",
+                     :not_in_range         =>
+                       "Your answer isn't within the expected range " +
+                       "(#{expected_range}).",
+                     :not_valid            =>
+                       "Your answer isn't valid (must match " +
+                       "#{@validate.inspect})."
+                   )
+    end
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/question.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/question.rb
new file mode 100644 (file)
index 0000000..96c752f
--- /dev/null
@@ -0,0 +1,462 @@
+#!/usr/local/bin/ruby -w
+
+# question.rb
+#
+#  Created by James Edward Gray II on 2005-04-26.
+#  Copyright 2005 Gray Productions. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+require "optparse"
+require "date"
+require "pathname"
+
+class HighLine
+  #
+  # Question objects contain all the details of a single invocation of
+  # HighLine.ask().  The object is initialized by the parameters passed to
+  # HighLine.ask() and then queried to make sure each step of the input
+  # process is handled according to the users wishes.
+  #
+  class Question
+    # An internal HighLine error.  User code does not need to trap this.
+    class NoAutoCompleteMatch < StandardError
+      # do nothing, just creating a unique error type
+    end
+
+    #
+    # Create an instance of HighLine::Question.  Expects a _question_ to ask
+    # (can be <tt>""</tt>) and an _answer_type_ to convert the answer to.
+    # The _answer_type_ parameter must be a type recognized by
+    # Question.convert(). If given, a block is yeilded the new Question
+    # object to allow custom initializaion.
+    #
+    def initialize( question, answer_type )
+      # initialize instance data
+      @question    = question
+      @answer_type = answer_type
+      
+      @character    = nil
+      @limit        = nil
+      @echo         = true
+      @readline     = false
+      @whitespace   = :strip
+      @case         = nil
+      @default      = nil
+      @validate     = nil
+      @above        = nil
+      @below        = nil
+      @in           = nil
+      @confirm      = nil
+      @gather       = false
+      @first_answer = nil
+      @directory    = Pathname.new(File.expand_path(File.dirname($0)))
+      @glob         = "*"
+      @responses    = Hash.new
+      @overwrite    = false
+      
+      # allow block to override settings
+      yield self if block_given?
+
+      # finalize responses based on settings
+      build_responses
+    end
+    
+    # The ERb template of the question to be asked.
+    attr_accessor :question
+    # The type that will be used to convert this answer.
+    attr_accessor :answer_type
+    #
+    # Can be set to +true+ to use HighLine's cross-platform character reader
+    # instead of fetching an entire line of input.  (Note: HighLine's character
+    # reader *ONLY* supports STDIN on Windows and Unix.)  Can also be set to
+    # <tt>:getc</tt> to use that method on the input stream.
+    #
+    # *WARNING*:  The _echo_ and _overwrite_ attributes for a question are 
+    # ignored when using the <tt>:getc</tt> method.  
+    # 
+    attr_accessor :character
+    #
+    # Allows you to set a character limit for input.
+    # 
+    # *WARNING*:  This option forces a character by character read.
+    # 
+    attr_accessor :limit
+    #
+    # Can be set to +true+ or +false+ to control whether or not input will
+    # be echoed back to the user.  A setting of +true+ will cause echo to
+    # match input, but any other true value will be treated as to String to
+    # echo for each character typed.
+    # 
+    # This requires HighLine's character reader.  See the _character_
+    # attribute for details.
+    # 
+    # *Note*:  When using HighLine to manage echo on Unix based systems, we
+    # recommend installing the termios gem.  Without it, it's possible to type
+    # fast enough to have letters still show up (when reading character by
+    # character only).
+    #
+    attr_accessor :echo
+    #
+    # Use the Readline library to fetch input.  This allows input editing as
+    # well as keeping a history.  In addition, tab will auto-complete 
+    # within an Array of choices or a file listing.
+    # 
+    # *WARNING*:  This option is incompatible with all of HighLine's 
+    # character reading  modes and it causes HighLine to ignore the
+    # specified _input_ stream.
+    # 
+    attr_accessor :readline
+    #
+    # Used to control whitespace processing for the answer to this question.
+    # See HighLine::Question.remove_whitespace() for acceptable settings.
+    #
+    attr_accessor :whitespace
+    #
+    # Used to control character case processing for the answer to this question.
+    # See HighLine::Question.change_case() for acceptable settings.
+    #
+    attr_accessor :case
+    # Used to provide a default answer to this question.
+    attr_accessor :default
+    #
+    # If set to a Regexp, the answer must match (before type conversion).
+    # Can also be set to a Proc which will be called with the provided
+    # answer to validate with a +true+ or +false+ return.
+    #
+    attr_accessor :validate
+    # Used to control range checks for answer.
+    attr_accessor :above, :below
+    # If set, answer must pass an include?() check on this object.
+    attr_accessor :in
+    #
+    # Asks a yes or no confirmation question, to ensure a user knows what
+    # they have just agreed to.  If set to +true+ the question will be,
+    # "Are you sure?  "  Any other true value for this attribute is assumed
+    # to be the question to ask.  When +false+ or +nil+ (the default), 
+    # answers are not confirmed.
+    # 
+    attr_accessor :confirm
+    #
+    # When set, the user will be prompted for multiple answers which will
+    # be collected into an Array or Hash and returned as the final answer.
+    # 
+    # You can set _gather_ to an Integer to have an Array of exactly that
+    # many answers collected, or a String/Regexp to match an end input which
+    # will not be returned in the Array.
+    # 
+    # Optionally _gather_ can be set to a Hash.  In this case, the question
+    # will be asked once for each key and the answers will be returned in a
+    # Hash, mapped by key.  The <tt>@key</tt> variable is set before each 
+    # question is evaluated, so you can use it in your question.
+    # 
+    attr_accessor :gather
+    # 
+    # When set to a non *nil* value, this will be tried as an answer to the
+    # question.  If this answer passes validations, it will become the result
+    # without the user ever being prompted.  Otherwise this value is discarded, 
+    # and this Question is resolved as a normal call to HighLine.ask().
+    # 
+    attr_writer :first_answer
+    #
+    # The directory from which a user will be allowed to select files, when
+    # File or Pathname is specified as an _answer_type_.  Initially set to
+    # <tt>Pathname.new(File.expand_path(File.dirname($0)))</tt>.
+    # 
+    attr_accessor :directory
+    # 
+    # The glob pattern used to limit file selection when File or Pathname is
+    # specified as an _answer_type_.  Initially set to <tt>"*"</tt>.
+    # 
+    attr_accessor :glob
+    #
+    # A Hash that stores the various responses used by HighLine to notify
+    # the user.  The currently used responses and their purpose are as
+    # follows:
+    #
+    # <tt>:ambiguous_completion</tt>::  Used to notify the user of an
+    #                                   ambiguous answer the auto-completion
+    #                                   system cannot resolve.
+    # <tt>:ask_on_error</tt>::          This is the question that will be
+    #                                   redisplayed to the user in the event
+    #                                   of an error.  Can be set to
+    #                                   <tt>:question</tt> to repeat the
+    #                                   original question.
+    # <tt>:invalid_type</tt>::          The error message shown when a type
+    #                                   conversion fails.
+    # <tt>:no_completion</tt>::         Used to notify the user that their
+    #                                   selection does not have a valid
+    #                                   auto-completion match.
+    # <tt>:not_in_range</tt>::          Used to notify the user that a
+    #                                   provided answer did not satisfy
+    #                                   the range requirement tests.
+    # <tt>:not_valid</tt>::             The error message shown when
+    #                                   validation checks fail.
+    #
+    attr_reader :responses
+    #
+    # When set to +true+ the question is asked, but output does not progress to
+    # the next line.  The Cursor is moved back to the beginning of the question
+    # line and it is cleared so that all the contents of the line disappear from
+    # the screen.
+    #
+    attr_accessor :overwrite
+   
+    #
+    # Returns the provided _answer_string_ or the default answer for this
+    # Question if a default was set and the answer is empty.
+    #
+    def answer_or_default( answer_string )
+      if answer_string.length == 0 and not @default.nil?
+        @default
+      else
+        answer_string
+      end
+    end
+    
+    #
+    # Called late in the initialization process to build intelligent
+    # responses based on the details of this Question object.
+    #
+    def build_responses(  )
+      ### WARNING:  This code is quasi-duplicated in     ###
+      ### Menu.update_responses().  Check there too when ###
+      ### making changes!                                ###
+      append_default unless default.nil?
+      @responses = { :ambiguous_completion =>
+                       "Ambiguous choice.  " +
+                       "Please choose one of #{@answer_type.inspect}.",
+                     :ask_on_error         =>
+                       "?  ",
+                     :invalid_type         =>
+                       "You must enter a valid #{@answer_type}.",
+                     :no_completion        =>
+                       "You must choose one of " +
+                       "#{@answer_type.inspect}.",
+                     :not_in_range         =>
+                       "Your answer isn't within the expected range " +
+                       "(#{expected_range}).",
+                     :not_valid            =>
+                       "Your answer isn't valid (must match " +
+                       "#{@validate.inspect})." }.merge(@responses)
+      ### WARNING:  This code is quasi-duplicated in     ###
+      ### Menu.update_responses().  Check there too when ###
+      ### making changes!                                ###
+    end
+    
+    #
+    # Returns the provided _answer_string_ after changing character case by
+    # the rules of this Question.  Valid settings for whitespace are:
+    #
+    # +nil+::                        Do not alter character case. 
+    #                                (Default.)
+    # <tt>:up</tt>::                 Calls upcase().
+    # <tt>:upcase</tt>::             Calls upcase().
+    # <tt>:down</tt>::               Calls downcase().
+    # <tt>:downcase</tt>::           Calls downcase().
+    # <tt>:capitalize</tt>::         Calls capitalize().
+    # 
+    # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
+    # 
+    def change_case( answer_string )
+      if [:up, :upcase].include?(@case)
+        answer_string.upcase
+      elsif [:down, :downcase].include?(@case)
+        answer_string.downcase
+      elsif @case == :capitalize
+        answer_string.capitalize
+      else
+        answer_string
+      end
+    end
+
+    #
+    # Transforms the given _answer_string_ into the expected type for this
+    # Question.  Currently supported conversions are:
+    #
+    # <tt>[...]</tt>::         Answer must be a member of the passed Array. 
+    #                          Auto-completion is used to expand partial
+    #                          answers.
+    # <tt>lambda {...}</tt>::  Answer is passed to lambda for conversion.
+    # Date::                   Date.parse() is called with answer.
+    # DateTime::               DateTime.parse() is called with answer.
+    # File::                   The entered file name is auto-completed in 
+    #                          terms of _directory_ + _glob_, opened, and
+    #                          returned.
+    # Float::                  Answer is converted with Kernel.Float().
+    # Integer::                Answer is converted with Kernel.Integer().
+    # +nil+::                  Answer is left in String format.  (Default.)
+    # Pathname::               Same as File, save that a Pathname object is
+    #                          returned.
+    # String::                 Answer is converted with Kernel.String().
+    # Regexp::                 Answer is fed to Regexp.new().
+    # Symbol::                 The method to_sym() is called on answer and
+    #                          the result returned.
+    # <i>any other Class</i>:: The answer is passed on to
+    #                          <tt>Class.parse()</tt>.
+    #
+    # This method throws ArgumentError, if the conversion cannot be
+    # completed for any reason.
+    # 
+    def convert( answer_string )
+      if @answer_type.nil?
+        answer_string
+      elsif [Float, Integer, String].include?(@answer_type)
+        Kernel.send(@answer_type.to_s.to_sym, answer_string)
+      elsif @answer_type == Symbol
+        answer_string.to_sym
+      elsif @answer_type == Regexp
+        Regexp.new(answer_string)
+      elsif @answer_type.is_a?(Array) or [File, Pathname].include?(@answer_type)
+        # cheating, using OptionParser's Completion module
+        choices = selection
+        choices.extend(OptionParser::Completion)
+        answer = choices.complete(answer_string)
+        if answer.nil?
+          raise NoAutoCompleteMatch
+        end
+        if @answer_type.is_a?(Array)
+          answer.last
+        elsif @answer_type == File
+          File.open(File.join(@directory.to_s, answer.last))
+        else
+          Pathname.new(File.join(@directory.to_s, answer.last))
+        end
+      elsif [Date, DateTime].include?(@answer_type) or @answer_type.is_a?(Class)
+        @answer_type.parse(answer_string)
+      elsif @answer_type.is_a?(Proc)
+        @answer_type[answer_string]
+      end
+    end
+
+    # Returns a english explination of the current range settings.
+    def expected_range(  )
+      expected = [ ]
+
+      expected << "above #{@above}" unless @above.nil?
+      expected << "below #{@below}" unless @below.nil?
+      expected << "included in #{@in.inspect}" unless @in.nil?
+
+      case expected.size
+      when 0 then ""
+      when 1 then expected.first
+      when 2 then expected.join(" and ")
+      else        expected[0..-2].join(", ") + ", and #{expected.last}"
+      end
+    end
+
+    # Returns _first_answer_, which will be unset following this call.
+    def first_answer( )
+      @first_answer
+    ensure
+      @first_answer = nil
+    end
+    
+    # Returns true if _first_answer_ is set.
+    def first_answer?( )
+      not @first_answer.nil?
+    end
+    
+    #
+    # Returns +true+ if the _answer_object_ is greater than the _above_
+    # attribute, less than the _below_ attribute and included?()ed in the
+    # _in_ attribute.  Otherwise, +false+ is returned.  Any +nil+ attributes
+    # are not checked.
+    #
+    def in_range?( answer_object )
+      (@above.nil? or answer_object > @above) and
+      (@below.nil? or answer_object < @below) and
+      (@in.nil? or @in.include?(answer_object))
+    end
+    
+    #
+    # Returns the provided _answer_string_ after processing whitespace by
+    # the rules of this Question.  Valid settings for whitespace are:
+    #
+    # +nil+::                        Do not alter whitespace.
+    # <tt>:strip</tt>::              Calls strip().  (Default.)
+    # <tt>:chomp</tt>::              Calls chomp().
+    # <tt>:collapse</tt>::           Collapses all whitspace runs to a
+    #                                single space.
+    # <tt>:strip_and_collapse</tt>:: Calls strip(), then collapses all
+    #                                whitspace runs to a single space.
+    # <tt>:chomp_and_collapse</tt>:: Calls chomp(), then collapses all
+    #                                whitspace runs to a single space.
+    # <tt>:remove</tt>::             Removes all whitespace.
+    # 
+    # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
+    # 
+    # This process is skipped, for single character input.
+    # 
+    def remove_whitespace( answer_string )
+      if @whitespace.nil?
+        answer_string
+      elsif [:strip, :chomp].include?(@whitespace)
+        answer_string.send(@whitespace)
+      elsif @whitespace == :collapse
+        answer_string.gsub(/\s+/, " ")
+      elsif [:strip_and_collapse, :chomp_and_collapse].include?(@whitespace)
+        result = answer_string.send(@whitespace.to_s[/^[a-z]+/])
+        result.gsub(/\s+/, " ")
+      elsif @whitespace == :remove
+        answer_string.gsub(/\s+/, "")
+      else
+        answer_string
+      end
+    end
+
+    #
+    # Returns an Array of valid answers to this question.  These answers are
+    # only known when _answer_type_ is set to an Array of choices, File, or
+    # Pathname.  Any other time, this method will return an empty Array.
+    # 
+    def selection(  )
+      if @answer_type.is_a?(Array)
+        @answer_type
+      elsif [File, Pathname].include?(@answer_type)
+        Dir[File.join(@directory.to_s, @glob)].map do |file|
+          File.basename(file)
+        end
+      else
+        [ ]
+      end      
+    end
+    
+    # Stringifies the question to be asked.
+    def to_str(  )
+      @question
+    end
+
+    #
+    # Returns +true+ if the provided _answer_string_ is accepted by the 
+    # _validate_ attribute or +false+ if it's not.
+    # 
+    # It's important to realize that an answer is validated after whitespace
+    # and case handling.
+    #
+    def valid_answer?( answer_string )
+      @validate.nil? or 
+      (@validate.is_a?(Regexp) and answer_string =~ @validate) or
+      (@validate.is_a?(Proc)   and @validate[answer_string])
+    end
+    
+    private
+    
+    #
+    # Adds the default choice to the end of question between <tt>|...|</tt>.
+    # Trailing whitespace is preserved so the function of HighLine.say() is
+    # not affected.
+    #
+    def append_default(  )
+      if @question =~ /([\t ]+)\Z/
+        @question << "|#{@default}|#{$1}"
+      elsif @question == ""
+        @question << "|#{@default}|  "
+      elsif @question[-1, 1] == "\n"
+        @question[-2, 0] =  "  |#{@default}|"
+      else
+        @question << "  |#{@default}|"
+      end
+    end
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/system_extensions.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/lib/highline/system_extensions.rb
new file mode 100644 (file)
index 0000000..c738055
--- /dev/null
@@ -0,0 +1,184 @@
+#!/usr/local/bin/ruby -w
+
+# system_extensions.rb
+#
+#  Created by James Edward Gray II on 2006-06-14.
+#  Copyright 2006 Gray Productions. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+
+require "highline/compatibility"
+
+class HighLine
+  module SystemExtensions
+    module_function
+
+    JRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
+    
+    #
+    # This section builds character reading and terminal size functions
+    # to suit the proper platform we're running on.  Be warned:  Here be
+    # dragons!
+    #
+    begin
+      # Cygwin will look like Windows, but we want to treat it like a Posix OS:
+      raise LoadError, "Cygwin is a Posix OS." if RUBY_PLATFORM =~ /\bcygwin\b/i
+
+      require "Win32API"             # See if we're on Windows.
+
+      CHARACTER_MODE = "Win32API"    # For Debugging purposes only.
+
+      #
+      # Windows savvy getc().
+      # 
+      # *WARNING*:  This method ignores <tt>input</tt> and reads one
+      # character from +STDIN+!
+      # 
+      def get_character( input = STDIN )
+        Win32API.new("crtdll", "_getch", [ ], "L").Call
+      end
+
+      # A Windows savvy method to fetch the console columns, and rows.
+      def terminal_size
+        m_GetStdHandle               = Win32API.new( 'kernel32',
+                                                     'GetStdHandle',
+                                                     ['L'],
+                                                     'L' )
+        m_GetConsoleScreenBufferInfo = Win32API.new(
+          'kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L'
+        )
+
+        format        = 'SSSSSssssSS'
+        buf           = ([0] * format.size).pack(format)
+        stdout_handle = m_GetStdHandle.call(0xFFFFFFF5)
+        
+        m_GetConsoleScreenBufferInfo.call(stdout_handle, buf)
+        bufx, bufy, curx, cury, wattr,
+        left, top, right, bottom, maxx, maxy = buf.unpack(format)
+        return right - left + 1, bottom - top + 1
+      end
+    rescue LoadError                  # If we're not on Windows try...
+      begin
+        raise LoadError
+        require "termios"             # Unix, first choice termios.
+
+        CHARACTER_MODE = "termios"    # For Debugging purposes only.
+
+        #
+        # Unix savvy getc().  (First choice.)
+        #
+        # *WARNING*:  This method requires the "termios" library!
+        #
+        def get_character( input = STDIN )
+          old_settings = Termios.getattr(input)
+
+          new_settings                     =  old_settings.dup
+          new_settings.c_lflag             &= ~(Termios::ECHO | Termios::ICANON)
+          new_settings.c_cc[Termios::VMIN] =  1
+
+          begin
+            Termios.setattr(input, Termios::TCSANOW, new_settings)
+            input.getbyte
+          ensure
+            Termios.setattr(input, Termios::TCSANOW, old_settings)
+          end
+        end
+      rescue LoadError            # If our first choice fails, try using ffi-ncurses.
+        begin
+          require 'ffi-ncurses'   # The ffi gem is builtin to JRUBY and because stty does not
+                                  # work correctly in JRuby manually installing the ffi-ncurses
+                                  # gem is the only way to get highline to operate correctly in
+                                  # JRuby. The ncurses library is only present on unix platforms
+                                  # so this is not a solution for using highline in JRuby on
+                                  # windows.
+
+          CHARACTER_MODE = "ncurses"    # For Debugging purposes only.
+
+          #
+          # ncurses savvy getc().  (JRuby choice.)
+          #
+          def get_character( input = STDIN )
+            FFI::NCurses.initscr
+            FFI::NCurses.cbreak
+            begin
+              FFI::NCurses.curs_set 0
+              input.getbyte
+            ensure
+              FFI::NCurses.endwin
+            end
+          end
+
+        rescue LoadError => e            # If the ffi-ncurses choice fails, try using stty
+          if JRUBY
+            if e.message =~ /^no such file to load/
+              STDERR.puts "\n*** Using highline effectively in JRuby requires manually installing the ffi-ncurses gem.\n*** jruby -S gem install ffi-ncurses"
+            else
+              raise
+            end
+          end
+          CHARACTER_MODE = "stty"    # For Debugging purposes only.
+
+          #
+          # Unix savvy getc().  (Second choice.)
+          #
+          # *WARNING*:  This method requires the external "stty" program!
+          #
+          def get_character( input = STDIN )
+            raw_no_echo_mode
+
+            begin
+              input.getbyte
+            ensure
+              restore_mode
+            end
+          end
+
+          #
+          # Switched the input mode to raw and disables echo.
+          #
+          # *WARNING*:  This method requires the external "stty" program!
+          #
+          def raw_no_echo_mode
+            @state = `stty -g`
+            system "stty raw -echo -icanon isig"
+          end
+
+          #
+          # Restores a previously saved input mode.
+          #
+          # *WARNING*:  This method requires the external "stty" program!
+          #
+          def restore_mode
+            system "stty #{@state}"
+          end
+        end
+      end
+      if CHARACTER_MODE == 'ncurses'
+        #
+        # A ncurses savvy method to fetch the console columns, and rows.
+        #
+        def terminal_size
+          size = [80, 40]
+          FFI::NCurses.initscr
+          begin
+            size = FFI::NCurses.getmaxyx(stdscr).reverse
+          ensure
+            FFI::NCurses.endwin
+          end
+          size
+        end
+      else
+        # A Unix savvy method using stty that to fetch the console columns, and rows.
+        # ... stty does not work in JRuby
+        def terminal_size
+          if /solaris/ =~ RUBY_PLATFORM and
+            `stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/
+            [$2, $1].map { |c| x.to_i }
+          else
+            `stty size`.split.map { |x| x.to_i }.reverse
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/setup.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/setup.rb
new file mode 100644 (file)
index 0000000..0807023
--- /dev/null
@@ -0,0 +1,1360 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2004 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
+  module Enumerable
+    alias map collect
+  end
+end
+
+unless File.respond_to?(:read)   # Ruby 1.6
+  def File.read(fname)
+    open(fname) {|f|
+      return f.read
+    }
+  end
+end
+
+def File.binread(fname)
+  open(fname, 'rb') {|f|
+    return f.read
+  }
+end
+
+# for corrupted windows stat(2)
+def File.dir?(path)
+  File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+  raise SetupError, msg
+end
+
+#
+# Config
+#
+
+if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+  ARGV.delete(arg)
+  require arg.split(/=/, 2)[1]
+  $".push 'rbconfig.rb'
+else
+  require 'rbconfig'
+end
+
+def multipackage_install?
+  FileTest.directory?(File.dirname($0) + '/packages')
+end
+
+
+class ConfigItem
+  def initialize(name, template, default, desc)
+    @name = name.freeze
+    @template = template
+    @value = default
+    @default = default.dup.freeze
+    @description = desc
+  end
+
+  attr_reader :name
+  attr_reader :description
+
+  attr_accessor :default
+  alias help_default default
+
+  def help_opt
+    "--#{@name}=#{@template}"
+  end
+
+  def value
+    @value
+  end
+
+  def eval(table)
+    @value.gsub(%r<\$([^/]+)>) { table[$1] }
+  end
+
+  def set(val)
+    @value = check(val)
+  end
+
+  private
+
+  def check(val)
+    setup_rb_error "config: --#{name} requires argument" unless val
+    val
+  end
+end
+
+class BoolItem < ConfigItem
+  def config_type
+    'bool'
+  end
+
+  def help_opt
+    "--#{@name}"
+  end
+
+  private
+
+  def check(val)
+    return 'yes' unless val
+    unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
+      setup_rb_error "config: --#{@name} accepts only yes/no for argument"
+    end
+    (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
+  end
+end
+
+class PathItem < ConfigItem
+  def config_type
+    'path'
+  end
+
+  private
+
+  def check(path)
+    setup_rb_error "config: --#{@name} requires argument"  unless path
+    path[0,1] == '$' ? path : File.expand_path(path)
+  end
+end
+
+class ProgramItem < ConfigItem
+  def config_type
+    'program'
+  end
+end
+
+class SelectItem < ConfigItem
+  def initialize(name, template, default, desc)
+    super
+    @ok = template.split('/')
+  end
+
+  def config_type
+    'select'
+  end
+
+  private
+
+  def check(val)
+    unless @ok.include?(val.strip)
+      setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
+    end
+    val.strip
+  end
+end
+
+class PackageSelectionItem < ConfigItem
+  def initialize(name, template, default, help_default, desc)
+    super name, template, default, desc
+    @help_default = help_default
+  end
+
+  attr_reader :help_default
+
+  def config_type
+    'package'
+  end
+
+  private
+
+  def check(val)
+    unless File.dir?("packages/#{val}")
+      setup_rb_error "config: no such package: #{val}"
+    end
+    val
+  end
+end
+
+class ConfigTable_class
+
+  def initialize(items)
+    @items = items
+    @table = {}
+    items.each do |i|
+      @table[i.name] = i
+    end
+    ALIASES.each do |ali, name|
+      @table[ali] = @table[name]
+    end
+  end
+
+  include Enumerable
+
+  def each(&block)
+    @items.each(&block)
+  end
+
+  def key?(name)
+    @table.key?(name)
+  end
+
+  def lookup(name)
+    @table[name] or raise ArgumentError, "no such config item: #{name}"
+  end
+
+  def add(item)
+    @items.push item
+    @table[item.name] = item
+  end
+
+  def remove(name)
+    item = lookup(name)
+    @items.delete_if {|i| i.name == name }
+    @table.delete_if {|name, i| i.name == name }
+    item
+  end
+
+  def new
+    dup()
+  end
+
+  def savefile
+    '.config'
+  end
+
+  def load
+    begin
+      t = dup()
+      File.foreach(savefile()) do |line|
+        k, v = *line.split(/=/, 2)
+        t[k] = v.strip
+      end
+      t
+    rescue Errno::ENOENT
+      setup_rb_error $!.message + "#{File.basename($0)} config first"
+    end
+  end
+
+  def save
+    @items.each {|i| i.value }
+    File.open(savefile(), 'w') {|f|
+      @items.each do |i|
+        f.printf "%s=%s\n", i.name, i.value if i.value
+      end
+    }
+  end
+
+  def [](key)
+    lookup(key).eval(self)
+  end
+
+  def []=(key, val)
+    lookup(key).set val
+  end
+
+end
+
+c = ::Config::CONFIG
+
+rubypath = c['bindir'] + '/' + c['ruby_install_name']
+
+major = c['MAJOR'].to_i
+minor = c['MINOR'].to_i
+teeny = c['TEENY'].to_i
+version = "#{major}.#{minor}"
+
+# ruby ver. >= 1.4.4?
+newpath_p = ((major >= 2) or
+             ((major == 1) and
+              ((minor >= 5) or
+               ((minor == 4) and (teeny >= 4)))))
+
+if c['rubylibdir']
+  # V < 1.6.3
+  _stdruby         = c['rubylibdir']
+  _siteruby        = c['sitedir']
+  _siterubyver     = c['sitelibdir']
+  _siterubyverarch = c['sitearchdir']
+elsif newpath_p
+  # 1.4.4 <= V <= 1.6.3
+  _stdruby         = "$prefix/lib/ruby/#{version}"
+  _siteruby        = c['sitedir']
+  _siterubyver     = "$siteruby/#{version}"
+  _siterubyverarch = "$siterubyver/#{c['arch']}"
+else
+  # V < 1.4.4
+  _stdruby         = "$prefix/lib/ruby/#{version}"
+  _siteruby        = "$prefix/lib/ruby/#{version}/site_ruby"
+  _siterubyver     = _siteruby
+  _siterubyverarch = "$siterubyver/#{c['arch']}"
+end
+libdir = '-* dummy libdir *-'
+stdruby = '-* dummy rubylibdir *-'
+siteruby = '-* dummy site_ruby *-'
+siterubyver = '-* dummy site_ruby version *-'
+parameterize = lambda {|path|
+  path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
+      .sub(/\A#{Regexp.quote(libdir)}/,      '$libdir')\
+      .sub(/\A#{Regexp.quote(stdruby)}/,     '$stdruby')\
+      .sub(/\A#{Regexp.quote(siteruby)}/,    '$siteruby')\
+      .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
+}
+libdir          = parameterize.call(c['libdir'])
+stdruby         = parameterize.call(_stdruby)
+siteruby        = parameterize.call(_siteruby)
+siterubyver     = parameterize.call(_siterubyver)
+siterubyverarch = parameterize.call(_siterubyverarch)
+
+if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
+  makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+else
+  makeprog = 'make'
+end
+
+common_conf = [
+  PathItem.new('prefix', 'path', c['prefix'],
+               'path prefix of target environment'),
+  PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+               'the directory for commands'),
+  PathItem.new('libdir', 'path', libdir,
+               'the directory for libraries'),
+  PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+               'the directory for shared data'),
+  PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+               'the directory for man pages'),
+  PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+               'the directory for man pages'),
+  PathItem.new('stdruby', 'path', stdruby,
+               'the directory for standard ruby libraries'),
+  PathItem.new('siteruby', 'path', siteruby,
+      'the directory for version-independent aux ruby libraries'),
+  PathItem.new('siterubyver', 'path', siterubyver,
+               'the directory for aux ruby libraries'),
+  PathItem.new('siterubyverarch', 'path', siterubyverarch,
+               'the directory for aux ruby binaries'),
+  PathItem.new('rbdir', 'path', '$siterubyver',
+               'the directory for ruby scripts'),
+  PathItem.new('sodir', 'path', '$siterubyverarch',
+               'the directory for ruby extentions'),
+  PathItem.new('rubypath', 'path', rubypath,
+               'the path to set to #! line'),
+  ProgramItem.new('rubyprog', 'name', rubypath,
+                  'the ruby program using for installation'),
+  ProgramItem.new('makeprog', 'name', makeprog,
+                  'the make program to compile ruby extentions'),
+  SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+                 'shebang line (#!) editing mode'),
+  BoolItem.new('without-ext', 'yes/no', 'no',
+               'does not compile/install ruby extentions')
+]
+class ConfigTable_class   # open again
+  ALIASES = {
+    'std-ruby'         => 'stdruby',
+    'site-ruby-common' => 'siteruby',     # For backward compatibility
+    'site-ruby'        => 'siterubyver',  # For backward compatibility
+    'bin-dir'          => 'bindir',
+    'bin-dir'          => 'bindir',
+    'rb-dir'           => 'rbdir',
+    'so-dir'           => 'sodir',
+    'data-dir'         => 'datadir',
+    'ruby-path'        => 'rubypath',
+    'ruby-prog'        => 'rubyprog',
+    'ruby'             => 'rubyprog',
+    'make-prog'        => 'makeprog',
+    'make'             => 'makeprog'
+  }
+end
+multipackage_conf = [
+  PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+                           'package names that you want to install'),
+  PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+                           'package names that you do not want to install')
+]
+if multipackage_install?
+  ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
+else
+  ConfigTable = ConfigTable_class.new(common_conf)
+end
+
+
+module MetaConfigAPI
+
+  def eval_file_ifexist(fname)
+    instance_eval File.read(fname), fname, 1 if File.file?(fname)
+  end
+
+  def config_names
+    ConfigTable.map {|i| i.name }
+  end
+
+  def config?(name)
+    ConfigTable.key?(name)
+  end
+
+  def bool_config?(name)
+    ConfigTable.lookup(name).config_type == 'bool'
+  end
+
+  def path_config?(name)
+    ConfigTable.lookup(name).config_type == 'path'
+  end
+
+  def value_config?(name)
+    case ConfigTable.lookup(name).config_type
+    when 'bool', 'path'
+      true
+    else
+      false
+    end
+  end
+
+  def add_config(item)
+    ConfigTable.add item
+  end
+
+  def add_bool_config(name, default, desc)
+    ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+  end
+
+  def add_path_config(name, default, desc)
+    ConfigTable.add PathItem.new(name, 'path', default, desc)
+  end
+
+  def set_config_default(name, default)
+    ConfigTable.lookup(name).default = default
+  end
+
+  def remove_config(name)
+    ConfigTable.remove(name)
+  end
+
+end
+
+
+#
+# File Operations
+#
+
+module FileOperations
+
+  def mkdir_p(dirname, prefix = nil)
+    dirname = prefix + File.expand_path(dirname) if prefix
+    $stderr.puts "mkdir -p #{dirname}" if verbose?
+    return if no_harm?
+
+    # does not check '/'... it's too abnormal case
+    dirs = File.expand_path(dirname).split(%r<(?=/)>)
+    if /\A[a-z]:\z/i =~ dirs[0]
+      disk = dirs.shift
+      dirs[0] = disk + dirs[0]
+    end
+    dirs.each_index do |idx|
+      path = dirs[0..idx].join('')
+      Dir.mkdir path unless File.dir?(path)
+    end
+  end
+
+  def rm_f(fname)
+    $stderr.puts "rm -f #{fname}" if verbose?
+    return if no_harm?
+
+    if File.exist?(fname) or File.symlink?(fname)
+      File.chmod 0777, fname
+      File.unlink fname
+    end
+  end
+
+  def rm_rf(dn)
+    $stderr.puts "rm -rf #{dn}" if verbose?
+    return if no_harm?
+
+    Dir.chdir dn
+    Dir.foreach('.') do |fn|
+      next if fn == '.'
+      next if fn == '..'
+      if File.dir?(fn)
+        verbose_off {
+          rm_rf fn
+        }
+      else
+        verbose_off {
+          rm_f fn
+        }
+      end
+    end
+    Dir.chdir '..'
+    Dir.rmdir dn
+  end
+
+  def move_file(src, dest)
+    File.unlink dest if File.exist?(dest)
+    begin
+      File.rename src, dest
+    rescue
+      File.open(dest, 'wb') {|f| f.write File.binread(src) }
+      File.chmod File.stat(src).mode, dest
+      File.unlink src
+    end
+  end
+
+  def install(from, dest, mode, prefix = nil)
+    $stderr.puts "install #{from} #{dest}" if verbose?
+    return if no_harm?
+
+    realdest = prefix ? prefix + File.expand_path(dest) : dest
+    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+    str = File.binread(from)
+    if diff?(str, realdest)
+      verbose_off {
+        rm_f realdest if File.exist?(realdest)
+      }
+      File.open(realdest, 'wb') {|f|
+        f.write str
+      }
+      File.chmod mode, realdest
+
+      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+        if prefix
+          f.puts realdest.sub(prefix, '')
+        else
+          f.puts realdest
+        end
+      }
+    end
+  end
+
+  def diff?(new_content, path)
+    return true unless File.exist?(path)
+    new_content != File.binread(path)
+  end
+
+  def command(str)
+    $stderr.puts str if verbose?
+    system str or raise RuntimeError, "'system #{str}' failed"
+  end
+
+  def ruby(str)
+    command config('rubyprog') + ' ' + str
+  end
+  
+  def make(task = '')
+    command config('makeprog') + ' ' + task
+  end
+
+  def extdir?(dir)
+    File.exist?(dir + '/MANIFEST')
+  end
+
+  def all_files_in(dirname)
+    Dir.open(dirname) {|d|
+      return d.select {|ent| File.file?("#{dirname}/#{ent}") }
+    }
+  end
+
+  REJECT_DIRS = %w(
+    CVS SCCS RCS CVS.adm .svn
+  )
+
+  def all_dirs_in(dirname)
+    Dir.open(dirname) {|d|
+      return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
+    }
+  end
+
+end
+
+
+#
+# Main Installer
+#
+
+module HookUtils
+
+  def run_hook(name)
+    try_run_hook "#{curr_srcdir()}/#{name}" or
+    try_run_hook "#{curr_srcdir()}/#{name}.rb"
+  end
+
+  def try_run_hook(fname)
+    return false unless File.file?(fname)
+    begin
+      instance_eval File.read(fname), fname, 1
+    rescue
+      setup_rb_error "hook #{fname} failed:\n" + $!.message
+    end
+    true
+  end
+
+end
+
+
+module HookScriptAPI
+
+  def get_config(key)
+    @config[key]
+  end
+
+  alias config get_config
+
+  def set_config(key, val)
+    @config[key] = val
+  end
+
+  #
+  # srcdir/objdir (works only in the package directory)
+  #
+
+  #abstract srcdir_root
+  #abstract objdir_root
+  #abstract relpath
+
+  def curr_srcdir
+    "#{srcdir_root()}/#{relpath()}"
+  end
+
+  def curr_objdir
+    "#{objdir_root()}/#{relpath()}"
+  end
+
+  def srcfile(path)
+    "#{curr_srcdir()}/#{path}"
+  end
+
+  def srcexist?(path)
+    File.exist?(srcfile(path))
+  end
+
+  def srcdirectory?(path)
+    File.dir?(srcfile(path))
+  end
+  
+  def srcfile?(path)
+    File.file? srcfile(path)
+  end
+
+  def srcentries(path = '.')
+    Dir.open("#{curr_srcdir()}/#{path}") {|d|
+      return d.to_a - %w(. ..)
+    }
+  end
+
+  def srcfiles(path = '.')
+    srcentries(path).select {|fname|
+      File.file?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+  def srcdirectories(path = '.')
+    srcentries(path).select {|fname|
+      File.dir?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+end
+
+
+class ToplevelInstaller
+
+  Version   = '3.3.1'
+  Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
+
+  TASKS = [
+    [ 'all',      'do config, setup, then install' ],
+    [ 'config',   'saves your configurations' ],
+    [ 'show',     'shows current configuration' ],
+    [ 'setup',    'compiles ruby extentions and others' ],
+    [ 'install',  'installs files' ],
+    [ 'clean',    "does `make clean' for each extention" ],
+    [ 'distclean',"does `make distclean' for each extention" ]
+  ]
+
+  def ToplevelInstaller.invoke
+    instance().invoke
+  end
+
+  @singleton = nil
+
+  def ToplevelInstaller.instance
+    @singleton ||= new(File.dirname($0))
+    @singleton
+  end
+
+  include MetaConfigAPI
+
+  def initialize(ardir_root)
+    @config = nil
+    @options = { 'verbose' => true }
+    @ardir = File.expand_path(ardir_root)
+  end
+
+  def inspect
+    "#<#{self.class} #{__id__()}>"
+  end
+
+  def invoke
+    run_metaconfigs
+    case task = parsearg_global()
+    when nil, 'all'
+      @config = load_config('config')
+      parsearg_config
+      init_installers
+      exec_config
+      exec_setup
+      exec_install
+    else
+      @config = load_config(task)
+      __send__ "parsearg_#{task}"
+      init_installers
+      __send__ "exec_#{task}"
+    end
+  end
+  
+  def run_metaconfigs
+    eval_file_ifexist "#{@ardir}/metaconfig"
+  end
+
+  def load_config(task)
+    case task
+    when 'config'
+      ConfigTable.new
+    when 'clean', 'distclean'
+      if File.exist?(ConfigTable.savefile)
+      then ConfigTable.load
+      else ConfigTable.new
+      end
+    else
+      ConfigTable.load
+    end
+  end
+
+  def init_installers
+    @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
+  end
+
+  #
+  # Hook Script API bases
+  #
+
+  def srcdir_root
+    @ardir
+  end
+
+  def objdir_root
+    '.'
+  end
+
+  def relpath
+    '.'
+  end
+
+  #
+  # Option Parsing
+  #
+
+  def parsearg_global
+    valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
+
+    while arg = ARGV.shift
+      case arg
+      when /\A\w+\z/
+        setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
+        return arg
+
+      when '-q', '--quiet'
+        @options['verbose'] = false
+
+      when       '--verbose'
+        @options['verbose'] = true
+
+      when '-h', '--help'
+        print_usage $stdout
+        exit 0
+
+      when '-v', '--version'
+        puts "#{File.basename($0)} version #{Version}"
+        exit 0
+      
+      when '--copyright'
+        puts Copyright
+        exit 0
+
+      else
+        setup_rb_error "unknown global option '#{arg}'"
+      end
+    end
+
+    nil
+  end
+
+
+  def parsearg_no_options
+    unless ARGV.empty?
+      setup_rb_error "#{task}:  unknown options: #{ARGV.join ' '}"
+    end
+  end
+
+  alias parsearg_show       parsearg_no_options
+  alias parsearg_setup      parsearg_no_options
+  alias parsearg_clean      parsearg_no_options
+  alias parsearg_distclean  parsearg_no_options
+
+  def parsearg_config
+    re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
+    @options['config-opt'] = []
+
+    while i = ARGV.shift
+      if /\A--?\z/ =~ i
+        @options['config-opt'] = ARGV.dup
+        break
+      end
+      m = re.match(i)  or setup_rb_error "config: unknown option #{i}"
+      name, value = *m.to_a[1,2]
+      @config[name] = value
+    end
+  end
+
+  def parsearg_install
+    @options['no-harm'] = false
+    @options['install-prefix'] = ''
+    while a = ARGV.shift
+      case a
+      when /\A--no-harm\z/
+        @options['no-harm'] = true
+      when /\A--prefix=(.*)\z/
+        path = $1
+        path = File.expand_path(path) unless path[0,1] == '/'
+        @options['install-prefix'] = path
+      else
+        setup_rb_error "install: unknown option #{a}"
+      end
+    end
+  end
+
+  def print_usage(out)
+    out.puts 'Typical Installation Procedure:'
+    out.puts "  $ ruby #{File.basename $0} config"
+    out.puts "  $ ruby #{File.basename $0} setup"
+    out.puts "  # ruby #{File.basename $0} install (may require root privilege)"
+    out.puts
+    out.puts 'Detailed Usage:'
+    out.puts "  ruby #{File.basename $0} <global option>"
+    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+    fmt = "  %-24s %s\n"
+    out.puts
+    out.puts 'Global options:'
+    out.printf fmt, '-q,--quiet',   'suppress message outputs'
+    out.printf fmt, '   --verbose', 'output messages verbosely'
+    out.printf fmt, '-h,--help',    'print this message'
+    out.printf fmt, '-v,--version', 'print version and quit'
+    out.printf fmt, '   --copyright',  'print copyright and quit'
+    out.puts
+    out.puts 'Tasks:'
+    TASKS.each do |name, desc|
+      out.printf fmt, name, desc
+    end
+
+    fmt = "  %-24s %s [%s]\n"
+    out.puts
+    out.puts 'Options for CONFIG or ALL:'
+    ConfigTable.each do |item|
+      out.printf fmt, item.help_opt, item.description, item.help_default
+    end
+    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+    out.puts
+    out.puts 'Options for INSTALL:'
+    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+    out.printf fmt, '--prefix=path',  'install path prefix', '$prefix'
+    out.puts
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    @installer.exec_config
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    @installer.exec_setup
+  end
+
+  def exec_install
+    @installer.exec_install
+  end
+
+  def exec_show
+    ConfigTable.each do |i|
+      printf "%-20s %s\n", i.name, i.value
+    end
+  end
+
+  def exec_clean
+    @installer.exec_clean
+  end
+
+  def exec_distclean
+    @installer.exec_distclean
+  end
+
+end
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+  include HookUtils
+  include HookScriptAPI
+  include FileOperations
+
+  def initialize(ardir)
+    super
+    @packages = all_dirs_in("#{@ardir}/packages")
+    raise 'no package exists' if @packages.empty?
+  end
+
+  def run_metaconfigs
+    eval_file_ifexist "#{@ardir}/metaconfig"
+    @packages.each do |name|
+      eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
+    end
+  end
+
+  def init_installers
+    @installers = {}
+    @packages.each do |pack|
+      @installers[pack] = Installer.new(@config, @options,
+                                       "#{@ardir}/packages/#{pack}",
+                                       "packages/#{pack}")
+    end
+
+    with    = extract_selection(config('with'))
+    without = extract_selection(config('without'))
+    @selected = @installers.keys.select {|name|
+                  (with.empty? or with.include?(name)) \
+                      and not without.include?(name)
+                }
+  end
+
+  def extract_selection(list)
+    a = list.split(/,/)
+    a.each do |name|
+      setup_rb_error "no such package: #{name}"  unless @installers.key?(name)
+    end
+    a
+  end
+
+  def print_usage(f)
+    super
+    f.puts 'Inluded packages:'
+    f.puts '  ' + @packages.sort.join(' ')
+    f.puts
+  end
+
+  #
+  # multi-package metaconfig API
+  #
+
+  attr_reader :packages
+
+  def declare_packages(list)
+    raise 'package list is empty' if list.empty?
+    list.each do |name|
+      raise "directory packages/#{name} does not exist"\
+              unless File.dir?("#{@ardir}/packages/#{name}")
+    end
+    @packages = list
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    run_hook 'pre-config'
+    each_selected_installers {|inst| inst.exec_config }
+    run_hook 'post-config'
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    run_hook 'pre-setup'
+    each_selected_installers {|inst| inst.exec_setup }
+    run_hook 'post-setup'
+  end
+
+  def exec_install
+    run_hook 'pre-install'
+    each_selected_installers {|inst| inst.exec_install }
+    run_hook 'post-install'
+  end
+
+  def exec_clean
+    rm_f ConfigTable.savefile
+    run_hook 'pre-clean'
+    each_selected_installers {|inst| inst.exec_clean }
+    run_hook 'post-clean'
+  end
+
+  def exec_distclean
+    rm_f ConfigTable.savefile
+    run_hook 'pre-distclean'
+    each_selected_installers {|inst| inst.exec_distclean }
+    run_hook 'post-distclean'
+  end
+
+  #
+  # lib
+  #
+
+  def each_selected_installers
+    Dir.mkdir 'packages' unless File.dir?('packages')
+    @selected.each do |pack|
+      $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
+      Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+      Dir.chdir "packages/#{pack}"
+      yield @installers[pack]
+      Dir.chdir '../..'
+    end
+  end
+
+  def verbose?
+    @options['verbose']
+  end
+
+  def no_harm?
+    @options['no-harm']
+  end
+
+end
+
+
+class Installer
+
+  FILETYPES = %w( bin lib ext data )
+
+  include HookScriptAPI
+  include HookUtils
+  include FileOperations
+
+  def initialize(config, opt, srcroot, objroot)
+    @config = config
+    @options = opt
+    @srcdir = File.expand_path(srcroot)
+    @objdir = File.expand_path(objroot)
+    @currdir = '.'
+  end
+
+  def inspect
+    "#<#{self.class} #{File.basename(@srcdir)}>"
+  end
+
+  #
+  # Hook Script API base methods
+  #
+
+  def srcdir_root
+    @srcdir
+  end
+
+  def objdir_root
+    @objdir
+  end
+
+  def relpath
+    @currdir
+  end
+
+  #
+  # configs/options
+  #
+
+  def no_harm?
+    @options['no-harm']
+  end
+
+  def verbose?
+    @options['verbose']
+  end
+
+  def verbose_off
+    begin
+      save, @options['verbose'] = @options['verbose'], false
+      yield
+    ensure
+      @options['verbose'] = save
+    end
+  end
+
+  #
+  # TASK config
+  #
+
+  def exec_config
+    exec_task_traverse 'config'
+  end
+
+  def config_dir_bin(rel)
+  end
+
+  def config_dir_lib(rel)
+  end
+
+  def config_dir_ext(rel)
+    extconf if extdir?(curr_srcdir())
+  end
+
+  def extconf
+    opt = @options['config-opt'].join(' ')
+    command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
+  end
+
+  def config_dir_data(rel)
+  end
+
+  #
+  # TASK setup
+  #
+
+  def exec_setup
+    exec_task_traverse 'setup'
+  end
+
+  def setup_dir_bin(rel)
+    all_files_in(curr_srcdir()).each do |fname|
+      adjust_shebang "#{curr_srcdir()}/#{fname}"
+    end
+  end
+
+  def adjust_shebang(path)
+    return if no_harm?
+    tmpfile = File.basename(path) + '.tmp'
+    begin
+      File.open(path, 'rb') {|r|
+        first = r.gets
+        return unless File.basename(config('rubypath')) == 'ruby'
+        return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
+        $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
+        File.open(tmpfile, 'wb') {|w|
+          w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
+          w.write r.read
+        }
+        move_file tmpfile, File.basename(path)
+      }
+    ensure
+      File.unlink tmpfile if File.exist?(tmpfile)
+    end
+  end
+
+  def setup_dir_lib(rel)
+  end
+
+  def setup_dir_ext(rel)
+    make if extdir?(curr_srcdir())
+  end
+
+  def setup_dir_data(rel)
+  end
+
+  #
+  # TASK install
+  #
+
+  def exec_install
+    rm_f 'InstalledFiles'
+    exec_task_traverse 'install'
+  end
+
+  def install_dir_bin(rel)
+    install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
+  end
+
+  def install_dir_lib(rel)
+    install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
+  end
+
+  def install_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    install_files ruby_extentions('.'),
+                  "#{config('sodir')}/#{File.dirname(rel)}",
+                  0555
+  end
+
+  def install_dir_data(rel)
+    install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
+  end
+
+  def install_files(list, dest, mode)
+    mkdir_p dest, @options['install-prefix']
+    list.each do |fname|
+      install fname, dest, mode, @options['install-prefix']
+    end
+  end
+
+  def ruby_scripts
+    collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
+  end
+  
+  # picked up many entries from cvs-1.11.1/src/ignore.c
+  reject_patterns = %w( 
+    core RCSLOG tags TAGS .make.state
+    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+    *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+    *.org *.in .*
+  )
+  mapping = {
+    '.' => '\.',
+    '$' => '\$',
+    '#' => '\#',
+    '*' => '.*'
+  }
+  REJECT_PATTERNS = Regexp.new('\A(?:' +
+                               reject_patterns.map {|pat|
+                                 pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
+                               }.join('|') +
+                               ')\z')
+
+  def collect_filenames_auto
+    mapdir((existfiles() - hookfiles()).reject {|fname|
+             REJECT_PATTERNS =~ fname
+           })
+  end
+
+  def existfiles
+    all_files_in(curr_srcdir()) | all_files_in('.')
+  end
+
+  def hookfiles
+    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+      %w( config setup install clean ).map {|t| sprintf(fmt, t) }
+    }.flatten
+  end
+
+  def mapdir(filelist)
+    filelist.map {|fname|
+      if File.exist?(fname)   # objdir
+        fname
+      else                    # srcdir
+        File.join(curr_srcdir(), fname)
+      end
+    }
+  end
+
+  def ruby_extentions(dir)
+    Dir.open(dir) {|d|
+      ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
+      if ents.empty?
+        setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+      end
+      return ents
+    }
+  end
+
+  #
+  # TASK clean
+  #
+
+  def exec_clean
+    exec_task_traverse 'clean'
+    rm_f ConfigTable.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  def clean_dir_bin(rel)
+  end
+
+  def clean_dir_lib(rel)
+  end
+
+  def clean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'clean' if File.file?('Makefile')
+  end
+
+  def clean_dir_data(rel)
+  end
+
+  #
+  # TASK distclean
+  #
+
+  def exec_distclean
+    exec_task_traverse 'distclean'
+    rm_f ConfigTable.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  def distclean_dir_bin(rel)
+  end
+
+  def distclean_dir_lib(rel)
+  end
+
+  def distclean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'distclean' if File.file?('Makefile')
+  end
+
+  #
+  # lib
+  #
+
+  def exec_task_traverse(task)
+    run_hook "pre-#{task}"
+    FILETYPES.each do |type|
+      if config('without-ext') == 'yes' and type == 'ext'
+        $stderr.puts 'skipping ext/* by user option' if verbose?
+        next
+      end
+      traverse task, type, "#{task}_dir_#{type}"
+    end
+    run_hook "post-#{task}"
+  end
+
+  def traverse(task, rel, mid)
+    dive_into(rel) {
+      run_hook "pre-#{task}"
+      __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+      all_dirs_in(curr_srcdir()).each do |d|
+        traverse task, "#{rel}/#{d}", mid
+      end
+      run_hook "post-#{task}"
+    }
+  end
+
+  def dive_into(rel)
+    return unless File.dir?("#{@srcdir}/#{rel}")
+
+    dir = File.basename(rel)
+    Dir.mkdir dir unless File.dir?(dir)
+    prevdir = Dir.pwd
+    Dir.chdir dir
+    $stderr.puts '---> ' + rel if verbose?
+    @currdir = rel
+    yield
+    Dir.chdir prevdir
+    $stderr.puts '<--- ' + rel if verbose?
+    @currdir = File.dirname(rel)
+  end
+
+end
+
+
+if $0 == __FILE__
+  begin
+    if multipackage_install?
+      ToplevelInstallerMulti.invoke
+    else
+      ToplevelInstaller.invoke
+    end
+  rescue SetupError
+    raise if $DEBUG
+    $stderr.puts $!.message
+    $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+    exit 1
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_color_scheme.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_color_scheme.rb
new file mode 100644 (file)
index 0000000..cb5cbd0
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/local/bin/ruby -w
+
+# tc_color_scheme.rb
+#
+#  Created by Jeremy Hinegardner on 2007-01-24.  
+#  Copyright 2007 Jeremy Hinegardner. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+
+require "test/unit"
+
+require "highline"
+require "stringio"
+
+class TestColorScheme < Test::Unit::TestCase
+  def setup
+    @input    = StringIO.new
+    @output   = StringIO.new
+    @terminal = HighLine.new(@input, @output)
+    
+    @old_color_scheme = HighLine.color_scheme
+  end
+  
+  def teardown
+    HighLine.color_scheme = @old_color_scheme
+  end
+
+  def test_using_color_scheme
+    assert_equal(false,HighLine.using_color_scheme?)
+
+    HighLine.color_scheme = HighLine::ColorScheme.new
+    assert_equal(true,HighLine.using_color_scheme?)
+  end
+
+  def test_scheme
+    HighLine.color_scheme = HighLine::SampleColorScheme.new
+
+    @terminal.say("This should be <%= color('warning yellow', :warning) %>.")
+    assert_equal("This should be \e[1m\e[33mwarning yellow\e[0m.\n",@output.string)
+    @output.rewind
+    
+    @terminal.say("This should be <%= color('warning yellow', 'warning') %>.")
+    assert_equal("This should be \e[1m\e[33mwarning yellow\e[0m.\n",@output.string)
+    @output.rewind
+
+    @terminal.say("This should be <%= color('warning yellow', 'WarNing') %>.")
+    assert_equal("This should be \e[1m\e[33mwarning yellow\e[0m.\n",@output.string)
+    @output.rewind
+
+    # turn it back off, should raise an exception
+    HighLine.color_scheme = @old_color_scheme
+    assert_raises(NameError) {
+      @terminal.say("This should be <%= color('nothing at all', :error) %>.")
+    }
+  end
+end 
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_highline.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_highline.rb
new file mode 100644 (file)
index 0000000..ee62a04
--- /dev/null
@@ -0,0 +1,823 @@
+#!/usr/local/bin/ruby -w
+
+# tc_highline.rb
+#
+#  Created by James Edward Gray II on 2005-04-26.
+#  Copyright 2005 Gray Productions. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+
+require "test/unit"
+
+require "highline"
+require "stringio"
+
+if HighLine::CHARACTER_MODE == "Win32API"
+  class HighLine
+    # Override Windows' character reading so it's not tied to STDIN.
+    def get_character( input = STDIN )
+      input.getc
+    end
+  end
+end
+
+class TestHighLine < Test::Unit::TestCase
+  def setup
+    @input    = StringIO.new
+    @output   = StringIO.new
+    @terminal = HighLine.new(@input, @output)  
+  end
+  
+  def test_agree
+    @input << "y\nyes\nYES\nHell no!\nNo\n"
+    @input.rewind
+
+    assert_equal(true, @terminal.agree("Yes or no?  "))
+    assert_equal(true, @terminal.agree("Yes or no?  "))
+    assert_equal(true, @terminal.agree("Yes or no?  "))
+    assert_equal(false, @terminal.agree("Yes or no?  "))
+    
+    @input.truncate(@input.rewind)
+    @input << "yellow"
+    @input.rewind
+
+    assert_equal(true, @terminal.agree("Yes or no?  ", :getc))
+  end
+  
+  def test_agree_with_block
+    @input << "\n\n"
+    @input.rewind
+
+    assert_equal(true, @terminal.agree("Yes or no?  ") { |q| q.default = "y" })
+    assert_equal(false, @terminal.agree("Yes or no?  ") { |q| q.default = "n" })
+  end
+  
+  def test_ask
+    name = "James Edward Gray II"
+    @input << name << "\n"
+    @input.rewind
+
+    assert_equal(name, @terminal.ask("What is your name?  "))
+    
+    assert_raise(EOFError) { @terminal.ask("Any input left?  ") }
+  end
+  
+  def test_bug_fixes
+    # auto-complete bug
+    @input << "ruby\nRuby\n"
+    @input.rewind
+
+    languages = [:Perl, :Python, :Ruby]
+    answer = @terminal.ask( "What is your favorite programming language?  ",
+                            languages )
+    assert_equal(languages.last, answer)
+
+    @input.truncate(@input.rewind)
+    @input << "ruby\n"
+    @input.rewind
+
+    answer = @terminal.ask( "What is your favorite programming language?  ",
+                            languages ) do |q|
+      q.case = :capitalize
+    end
+    assert_equal(languages.last, answer)
+    
+    # poor auto-complete error message
+    @input.truncate(@input.rewind)
+    @input << "lisp\nruby\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask( "What is your favorite programming language?  ",
+                            languages ) do |q|
+      q.case = :capitalize
+    end
+    assert_equal(languages.last, answer)
+    assert_equal( "What is your favorite programming language?  " +
+                  "You must choose one of [:Perl, :Python, :Ruby].\n" +
+                  "?  ", @output.string )
+  end
+  
+  def test_case_changes
+    @input << "jeg2\n"
+    @input.rewind
+
+    answer = @terminal.ask("Enter your initials  ") do |q|
+      q.case = :up
+    end
+    assert_equal("JEG2", answer)
+
+    @input.truncate(@input.rewind)
+    @input << "cRaZY\n"
+    @input.rewind
+
+    answer = @terminal.ask("Enter a search string:  ") do |q|
+      q.case = :down
+    end
+    assert_equal("crazy", answer)
+  end
+
+  def test_character_echo
+    @input << "password\r"
+    @input.rewind
+
+    answer = @terminal.ask("Please enter your password:  ") do |q|
+      q.echo = "*"
+    end
+    assert_equal("password", answer)
+    assert_equal("Please enter your password:  ********\n", @output.string)
+
+    @input.truncate(@input.rewind)
+    @input << "2"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask( "Select an option (1, 2 or 3):  ",
+                            Integer ) do |q|
+      q.echo      = "*"
+      q.character = true
+    end
+    assert_equal(2, answer)
+    assert_equal("Select an option (1, 2 or 3):  *\n", @output.string)
+  end
+
+  def test_backspace_does_not_enter_prompt
+      @input << "\b\b"
+      @input.rewind
+      answer = @terminal.ask("Please enter your password: ") do |q| 
+          q.echo = "*" 
+      end
+      assert_equal("", answer)
+      assert_equal("Please enter your password: \n",@output.string)
+  end
+  
+  def test_readline_on_non_echo_question_has_prompt
+    @input << "you can't see me"
+    @input.rewind
+    answer = @terminal.ask("Please enter some hidden text: ") do |q|
+      q.readline = true
+      q.echo = "*"
+    end
+    assert_equal("you can't see me", answer)
+    assert_equal("Please enter some hidden text: ****************\n",@output.string)
+  end
+  
+  def test_character_reading
+    # WARNING:  This method does NOT cover Unix and Windows savvy testing!
+    @input << "12345"
+    @input.rewind
+
+    answer = @terminal.ask("Enter a single digit:  ", Integer) do |q|
+      q.character = :getc
+    end
+    assert_equal(1, answer)
+  end
+
+  def test_color
+    @terminal.say("This should be <%= BLUE %>blue<%= CLEAR %>!")
+    assert_equal("This should be \e[34mblue\e[0m!\n", @output.string)
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say( "This should be " +
+                   "<%= BOLD + ON_WHITE %>bold on white<%= CLEAR %>!" )
+    assert_equal( "This should be \e[1m\e[47mbold on white\e[0m!\n",
+                  @output.string )
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("This should be <%= color('cyan', CYAN) %>!")
+    assert_equal("This should be \e[36mcyan\e[0m!\n", @output.string)
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say( "This should be " +
+                   "<%= color('blinking on red', :blink, :on_red) %>!" )
+    assert_equal( "This should be \e[5m\e[41mblinking on red\e[0m!\n",
+                  @output.string )
+
+    @output.truncate(@output.rewind)
+
+    # turn off color
+    old_setting = HighLine.use_color?
+    assert_nothing_raised(Exception) { HighLine.use_color = false }
+    @terminal.say("This should be <%= color('cyan', CYAN) %>!")
+    assert_equal("This should be cyan!\n", @output.string)
+    HighLine.use_color = old_setting
+  end
+                                  
+  def test_confirm
+    @input << "junk.txt\nno\nsave.txt\ny\n"
+    @input.rewind
+
+    answer = @terminal.ask("Enter a filename:  ") do |q|
+      q.confirm = "Are you sure you want to overwrite <%= @answer %>?  "
+      q.responses[:ask_on_error] = :question
+    end
+    assert_equal("save.txt", answer)
+    assert_equal( "Enter a filename:  " +
+                  "Are you sure you want to overwrite junk.txt?  " +
+                  "Enter a filename:  " +
+                  "Are you sure you want to overwrite save.txt?  ",
+                  @output.string )
+
+    @input.truncate(@input.rewind)
+    @input << "junk.txt\nyes\nsave.txt\nn\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask("Enter a filename:  ") do |q|
+      q.confirm = "Are you sure you want to overwrite <%= @answer %>?  "
+    end
+    assert_equal("junk.txt", answer)
+    assert_equal( "Enter a filename:  " +
+                  "Are you sure you want to overwrite junk.txt?  ",
+                  @output.string )
+  end
+  
+  def test_defaults
+    @input << "\nNo Comment\n"
+    @input.rewind
+
+    answer = @terminal.ask("Are you sexually active?  ") do |q|
+      q.validate = /\Ay(?:es)?|no?|no comment\Z/i
+    end
+    assert_equal("No Comment", answer)
+
+    @input.truncate(@input.rewind)
+    @input << "\nYes\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask("Are you sexually active?  ") do |q|
+      q.default  = "No Comment"
+      q.validate = /\Ay(?:es)?|no?|no comment\Z/i
+    end
+    assert_equal("No Comment", answer)
+    assert_equal( "Are you sexually active?  |No Comment|  ",
+                  @output.string )
+  end
+  
+  def test_empty
+    @input << "\n"
+    @input.rewind
+
+    answer = @terminal.ask("") do |q|
+      q.default  = "yes"
+      q.validate = /\Ay(?:es)?|no?\Z/i
+    end
+    assert_equal("yes", answer)
+  end
+  
+  def test_erb
+    @terminal.say( "The integers from 1 to 10 are:\n" +
+                   "% (1...10).each do |n|\n" +
+                   "\t<%= n %>,\n" +
+                   "% end\n" +
+                   "\tand 10" )
+    assert_equal( "The integers from 1 to 10 are:\n" +
+                  "\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n" +
+                  "\t6,\n\t7,\n\t8,\n\t9,\n\tand 10\n",
+                  @output.string )
+  end
+  
+  def test_files
+    @input << "#{File.basename(__FILE__)[0, 5]}\n"
+    @input.rewind
+
+    file = @terminal.ask("Select a file:  ", File) do |q|
+      q.directory = File.expand_path(File.dirname(__FILE__))
+      q.glob      = "*.rb"
+    end
+    assert_instance_of(File, file)
+    assert_equal("#!/usr/local/bin/ruby -w\n", file.gets)
+    assert_equal("\n", file.gets)
+    assert_equal("# tc_highline.rb\n", file.gets)
+    file.close
+
+    @input.rewind
+
+    pathname = @terminal.ask("Select a file:  ", Pathname) do |q|
+      q.directory = File.expand_path(File.dirname(__FILE__))
+      q.glob      = "*.rb"
+    end
+    assert_instance_of(Pathname, pathname)
+    assert_equal(File.size(__FILE__), pathname.size)
+  end
+  
+  def test_gather
+    @input << "James\nDana\nStorm\nGypsy\n\n"
+    @input.rewind
+
+    answers = @terminal.ask("Enter four names:") do |q|
+      q.gather = 4
+    end
+    assert_equal(%w{James Dana Storm Gypsy}, answers)
+    assert_equal("\n", @input.gets)
+    assert_equal("Enter four names:\n", @output.string)
+
+    @input.rewind
+
+    answers = @terminal.ask("Enter four names:") do |q|
+      q.gather = ""
+    end
+    assert_equal(%w{James Dana Storm Gypsy}, answers)
+
+    @input.rewind
+
+    answers = @terminal.ask("Enter four names:") do |q|
+      q.gather = /^\s*$/
+    end
+    assert_equal(%w{James Dana Storm Gypsy}, answers)
+
+    @input.truncate(@input.rewind)
+    @input << "29\n49\n30\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answers = @terminal.ask("<%= @key %>:  ", Integer) do |q|
+      q.gather = { "Age" => 0, "Wife's Age" => 0, "Father's Age" => 0}
+    end
+    assert_equal( { "Age" => 29, "Wife's Age" => 30, "Father's Age" => 49},
+                  answers )
+    assert_equal("Age:  Father's Age:  Wife's Age:  ", @output.string)
+  end
+  
+  def test_lists
+    digits     = %w{Zero One Two Three Four Five Six Seven Eight Nine}
+    erb_digits = digits.dup
+    erb_digits[erb_digits.index("Five")] = "<%= color('Five', :blue) %%>"
+    
+    @terminal.say("<%= list(#{digits.inspect}) %>")
+    assert_equal(digits.map { |d| "#{d}\n" }.join, @output.string)
+    
+    @output.truncate(@output.rewind)
+
+    @terminal.say("<%= list(#{digits.inspect}, :inline) %>")
+    assert_equal( digits[0..-2].join(", ") + " or #{digits.last}\n",
+                  @output.string )
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("<%= list(#{digits.inspect}, :inline, ' and ') %>")
+    assert_equal( digits[0..-2].join(", ") + " and #{digits.last}\n",
+                  @output.string )
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("<%= list(#{digits.inspect}, :columns_down, 3) %>")
+    assert_equal( "Zero   Four   Eight\n" +
+                  "One    Five   Nine \n" +
+                  "Two    Six  \n" +
+                  "Three  Seven\n",
+                  @output.string )
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("<%= list(#{erb_digits.inspect}, :columns_down, 3) %>")
+    assert_equal( "Zero   Four   Eight\n" +
+                  "One    \e[34mFive\e[0m   Nine \n" +
+                  "Two    Six  \n" +
+                  "Three  Seven\n",
+                  @output.string )
+
+    colums_of_twenty = ["12345678901234567890"] * 5
+    
+    @output.truncate(@output.rewind)
+
+    @terminal.say("<%= list(#{colums_of_twenty.inspect}, :columns_down) %>")
+    assert_equal( "12345678901234567890  12345678901234567890  " +
+                  "12345678901234567890\n" +
+                  "12345678901234567890  12345678901234567890\n",
+                  @output.string )
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("<%= list(#{digits.inspect}, :columns_across, 3) %>")
+    assert_equal( "Zero   One    Two  \n" +
+                  "Three  Four   Five \n" + 
+                  "Six    Seven  Eight\n" +
+                  "Nine \n",
+                  @output.string )
+        
+    colums_of_twenty.pop
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("<%= list( #{colums_of_twenty.inspect}, :columns_across ) %>")
+    assert_equal( "12345678901234567890  12345678901234567890  " +
+                  "12345678901234567890\n" +
+                  "12345678901234567890\n",
+                  @output.string )
+  end
+  
+  def test_mode
+    assert(%w[Win32API termios ncurses stty].include?(HighLine::CHARACTER_MODE))
+  end
+  
+  class NameClass
+    def self.parse( string )
+      if string =~ /^\s*(\w+),\s*(\w+)\s+(\w+)\s*$/
+        self.new($2, $3, $1)
+      else
+        raise ArgumentError, "Invalid name format."
+      end
+    end
+
+    def initialize(first, middle, last)
+      @first, @middle, @last = first, middle, last
+    end
+    
+    attr_reader :first, :middle, :last
+  end
+  
+  def test_my_class_conversion
+    @input << "Gray, James Edward\n"
+    @input.rewind
+
+    answer = @terminal.ask("Your name?  ", NameClass) do |q|
+      q.validate = lambda do |name|
+        names = name.split(/,\s*/)
+        return false unless names.size == 2
+        return false if names.first =~ /\s/
+        names.last.split.size == 2
+      end
+    end
+    assert_instance_of(NameClass, answer)
+    assert_equal("Gray", answer.last)
+    assert_equal("James", answer.first)
+    assert_equal("Edward", answer.middle)
+  end
+  
+  def test_no_echo
+    @input << "password\r"
+    @input.rewind
+
+    answer = @terminal.ask("Please enter your password:  ") do |q|
+      q.echo = false
+    end
+    assert_equal("password", answer)
+    assert_equal("Please enter your password:  \n", @output.string)
+
+    @input.rewind
+    @output.truncate(@output.rewind)
+    
+    answer = @terminal.ask("Pick a letter or number:  ") do |q|
+      q.character = true
+      q.echo      = false
+    end
+    assert_equal("p", answer)
+    assert_equal("a", @input.getc.chr)
+    assert_equal("Pick a letter or number:  \n", @output.string)
+  end
+  
+  def test_paging
+    @terminal.page_at = 22
+
+    @input << "\n\n"
+    @input.rewind
+
+    @terminal.say((1..50).map { |n| "This is line #{n}.\n"}.join)
+    assert_equal( (1..22).map { |n| "This is line #{n}.\n"}.join +
+                  "\n-- press enter/return to continue or q to stop -- \n\n" +
+                  (23..44).map { |n| "This is line #{n}.\n"}.join +
+                  "\n-- press enter/return to continue or q to stop -- \n\n" +
+                  (45..50).map { |n| "This is line #{n}.\n"}.join,
+                  @output.string )
+  end
+  
+  def test_range_requirements
+    @input << "112\n-541\n28\n"
+    @input.rewind
+
+    answer = @terminal.ask("Tell me your age.", Integer) do |q|
+      q.in = 0..105
+    end
+    assert_equal(28, answer)
+    assert_equal( "Tell me your age.\n" +
+                  "Your answer isn't within the expected range " +
+                  "(included in 0..105).\n" +
+                  "?  " +
+                  "Your answer isn't within the expected range " +
+                  "(included in 0..105).\n" +
+                  "?  ", @output.string )
+
+    @input.truncate(@input.rewind)
+    @input << "1\n-541\n28\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask("Tell me your age.", Integer) do |q|
+      q.above = 3
+    end
+    assert_equal(28, answer)
+    assert_equal( "Tell me your age.\n" +
+                  "Your answer isn't within the expected range " +
+                  "(above 3).\n" +
+                  "?  " +
+                  "Your answer isn't within the expected range " +
+                  "(above 3).\n" +
+                  "?  ", @output.string )
+
+    @input.truncate(@input.rewind)
+    @input << "1\n28\n-541\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask("Lowest numer you can think of?", Integer) do |q|
+      q.below = 0
+    end
+    assert_equal(-541, answer)
+    assert_equal( "Lowest numer you can think of?\n" +
+                  "Your answer isn't within the expected range " +
+                  "(below 0).\n" +
+                  "?  " +
+                  "Your answer isn't within the expected range " +
+                  "(below 0).\n" +
+                  "?  ", @output.string )
+
+    @input.truncate(@input.rewind)
+    @input << "1\n-541\n6\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask("Enter a low even number:  ", Integer) do |q|
+      q.above = 0
+      q.below = 10
+      q.in    = [2, 4, 6, 8]
+    end
+    assert_equal(6, answer)
+    assert_equal( "Enter a low even number:  " +
+                  "Your answer isn't within the expected range " +
+                  "(above 0, below 10, and included in [2, 4, 6, 8]).\n" +
+                  "?  " +
+                  "Your answer isn't within the expected range " +
+                  "(above 0, below 10, and included in [2, 4, 6, 8]).\n" +
+                  "?  ", @output.string )
+  end
+  
+  def test_reask
+    number = 61676
+    @input << "Junk!\n" << number << "\n"
+    @input.rewind
+
+    answer = @terminal.ask("Favorite number?  ", Integer)
+    assert_kind_of(Integer, number)
+    assert_instance_of(Fixnum, number)
+    assert_equal(number, answer)
+    assert_equal( "Favorite number?  " +
+                  "You must enter a valid Integer.\n" +
+                  "?  ", @output.string )
+
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask("Favorite number?  ", Integer) do |q|
+      q.responses[:ask_on_error] = :question
+      q.responses[:invalid_type] = "Not a valid number!"
+    end
+    assert_kind_of(Integer, number)
+    assert_instance_of(Fixnum, number)
+    assert_equal(number, answer)
+    assert_equal( "Favorite number?  " +
+                  "Not a valid number!\n" +
+                  "Favorite number?  ", @output.string )
+
+    @input.truncate(@input.rewind)
+    @input << "gen\ngene\n"
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    answer = @terminal.ask("Select a mode:  ", [:generate, :gentle])
+    assert_instance_of(Symbol, answer)
+    assert_equal(:generate, answer)
+    assert_equal( "Select a mode:  " +
+                  "Ambiguous choice.  " +
+                  "Please choose one of [:generate, :gentle].\n" +
+                  "?  ", @output.string )
+  end
+  
+  def test_response_embedding
+    @input << "112\n-541\n28\n"
+    @input.rewind
+
+    answer = @terminal.ask("Tell me your age.", Integer) do |q|
+      q.in = 0..105
+      q.responses[:not_in_range] = "Need a <%= @question.answer_type %>" +
+                                   " <%= @question.expected_range %>."
+    end
+    assert_equal(28, answer)
+    assert_equal( "Tell me your age.\n" +
+                  "Need a Integer included in 0..105.\n" +
+                  "?  " +
+                  "Need a Integer included in 0..105.\n" +
+                  "?  ", @output.string )
+  end
+  
+  def test_say
+    @terminal.say("This will have a newline.")
+    assert_equal("This will have a newline.\n", @output.string)
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("This will also have one newline.\n")
+    assert_equal("This will also have one newline.\n", @output.string)
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("This will not have a newline.  ")
+    assert_equal("This will not have a newline.  ", @output.string)
+  end
+
+  def test_type_conversion
+    number = 61676
+    @input << number << "\n"
+    @input.rewind
+
+    answer = @terminal.ask("Favorite number?  ", Integer)
+    assert_kind_of(Integer, answer)
+    assert_instance_of(Fixnum, answer)
+    assert_equal(number, answer)
+    
+    @input.truncate(@input.rewind)
+    number = 1_000_000_000_000_000_000_000_000_000_000
+    @input << number << "\n"
+    @input.rewind
+
+    answer = @terminal.ask("Favorite number?  ", Integer)
+    assert_kind_of(Integer, answer)
+    assert_instance_of(Bignum, answer)
+    assert_equal(number, answer)
+
+    @input.truncate(@input.rewind)
+    number = 10.5002
+    @input << number << "\n"
+    @input.rewind
+
+    answer = @terminal.ask( "Favorite number?  ",
+                            lambda { |n| n.to_f.abs.round } )
+    assert_kind_of(Integer, answer)
+    assert_instance_of(Fixnum, answer)
+    assert_equal(11, answer)
+
+    @input.truncate(@input.rewind)
+    animal = :dog
+    @input << animal << "\n"
+    @input.rewind
+
+    answer = @terminal.ask("Favorite animal?  ", Symbol)
+    assert_instance_of(Symbol, answer)
+    assert_equal(animal, answer)
+
+    @input.truncate(@input.rewind)
+    @input << "16th June 1976\n"
+    @input.rewind
+
+    answer = @terminal.ask("Enter your birthday.", Date)
+    assert_instance_of(Date, answer)
+    assert_equal(16, answer.day)
+    assert_equal(6, answer.month)
+    assert_equal(1976, answer.year)
+
+    @input.truncate(@input.rewind)
+    pattern = "^yes|no$"
+    @input << pattern << "\n"
+    @input.rewind
+
+    answer = @terminal.ask("Give me a pattern to match with:  ", Regexp)
+    assert_instance_of(Regexp, answer)
+    assert_equal(/#{pattern}/, answer)
+
+    @input.truncate(@input.rewind)
+    @input << "gen\n"
+    @input.rewind
+
+    answer = @terminal.ask("Select a mode:  ", [:generate, :run])
+    assert_instance_of(Symbol, answer)
+    assert_equal(:generate, answer)
+  end
+  
+  def test_validation
+    @input << "system 'rm -rf /'\n105\n0b101_001\n"
+    @input.rewind
+
+    answer = @terminal.ask("Enter a binary number:  ") do |q|
+      q.validate = /\A(?:0b)?[01_]+\Z/
+    end
+    assert_equal("0b101_001", answer)
+    assert_equal( "Enter a binary number:  " +
+                  "Your answer isn't valid " +
+                  "(must match /\\A(?:0b)?[01_]+\\Z/).\n" +
+                  "?  " +
+                  "Your answer isn't valid " +
+                  "(must match /\\A(?:0b)?[01_]+\\Z/).\n" +
+                  "?  ", @output.string )
+
+    @input.truncate(@input.rewind)
+    @input << "Gray II, James Edward\n" +
+              "Gray, Dana Ann Leslie\n" +
+              "Gray, James Edward\n"
+    @input.rewind
+
+    answer = @terminal.ask("Your name?  ") do |q|
+      q.validate = lambda do |name|
+        names = name.split(/,\s*/)
+        return false unless names.size == 2
+        return false if names.first =~ /\s/
+        names.last.split.size == 2
+      end
+    end
+    assert_equal("Gray, James Edward", answer)
+  end
+  
+  def test_whitespace
+    @input << "  A   lot\tof  \t  space\t  \there!   \n"
+    @input.rewind
+    
+    answer = @terminal.ask("Enter a whitespace filled string:  ") do |q|
+      q.whitespace = :chomp
+    end
+    assert_equal("  A   lot\tof  \t  space\t  \there!   ", answer)
+
+    @input.rewind
+
+    answer = @terminal.ask("Enter a whitespace filled string:  ")
+    assert_equal("A   lot\tof  \t  space\t  \there!", answer)
+
+    @input.rewind
+
+    answer = @terminal.ask("Enter a whitespace filled string:  ") do |q|
+      q.whitespace = :strip_and_collapse
+    end
+    assert_equal("A lot of space here!", answer)
+
+    @input.rewind
+
+    answer = @terminal.ask("Enter a whitespace filled string:  ") do |q|
+      q.whitespace = :remove
+    end
+    assert_equal("Alotofspacehere!", answer)
+
+    @input.rewind
+
+    answer = @terminal.ask("Enter a whitespace filled string:  ") do |q|
+      q.whitespace = :none
+    end
+    assert_equal("  A   lot\tof  \t  space\t  \there!   \n", answer)
+  end
+  
+  def test_wrap
+    @terminal.wrap_at = 80
+    
+    @terminal.say("This is a very short line.")
+    assert_equal("This is a very short line.\n", @output.string)
+    
+    @output.truncate(@output.rewind)
+
+    @terminal.say( "This is a long flowing paragraph meant to span " +
+                   "several lines.  This text should definitely be " +
+                   "wrapped at the set limit, in the result.  Your code " +
+                   "does well with things like this.\n\n" +
+                   "  * This is a simple embedded list.\n" +
+                   "  * You're code should not mess with this...\n" +
+                       "  * Because it's already formatted correctly and " +
+                   "does not\n" +
+                   "    exceed the limit!" )
+    assert_equal( "This is a long flowing paragraph meant to span " +
+                  "several lines.  This text should\n" +
+                  "definitely be wrapped at the set limit, in the " +
+                  "result.  Your code does well with\n" +
+                  "things like this.\n\n" +
+                  "  * This is a simple embedded list.\n" +
+                  "  * You're code should not mess with this...\n" +
+                  "  * Because it's already formatted correctly and does " +
+                  "not\n" +
+                  "    exceed the limit!\n", @output.string )
+
+    @output.truncate(@output.rewind)
+
+    @terminal.say("-=" * 50)
+    assert_equal(("-=" * 40 + "\n") + ("-=" * 10 + "\n"), @output.string)
+  end
+  
+  def test_track_eof
+    assert_raise(EOFError) { @terminal.ask("Any input left?  ") }
+    
+    # turn EOF tracking
+    old_setting = HighLine.track_eof?
+    assert_nothing_raised(Exception) { HighLine.track_eof = false }
+    begin
+      @terminal.ask("And now?  ")  # this will still blow up, nothing available
+    rescue
+      assert_not_equal(EOFError, $!.class)  # but HighLine's safe guards are off
+    end
+    HighLine.track_eof = old_setting
+  end
+  
+  def test_version
+    assert_not_nil(HighLine::VERSION)
+    assert_instance_of(String, HighLine::VERSION)
+    assert(HighLine::VERSION.frozen?)
+    assert_match(/\A\d\.\d\.\d\Z/, HighLine::VERSION)
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_import.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_import.rb
new file mode 100644 (file)
index 0000000..005d5a9
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/local/bin/ruby -w
+
+# tc_import.rb
+#
+#  Created by James Edward Gray II on 2005-04-26.
+#  Copyright 2005 Gray Productions. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+
+require "test/unit"
+
+require "highline/import"
+require "stringio"
+
+class TestImport < Test::Unit::TestCase
+  def test_import
+    assert_respond_to(self, :agree)
+    assert_respond_to(self, :ask)
+    assert_respond_to(self, :choose)
+    assert_respond_to(self, :say)
+  end
+  
+  def test_or_ask
+    old_terminal = $terminal
+    
+    input     = StringIO.new
+    output    = StringIO.new
+    $terminal = HighLine.new(input, output)  
+    
+    input << "10\n"
+    input.rewind
+
+    assert_equal(10, nil.or_ask("How much?  ", Integer))
+
+    input.rewind
+
+    assert_equal(20, "20".or_ask("How much?  ", Integer))
+    assert_equal(20, 20.or_ask("How much?  ", Integer))
+    
+    assert_equal(10, 20.or_ask("How much?  ", Integer) { |q| q.in = 1..10 })
+  ensure
+    $terminal = old_terminal
+  end
+  
+  def test_redirection
+    old_terminal = $terminal
+    
+    $terminal = HighLine.new(nil, (output = StringIO.new))
+    say("Testing...")
+    assert_equal("Testing...\n", output.string)
+  ensure
+    $terminal = old_terminal
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_menu.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/tc_menu.rb
new file mode 100644 (file)
index 0000000..fee1871
--- /dev/null
@@ -0,0 +1,429 @@
+#!/usr/local/bin/ruby -w
+
+# tc_menu.rb
+#
+#  Created by Gregory Thomas Brown on 2005-05-10.
+#  Copyright 2005. All rights reserved.
+#
+#  This is Free Software. See LICENSE and COPYING for details.
+
+require "test/unit"
+
+require "highline"
+require "stringio"
+
+class TestMenu < Test::Unit::TestCase
+  def setup
+    @input    = StringIO.new
+    @output   = StringIO.new
+    @terminal = HighLine.new(@input, @output)
+  end
+
+  def test_choices
+    @input << "2\n"
+    @input.rewind
+
+    output = @terminal.choose do |menu|
+      menu.choices("Sample1", "Sample2", "Sample3")
+    end
+    assert_equal("Sample2", output)
+  end
+
+  def test_flow
+    @input << "Sample1\n"
+    @input.rewind
+
+    @terminal.choose do |menu|
+      # Default:  menu.flow = :rows
+      
+      menu.choice "Sample1" 
+      menu.choice "Sample2" 
+      menu.choice "Sample3" 
+    end
+    assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n?  ", @output.string)
+
+    @output.truncate(@output.rewind)
+    @input.rewind
+    
+    @terminal.choose do |menu|
+      menu.flow = :columns_across
+      
+      menu.choice "Sample1" 
+      menu.choice "Sample2" 
+      menu.choice "Sample3"
+    end
+    assert_equal("1. Sample1  2. Sample2  3. Sample3\n?  ", @output.string)
+
+    @output.truncate(@output.rewind)
+    @input.rewind
+
+    @terminal.choose do |menu|
+      menu.flow  = :inline
+      menu.index = :none
+
+      menu.choice "Sample1" 
+      menu.choice "Sample2" 
+      menu.choice "Sample3"  
+    end
+    assert_equal("Sample1, Sample2 or Sample3?  ", @output.string)
+  end
+
+  def test_help
+    @input << "help\nhelp load\nhelp rules\nhelp missing\n"
+    @input.rewind
+
+    4.times do
+      @terminal.choose do |menu|
+        menu.shell = true
+
+        menu.choice(:load, "Load a file.")
+        menu.choice(:save, "Save data in file.")
+        menu.choice(:quit, "Exit program.")
+        
+        menu.help("rules", "The rules of this system are as follows...")
+      end
+    end
+    assert_equal( "1. load\n2. save\n3. quit\n4. help\n?  " +
+                  "This command will display helpful messages about " +
+                  "functionality, like this one.  To see the help for a " +
+                  "specific topic enter:\n" +
+                  "\thelp [TOPIC]\n" +
+                  "Try asking for help on any of the following:\n" +
+                  "\nload   quit   rules  save \n" + 
+                  "1. load\n2. save\n3. quit\n4. help\n?  " +
+                  "= load\n\n" + 
+                  "Load a file.\n" +
+                  "1. load\n2. save\n3. quit\n4. help\n?  " +
+                  "= rules\n\n" +
+                  "The rules of this system are as follows...\n" +
+                  "1. load\n2. save\n3. quit\n4. help\n?  " +
+                  "= missing\n\n" + 
+                  "There's no help for that topic.\n", @output.string )
+  end
+
+  def test_index
+    @input << "Sample1\n"
+    @input.rewind
+
+    @terminal.choose do |menu|
+      # Default:  menu.index = :number
+      
+      menu.choice "Sample1" 
+      menu.choice "Sample2" 
+      menu.choice "Sample3" 
+    end
+    assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n?  ", @output.string)
+
+    @output.truncate(@output.rewind)
+    @input.rewind
+    
+    @terminal.choose do |menu|
+      menu.index        = :letter
+      menu.index_suffix = ") "
+      
+      menu.choice "Sample1" 
+      menu.choice "Sample2" 
+      menu.choice "Sample3"
+    end
+    assert_equal("a) Sample1\nb) Sample2\nc) Sample3\n?  ", @output.string)
+
+    @output.truncate(@output.rewind)
+    @input.rewind
+
+    @terminal.choose do |menu|
+      menu.index = :none
+
+      menu.choice "Sample1" 
+      menu.choice "Sample2" 
+      menu.choice "Sample3"  
+    end
+    assert_equal("Sample1\nSample2\nSample3\n?  ", @output.string)
+
+    @output.truncate(@output.rewind)
+    @input.rewind
+    
+    @terminal.choose do |menu|
+      menu.index        = "*"
+
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+    end
+    assert_equal("* Sample1\n* Sample2\n* Sample3\n?  ", @output.string)
+  end
+  
+  def test_layouts
+    @input << "save\n"
+    @input.rewind
+    
+    @terminal.choose(:load, :save, :quit) # Default:  layout = :list
+    assert_equal("1. load\n2. save\n3. quit\n?  ", @output.string)
+
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    @terminal.choose(:load, :save, :quit) do |menu|
+      menu.header = "File Menu"
+    end
+    assert_equal( "File Menu:\n" + 
+                  "1. load\n2. save\n3. quit\n?  ", @output.string )
+
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    @terminal.choose(:load, :save, :quit) do |menu|
+      menu.layout = :one_line
+      menu.header = "File Menu"
+      menu.prompt = "Operation?  "
+    end
+    assert_equal( "File Menu:  Operation?  " + 
+                  "(load, save or quit)  ", @output.string )
+
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    @terminal.choose(:load, :save, :quit) do |menu|
+      menu.layout   = :menu_only
+    end
+    assert_equal("load, save or quit?  ", @output.string)
+
+    @input.rewind
+    @output.truncate(@output.rewind)
+
+    @terminal.choose(:load, :save, :quit) do |menu|
+      menu.layout = '<%= list(@menu) %>File Menu:  '
+    end
+    assert_equal("1. load\n2. save\n3. quit\nFile Menu:  ", @output.string)
+  end
+  
+  def test_list_option
+    @input << "l\n"
+    @input.rewind
+
+    @terminal.choose(:load, :save, :quit) do |menu|
+      menu.layout      = :menu_only
+      menu.list_option = ", or "
+    end
+    assert_equal("load, save, or quit?  ", @output.string)
+  end
+
+  def test_nil_on_handled
+    @input << "3\n3\n2\n"
+    @input.rewind
+
+    # Shows that by default proc results are returned.
+    output = @terminal.choose do |menu|
+        menu.choice "Sample1" do "output1" end
+        menu.choice "Sample2" do "output2" end
+        menu.choice "Sample3" do "output3" end
+    end
+    assert_equal("output3", output)
+
+    #
+    # Shows that they can be replaced with +nil+ by setting
+    # _nil_on_handled to +true+.
+    #
+    output = @terminal.choose do |menu|
+        menu.nil_on_handled = true
+        menu.choice "Sample1" do "output1" end
+        menu.choice "Sample2" do "output2" end
+        menu.choice "Sample3" do "output3" end
+    end
+    assert_equal(nil, output)
+
+    # Shows that a menu item without a proc will be returned no matter what.
+    output = @terminal.choose do |menu|
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+    end
+    assert_equal("Sample2", output)
+  end
+  
+  def test_passed_command
+    @input << "q\n"
+    @input.rewind
+    
+    selected = nil
+    @terminal.choose do |menu|
+      menu.choices(:load, :save, :quit) { |command| selected = command }
+    end
+    assert_equal(:quit, selected)
+  end
+  
+  def test_question_options
+    @input << "save\n"
+    @input.rewind
+
+    answer = @terminal.choose(:Load, :Save, :Quit) do |menu|
+      menu.case = :capitalize
+    end
+    assert_equal(:Save, answer)
+
+    @input.rewind
+
+    answer = @terminal.choose(:Load, :Save, :Quit) do |menu|
+      menu.case      = :capitalize
+      menu.character = :getc
+    end
+    assert_equal(:Save, answer)
+    assert_equal(?a, @input.getc)
+  end
+
+  def test_select_by
+    @input << "Sample1\n2\n"
+    @input.rewind
+    
+    selected = @terminal.choose do |menu|
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+    end
+    assert_equal("Sample1", selected)
+    
+    @input.rewind
+
+    selected = @terminal.choose do |menu|
+      menu.select_by = :index
+      
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+    end
+    assert_equal("Sample2", selected)
+
+    @input.rewind
+
+    selected = @terminal.choose do |menu|
+      menu.select_by = :name
+      
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+    end
+    assert_equal("Sample1", selected)
+  end
+
+  def test_hidden
+    @input << "Hidden\n4\n"
+    @input.rewind
+    
+    selected = @terminal.choose do |menu|
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+      menu.hidden "Hidden!"
+    end
+    assert_equal("Hidden!", selected)
+    assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n?  ", @output.string)
+    
+    @input.rewind
+
+    selected = @terminal.choose do |menu|
+      menu.select_by = :index
+      
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+      menu.hidden "Hidden!"
+    end
+    assert_equal("Hidden!", selected)
+
+    @input.rewind
+
+    selected = @terminal.choose do |menu|
+      menu.select_by = :name
+      
+      menu.choice "Sample1"
+      menu.choice "Sample2"
+      menu.choice "Sample3"
+      menu.hidden "Hidden!"
+    end
+    assert_equal("Hidden!", selected)
+
+    @input.rewind
+  end
+
+  def test_select_by_letter
+    @input << "b\n"
+    @input.rewind
+    
+    selected = @terminal.choose do |menu| 
+      menu.index  = :letter
+      menu.choice   :save
+      menu.choice   :load
+      menu.choice   :quit
+    end
+    assert_equal(:load, selected)
+  end
+  
+  def test_shell
+    @input << "save --some-option my_file.txt\n"
+    @input.rewind
+
+    selected = nil
+    options  = nil
+    answer = @terminal.choose do |menu|
+      menu.choices(:load, :quit)
+      menu.choice(:save) do |command, details|
+        selected = command
+        options  = details
+        
+        "Saved!"
+      end
+      menu.shell = true
+    end
+    assert_equal("Saved!", answer)
+    assert_equal(:save, selected)
+    assert_equal("--some-option my_file.txt", options)
+  end
+
+  def test_simple_menu_shortcut
+    @input << "3\n"
+    @input.rewind
+
+    selected = @terminal.choose(:save, :load, :quit)
+    assert_equal(:quit, selected)
+  end
+
+  def test_symbols
+    @input << "3\n"
+    @input.rewind
+    
+    selected = @terminal.choose do |menu|
+      menu.choices(:save, :load, :quit) 
+    end
+    assert_equal(:quit, selected)
+  end
+
+  def test_paged_print_infinite_loop_bug
+    @terminal.page_at = 5
+    # Will page twice, so start with two new lines
+    @input << "\n\n3\n"
+    @input.rewind
+  
+    # Sadly this goes into an infinite loop without the fix to page_print    
+    selected = @terminal.choose(* 1..10) 
+    assert_equal(selected, 3)
+  end
+
+
+  def test_cancel_paging
+    # Tests that paging can be cancelled halfway through
+    @terminal.page_at = 5
+    # Will page twice, so stop after first page and make choice 3
+    @input << "q\n3\n"
+    @input.rewind
+
+    selected = @terminal.choose(* 1..10)
+    assert_equal(selected, 3)
+
+    # Make sure paging message appeared
+    assert( @output.string.index('press enter/return to continue or q to stop'),
+            "Paging message did not appear." )
+   
+    # Make sure it only appeared once
+    assert( @output.string !~ /q to stop.*q to stop/m,
+            "Paging message appeared more than once." )
+  end
+end
diff --git a/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/ts_all.rb b/ruby/lib/ruby/gems/1.8/gems/highline-1.6.1/test/ts_all.rb
new file mode 100644 (file)
index 0000000..735dcce
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/local/bin/ruby -w
+
+# ts_all.rb
+#
+#  Created by James Edward Gray II on 2005-04-26.
+#  Copyright 2005 Gray Productions. All rights reserved.
+#
+#  This is Free Software.  See LICENSE and COPYING for details.
+
+require "test/unit"
+
+require "tc_highline"
+require "tc_import"
+require "tc_menu"
+require "tc_color_scheme"
diff --git a/ruby/lib/ruby/gems/1.8/specifications/highline-1.6.1.gemspec b/ruby/lib/ruby/gems/1.8/specifications/highline-1.6.1.gemspec
new file mode 100644 (file)
index 0000000..19eca0c
--- /dev/null
@@ -0,0 +1,35 @@
+# -*- encoding: utf-8 -*-\r
+\r
+Gem::Specification.new do |s|\r
+  s.name = %q{highline}\r
+  s.version = "1.6.1"\r
+\r
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=\r
+  s.authors = ["James Edward Gray II"]\r
+  s.date = %q{2010-07-15}\r
+  s.description = %q{A high-level IO library that provides validation, type conversion, and more for\r
+command-line interfaces. HighLine also includes a complete menu system that can\r
+crank out anything from simple list selection to complete shells with just\r
+minutes of work.\r
+}\r
+  s.email = %q{james@grayproductions.net}\r
+  s.extra_rdoc_files = ["README", "INSTALL", "TODO", "CHANGELOG", "LICENSE"]\r
+  s.files = ["examples/ansi_colors.rb", "examples/asking_for_arrays.rb", "examples/basic_usage.rb", "examples/color_scheme.rb", "examples/limit.rb", "examples/menus.rb", "examples/overwrite.rb", "examples/page_and_wrap.rb", "examples/password.rb", "examples/trapping_eof.rb", "examples/using_readline.rb", "lib/highline/color_scheme.rb", "lib/highline/compatibility.rb", "lib/highline/import.rb", "lib/highline/menu.rb", "lib/highline/question.rb", "lib/highline/system_extensions.rb", "lib/highline.rb", "test/tc_color_scheme.rb", "test/tc_highline.rb", "test/tc_import.rb", "test/tc_menu.rb", "test/ts_all.rb", "Rakefile", "setup.rb", "README", "INSTALL", "TODO", "CHANGELOG", "LICENSE"]\r
+  s.homepage = %q{http://highline.rubyforge.org}\r
+  s.rdoc_options = ["--title", "HighLine Documentation", "--main", "README"]\r
+  s.require_paths = ["lib"]\r
+  s.rubyforge_project = %q{highline}\r
+  s.rubygems_version = %q{1.3.5}\r
+  s.summary = %q{HighLine is a high-level command-line IO library.}\r
+  s.test_files = ["test/ts_all.rb"]\r
+\r
+  if s.respond_to? :specification_version then\r
+    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\r
+    s.specification_version = 3\r
+\r
+    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\r
+    else\r
+    end\r
+  else\r
+  end\r
+end\r
index 8d5b0f1..e1c61b1 100644 (file)
@@ -3,10 +3,18 @@
 require 'optparse'\r
 require 'socket'\r
 require 'base64'\r
+require 'highline/import'\r
+\r
+# monkey patch\r
+class HighLine::Question\r
+  def append_default()\r
+    @question\r
+  end\r
+end\r
 \r
 ScriptDir = File.dirname(__FILE__)\r
 Dir.glob(ScriptDir + "/lib/*.rb").each {|rb|\r
-       require rb\r
+  require rb\r
 }\r
 \r
 Windows::Authorization.runas_admin\r
@@ -14,207 +22,221 @@ Windows::Authorization.runas_admin
 home = File.expand_path(ENV["PACKAGE_HOME"])\r
 host = Socket.gethostbyname(Socket.gethostname).first\r
 options = {\r
-       :interact => true,\r
-       :home => home,\r
-       :fqdn_or_ipaddr => host.include?(".") ? host : IPSocket.getaddress(host),\r
-       :apache_root => File.join(home, "apache"),\r
-       :redmine_root => File.join(home, "redmine"),\r
-       :opends_root => File.join(home, "opends"),\r
-       :opends_manager_dn => "cn=Directory Manager",\r
-       :opends_manager_password => Account.random_password(10)\r
+  :interact => true,\r
+  :home => home,\r
+  :fqdn_or_ipaddr => host.include?(".") ? host : IPSocket.getaddress(host),\r
+  :apache_root => File.join(home, "apache"),\r
+  :redmine_root => File.join(home, "redmine"),\r
+  :opends_root => File.join(home, "opends"),\r
+  :opends_manager_dn => "cn=Directory Manager",\r
+  :opends_manager_password => Account.random_password(10)\r
 }\r
 options[:apache_host] = options[:fqdn_or_ipaddr]\r
 \r
 config = [\r
-       {:name => :apache_name, :default => "Apache"},\r
-       {:name => :apache_port, :type => :int, :default => 80},\r
-       {:name => :redmine_name, :default => "Redmine"},\r
-       {:name => :redmine_port, :type => :int, :default => 8000},\r
-       {:name => :hudson_name, :default => "Hudson"},\r
-       {:name => :hudson_port, :type => :int, :default => 8001},\r
-\r
-       {:name => :ldap_setting, :type => :bool,\r
-               :message => "Use external LDAP server? (y/n): "},\r
-       {:name => :opends_name, :default => "OpenDS", :parent => :ldap_setting, :if => false},\r
-       {:name => :opends_port, :type => :int, :default => 389, :parent => :ldap_setting, :if => false},\r
-       {:name => :opends_admin_port, :type => :int, :default => 8002, :parent => :ldap_setting, :if => false},\r
-       {:name => :opends_base_dn, :default => "dc=redminele,dc=local", :parent => :ldap_setting, :if => false},\r
-\r
-       {:name => :ldap_host, :default => "localhost", :parent => :ldap_setting, :if => true},\r
-       {:name => :ldap_port, :type => :int, :default => 389, :parent => :ldap_setting, :if => true},\r
-       {:name => :ldap_base_dn, :parent => :ldap_setting, :if => true, :message => "Enter LDAP Base DN (ex. ou=users, dc=local): "},\r
-       {:name => :ldap_anonymous, :type => :bool, :message => "LDAP server permits anonymous bind? ([y]/n): ", :default => true, :parent => :ldap_setting, :if => true},\r
-       {:name => :ldap_bind_dn, :message => "Enter LDAP bind DN (ex. uid=xxx,ou=users,dc=local): ", :parent => :ldap_anonymous, :if => false},\r
-       {:name => :ldap_bind_password, :message => "Enter LDAP bind password: ", :parent => :ldap_anonymous, :if => false},\r
-       {:name => :ldap_user_attribute, :default => "uid", :parent => :ldap_setting, :if => true},\r
-       {:name => :ldap_first_name_attribute, :default => "givenName", :parent => :ldap_setting, :if => true},\r
-       {:name => :ldap_last_name_attribute, :default => "sn", :parent => :ldap_setting, :if => true},\r
-       {:name => :ldap_mail_attribute, :default => "mail", :parent => :ldap_setting, :if => true},\r
-\r
-       {:name => :admin_account},\r
-       {:name => :admin_password},\r
-       {:name => :admin_mail},\r
-       {:name => :admin_first_name},\r
-       {:name => :admin_last_name},\r
-\r
-       {:name => :smtp_setting, :type => :bool,\r
-               :message => "Use redmine email notification? (y/n): "},\r
-       {:name => :mail_sender_address, :parent => :smtp_setting, :if => true},\r
-       {:name => :smtp_host, :parent => :smtp_setting, :if => true},\r
-       {:name => :smtp_port, :parent => :smtp_setting,:type => :int, :default => 25, :if => true},\r
-       {:name => :smtp_domain, :parent => :smtp_setting, :if => true,\r
-               :default => options[:fqdn_or_ipaddr]},\r
-       {:name => :smtp_auth, :parent => :smtp_setting, :if => true, :type => :bool,\r
-               :default => false, :message => "Use smtp auth? (y/[n]): "},\r
-       {:name => :smtp_user, :parent => :smtp_auth, :if => true},\r
-       {:name => :smtp_password, :parent => :smtp_auth, :if => true}\r
+  {:name => :apache_name, :default => "Apache"},\r
+  {:name => :apache_port, :type => :int, :default => 80},\r
+  {:name => :redmine_name, :default => "Redmine"},\r
+  {:name => :redmine_port, :type => :int, :default => 8000},\r
+  {:name => :hudson_name, :default => "Hudson"},\r
+  {:name => :hudson_port, :type => :int, :default => 8001},\r
+\r
+  {:name => :ldap_setting, :type => :bool,\r
+    :message => "Use external LDAP server? (y/n): "},\r
+  {:name => :opends_name, :default => "OpenDS", :parent => :ldap_setting, :if => false},\r
+  {:name => :opends_port, :type => :int, :default => 389, :parent => :ldap_setting, :if => false},\r
+  {:name => :opends_admin_port, :type => :int, :default => 8002, :parent => :ldap_setting, :if => false},\r
+  {:name => :opends_base_dn, :default => "dc=redminele,dc=local", :parent => :ldap_setting, :if => false},\r
+\r
+  {:name => :ldap_host, :default => "localhost", :parent => :ldap_setting, :if => true},\r
+  {:name => :ldap_port, :type => :int, :default => 389, :parent => :ldap_setting, :if => true},\r
+  {:name => :ldap_base_dn, :parent => :ldap_setting, :if => true, :message => "Enter LDAP Base DN (ex. ou=users,dc=local): "},\r
+  {:name => :ldap_anonymous, :type => :bool, :message => "LDAP server permits anonymous bind? ([y]/n): ", :default => true, :parent => :ldap_setting, :if => true},\r
+  {:name => :ldap_bind_dn, :message => "Enter LDAP bind DN (ex. uid=xxx,ou=users,dc=local): ", :parent => :ldap_anonymous, :if => false},\r
+  {:name => :ldap_bind_password, :message => "Enter LDAP bind password: ", :parent => :ldap_anonymous, :if => false, :type => :password},\r
+  {:name => :ldap_user_attribute, :default => "uid", :parent => :ldap_setting, :if => true},\r
+  {:name => :ldap_first_name_attribute, :default => "givenName", :parent => :ldap_setting, :if => true},\r
+  {:name => :ldap_last_name_attribute, :default => "sn", :parent => :ldap_setting, :if => true},\r
+  {:name => :ldap_mail_attribute, :default => "mail", :parent => :ldap_setting, :if => true},\r
+\r
+  {:name => :admin_account},\r
+  {:name => :admin_password, :type => :password},\r
+  {:name => :admin_mail, :type => :mail},\r
+  {:name => :admin_first_name},\r
+  {:name => :admin_last_name},\r
+\r
+  {:name => :smtp_setting, :type => :bool,\r
+    :message => "Use redmine email notification? (y/n): "},\r
+  {:name => :mail_sender_address, :parent => :smtp_setting, :if => true, :type => :mail},\r
+  {:name => :smtp_host, :parent => :smtp_setting, :if => true},\r
+  {:name => :smtp_port, :parent => :smtp_setting,:type => :int, :default => 25, :if => true},\r
+  {:name => :smtp_domain, :parent => :smtp_setting, :if => true,\r
+    :default => options[:fqdn_or_ipaddr]},\r
+  {:name => :smtp_auth, :parent => :smtp_setting, :if => true, :type => :bool,\r
+    :message => "Use smtp auth? (y/n): "},\r
+  {:name => :smtp_user, :parent => :smtp_auth, :if => true},\r
+  {:name => :smtp_password, :parent => :smtp_auth, :if => true, :type => :password}\r
 ]\r
 \r
 option_keys = []\r
 config_hash = {}\r
 config.each {|h|\r
-       option_keys.push(key = h[:name])\r
-       name = key.to_s\r
-\r
-       if h[:message].nil?\r
-               default = h[:default]\r
-               default = default.nil? ? "" : " (default: #{default})"\r
-               h[:message] = "Enter #{name.gsub('_', ' ')}#{default}: "\r
-       end\r
-\r
-       optname = name.gsub('_', '-')\r
-       h[:option_name] = (h[:type] == :bool) ?\r
-               "--[no-]" + optname : "--#{optname}=VAL"\r
-       h[:class] = Integer if h[:type] == :int\r
-       \r
-       config_hash[key] = h\r
+  option_keys.push(key = h[:name])\r
+  name = key.to_s\r
+\r
+  if h[:message].nil?\r
+    default = h[:default]\r
+    default = default.nil? ? "" : " (default: #{default})"\r
+    h[:message] = "Enter #{name.gsub('_', ' ')}#{default}: "\r
+  end\r
+\r
+  optname = name.gsub('_', '-')\r
+  h[:option_name] = (h[:type] == :bool) ?\r
+    "--[no-]" + optname : "--#{optname}=VAL"\r
+  h[:class] = Integer if h[:type] == :int\r
+  \r
+  config_hash[key] = h\r
 }\r
 \r
 OptionParser.new {|opt|\r
-       opt.banner = "Usage: install [options] [file|-]"\r
-       opt.on('--[no-]interact') {|v| options[:interact] = v}\r
-\r
-       option_keys.each {|key|\r
-               conf = config_hash[key]\r
-               args = conf[:option_name].to_a\r
-               args.push conf[:class] if conf[:class]\r
-               opt.on(*args) {|v| options[key] = v.toutf8}\r
-       }\r
-       opt.parse!\r
+  opt.banner = "Usage: install [options] [file|-]"\r
+  opt.on('--[no-]interact') {|v| options[:interact] = v}\r
+\r
+  option_keys.each {|key|\r
+    conf = config_hash[key]\r
+    args = conf[:option_name].to_a\r
+    args.push conf[:class] if conf[:class]\r
+    opt.on(*args) {|v| options[key] = v.toutf8}\r
+  }\r
+  opt.parse!\r
 }\r
 \r
 if config_file = ARGV.first\r
-       hash = if config_file == "-"\r
-               YAML.load(STDIN.read.toutf8)\r
-       else\r
-               YAML.load_file(config_file)\r
-       end || {}\r
-       hash.each {|key, val| options[key.to_sym] = val} if hash.is_a?(Hash)\r
-       options[:interact] = false\r
+  hash = if config_file == "-"\r
+    YAML.load(STDIN.read.toutf8)\r
+  else\r
+    YAML.load_file(config_file)\r
+  end || {}\r
+  hash.each {|key, val| options[key.to_sym] = val} if hash.is_a?(Hash)\r
+  options[:interact] = false\r
 end\r
 \r
 def bind_check(options)\r
-       LDAP.setup_connection(options)\r
-       unless LDAP.check_connection\r
-               %w[ldap_host ldap_port ldap_anonymous ldap_bind_dn ldap_bind_password\r
-               ].each {|key| options.delete(key.to_sym)}\r
-               return false\r
-       end\r
-       true\r
+  LDAP.setup_connection(options)\r
+  unless LDAP.check_connection\r
+    %w[ldap_host ldap_port ldap_anonymous ldap_bind_dn ldap_bind_password\r
+    ].each {|key| options.delete(key.to_sym)}\r
+    return false\r
+  end\r
+  true\r
 end\r
 \r
 def admin_check(options)\r
-       LDAP.setup_connection(options)\r
-       unless LDAP.check_bind(options[:admin_account], options[:admin_password])\r
-               %w[ldap_base_dn ldap_user_attribute admin_account admin_password\r
-               ].each {|key| options.delete(key.to_sym)}\r
-               return false\r
-       end\r
-\r
-       attrs = LDAP.search_attributes(options[:admin_account])\r
-       %w[first_name last_name mail].each {|v|\r
-               if value = attrs[options[:"ldap_#{v}_attribute"]]\r
-                       options[:"admin_#{v}"] = value\r
-               end\r
-       }\r
-       true\r
+  LDAP.setup_connection(options)\r
+  unless LDAP.check_bind(options[:admin_account], options[:admin_password])\r
+    %w[ldap_base_dn ldap_user_attribute admin_account admin_password\r
+    ].each {|key| options.delete(key.to_sym)}\r
+    return false\r
+  end\r
+\r
+  attrs = LDAP.search_attributes(options[:admin_account])\r
+  %w[first_name last_name mail].each {|v|\r
+    if value = attrs[options[:"ldap_#{v}_attribute"]]\r
+      options[:"admin_#{v}"] = value\r
+    end\r
+  }\r
+  true\r
 end\r
 \r
 if options[:interact]\r
-       option_keys.each {|key|\r
-               if options[:ldap_setting]\r
-                       if key == :ldap_user_attribute && !bind_check(options)\r
-                               warn "Failed to bind to LDAP server"\r
-                               retry\r
-                       end\r
-                       if key == :admin_mail && !admin_check(options)\r
-                               warn "Failed to bind as admin account"\r
-                               retry\r
-                       end\r
-               end\r
-               next unless options[key].nil?\r
-\r
-               conf = config_hash[key]\r
-               p_key = conf[:parent]\r
-               if p_key && options[p_key] != conf[:if]\r
-                       options[key] = conf[:default] unless conf[:default].nil?\r
-                       options[key] = nil if conf[:type] == :bool\r
-                       next\r
-               end\r
-\r
-               print conf[:message]\r
-               input = gets.chomp.toutf8\r
-               default = conf[:default]\r
-               if conf[:type] == :bool\r
-                       c = input[0..0].downcase\r
-                       if c.empty?\r
-                               redo if default.nil?\r
-                               options[key] = default\r
-                       else\r
-                               redo unless c.match(/y|n/)\r
-                               options[key] = c == "y"\r
-                       end\r
-               else\r
-                       if input.empty?\r
-                               redo if default.nil?\r
-                               input = default\r
-                       end\r
-                       options[key] = input\r
-               end\r
-       }\r
+  option_keys.each {|key|\r
+    if options[:ldap_setting]\r
+      if key == :ldap_user_attribute && !bind_check(options)\r
+        puts "Failed to bind to LDAP server."\r
+        retry\r
+      end\r
+      if key == :admin_mail && !admin_check(options)\r
+        puts "Failed to bind as admin account."\r
+        retry\r
+      end\r
+    end\r
+    next unless options[key].nil?\r
+\r
+    conf = config_hash[key]\r
+    type = conf[:type]\r
+    default = conf[:default]\r
+    p_key = conf[:parent]\r
+    if p_key && options[p_key] != conf[:if]\r
+      options[key] = type == :bool ? nil : default\r
+      next\r
+    end\r
+\r
+    msg = conf[:message]\r
+    options[key] = case type\r
+    when :bool\r
+      agree(msg) {|q|\r
+        q.default = default ? 'y' : 'n' unless default.nil?\r
+        q.responses[:ask_on_error] = :question\r
+      }\r
+    when :int\r
+      ask(msg, Integer) {|q|\r
+        q.default = default\r
+        q.responses[:ask_on_error] = :question\r
+      }\r
+    when :password\r
+      password = ask(msg) {|q| q.echo = '*'}\r
+      redo if password.empty?\r
+      confirmation = ask("Re-" + msg) {|q| q.echo = '*'}\r
+      if password != confirmation\r
+        puts "Password doesn't match."\r
+        redo\r
+      end\r
+      password\r
+    when :mail\r
+      ask(msg) {|q|\r
+        q.validate = /^[\w\.]+@[\w\.]+$/\r
+        q.responses[:ask_on_error] = :question\r
+        q.responses[:not_valid] = "Invalid email address."\r
+      }\r
+    else\r
+      ans = ask(msg) {|q| q.default = default}.toutf8\r
+      redo if ans.empty?\r
+      ans\r
+    end\r
+  }\r
 else\r
-       config_hash.each {|key, conf|\r
-               if options[:ldap_setting]\r
-                       raise "Failed to bind to LDAP server" if key == :ldap_user_attribute && !bind_check(options)\r
-                       raise "Failed to bind as admin account" if key == :admin_mail && !admin_check(options)\r
-               end\r
-\r
-               next unless options[key].nil?\r
-               p_key = conf[:parent]\r
-               next if p_key && options[p_key].nil?\r
-               raise "#{key.to_s} is not specified" if conf[:default].nil? && p_key.nil?\r
-               options[key] = conf[:default]\r
-       }\r
+  config_hash.each {|key, conf|\r
+    if options[:ldap_setting]\r
+      raise "Failed to bind to LDAP server" if key == :ldap_user_attribute && !bind_check(options)\r
+      raise "Failed to bind as admin account" if key == :admin_mail && !admin_check(options)\r
+    end\r
+\r
+    next unless options[key].nil?\r
+    p_key = conf[:parent]\r
+    next if p_key && options[p_key].nil?\r
+    raise "#{key.to_s} is not specified" if conf[:default].nil? && p_key.nil?\r
+    options[key] = conf[:default]\r
+  }\r
 end\r
-options[:apache_host] += ":#{options[:apache_port]}" unless options[:apache_port].to_s == "80"\r
+options[:apache_host] += ":#{options[:apache_port]}" unless options[:apache_port] == 80\r
 \r
 options.each {|key, value|\r
-       next unless value.is_a?(String)\r
-       next if key.to_s.index("password")\r
-       options[key].strip!\r
+  next unless value.is_a?(String)\r
+  next if key.to_s.index("password")\r
+  options[key].strip!\r
 }\r
 \r
 unless options[:ldap_setting]\r
-       options[:ldap_host] = "localhost"\r
-       options[:ldap_port] = options[:opends_port]\r
-       options[:ldap_base_dn] = options[:opends_base_dn]\r
-       options[:ldap_anonymous] = false\r
-       options[:ldap_bind_dn] = "uid=#{options[:admin_account]},ou=users,#{options[:ldap_base_dn]}"\r
-       options[:ldap_bind_password] = options[:admin_password]\r
-       options[:ldap_user_attribute] = "uid"\r
-       options[:ldap_first_name_attribute] = "givenName"\r
-       options[:ldap_last_name_attribute] = "sn"\r
-       options[:ldap_mail_attribute] = "mail"\r
+  options[:ldap_host] = "localhost"\r
+  options[:ldap_port] = options[:opends_port]\r
+  options[:ldap_base_dn] = options[:opends_base_dn]\r
+  options[:ldap_anonymous] = false\r
+  options[:ldap_bind_dn] = "uid=#{options[:admin_account]},ou=users,#{options[:ldap_base_dn]}"\r
+  options[:ldap_bind_password] = options[:admin_password]\r
+  options[:ldap_user_attribute] = "uid"\r
+  options[:ldap_first_name_attribute] = "givenName"\r
+  options[:ldap_last_name_attribute] = "sn"\r
+  options[:ldap_mail_attribute] = "mail"\r
 end\r
 \r
 Template.install(options)\r
index 565be3b..05b7479 100644 (file)
@@ -8,6 +8,7 @@ goto :end
 require 'yaml'\r
 require 'win32/service'\r
 require 'windows/authorization'\r
+require 'highline/import'\r
 \r
 PACKAGE_HOME = File.expand_path(ENV["PACKAGE_HOME"])\r
 \r
@@ -172,10 +173,10 @@ if %w[install uninstall start stop restart].include?(command)
 end\r
 Service.send(command)\r
 \r
-if pause\r
-  print "Press any key to exit..."\r
-  STDIN.gets\r
-end\r
+ask("Press any key to exit ... ") {|q|\r
+  q.character = true\r
+  q.echo = false\r
+} if pause\r
 \r
 __END__\r
 :end\r