Applied Simon Rozet's patch to provide a rake task for resetting a user's password.

I vendored highline, a gem the task uses to ask the user to type the new password without echoing it.

Thanks, Simon! Closes #623.



git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@696 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2008-01-06 19:52:59 +00:00
parent b17a1389cf
commit 9ac67bfc96
30 changed files with 5661 additions and 0 deletions

View file

@ -30,6 +30,7 @@ Wiki (deprecated - please use Trac): http://www.rousette.org.uk/projects/wiki/
14. Add ability to sort projects alphabetically
15. Add "starring" of actions
16. Statistics page with graphs
17. Rake task to set password. Usage: rake tracks:password USER=useranme
== Version 1.041

View file

@ -0,0 +1,25 @@
namespace :tracks do
desc 'Replace the password of USER with a new one.'
task :password => :environment do
Dependencies.load_paths.unshift(File.dirname(__FILE__) + "/..../vendor/gems/highline-1.4.0/lib")
require "highline/import"
user = User.find_by_login(ENV['USER'])
if user.nil?
puts "Sorry, we couldn't find user '#{ENV['USER']}'. To specify a different user, pass USER=username to this task."
exit 0
end
puts "Changing Tracks password for #{ENV['USER']}."
password = ask("New password: ") { |q| q.echo = false }
password_confirmation = ask('Retype new password: ') { |q| q.echo = false }
begin
user.change_password(password, password_confirmation)
rescue ActiveRecord::RecordInvalid
puts "Sorry, we couldn't change #{ENV['USER']}'s password: "
user.errors.each_full { |msg| puts "- #{msg}\n" }
end
end
end

View file

@ -0,0 +1,204 @@
= Change Log
Below is a complete listing of changes for each revision of HighLine.
== 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].

View file

@ -0,0 +1,35 @@
= 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.
== 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
== 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.

View file

@ -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.

View file

@ -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.

View file

@ -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_suite_file = "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

View file

@ -0,0 +1,6 @@
= To Do List
The following is a list of planned expansions for HighLine, in no particular
order.
* Rent this space.

View file

@ -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) %>")

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) %>")

View file

@ -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

View file

@ -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}!"

View file

@ -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

View file

@ -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 load reset quit}) do |q|
q.readline = true
end
say("Executing \"#{cmd}\"...")
break if cmd == "quit"
end

View file

@ -0,0 +1,744 @@
#!/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 "highline/system_extensions"
require "highline/question"
require "highline/menu"
require "highline/color_scheme"
require "erb"
require "optparse"
require "stringio"
require "abbrev"
#
# 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.4.0".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.
#
# 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
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
explain_error(:invalid_type)
retry
rescue Question::NoAutoCompleteMatch
explain_error(:no_completion)
retry
rescue NameError
raise if $!.is_a?(NoMethodError)
explain_error(:ambiguous_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 : 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
completions = @question.selection.abbrev
Readline.completion_proc = lambda { |string| completions[string] }
# 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.getc : 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
@output.print(@question.echo)
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.getc.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( lines )
wrapped = [ ]
lines.each 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[@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

View file

@ -0,0 +1,120 @@
#!/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
require 'highline'
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

View file

@ -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

View file

@ -0,0 +1,395 @@
#!/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?
update_responses # rebuild responses based on our settings
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?
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 = { :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})." }.merge(@responses)
end
end
end

View file

@ -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 recongnized 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

View file

@ -0,0 +1,130 @@
#!/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.
class HighLine
module SystemExtensions
module_function
#
# 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
require "termios" # Unix, first choice.
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.getc
ensure
Termios.setattr(input, Termios::TCSANOW, old_settings)
end
end
rescue LoadError # If our first choice fails, default.
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.getc
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 cbreak isig"
end
#
# Restores a previously saved input mode.
#
# *WARNING*: This method requires the external "stty" program!
#
def restore_mode
system "stty #{@state}"
end
end
# A Unix savvy method to fetch the console columns, and rows.
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

1360
tracks/vendor/gems/highline-1.4.0/setup.rb vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -0,0 +1,815 @@
#!/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_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 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 << "6/16/76\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(76, 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

View file

@ -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

View file

@ -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

View file

@ -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"