[Pkg-ruby-extras-commits] r1092 - in packages-wip: . libevent-loop-ruby libevent-loop-ruby/branches libevent-loop-ruby/branches/upstream libevent-loop-ruby/branches/upstream/current libevent-loop-ruby/branches/upstream/current/lib libevent-loop-ruby/branches/upstream/current/lib/event-loop

Florian Ragwitz florian-guest at alioth.debian.org
Mon Nov 13 14:52:38 CET 2006


Author: florian-guest
Date: 2006-11-13 14:52:29 +0100 (Mon, 13 Nov 2006)
New Revision: 1092

Added:
   packages-wip/libevent-loop-ruby/
   packages-wip/libevent-loop-ruby/branches/
   packages-wip/libevent-loop-ruby/branches/upstream/
   packages-wip/libevent-loop-ruby/branches/upstream/current/
   packages-wip/libevent-loop-ruby/branches/upstream/current/AUTHORS
   packages-wip/libevent-loop-ruby/branches/upstream/current/COPYING
   packages-wip/libevent-loop-ruby/branches/upstream/current/ChangeLog
   packages-wip/libevent-loop-ruby/branches/upstream/current/GFDL
   packages-wip/libevent-loop-ruby/branches/upstream/current/README
   packages-wip/libevent-loop-ruby/branches/upstream/current/README.utf-8
   packages-wip/libevent-loop-ruby/branches/upstream/current/Rakefile
   packages-wip/libevent-loop-ruby/branches/upstream/current/VERSION
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop.rb
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/better-definers.rb
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/event-loop.rb
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/io.rb
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/signal-system.rb
   packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/timer.rb
   packages-wip/libevent-loop-ruby/branches/upstream/current/setup.rb
   packages-wip/libevent-loop-ruby/tags/
Log:
[svn-inject] Installing original source of libevent-loop-ruby

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/AUTHORS
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/AUTHORS	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/AUTHORS	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,2 @@
+Daniel Brockman <daniel at brockman.se>
+Tilman Sauerbeck <tilman at code-monkey.de>

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/COPYING
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/COPYING	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/COPYING	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/ChangeLog
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/ChangeLog	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/ChangeLog	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,277 @@
+2006-10-19  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.3.
+
+	* Rakefile: No longer depend on rubygems.
+
+	* gemspec.rb: Move contents into `Rakefile'.
+
+	* VERSION: New file.
+
+	* setup.rb: New file (copied from upstream).
+
+	* README.utf-8: Update to reflect changes.
+
+	* lib/event-loop/timer.rb: Make lots and lots of changes without
+	having enough patience to document them here.
+
+	* lib/event-loop/signal-system.rb
+	(SignalEmitterModule#define_signal_handler): Define
+	`prehandle_...' and `posthandle_...' instead of `handle_...' and
+	`after_handle_...'.
+	(SignalEmitter#__signal__): Invoke `prehandle_...' and
+	`posthandle_...'.
+
+2006-04-23  Daniel Brockman  <daniel at brockman.se>
+
+	* lib/event-loop/timer.rb: New file extracted from
+	`lib/event-loop/event-loop.rb'.
+	(Timer#initialize): New instance variable `@alarm_handler'.
+	(Timer#replace_alarm_handler): New method.
+	(Timer#initialize, Timer#restart, Timer#start): Use it.
+	(Timer#initialize): Remove option parameter `:start?'.
+	(TimerTest#test_start_monitoring_timer_while_running): Explicitly
+	call `#start'.
+	(Timer#start, Timer#stop): Set `@running'.
+	(Timer#stop): Don't clear `@start_time'.
+	(Timer#stopped?, Timer#running?): Check `@running' instead of
+	`@start_time'.
+	(Timer#started?): New method.
+	(Timer#start_time, Timer#end_time, Timer#time_left, Timer#ready?):
+	Fail if `@start_time' is nil.
+	(Timer#end_time=, Timer#time_left=): New methods.
+	(Timer#initialize): Make `interval' a mandatory
+	positional parameter.  Remove `:interval' keyword parameter.
+
+	* lib/event-loop/io.rb: New file extracted from
+	`lib/event-loop/event-loop.rb'.
+
+	* lib/event-loop/event-loop.rb
+	(EventLoop::Utitilies.validate_keyword_arguments): New method
+	extracted from EventLoop::Timer::initialize.
+	(EventLoop#initialize): Document why we have to explicitly extend
+	the notify source with EventLoop::Watchable.
+
+2006-02-06  Daniel Brockman  <daniel at brockman.se>
+
+	* lib/event-loop/event-loop.rb (Numeric#seconds, Numeric#minutes)
+	(Numeric#hours, Numeric#days, Numeric#weeks, Numeric#years)
+	(Integer#years): New methods.
+
+2006-02-05  Daniel Brockman  <daniel at brockman.se>
+
+	* Rakefile (check): Run tests with `ruby -w'.
+	Suggested by Tilman Sauerbeck.
+
+2006-02-05  Tilman Sauerbeck  <tilman at code-monkey.de>
+
+	* lib/event-loop/event-loop.rb (EventLoop#restart)
+	(EventLoop#start): Add parentheses (this avoids warnings).
+
+2006-01-31  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.2.
+
+	This time I won't use Ruby 1.8.3 to build the Gem package.
+	Thanks to Tilman Sauerbeck for pointing out that problem.
+
+	* lib/event-loop/event-loop.rb (Timer#interval=): Only invoke
+	EventLoop#check_timer when the timer is running.
+	(Timer#start, Timer#restart): Accept blocks (for convenience).
+	(EventLoop#monitor_timer): Actually check the timer.
+	(TimerTest): Create new event loops for each test.
+	(TimerTest::test_start_monitoring_timer_while_running): New test.
+	(Time.measure): New method.
+
+	* Rakefile (README): Convert Unicode copyright symbols to
+	conventional ASCII ones.  Add note warning that README is
+	automatically generated.
+
+	* GFDL: New file.
+
+	* README.utf-8: License this document under the GFDL.
+	(Table of Contents): New section.
+	(time-stamp-format, time-stamp-start, time-stamp-end):
+	New local variables (for Emacs).
+
+2006-01-30  Daniel Brockman  <daniel at brockman.se>
+
+	* README.utf-8 (Event Sources): New section.
+	Suggested by Luke Kanies.
+
+	* lib/event-loop/event-loop.rb (Timer#end_time): Raise an
+	exception if the timer is not running.
+	(TimerTest#test_monitor_unstarted_timer): New test case.
+	(Timer#restart, Timer#sound_alarm, Timer#start, Timer#stop)
+	(EventLoop#wake_up): For convenience, return self.
+
+2006-01-25  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.1.
+
+	* README.utf-8: Improve the documentation, explaining more
+	in-depth how IO objects and timers interact with event loops, and
+	providing some meaningful examples, including one that shows how
+	to use the `IO#will_block' property, and one at the end that
+	provides an outline for the typical application.
+
+	* lib/event-loop/event-loop.rb (Timer.new): Fail if given
+	unrecognized keyword arguments.  Suggested by Luke Kanies.
+	(Timer): Add reader for property `event_loop'.
+	(EventLoop): Rename property `sleeping?' to `asleep?', for
+	symmetry with `awake?'.
+	(EventLoop.with_current): Warn the user if `EventLoop.current' is
+	permanently changed within the dynamic extent of `with_current'.
+
+2005-11-17  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.0.20051116.
+
+	* lib/event-loop/signal-system.rb (SignalEmitterModule.extended):
+	Use `fcall' instead of `send' on Ruby 1.9.
+
+2005-09-28  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.0.20050928.
+
+	* lib/event-loop/signal-system.rb
+	(SignalEmitter#__maybe_initialize_signal_emitter): Avoid warnings
+	about using an uninitialized instance variable.
+
+2005-09-04  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.0.20050904.
+
+	* Rakefile (upload): Print an error message if this target is used
+	by someone other than the maintaner.
+	(README): Warn if the Unicode string handling is broken.
+
+2005-09-04  Tilman Sauerbeck  <tilman at code-monkey.de>
+
+	* Rakefile: Add `install' target.
+
+2005-08-28  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.0.20050829.0000.
+
+	* lib/event-loop/signal-system.rb (SignalEmitterClass):
+	Rename to SignalEmitterModule.
+	(SignalEmitterModule.extended): New method.
+
+2005-08-26  Daniel Brockman  <daniel at brockman.se>
+
+	* lib/event-loop/signal-system.rb
+	(SignalEmitterClass#define_signal_handler): New method.
+	(SignalEmitterClass#define_signal): Use it.
+	(SignalObserver#absorb_signals): New method.
+	(SignalObserver#absorb_signal, SignalObserver#map_signal):
+	New soft aliases.
+
+	* lib/event-loop/better-definers.rb
+	(Module#define_guarded_writers): Pass the block along to
+	`guard_writers' (fixes an obvious bug).
+
+	* lib/event-loop/signal-system.rb
+	(SignalEmitter): New attribute `allow_dynamic_signals?'.
+	(SignalEmitter#__signal__): Fail for undefined signals unless
+	these are explicitly allowed (by the new attribute).
+
+2005-08-25  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.0.20050825.1600.
+
+	* README.utf-8: Update installation instructions, thank Tilman
+	some more for the gem specification, and add a section explaining
+	what timer tolerances are for.
+
+	* lib/event-loop.rb: New file.
+
+	* event-loop.rb, signal-system.rb, better-definers.rb:
+	Move source files to `lib/event-loop/'.  Change `require'
+	statements accordingly.
+
+	* lib/, lib/event-loop/: New directories.
+
+	* Rakefile: Add new `upload' target.
+
+	* Makefile: Move `check' target to Rakefile and delete.
+
+	* gemspec.rb: Clean up and copyedit. :-)
+
+2005-08-23  Tilman Sauerbeck  <tilman at code-monkey.de>
+
+	* Rakefile: New file.
+
+	* gemspec.rb: New file.
+
+2005-08-23  Daniel Brockman  <daniel at brockman.se>
+
+	* event-loop.rb (EventLoop#select, EventLoop#run): Don't call
+	`maybe_initialize_pipe'.
+
+	* event-loop.rb (EventLoop#maybe_initialize_pipe):
+	Remove unused method.
+
+2005-08-21  Daniel Brockman  <daniel at brockman.se>
+
+	Release 0.0.20050821.2356.
+
+	* README.utf-8: Fix typos.
+
+	* better-definers.rb (Module#define_soft_aliases):
+	Parenthesize splatted arguments to avoid warnings.
+
+	* event-loop.rb (EventLoop#initialize): Initialize @awake.
+
+2005-08-20  Daniel Brockman  <daniel at brockman.se>
+
+	* signal-system.rb (SignalObserver#ignore_signal): Fix fatal bug.
+	(SignalEmitter#__signal__): Don't pass `self' as first argument.
+
+	* better-definers.rb (Module#guard_writers):
+	Use `define_hard_alias' rather than `define_alias'.
+
+	* signal-system.rb: Likewise.
+
+	* event-loop.rb: Use qualified names in `require'.
+	(EventLoop#maybe_initialize_pipe): Use `sysread(256)' instead of
+	`read' to read from the notification pipe.
+
+	* Makefile (check): Pass `-I..' option to `ruby'.
+
+2005-08-19  Daniel Brockman  <daniel at brockman.se>
+
+	* README.utf-8 (IO Events): Update documentation to reflect the
+	changes related to Watchable::Automatic.
+
+	* event-loop.rb (Watchable::Automatic): New module.
+	(Watchable#remove_signal_handler, Watchable#add_signal_handler):
+	Move to new module.
+	(Watchable#monitor_events, Watchable#ignore_events):  New methods.
+	(Watchable#close_read, Watchable#close_write)
+	(Watchable#close): Use them.
+	(IO#on_readable, IO#on_writable, IO#on_exceptional):  Extend with
+	Watchable::Automatic instead of just Watchable.
+	(EventLoop#maybe_initialize_pipe): Use `read' instead of
+	`sysread(1)' to read from the notification pipe.
+	(Symbol#io_state?): New convenience method.
+
+	* event-loop.rb (EventLoop#check_timer): New method.
+	(EventLoop#monitor_timer): Use it.
+	(EventLoop#select): New private method.
+	(EventLoop#iterate): Refactor using new `select' helper method.
+
+	* event-loop.rb (Timer.new): New option `event_loop'.  Each timer
+	is now associated with exactly one event loop.
+	(Timer#fire_alarm): Only restart the timer if it is still running
+	when the alarm returns.
+	(Timer#start, Timer#stop): Use @event_loop instead of EventLoop.
+	(Timer#fire_alarm): Rename to `sound_alarm'.
+	(Timer#stopped?, Timer#running?): Instead of checking @running,
+	assume that @start_time is nil iff the timer is running.
+
+	* event-loop.rb (Timer#initialize): Allow a single numeric
+	argument as a shorthand for specifying the interval.
+	(Timer#interval=): New method.
+
+	* ChangeLog: New file.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/GFDL
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/GFDL	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/GFDL	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,397 @@
+		GNU Free Documentation License
+		  Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject.  (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License.  Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License.  However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+    Copyright (c)  YEAR  YOUR NAME.
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.2
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+    with the Invariant Sections being LIST THEIR TITLES, with the
+    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/README
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/README	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/README	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,708 @@
+------------------------------------------------------------
+ This file was automatically generated from `README.utf-8'.
+------------------------------------------------------------
+
+README for event-loop 0.3
+Copyright (C) 2005, 2006  Daniel Brockman
+
+Author: Daniel Brockman <daniel at brockman.se>
+Written: August 19, 2005
+Updated: October 19, 2006
+
+This document describes a simple signal system and an event
+loop that uses said signal system.
+
+Permission is granted to copy, distribute and/or modify this
+document under the terms of the GNU Free Documentation
+License, Version 1.2 or any later version published by the
+Free Software Foundation; with no Invariant Sections, no
+Front-Cover Texts, and no Back-Cover Texts.  You should have
+received a copy of the license along with this document; if
+not, write to the Free Software Foundation, 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+The next screenful of paragraphs is mostly side-chatter.
+If you scroll down a bit, you'll find a table of contents.
+
+If you have any questions, comments, requests, bug reports,
+or patches, please send them to me at <daniel at brockman.se>.
+
+I have a Darcs repository at this URL,
+
+   <http://www.brockman.se/software/ruby-event-loop/>
+
+so you can easily grab a copy of the latest version:
+
+   $ darcs get http://www.brockman.se/software/ruby-event-loop/
+
+If you make any changes, you can send them back to me:
+
+   $ darcs record
+   $ darcs send
+
+You can also reach me on IRC as `dbrock' on Freenode.
+But I'll say that a couple more times below.
+
+This software originated in a Direct Connect client
+codenamed Refusde, but now stands on its own.
+
+Thanks to Tilman Sauerbeck for prompting me to wrap these
+files up in a self-contained package, and then demanding
+documentation.  Without him, this file wouldn't exist. :-)
+
+Tilman also helped by creating a RubyGems specification,
+and by translating the Makefile into a Rakefile.
+
+To counteract confusion, I'll say a few words about
+version numbers before I begin.
+
+Prior to version 0.1, this package used to have version
+numbers like 0.0.20051116 --- a kind of self-inflicted FUD.
+Now that it's been used by at least a couple of people other
+than myself, I've decided to switch to a more conventional
+line of version numbers: 0.1, 0.2, ..., 0.10, and so on.
+
+Should a smart person read the code today and come across
+some deeply embedded idiocy, I can point to these other
+people as proof that I'm not the only idiot around here.
+Then I can proceed to fix the idiocy by completely changing
+the API, totally breaking compatibility, and if anyone
+complains I can always tell them they're idiots.
+
+
+Table of Contents
+=================
+
+This document is getting long enough that I'm starting to
+have trouble navigating it myself.  I probably should
+convert it into an Info manual.  But until that happens,
+maybe this table of contents will help a little.
+
+You will note that there's no section that says anything
+about the file `better-definers.rb'.  I don't have any good
+excuse for this; maybe I'll write that section some day.
+In the meantime, the code itself is really easy to follow.
+
+ * Installation
+ * The Signal System: `signal-system.rb'
+   - Emitting Signals
+   - Receiving Signals
+ * The Event Loop: `event-loop.rb'
+   - Creating Event Loops
+   - Event Sources
+   - IO Events: `io.rb'
+   - Timer Events: `timer.rb'
+   - Running the Event Loop
+
+Installation
+============
+
+I suppose the recommended way of using this software is to
+install the gem package.  But if you don't want to do that,
+you could simply copy or symlink the files into your project
+directory and require whichever ones you need.
+
+The files in `lib/event-loop/' must reside in a directory
+called `event-loop/' for the dependencies to work, so if you
+are taking anything, take the whole `event-loop/' directory.
+
+While `signal-system.rb' depends on `better-definers.rb',
+and `event-loop.rb' depends on both the aforementioned two,
+it is quite possible to use `signal-system.rb' without
+`event-loop.rb', or `better-definers.rb' without either.
+
+Indeed, `better-definers.rb' and `signal-system.rb' are two
+very general-purpose libraries, and you are likely to be
+able to put them to use for most applications, regardless of
+whether or not they are based on an event loop.
+
+For completeness, `timer.rb' depends on `event-loop.rb',
+and `event-loop.rb' and `io.rb' depend on each other.
+
+
+The Signal System
+=================
+
+This package comes with an intra-process signal system.
+I call these signals "intra-process signals" to distinguish
+them from Unix signals, which are "inter-process signals".
+
+But now that I've made that clear, I'm going to go ahead and
+refer to intra-process signals as just "signals", and to the
+intra-process signal system simply as "the signal system".
+
+Anyway, the signal system is a generic callback mechanism,
+similar in spirit to the `observable' library that comes
+with the standard Ruby distribution.  It allows anonymous
+observers to track the events of signal-emitting objects
+(thereby helping to decrease coupling).
+
+The idea is similar to that of the GObject signal system,
+and a myriad of others like it.  (If you know INTERCAL,
+signals are to methods as COME FROM is to GO TO.)
+
+
+Emitting Signals
+----------------
+
+If you want your objects to be capable of emitting signals,
+their classes should include the `SignalEmitter' module.
+That will automatically rig the classes with everything you
+need to define signals (the `SignalEmitterModule' module).
+
+For example, this code
+
+   class Dog
+     include SignalEmitter
+     define_signal :bark
+     def bark
+       puts "Bark!"
+       signal :bark
+     end
+   end
+
+   spot = Dog.new
+   spot.on_signal :bark do
+     puts "Hush, Spot!"
+   end
+
+   3.times { spot.bark }
+
+results in the following output:
+
+   Bark!
+   Hush, Spot!
+   Bark!
+   Hush, Spot!
+   Bark!
+   Hush, Spot!
+
+
+Receiving Signals
+-----------------
+
+The true name for the method that connects a block or proc
+to a signal is `add_signal_handler'.  However, that gets
+awfully long when connecting to lots of signals, so there
+are a couple of shortcuts.
+
+First, there are the `on' and `on_signal' aliases.
+These synonyms just delegate to `add_signal_handler'.
+
+Second, every predefined signal FOO gets a shorthand
+connector method called `on_FOO'.  So in the above example,
+we could have written this instead:
+
+   spot = Dog.new
+   spot.on_bark { puts "Hush, Spot!" }
+
+The `on_FOO' variant is nice for connecting to signals whose
+names are known statically.  Otherwise, `on_signal' is
+usually preferable; these other cases are typically not
+common enough to justify the short form `on'.
+
+Connecting signal handlers is a breeze, but *disconnecting*
+them is actually a minor pain in the ass.  Without having an
+explicit reference to the handler, you cannot identify it,
+which means that you cannot tell `remove_signal_handler'
+what handler you want to remove.
+
+An example of the obvious but painful solution follows:
+
+   spot = Dog.new
+   @bark_handler = lambda { puts "Hush, Spot!" }
+   spot.on_bark &@bark_handler
+   # ...
+   spot.remove_signal_handler @bark_handler
+
+The `SignalObserver' module provides a slightly
+better solution:
+
+   class DogOwner
+     include SignalObserver
+
+     def initialize(dog=nil)
+       @dog = dog || Dog.new("Spot")
+       observe_signal @dog, :bark do
+         puts "Shut up, #{@dog.name}"
+       end
+     end
+
+     def stop_yelling
+       ignore_signal @dog, :bark
+     end
+   end
+
+But `SignalObserver' has a few caveats that make it
+insufficient as a general solution (see the source).
+
+In the future, I'd like to provide a more powerful mechanism
+for connecting to signals.  Perhaps involving handler tags.
+If you want this feature, nagging me about it on IRC (I'm
+`dbrock' on Freenode) or via e-mail usually works best.
+
+
+The Event Loop
+==============
+
+This section explains how IO multiplexing works in general
+(albeit briefly and not very in-depth), and specifically the
+issues relevant for Ruby applications.  You may safely skip
+it if you (a) already know this subject, or (b) don't care.
+
+Plain ol' blocking IO works well when you're reading from
+just a single file descriptor.  But when you're interested
+in a whole bunch of FDs, you can't wait for any single one
+of them to become readable or writable, because then you'll
+inevitably miss that happening to the other ones.  Instead,
+you need a multiplexer that can wait for them *all at once*.
+
+There are a handful of low-level multiplexing primitives:
+`select', `poll', `epoll', `/dev/poll', and `kqueue'.
+In addition, there are portable low-level wrapper libraries
+such as libevent, which can use any of those primitives.
+The event loop in this package uses the standard `select'
+wrapper shipped with Ruby, `IO::select'.  But in the future,
+I'd like to use libevent instead, because that'd be cooler.
+
+Most applications use a higher-level abstraction built on
+top of the low-level multiplexer, usually called a `main
+loop', an `event loop', or an `event source'.  There are
+also libraries such as liboop, which generalizes the event
+source and event sink concepts, so that components (event
+sinks) written against liboop become event-source-agnostic.
+
+Actually, the combination of blocking IO and Ruby's green
+threads works well in most cases where you would normally
+use an event loop.  When you call `IO#read' on an empty file
+descriptor, for instance, Ruby suspends that thread until
+its internal event loop, known as the scheduler (currently
+based on `select'), determines that the file descriptor has
+become readable.  In particular, Ruby never calls the
+low-level `read' function unless it knows that it will not
+block (because `select' said it wouldn't, but see below).
+
+There are several reasons why you would use an event loop
+such as the one implemented by this library instead of
+not-so-plain ol' blocking IO with Ruby's green threads.
+
+First of all, you may consider the event loop API more
+pleasant than Ruby's threads and not-quite-blocking IO.
+Otherwise, don't listen to me; go on using the latter. :-)
+
+Blocking IO can occasionally cause unexpected problems.
+For example, in some cases a blocking read *can* block even
+though select said that the file descriptor was readable.
+This problem may be rare (it can happen, for instance, when
+the checksum of a piece of data fails to match the payload),
+but the bottom line is that non-blocking IO is safer.
+
+Perhaps most importantly, while Ruby's threads are green,
+they are still effectively preemptively scheduled, with all
+the implications thereof --- in a word, synchronization hell.
+By contrast, event handlers are executed in a strictly
+sequential manner; an event loop will never run two event
+handlers simultaneously.  (Though, of course, all bets are
+off if you run multiple event loops in separate threads.)
+
+
+Creating Event Loops
+--------------------
+
+You create a new event loop by calling `EventLoop.new'.
+However, if you only need one --- which is likely --- you
+can get it for free by reading from `EventLoop.default'.
+
+If you need multiple event loops in separate threads, put
+them in `EventLoop.current', which will make each of them
+end up in a thread-local variable.
+
+Actually, if you read from `EventLoop.current' before
+writing to it, it defaults to `EventLoop.default', so you
+might as well use `EventLoop.current' in single-threaded
+applications as well.
+
+In fact, `EventLoop.current' is so common that it can be
+shortened to just `EventLoop', if there is no ambiguity.
+So `EventLoop.run' is short for `EventLoop.current.run'.
+
+To dynamically change the "current event loop" for a block
+of code, it is convenient to use `EventLoop.with_current'.
+
+Once you've got the event loop sitting in front of you just
+waiting to be used, you'll want to add some event sources,
+and then finally run the loop.  So, first things first:
+What are event sources, and how do you add them to the loop?
+
+
+Event Sources
+-------------
+
+As for the first question, this package currently supports
+two kinds of event sources: watchable IO objects and timers.
+The former kind is used to detect file descriptor activity;
+the latter is used for wall-clock scheduling of execution.
+
+Typically, you don't add event sources to the loop manually.
+Both watchable IO objects and timers provide convenient ways
+of making them add themselves to the "current" event loop.
+
+For example, to add `@io' to the current event loop, you
+might write something like the following:
+
+   @io.monitor_events :readable, :writable
+
+That's short for the following more explicit code:
+
+   EventLoop.current.monitor_io(@io, :readable, :writable)
+
+The call to `EventLoop#monitor_io' causes the event loop to
+wake up --- if it was sleeping in a call to `IO.select' --- and
+adds `@io' to the event loop's set of monitored IO objects.
+For the next event loop iteration, `@io' will be included in
+one or more of the sets passed to `IO.select'.
+
+To add the IO object to another event loop,
+
+   other_loop.monitor_io(@io, :readable, :writable)
+
+you can do it like this,
+
+   EventLoop.with_current(other_loop) do
+     @io.monitor_events :readable, :writable end
+
+which is especially convenient when adding multiple objects.
+
+For timers, it's even easier:
+
+   @timer = EventLoop::PeriodicTimer.new(1.second)
+   @timer.start
+
+That call to `@timer.start' causes the following to happen:
+
+   EventLoop.current.monitor_timer(@timer)
+
+The call to `EventLoop#monitor_timer' may force the event
+loop to wake up, depending on the timer readings and the
+current timeout of the event loop.  In any case, the timer
+is added to the event loop's set of monitored timers.
+
+But there's a caveat.  This will not work as expected:
+
+   EventLoop.with_current(other_loop) { @timer.start }
+
+That's because timer objects decide in advance which event
+loop they are going to use.  Once initialized, timer objects
+no longer care about the value of the current event loop.
+Hence, this code starts a timer in a different event loop:
+
+   @timer = EventLoop.with_current(other_loop) do
+     EventLoop::PeriodicTimer.new(1.second) end
+   @timer.start
+
+Here is another way of writing it:
+
+   @timer = EventLoop::PeriodicTimer.new \
+     1.second, :event_loop => other_loop
+   @timer.start
+   
+In addition, there are quite a few convenient short forms.
+For example, you can write things like this:
+
+   3.seconds.from_now { puts "Boo!" }
+
+Read on, because the next two sections describe with better
+examples and in more detail how IO and timer events work.
+
+[Actually, there are no examples of using timers at all.
+But it would be nice to have some under "Timer Events".]
+
+
+IO Events
+---------
+
+In Ruby, file descriptors are instances of the class IO.
+Before you can use one of these with the event loop, you
+need to extend it with the module `EventLoop::Watchable'.
+That module defines two signals, `readable' and `writable',
+and a pair of methods for activating and deactivating them.
+
+When you want to start receiving `readable' signals, for
+instance, you call `io.monitor_event :readable'.  This makes
+the current event loop monitor `io' for readability, and
+emit the `readable' signal on it when the condition occurs.
+
+   require "socket"
+
+   def initialize (host, port)
+     @socket = TCPSocket.new(host, port)
+     @socket.extend EventLoop::Watchable
+     @socket.will_block = false
+     @socket.on_readable { perform_read }
+   end
+
+   def start_listening
+     @socket.monitor_event :readable
+   end
+
+The `will_block?' property is provided by this package as a
+convenient way of setting up non-blocking IO streams.
+(See `lib/event-loop/io.rb', circa line 81.)
+
+The method that actually performs the reading will probably
+look more or less like so:
+
+   def perform_read
+     process_data @socket.sysread(BUFFER_SIZE, @buffer)
+   rescue EOFError
+     ...
+   rescue Errno::ECONNRESET
+     ...
+   rescue
+     ...
+   end
+
+If you don't want to receive any more `readable' signals,
+you just call `io.ignore_event :readable'.
+
+   def stop_listening
+     @socket.ignore_event :readable
+   end
+
+The "current event loop" is just `EventLoop.current'.
+To make another event loop (say `other_loop') monitor or
+ignore an IO event, either call `other_loop.monitor_io' or
+`other_loop.ignore_io' directly,
+
+   other_loop.monitor_io(io, :readable)
+   other_loop.ignore_io(io, :writable)
+
+or use the `EventLoop.with_current' form,
+
+   EventLoop.with_current(other_loop) do
+     io.monitor_event :readable
+     io.ignore_event :writable
+   end
+
+which implements "dynamic scoping" of `EventLoop.current'.
+
+If you simply want readable signals to be emitted whenever
+there are handlers connected to the `readable' signal (and
+likewise for `writable'), without having to mess around with
+`monitor_event' and `ignore_event', you can extend the IO
+object with the `EventLoop::Watchable::Automatic' module
+instead of `EventLoop::Watchable'.
+
+The `EventLoop::Watchable::Automatic' module sets it up so
+that when you connect a handler to either the `readable' or
+the `writable' signal, the current event loop begins
+monitoring the IO object for the corresponding condition,
+and, inversely, when you remove the last handler, it tells
+the event loop to stop monitoring the condition.
+
+Because this is so often useful, you don't even have to
+extend the IO object yourself.  Stub implementations of the
+`on_readable' and `on_writable' methods are provided, which
+automatically bootstrap the IO by extending it with the
+`EventLoop::Watchable::Automatic' module when invoked.
+
+     @socket = TCPSocket.new(host, port)
+     @socket.will_block = false
+
+     # By invoking the stub `on_readable' method,
+     # we implicitly extend the IO object with the
+     # module `EventLoop::Watchable::Automatic'.
+     #
+     # That module hooks into the signal system and
+     # reacts when we start watching the `readable'
+     # signal by starting to monitor that event.
+     @socket.on_readable { perform_read }
+
+Note that once an IO object has been extended with the
+`EventLoop::Watchable::Automatic' module, there is currently
+no way to make it non-automatic (Ruby does not yet allow you
+to un-extend an object with a module).  So if you don't want
+the automatic behavior, you *have* to manually extend the
+object with the `EventLoop::Watchable' module before calling
+either of the `or_readable' and `on_writable' methods.
+
+There is actually a third signal: `exceptional', which is
+emitted when `select' reports that the file descriptor is in
+an "exceptional state".  You probably don't need to worry
+about this (and if you do, you'll probably know it already).
+
+But in case you're wondering, I think you can use it to
+watch for out-of-band data coming through a socket, provided
+you've set the right socket options.  I also believe you can
+use it to determine that a non-blocking connection attempt
+has failed.  (When such an attempt succeeds, a writability
+event is fired for the socket.)  But that doesn't matter,
+because you can't do non-blocking connects in Ruby. :-)
+
+
+Timer Events
+------------
+
+If you need to do something after a given amount of
+wall-clock time has passed, just do the following:
+
+ 1.  Create an `EventLoop::SporadicTimer', passing the
+     timeout (in seconds) to the constructor.
+ 2.  Connect to its `alarm' signal (using `on_alarm').
+ 3.  Start the timer (using `start').
+
+Sporadic timers only sound their alarm once, and then stop.
+If you want to do something periodically, like every second,
+use `EventLoop::PeriodicTimer' instead.
+
+You can start a sporadic timer as many times as you want,
+but it will still stop itself every time it goes off.
+Periodic timers must be stopped explicitly (using `stop'),
+or they will keep going off as long as the event loop runs.
+
+You can get the effect of an "idle function" by creating an
+periodic timer with a zero-second interval, meaning its
+alarm will sound as often as possible.
+
+If you pass a block to a timer constructor, then that block
+will become the timer's canonical "alarm handler", which is
+just a signal handler for the `alarm' signal, except that
+you can easily replace it, using `replace_alarm_handler'.
+
+Another way to replace the alarm handler is to pass a block
+to the `start' method or to the `restart' method, which will
+just cause `replace_alarm_handler' to be called first.
+
+There are a number of short forms for creating a timer and
+setting its alarm handler.  The following statements are
+pairwise equivalent:
+
+   sporadic_timer = EventLoop.after(3.seconds) do ... end
+   sporadic_timer = 3.seconds.from_now { ... }
+
+   periodic_timer = EventLoop.every(3.seconds) do ... end
+   periodic_timer = 3.seconds.from_now_and_repeat { ... }
+
+   sporadic_timer = other_loop.after(3.seconds) do ... end
+   EventLoop.with_current(other_loop) do
+     sporadic_timer = 3.seconds.from_now { ... } end
+
+   periodic_timer = other_loop.every(3.seconds) do ... end
+   EventLoop.with_current(other_loop) do
+     periodic_timer = 3.seconds.from_now_and_repeat { ... } end
+
+   idle_function_timer = EventLoop.every(0) { ... }
+   idle_function_timer = EventLoop.repeat { ... }
+
+   one_shot_idle_function_timer = EventLoop.after(0) { ... }
+   one_shot_idle_function_timer = EventLoop.later { ... }
+
+All of the above forms automatically start the timer.
+
+When a timer is started, the event loop associated with the
+timer is notified and its timeout value updated accordingly.
+(Unlike `Watchable#monitor_event', the `Timer#start' method
+does not depend on the value of `EventLoop.current'.)
+
+By passing `:event_loop => foo' to the timer constructor,
+you can specify which event loop the timer should use;
+otherwise, the "current event loop" (`EventLoop.current')
+will be used as a default.
+
+You can ask a timer for the amount of time left by invoking
+its `time_left' method.  When called from an alarm handler,
+it will typically return a negative value, representing the
+amount of time passed since the alarm was supposed to sound.
+
+However, if you specify `:tolerance => 0.1' when creating
+the timer, you are saying it's okay for the alarm to sound
+one-tenth of a second too early.  In that case, `time_left'
+can return a positive value even when called from within an
+alarm handler, indicating the alarm sounded too early.
+
+The next section explains why you should set the tolerance
+higher than zero (it is currently 0.001 by default).
+
+
+Timer Tolerances
+................
+
+It is useful for timers to have some amount of tolerance
+because the timeout specified to `select' is an upper bound.
+This means that the process will usually wake up slightly
+earlier than expected.  For example, if you start a timer
+set for two seconds and then enter an event loop iteration,
+the call to `select' is likely to return in 1.99 seconds.
+
+If your timer's tolerance is set to zero, that means that
+the alarm must not be sounded yet, and the event loop is
+forced to perform an extra iteration with a 0.01 timeout.
+If, on the other hand, the tolerance of the timer is set to
+at least 0.01 seconds, then that means it's okay for the
+alarm to sound slightly too early; in this case, the need
+for an extra iteration can be avoided.
+
+Currently, the error made by a tolerant timer during one
+iteration is not compensated for during the next iteration.
+Combined with the fact that a tolerant timer will usually
+sound too early rather than too late (because the kernel
+tries hard not to wake the process too late), this means
+that the more tolerant your timer is, the more frequently it
+will sound.  In other words, the error accumulates.
+
+This should not be a problem in most cases, simply because
+of the fact that people do not in most cases use Ruby for
+applications that need this kind of precision (the default
+timer tolerance is one millisecond).  However, if you would
+like to see this problem addressed, please contact me.
+
+
+Running the Event Loop
+----------------------
+
+To run the current event loop, just call `EventLoop.run'.
+That'll block until an event handler says `EventLoop.quit'.
+
+One typical event loop application looks like this:
+
+  ...
+  @socket.on_writable { ... }
+  @socket.on_readable do
+    ...
+    if something_or_other
+      EventLoop.quit
+    end
+  end
+  ...
+  @timer.start
+  ...
+  EventLoop.run
+
+While the event loop is running, everything that the
+application does takes place in event handlers.
+
+If you want more control, you can run a single iteration of
+the event loop by calling `EventLoop.iterate', which takes
+an optional argument specifying (in seconds) the upper bound
+on the amount of time to block.  The default value (`nil')
+means infinity; it causes the upper bound to be the amount
+of time left before the next timer is due.  If you're not
+using timers, `EventLoop.iterate' without an argument blocks
+until the first interesting IO event occurs.
+
+That should be all you need to know to use this event loop.
+If it turns out not to be, please bug me on IRC (as I said,
+I'm `dbrock' on Freenode) or send me an e-mail.  The source
+shouldn't be particularly hard to understand either.
+
+Thanks for your interest, and happy hacking!
+
+                        --- Daniel Brockman
+
+
+## Local Variables:
+## coding: utf-8
+## time-stamp-format: "%:b %:d, %:y"
+## time-stamp-start: "Updated: "
+## time-stamp-end: "$"
+## End:

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/README.utf-8
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/README.utf-8	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/README.utf-8	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,704 @@
+README for event-loop 0.3
+Copyright © 2005, 2006  Daniel Brockman
+
+Author: Daniel Brockman <daniel at brockman.se>
+Written: August 19, 2005
+Updated: October 19, 2006
+
+This document describes a simple signal system and an event
+loop that uses said signal system.
+
+Permission is granted to copy, distribute and/or modify this
+document under the terms of the GNU Free Documentation
+License, Version 1.2 or any later version published by the
+Free Software Foundation; with no Invariant Sections, no
+Front-Cover Texts, and no Back-Cover Texts.  You should have
+received a copy of the license along with this document; if
+not, write to the Free Software Foundation, 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+The next screenful of paragraphs is mostly side-chatter.
+If you scroll down a bit, you’ll find a table of contents.
+
+If you have any questions, comments, requests, bug reports,
+or patches, please send them to me at <daniel at brockman.se>.
+
+I have a Darcs repository at this URL,
+
+   <http://www.brockman.se/software/ruby-event-loop/>
+
+so you can easily grab a copy of the latest version:
+
+   $ darcs get http://www.brockman.se/software/ruby-event-loop/
+
+If you make any changes, you can send them back to me:
+
+   $ darcs record
+   $ darcs send
+
+You can also reach me on IRC as ‘dbrock’ on Freenode.
+But I’ll say that a couple more times below.
+
+This software originated in a Direct Connect client
+codenamed Refusde, but now stands on its own.
+
+Thanks to Tilman Sauerbeck for prompting me to wrap these
+files up in a self-contained package, and then demanding
+documentation.  Without him, this file wouldn’t exist. :-)
+
+Tilman also helped by creating a RubyGems specification,
+and by translating the Makefile into a Rakefile.
+
+To counteract confusion, I’ll say a few words about
+version numbers before I begin.
+
+Prior to version 0.1, this package used to have version
+numbers like 0.0.20051116 — a kind of self-inflicted FUD.
+Now that it’s been used by at least a couple of people other
+than myself, I’ve decided to switch to a more conventional
+line of version numbers: 0.1, 0.2, ..., 0.10, and so on.
+
+Should a smart person read the code today and come across
+some deeply embedded idiocy, I can point to these other
+people as proof that I’m not the only idiot around here.
+Then I can proceed to fix the idiocy by completely changing
+the API, totally breaking compatibility, and if anyone
+complains I can always tell them they’re idiots.
+
+
+Table of Contents
+=================
+
+This document is getting long enough that I’m starting to
+have trouble navigating it myself.  I probably should
+convert it into an Info manual.  But until that happens,
+maybe this table of contents will help a little.
+
+You will note that there’s no section that says anything
+about the file ‘better-definers.rb’.  I don’t have any good
+excuse for this; maybe I’ll write that section some day.
+In the meantime, the code itself is really easy to follow.
+
+ * Installation
+ * The Signal System: ‘signal-system.rb’
+   - Emitting Signals
+   - Receiving Signals
+ * The Event Loop: ‘event-loop.rb’
+   - Creating Event Loops
+   - Event Sources
+   - IO Events: ‘io.rb’
+   - Timer Events: ‘timer.rb’
+   - Running the Event Loop
+
+Installation
+============
+
+I suppose the recommended way of using this software is to
+install the gem package.  But if you don’t want to do that,
+you could simply copy or symlink the files into your project
+directory and require whichever ones you need.
+
+The files in ‘lib/event-loop/’ must reside in a directory
+called ‘event-loop/’ for the dependencies to work, so if you
+are taking anything, take the whole ‘event-loop/’ directory.
+
+While ‘signal-system.rb’ depends on ‘better-definers.rb’,
+and ‘event-loop.rb’ depends on both the aforementioned two,
+it is quite possible to use ‘signal-system.rb’ without
+‘event-loop.rb’, or ‘better-definers.rb’ without either.
+
+Indeed, ‘better-definers.rb’ and ‘signal-system.rb’ are two
+very general-purpose libraries, and you are likely to be
+able to put them to use for most applications, regardless of
+whether or not they are based on an event loop.
+
+For completeness, ‘timer.rb’ depends on ‘event-loop.rb’,
+and ‘event-loop.rb’ and ‘io.rb’ depend on each other.
+
+
+The Signal System
+=================
+
+This package comes with an intra-process signal system.
+I call these signals “intra-process signals” to distinguish
+them from Unix signals, which are “inter-process signals”.
+
+But now that I’ve made that clear, I’m going to go ahead and
+refer to intra-process signals as just “signals”, and to the
+intra-process signal system simply as “the signal system”.
+
+Anyway, the signal system is a generic callback mechanism,
+similar in spirit to the ‘observable’ library that comes
+with the standard Ruby distribution.  It allows anonymous
+observers to track the events of signal-emitting objects
+(thereby helping to decrease coupling).
+
+The idea is similar to that of the GObject signal system,
+and a myriad of others like it.  (If you know INTERCAL,
+signals are to methods as COME FROM is to GO TO.)
+
+
+Emitting Signals
+----------------
+
+If you want your objects to be capable of emitting signals,
+their classes should include the ‘SignalEmitter’ module.
+That will automatically rig the classes with everything you
+need to define signals (the ‘SignalEmitterModule’ module).
+
+For example, this code
+
+   class Dog
+     include SignalEmitter
+     define_signal :bark
+     def bark
+       puts "Bark!"
+       signal :bark
+     end
+   end
+
+   spot = Dog.new
+   spot.on_signal :bark do
+     puts "Hush, Spot!"
+   end
+
+   3.times { spot.bark }
+
+results in the following output:
+
+   Bark!
+   Hush, Spot!
+   Bark!
+   Hush, Spot!
+   Bark!
+   Hush, Spot!
+
+
+Receiving Signals
+-----------------
+
+The true name for the method that connects a block or proc
+to a signal is ‘add_signal_handler’.  However, that gets
+awfully long when connecting to lots of signals, so there
+are a couple of shortcuts.
+
+First, there are the ‘on’ and ‘on_signal’ aliases.
+These synonyms just delegate to ‘add_signal_handler’.
+
+Second, every predefined signal FOO gets a shorthand
+connector method called ‘on_FOO’.  So in the above example,
+we could have written this instead:
+
+   spot = Dog.new
+   spot.on_bark { puts "Hush, Spot!" }
+
+The ‘on_FOO’ variant is nice for connecting to signals whose
+names are known statically.  Otherwise, ‘on_signal’ is
+usually preferable; these other cases are typically not
+common enough to justify the short form ‘on’.
+
+Connecting signal handlers is a breeze, but *disconnecting*
+them is actually a minor pain in the ass.  Without having an
+explicit reference to the handler, you cannot identify it,
+which means that you cannot tell ‘remove_signal_handler’
+what handler you want to remove.
+
+An example of the obvious but painful solution follows:
+
+   spot = Dog.new
+   @bark_handler = lambda { puts "Hush, Spot!" }
+   spot.on_bark &@bark_handler
+   # ...
+   spot.remove_signal_handler @bark_handler
+
+The ‘SignalObserver’ module provides a slightly
+better solution:
+
+   class DogOwner
+     include SignalObserver
+
+     def initialize(dog=nil)
+       @dog = dog || Dog.new("Spot")
+       observe_signal @dog, :bark do
+         puts "Shut up, #{@dog.name}"
+       end
+     end
+
+     def stop_yelling
+       ignore_signal @dog, :bark
+     end
+   end
+
+But ‘SignalObserver’ has a few caveats that make it
+insufficient as a general solution (see the source).
+
+In the future, I’d like to provide a more powerful mechanism
+for connecting to signals.  Perhaps involving handler tags.
+If you want this feature, nagging me about it on IRC (I’m
+‘dbrock’ on Freenode) or via e-mail usually works best.
+
+
+The Event Loop
+==============
+
+This section explains how IO multiplexing works in general
+(albeit briefly and not very in-depth), and specifically the
+issues relevant for Ruby applications.  You may safely skip
+it if you (a) already know this subject, or (b) don’t care.
+
+Plain ol’ blocking IO works well when you’re reading from
+just a single file descriptor.  But when you’re interested
+in a whole bunch of FDs, you can’t wait for any single one
+of them to become readable or writable, because then you’ll
+inevitably miss that happening to the other ones.  Instead,
+you need a multiplexer that can wait for them *all at once*.
+
+There are a handful of low-level multiplexing primitives:
+‘select’, ‘poll’, ‘epoll’, ‘/dev/poll’, and ‘kqueue’.
+In addition, there are portable low-level wrapper libraries
+such as libevent, which can use any of those primitives.
+The event loop in this package uses the standard ‘select’
+wrapper shipped with Ruby, ‘IO::select’.  But in the future,
+I’d like to use libevent instead, because that’d be cooler.
+
+Most applications use a higher-level abstraction built on
+top of the low-level multiplexer, usually called a ‘main
+loop’, an ‘event loop’, or an ‘event source’.  There are
+also libraries such as liboop, which generalizes the event
+source and event sink concepts, so that components (event
+sinks) written against liboop become event-source-agnostic.
+
+Actually, the combination of blocking IO and Ruby’s green
+threads works well in most cases where you would normally
+use an event loop.  When you call ‘IO#read’ on an empty file
+descriptor, for instance, Ruby suspends that thread until
+its internal event loop, known as the scheduler (currently
+based on ‘select’), determines that the file descriptor has
+become readable.  In particular, Ruby never calls the
+low-level ‘read’ function unless it knows that it will not
+block (because ‘select’ said it wouldn’t, but see below).
+
+There are several reasons why you would use an event loop
+such as the one implemented by this library instead of
+not-so-plain ol’ blocking IO with Ruby’s green threads.
+
+First of all, you may consider the event loop API more
+pleasant than Ruby’s threads and not-quite-blocking IO.
+Otherwise, don’t listen to me; go on using the latter. :-)
+
+Blocking IO can occasionally cause unexpected problems.
+For example, in some cases a blocking read *can* block even
+though select said that the file descriptor was readable.
+This problem may be rare (it can happen, for instance, when
+the checksum of a piece of data fails to match the payload),
+but the bottom line is that non-blocking IO is safer.
+
+Perhaps most importantly, while Ruby’s threads are green,
+they are still effectively preemptively scheduled, with all
+the implications thereof — in a word, synchronization hell.
+By contrast, event handlers are executed in a strictly
+sequential manner; an event loop will never run two event
+handlers simultaneously.  (Though, of course, all bets are
+off if you run multiple event loops in separate threads.)
+
+
+Creating Event Loops
+--------------------
+
+You create a new event loop by calling ‘EventLoop.new’.
+However, if you only need one — which is likely — you
+can get it for free by reading from ‘EventLoop.default’.
+
+If you need multiple event loops in separate threads, put
+them in ‘EventLoop.current’, which will make each of them
+end up in a thread-local variable.
+
+Actually, if you read from ‘EventLoop.current’ before
+writing to it, it defaults to ‘EventLoop.default’, so you
+might as well use ‘EventLoop.current’ in single-threaded
+applications as well.
+
+In fact, ‘EventLoop.current’ is so common that it can be
+shortened to just ‘EventLoop’, if there is no ambiguity.
+So ‘EventLoop.run’ is short for ‘EventLoop.current.run’.
+
+To dynamically change the “current event loop” for a block
+of code, it is convenient to use ‘EventLoop.with_current’.
+
+Once you’ve got the event loop sitting in front of you just
+waiting to be used, you’ll want to add some event sources,
+and then finally run the loop.  So, first things first:
+What are event sources, and how do you add them to the loop?
+
+
+Event Sources
+-------------
+
+As for the first question, this package currently supports
+two kinds of event sources: watchable IO objects and timers.
+The former kind is used to detect file descriptor activity;
+the latter is used for wall-clock scheduling of execution.
+
+Typically, you don’t add event sources to the loop manually.
+Both watchable IO objects and timers provide convenient ways
+of making them add themselves to the “current” event loop.
+
+For example, to add ‘@io’ to the current event loop, you
+might write something like the following:
+
+   @io.monitor_events :readable, :writable
+
+That’s short for the following more explicit code:
+
+   EventLoop.current.monitor_io(@io, :readable, :writable)
+
+The call to ‘EventLoop#monitor_io’ causes the event loop to
+wake up — if it was sleeping in a call to ‘IO.select’ — and
+adds ‘@io’ to the event loop’s set of monitored IO objects.
+For the next event loop iteration, ‘@io’ will be included in
+one or more of the sets passed to ‘IO.select’.
+
+To add the IO object to another event loop,
+
+   other_loop.monitor_io(@io, :readable, :writable)
+
+you can do it like this,
+
+   EventLoop.with_current(other_loop) do
+     @io.monitor_events :readable, :writable end
+
+which is especially convenient when adding multiple objects.
+
+For timers, it’s even easier:
+
+   @timer = EventLoop::PeriodicTimer.new(1.second)
+   @timer.start
+
+That call to ‘@timer.start’ causes the following to happen:
+
+   EventLoop.current.monitor_timer(@timer)
+
+The call to ‘EventLoop#monitor_timer’ may force the event
+loop to wake up, depending on the timer readings and the
+current timeout of the event loop.  In any case, the timer
+is added to the event loop’s set of monitored timers.
+
+But there’s a caveat.  This will not work as expected:
+
+   EventLoop.with_current(other_loop) { @timer.start }
+
+That’s because timer objects decide in advance which event
+loop they are going to use.  Once initialized, timer objects
+no longer care about the value of the current event loop.
+Hence, this code starts a timer in a different event loop:
+
+   @timer = EventLoop.with_current(other_loop) do
+     EventLoop::PeriodicTimer.new(1.second) end
+   @timer.start
+
+Here is another way of writing it:
+
+   @timer = EventLoop::PeriodicTimer.new \
+     1.second, :event_loop => other_loop
+   @timer.start
+   
+In addition, there are quite a few convenient short forms.
+For example, you can write things like this:
+
+   3.seconds.from_now { puts "Boo!" }
+
+Read on, because the next two sections describe with better
+examples and in more detail how IO and timer events work.
+
+[Actually, there are no examples of using timers at all.
+But it would be nice to have some under “Timer Events”.]
+
+
+IO Events
+---------
+
+In Ruby, file descriptors are instances of the class IO.
+Before you can use one of these with the event loop, you
+need to extend it with the module ‘EventLoop::Watchable’.
+That module defines two signals, ‘readable’ and ‘writable’,
+and a pair of methods for activating and deactivating them.
+
+When you want to start receiving ‘readable’ signals, for
+instance, you call ‘io.monitor_event :readable’.  This makes
+the current event loop monitor ‘io’ for readability, and
+emit the ‘readable’ signal on it when the condition occurs.
+
+   require "socket"
+
+   def initialize (host, port)
+     @socket = TCPSocket.new(host, port)
+     @socket.extend EventLoop::Watchable
+     @socket.will_block = false
+     @socket.on_readable { perform_read }
+   end
+
+   def start_listening
+     @socket.monitor_event :readable
+   end
+
+The ‘will_block?’ property is provided by this package as a
+convenient way of setting up non-blocking IO streams.
+(See ‘lib/event-loop/io.rb’, circa line 81.)
+
+The method that actually performs the reading will probably
+look more or less like so:
+
+   def perform_read
+     process_data @socket.sysread(BUFFER_SIZE, @buffer)
+   rescue EOFError
+     ...
+   rescue Errno::ECONNRESET
+     ...
+   rescue
+     ...
+   end
+
+If you don’t want to receive any more ‘readable’ signals,
+you just call ‘io.ignore_event :readable’.
+
+   def stop_listening
+     @socket.ignore_event :readable
+   end
+
+The “current event loop” is just ‘EventLoop.current’.
+To make another event loop (say ‘other_loop’) monitor or
+ignore an IO event, either call ‘other_loop.monitor_io’ or
+‘other_loop.ignore_io’ directly,
+
+   other_loop.monitor_io(io, :readable)
+   other_loop.ignore_io(io, :writable)
+
+or use the ‘EventLoop.with_current’ form,
+
+   EventLoop.with_current(other_loop) do
+     io.monitor_event :readable
+     io.ignore_event :writable
+   end
+
+which implements “dynamic scoping” of ‘EventLoop.current’.
+
+If you simply want readable signals to be emitted whenever
+there are handlers connected to the ‘readable’ signal (and
+likewise for ‘writable’), without having to mess around with
+‘monitor_event’ and ‘ignore_event’, you can extend the IO
+object with the ‘EventLoop::Watchable::Automatic’ module
+instead of ‘EventLoop::Watchable’.
+
+The ‘EventLoop::Watchable::Automatic’ module sets it up so
+that when you connect a handler to either the ‘readable’ or
+the ‘writable’ signal, the current event loop begins
+monitoring the IO object for the corresponding condition,
+and, inversely, when you remove the last handler, it tells
+the event loop to stop monitoring the condition.
+
+Because this is so often useful, you don’t even have to
+extend the IO object yourself.  Stub implementations of the
+‘on_readable’ and ‘on_writable’ methods are provided, which
+automatically bootstrap the IO by extending it with the
+‘EventLoop::Watchable::Automatic’ module when invoked.
+
+     @socket = TCPSocket.new(host, port)
+     @socket.will_block = false
+
+     # By invoking the stub ‘on_readable’ method,
+     # we implicitly extend the IO object with the
+     # module ‘EventLoop::Watchable::Automatic’.
+     #
+     # That module hooks into the signal system and
+     # reacts when we start watching the ‘readable’
+     # signal by starting to monitor that event.
+     @socket.on_readable { perform_read }
+
+Note that once an IO object has been extended with the
+‘EventLoop::Watchable::Automatic’ module, there is currently
+no way to make it non-automatic (Ruby does not yet allow you
+to un-extend an object with a module).  So if you don’t want
+the automatic behavior, you *have* to manually extend the
+object with the ‘EventLoop::Watchable’ module before calling
+either of the ‘or_readable’ and ‘on_writable’ methods.
+
+There is actually a third signal: ‘exceptional’, which is
+emitted when ‘select’ reports that the file descriptor is in
+an “exceptional state”.  You probably don’t need to worry
+about this (and if you do, you’ll probably know it already).
+
+But in case you’re wondering, I think you can use it to
+watch for out-of-band data coming through a socket, provided
+you’ve set the right socket options.  I also believe you can
+use it to determine that a non-blocking connection attempt
+has failed.  (When such an attempt succeeds, a writability
+event is fired for the socket.)  But that doesn’t matter,
+because you can’t do non-blocking connects in Ruby. :-)
+
+
+Timer Events
+------------
+
+If you need to do something after a given amount of
+wall-clock time has passed, just do the following:
+
+ 1.  Create an ‘EventLoop::SporadicTimer’, passing the
+     timeout (in seconds) to the constructor.
+ 2.  Connect to its ‘alarm’ signal (using ‘on_alarm’).
+ 3.  Start the timer (using ‘start’).
+
+Sporadic timers only sound their alarm once, and then stop.
+If you want to do something periodically, like every second,
+use ‘EventLoop::PeriodicTimer’ instead.
+
+You can start a sporadic timer as many times as you want,
+but it will still stop itself every time it goes off.
+Periodic timers must be stopped explicitly (using ‘stop’),
+or they will keep going off as long as the event loop runs.
+
+You can get the effect of an “idle function” by creating an
+periodic timer with a zero-second interval, meaning its
+alarm will sound as often as possible.
+
+If you pass a block to a timer constructor, then that block
+will become the timer’s canonical “alarm handler”, which is
+just a signal handler for the ‘alarm’ signal, except that
+you can easily replace it, using ‘replace_alarm_handler’.
+
+Another way to replace the alarm handler is to pass a block
+to the ‘start’ method or to the ‘restart’ method, which will
+just cause ‘replace_alarm_handler’ to be called first.
+
+There are a number of short forms for creating a timer and
+setting its alarm handler.  The following statements are
+pairwise equivalent:
+
+   sporadic_timer = EventLoop.after(3.seconds) do ... end
+   sporadic_timer = 3.seconds.from_now { ... }
+
+   periodic_timer = EventLoop.every(3.seconds) do ... end
+   periodic_timer = 3.seconds.from_now_and_repeat { ... }
+
+   sporadic_timer = other_loop.after(3.seconds) do ... end
+   EventLoop.with_current(other_loop) do
+     sporadic_timer = 3.seconds.from_now { ... } end
+
+   periodic_timer = other_loop.every(3.seconds) do ... end
+   EventLoop.with_current(other_loop) do
+     periodic_timer = 3.seconds.from_now_and_repeat { ... } end
+
+   idle_function_timer = EventLoop.every(0) { ... }
+   idle_function_timer = EventLoop.repeat { ... }
+
+   one_shot_idle_function_timer = EventLoop.after(0) { ... }
+   one_shot_idle_function_timer = EventLoop.later { ... }
+
+All of the above forms automatically start the timer.
+
+When a timer is started, the event loop associated with the
+timer is notified and its timeout value updated accordingly.
+(Unlike ‘Watchable#monitor_event’, the ‘Timer#start’ method
+does not depend on the value of ‘EventLoop.current’.)
+
+By passing ‘:event_loop => foo’ to the timer constructor,
+you can specify which event loop the timer should use;
+otherwise, the “current event loop” (‘EventLoop.current’)
+will be used as a default.
+
+You can ask a timer for the amount of time left by invoking
+its ‘time_left’ method.  When called from an alarm handler,
+it will typically return a negative value, representing the
+amount of time passed since the alarm was supposed to sound.
+
+However, if you specify ‘:tolerance => 0.1’ when creating
+the timer, you are saying it’s okay for the alarm to sound
+one-tenth of a second too early.  In that case, ‘time_left’
+can return a positive value even when called from within an
+alarm handler, indicating the alarm sounded too early.
+
+The next section explains why you should set the tolerance
+higher than zero (it is currently 0.001 by default).
+
+
+Timer Tolerances
+................
+
+It is useful for timers to have some amount of tolerance
+because the timeout specified to ‘select’ is an upper bound.
+This means that the process will usually wake up slightly
+earlier than expected.  For example, if you start a timer
+set for two seconds and then enter an event loop iteration,
+the call to ‘select’ is likely to return in 1.99 seconds.
+
+If your timer’s tolerance is set to zero, that means that
+the alarm must not be sounded yet, and the event loop is
+forced to perform an extra iteration with a 0.01 timeout.
+If, on the other hand, the tolerance of the timer is set to
+at least 0.01 seconds, then that means it’s okay for the
+alarm to sound slightly too early; in this case, the need
+for an extra iteration can be avoided.
+
+Currently, the error made by a tolerant timer during one
+iteration is not compensated for during the next iteration.
+Combined with the fact that a tolerant timer will usually
+sound too early rather than too late (because the kernel
+tries hard not to wake the process too late), this means
+that the more tolerant your timer is, the more frequently it
+will sound.  In other words, the error accumulates.
+
+This should not be a problem in most cases, simply because
+of the fact that people do not in most cases use Ruby for
+applications that need this kind of precision (the default
+timer tolerance is one millisecond).  However, if you would
+like to see this problem addressed, please contact me.
+
+
+Running the Event Loop
+----------------------
+
+To run the current event loop, just call ‘EventLoop.run’.
+That’ll block until an event handler says ‘EventLoop.quit’.
+
+One typical event loop application looks like this:
+
+  ...
+  @socket.on_writable { ... }
+  @socket.on_readable do
+    ...
+    if something_or_other
+      EventLoop.quit
+    end
+  end
+  ...
+  @timer.start
+  ...
+  EventLoop.run
+
+While the event loop is running, everything that the
+application does takes place in event handlers.
+
+If you want more control, you can run a single iteration of
+the event loop by calling ‘EventLoop.iterate’, which takes
+an optional argument specifying (in seconds) the upper bound
+on the amount of time to block.  The default value (‘nil’)
+means infinity; it causes the upper bound to be the amount
+of time left before the next timer is due.  If you’re not
+using timers, ‘EventLoop.iterate’ without an argument blocks
+until the first interesting IO event occurs.
+
+That should be all you need to know to use this event loop.
+If it turns out not to be, please bug me on IRC (as I said,
+I’m ‘dbrock’ on Freenode) or send me an e-mail.  The source
+shouldn’t be particularly hard to understand either.
+
+Thanks for your interest, and happy hacking!
+
+                        — Daniel Brockman
+
+
+## Local Variables:
+## coding: utf-8
+## time-stamp-format: "%:b %:d, %:y"
+## time-stamp-start: "Updated: "
+## time-stamp-end: "$"
+## End:

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/Rakefile
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/Rakefile	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/Rakefile	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,82 @@
+require "rake/packagetask"
+
+begin
+  require "rubygems"
+  require "rake/gempackagetask"
+  $have_rubygems = true
+rescue
+  $have_rubygems = false
+end
+
+PKG_VERSION = File.open("VERSION").read.chomp
+PKG_FILES = FileList[*%w{[A-Z]* README setup.rb lib/**/*.rb}]
+
+MAINTAINER_MAILNAME = "wigwam.brockman.se"
+SCP_TARGET = "teepee:/var/www/www.brockman.se/software/ruby-event-loop/"
+
+task :default => ["README", :check]
+
+file "README" => ["README.utf-8", "Rakefile"] do |t|
+  # I'm paranoid and I don't trust Ruby with Unicode.
+  if "a—b".gsub(/—/, "---") != "a---b"
+    warn "Can't build `README': broken Unicode support."
+  else
+    File.open("README", "w") do |out|
+      out << "\
+------------------------------------------------------------
+ This file was automatically generated from `README.utf-8'.
+------------------------------------------------------------\n\n"
+      IO.foreach("README.utf-8") do |line|
+        out << line.
+          gsub(/©/, "(C)").
+          gsub(/—/, "---").
+          gsub(/‘/, "`").
+          gsub(/’/, "'").
+          gsub(/“/, "\"").
+          gsub(/”/, "\"")
+      end
+    end
+  end
+end
+
+task :check do
+  Dir.foreach("lib/event-loop/") do |basename|
+    next if basename[0] == ?.
+    system %{ruby -w -Ilib "lib/event-loop/#{basename}"}
+  end
+end
+
+if $have_rubygems
+  GEMSPEC = Gem::Specification.new do |gem|
+    gem.name = "event-loop"
+    gem.version = PKG_VERSION
+    gem.summary = "Simple and usable event loop and signal system"
+    gem.description =
+      "This package contains a simple select-based event loop " +
+      "featuring IO (file descriptor) and timer event sources.  " + 
+      "It comes with a signal system inspired by that of GLib."
+    gem.files = PKG_FILES.to_a
+    gem.require_path = "lib"
+    gem.author = "Daniel Brockman"
+    gem.email = "daniel at brockman.se"
+    gem.homepage = "http://www.brockman.se/software/ruby-event-loop/"
+  end
+
+  Rake::GemPackageTask.new(GEMSPEC) do |task|
+    task.need_tar_gz = true
+  end
+else
+  Rake::PackageTask.new("event-loop", PKG_VERSION) do |task|
+    task.need_tar_gz = true
+    task.package_files = PKG_FILES
+  end
+end
+
+task :upload => :package do
+  mailname = File.read("/etc/mailname").chomp rescue "(none)"
+  if mailname == MAINTAINER_MAILNAME
+    sh %{scp -r pkg/*#{PKG_VERSION}* #{SCP_TARGET}}
+  else
+    warn "The `upload' target is only meant for the maintainer."
+  end
+end

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/VERSION
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/VERSION	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/VERSION	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1 @@
+0.3

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/better-definers.rb
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/better-definers.rb	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/better-definers.rb	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,369 @@
+## better-definers.rb --- better attribute and method definers
+# Copyright (C) 2005  Daniel Brockman
+
+# This program is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation;
+# either version 2 of the License, or (at your option) any
+# later version.
+
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+class Symbol
+  def predicate?
+    to_s.include? "?" end
+  def imperative?
+    to_s.include? "!" end
+  def writer?
+    to_s.include? "=" end
+
+  def punctuated?
+    predicate? or imperative? or writer? end
+  def without_punctuation
+    to_s.delete("?!=").to_sym end
+
+  def predicate
+    without_punctuation.to_s + "?" end
+  def imperative
+    without_punctuation.to_s + "!" end
+  def writer
+    without_punctuation.to_s + "=" end
+end
+
+class Hash
+  def collect! (&block)
+    replace Hash[*collect(&block).flatten]
+  end
+
+  def flatten
+    to_a.flatten
+  end
+end
+
+module Kernel
+  def returning (value)
+    yield value ; value
+  end
+end
+
+class Module
+  def define_hard_aliases (name_pairs)
+    for new_aliases, existing_name in name_pairs do
+      new_aliases.kind_of? Array or new_aliases = [new_aliases]
+      for new_alias in new_aliases do
+        alias_method(new_alias, existing_name)
+      end
+    end
+  end
+
+  def define_soft_aliases (name_pairs)
+    for new_aliases, existing_name in name_pairs do
+      new_aliases.kind_of? Array or new_aliases = [new_aliases]
+      for new_alias in new_aliases do
+        class_eval %{def #{new_alias}(*args, &block)
+                       #{existing_name}(*args, &block) end}
+      end
+    end
+  end
+
+  define_soft_aliases \
+    :define_hard_alias => :define_hard_aliases,
+    :define_soft_alias => :define_soft_aliases
+
+  # This method lets you define predicates like :foo?,
+  # which will be defined to return the value of @foo.
+  def define_readers (*names)
+    for name in names.map { |x| x.to_sym } do
+      if name.punctuated?
+        # There's no way to define an efficient reader whose
+        # name is different from the instance variable.
+        class_eval %{def #{name} ; @#{name.without_punctuation} end}
+      else
+        # Use `attr_reader' to define an efficient method.
+        attr_reader(name)
+      end
+    end
+  end
+
+  def writer_defined? (name)
+    method_defined? name.to_sym.writer
+  end
+
+  # If you pass a predicate symbol :foo? to this method, it'll first
+  # define a regular writer method :foo, without a question mark.
+  # Then it'll define an imperative writer method :foo! as a shorthand
+  # for setting the property to true.
+  def define_writers (*names, &body)
+    for name in names.map { |x| x.to_sym } do
+      if block_given?
+        define_method(name.writer, &body)
+      else
+        attr_writer(name.without_punctuation)
+      end
+      if name.predicate?
+        class_eval %{def #{name.imperative}
+                       self.#{name.writer} true end}
+      end
+    end
+  end
+
+  define_soft_aliases \
+    :define_reader => :define_readers,
+    :define_writer => :define_writers
+
+  # We don't need a singular alias for `define_accessors',
+  # because it always defines at least two methods.
+
+  def define_accessors (*names)
+    define_readers(*names)
+    define_writers(*names)
+  end
+
+  def define_opposite_readers (name_pairs)
+    name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
+    for opposite_name, name in name_pairs do
+      define_reader(name) unless method_defined? name
+      class_eval %{def #{opposite_name} ; not #{name} end}
+    end
+  end
+
+  def define_opposite_writers (name_pairs)
+    name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
+    for opposite_name, name in name_pairs do
+      define_writer(name) unless writer_defined? name
+      class_eval %{def #{opposite_name.writer} x
+                     self.#{name.writer} !x end} 
+      class_eval %{def #{opposite_name.imperative}
+                     self.#{name.writer} false end}
+    end
+  end
+
+  define_soft_aliases \
+    :define_opposite_reader => :define_opposite_readers,
+    :define_opposite_writer => :define_opposite_writers
+
+  def define_opposite_accessors (name_pairs)
+    define_opposite_readers name_pairs
+    define_opposite_writers name_pairs
+  end
+
+  def define_reader_with_opposite (name_pair, &body)
+    name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
+    define_method(name, &body)
+    define_opposite_reader(opposite_name => name)
+  end
+
+  def define_writer_with_opposite (name_pair, &body)
+    name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
+    define_writer(name, &body)
+    define_opposite_writer(opposite_name => name)
+  end
+
+  public :define_method
+
+  def define_methods (*names, &body)
+    names.each { |name| define_method(name, &body) }
+  end
+  
+  def define_private_methods (*names, &body)
+    define_methods(*names, &body)
+    names.each { |name| private name }
+  end
+
+  def define_protected_methods (*names, &body)
+    define_methods(*names, &body)
+    names.each { |name| protected name }
+  end
+
+  def define_private_method (name, &body)
+    define_method(name, &body)
+    private name
+  end
+
+  def define_protected_method (name, &body)
+    define_method(name, &body)
+    protected name
+  end
+end
+
+class ImmutableAttributeError < StandardError
+  def initialize (attribute=nil, message=nil)
+    super message
+    @attribute = attribute
+  end
+
+  define_accessors :attribute
+
+  def to_s
+    if @attribute and @message
+      "cannot change the value of `#@attribute': #@message"
+    elsif @attribute
+      "cannot change the value of `#@attribute'"
+    elsif @message
+      "cannot change the value of attribute: #@message"
+    else
+      "cannot change the value of attribute"
+    end
+  end
+end
+
+class Module
+  # Guard each of the specified attributes by replacing the writer
+  # method with a proxy that asks the supplied block before proceeding
+  # with the change.
+  #
+  # If it's okay to change the attribute, the block should return
+  # either nil or the symbol :mutable.  If it isn't okay, the block
+  # should return a string saying why the attribute can't be changed.
+  # If you don't want to provide a reason, you can have the block
+  # return just the symbol :immutable.
+  def guard_writers(*names, &predicate)
+    for name in names.map { |x| x.to_sym } do
+      define_hard_alias("__unguarded_#{name.writer}" => name.writer)
+      define_method(name.writer) do |new_value|
+        case result = predicate.call
+        when :mutable, nil
+          __send__("__unguarded_#{name.writer}", new_value)
+        when :immutable
+          raise ImmutableAttributeError.new(name)
+        else
+          raise ImmutableAttributeError.new(name, result)
+        end
+      end
+    end
+  end
+
+  def define_guarded_writers (*names, &block)
+    define_writers(*names)
+    guard_writers(*names, &block)
+  end
+
+  define_soft_alias :guard_writer => :guard_writers
+  define_soft_alias :define_guarded_writer => :define_guarded_writers
+end
+
+if __FILE__ == $0
+  require "test/unit"
+
+  class DefineAccessorsTest < Test::Unit::TestCase
+    def setup
+      @X = Class.new
+      @Y = Class.new @X
+      @x = @X.new
+      @y = @Y.new
+    end
+
+    def test_define_hard_aliases
+      @X.define_method(:foo) { 123 }
+      @X.define_method(:baz) { 321 }
+      @X.define_hard_aliases :bar => :foo, :quux => :baz
+      assert_equal @x.foo, 123
+      assert_equal @x.bar, 123
+      assert_equal @y.foo, 123
+      assert_equal @y.bar, 123
+      assert_equal @x.baz, 321
+      assert_equal @x.quux, 321
+      assert_equal @y.baz, 321
+      assert_equal @y.quux, 321
+      @Y.define_method(:foo) { 456 }
+      assert_equal @y.foo, 456
+      assert_equal @y.bar, 123
+      @Y.define_method(:quux) { 654 }
+      assert_equal @y.baz, 321
+      assert_equal @y.quux, 654
+    end
+    
+    def test_define_soft_aliases
+      @X.define_method(:foo) { 123 }
+      @X.define_method(:baz) { 321 }
+      @X.define_soft_aliases :bar => :foo, :quux => :baz
+      assert_equal @x.foo, 123
+      assert_equal @x.bar, 123
+      assert_equal @y.foo, 123
+      assert_equal @y.bar, 123
+      assert_equal @x.baz, 321
+      assert_equal @x.quux, 321
+      assert_equal @y.baz, 321
+      assert_equal @y.quux, 321
+      @Y.define_method(:foo) { 456 }
+      assert_equal @y.foo, @y.bar, 456
+      @Y.define_method(:quux) { 654 }
+      assert_equal @y.baz, 321
+      assert_equal @y.quux, 654
+    end
+
+    def test_define_readers
+      @X.define_readers :foo, :bar
+      assert !@x.respond_to?(:foo=)
+      assert !@x.respond_to?(:bar=)
+      @x.instance_eval { @foo = 123 ; @bar = 456 }
+      assert_equal @x.foo, 123
+      assert_equal @x.bar, 456
+      @X.define_readers :baz?, :quux?
+      assert !@x.respond_to?(:baz=)
+      assert !@x.respond_to?(:quux=)
+      @x.instance_eval { @baz = false ; @quux = true }
+      assert !@x.baz?
+      assert @x.quux?
+    end
+
+    def test_define_writers
+      assert !@X.writer_defined?(:foo)
+      assert !@X.writer_defined?(:bar)
+      @X.define_writers :foo, :bar
+      assert @X.writer_defined?(:foo)
+      assert @X.writer_defined?(:bar)
+      assert @X.writer_defined?(:foo=)
+      assert @X.writer_defined?(:bar=)
+      assert @X.writer_defined?(:foo?)
+      assert @X.writer_defined?(:bar?)
+      assert !@x.respond_to?(:foo)
+      assert !@x.respond_to?(:bar)
+      @x.foo = 123
+      @x.bar = 456
+      assert_equal @x.instance_eval { @foo }, 123
+      assert_equal @x.instance_eval { @bar }, 456
+      @X.define_writers :baz?, :quux?
+      assert !@x.respond_to?(:baz?)
+      assert !@x.respond_to?(:quux?)
+      @x.baz = true
+      @x.quux = false
+      assert_equal @x.instance_eval { @baz }, true
+      assert_equal @x.instance_eval { @quux }, false
+    end
+
+    def test_define_accessors
+      @X.define_accessors :foo, :bar
+      @x.foo = 123 ; @x.bar = 456
+      assert_equal @x.foo, 123
+      assert_equal @x.bar, 456
+    end
+
+    def test_define_opposite_readers
+      @X.define_opposite_readers :foo? => :bar?, :baz? => :quux?
+      assert !@x.respond_to?(:foo=)
+      assert !@x.respond_to?(:bar=)
+      assert !@x.respond_to?(:baz=)
+      assert !@x.respond_to?(:quux=)
+      @x.instance_eval { @bar = true ; @quux = false }
+      assert !@x.foo?
+      assert @x.bar?
+      assert @x.baz?
+      assert !@x.quux?
+    end
+
+    def test_define_opposite_writers
+      @X.define_opposite_writers :foo? => :bar?, :baz => :quux
+    end
+  end
+end
+
+## better-definers.rb ends here.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/event-loop.rb
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/event-loop.rb	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/event-loop.rb	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,202 @@
+## event-loop.rb --- high-level IO multiplexer
+# Copyright (C) 2005, 2006  Daniel Brockman
+
+# This program is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation;
+# either version 2 of the License, or (at your option) any
+# later version.
+
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+require "event-loop/better-definers"
+require "event-loop/signal-system"
+
+class EventLoop ; end
+
+require "event-loop/io"
+
+class EventLoop
+  module Utilities
+    def self.validate_keyword_arguments (actual, allowed)
+      (unknown_keys = actual - allowed).empty? or
+        fail "unrecognized keyword argument" +
+          "#{"s" if unknown_keys.size > 1}: " +
+          unknown_keys.map { |x| "`#{x}'" }.join(", ")
+    end
+  end
+end
+
+class EventLoop
+  include SignalEmitter
+
+  IO_STATES = [:readable, :writable, :exceptional]
+
+  class << self
+    def default ; @default ||= new end
+    def default= x ; @default = x end
+
+    def current
+      Thread.current["event-loop::current"] || default end
+    def current= x
+      Thread.current["event-loop::current"] = x end
+
+    def with_current (new)
+      # Be sure to return the value of the block.
+      if current == new
+        yield
+      else
+        begin
+          old = self.current
+          self.current = new
+          yield
+        ensure
+          current == new or warn "uncontained change " +
+            "to `EventLoop.current' within dynamic " +
+            "extent of `EventLoop.with_current'"
+          self.current = old
+        end
+      end
+    end
+
+    def method_missing (name, *args, &block)
+      if current.respond_to? name
+        current.__send__(name, *args, &block)
+      else
+        super
+      end
+    end
+  end
+
+  define_signals :before_sleep, :after_sleep
+
+  def initialize
+    @running = false
+    @awake = false
+    @wakeup_time = nil
+    @timers = []
+
+    @io_arrays = [[], [], []]
+    @ios = Hash.new do |h, k| raise ArgumentError,
+      "invalid IO event: #{k}", caller(2) end
+    IO_STATES.each_with_index { |x, i| @ios[x] = @io_arrays[i] }
+
+    @notify_src, @notify_snk = IO.pipe
+
+    @notify_src.will_block = false
+    @notify_snk.will_block = false
+
+    # For bootstrapping reasons, we can't let the stub
+    # implementation of IO#on_readable set this up.
+    monitor_io(@notify_src, :readable)
+    @notify_src.extend(Watchable)
+    # Each time a byte is sent through the notification pipe
+    # we need to read it, or IO.select will keep returning.
+    @notify_src.on_readable do
+      begin
+        @notify_src.sysread(256)
+      rescue Errno::EAGAIN
+        # The pipe wasn't readable after all.
+      end
+    end
+  end
+
+  define_opposite_accessors \
+    :stopped? => :running?,
+    :asleep? => :awake?
+
+  # This is an old name for the property.
+  define_hard_alias :sleeping? => :asleep?
+
+  def run
+    if block_given?
+      thread = Thread.new { run }
+      yield ; quit ; thread.join
+    else
+      running!
+      iterate while running?
+    end
+  ensure
+    quit
+  end
+
+  def iterate (user_timeout=nil)
+    t1, t2 = user_timeout, max_timeout
+    timeout = t1 && t2 ? [t1, t2].min : t1 || t2
+    select(timeout).zip(IO_STATES) do |ios, state|
+      ios.each { |x| x.signal(state) } if ios
+    end
+  end
+
+ private
+
+  def select (timeout)
+    @wakeup_time = timeout ? Time.now + timeout : nil
+    # puts "waiting: #{timeout} seconds"
+    signal :before_sleep ; asleep!
+    IO.select(*@io_arrays + [timeout]) || []
+  ensure
+    awake! ; signal :after_sleep
+    @timers.each { |x| x.sound_alarm if x.ready? }
+  end
+
+ public
+
+  def quit ; stopped! ; wake_up ; self end
+
+  def monitoring_io? (io, event)
+    @ios[event].include? io end
+  def monitoring_timer? (timer)
+    @timers.include? timer end
+
+  def monitor_io (io, *events)
+    for event in events do
+      unless monitoring_io?(io, event)
+        @ios[event] << io ; wake_up
+      end
+    end
+  end
+
+  def monitor_timer (timer)
+    @timers << timer unless monitoring_timer? timer
+    check_timer(timer)
+  end
+
+  def check_timer (timer)
+    wake_up if running? and asleep? and
+      timer.end_time < @wakeup_time
+  end
+
+  def ignore_io (io, *events)
+    events = IO_STATES if events.empty?
+    for event in events do
+      wake_up if @ios[event].delete(io)
+    end
+  end
+
+  def ignore_timer (timer)
+    # Don't need to wake up for this.
+    @timers.delete(timer)
+  end
+
+  def max_timeout
+    return nil if @timers.empty?
+    [@timers.collect { |x| x.time_left }.min, 0].max
+  end
+
+  def wake_up
+    returning self do
+      @notify_snk.write('.') if asleep?
+    end
+  end
+end
+
+## event-loop.rb ends here.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/io.rb
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/io.rb	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/io.rb	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,98 @@
+## io.rb --- convenience features for IO objects
+# Copyright (C) 2005, 2006  Daniel Brockman
+
+# This program is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation;
+# either version 2 of the License, or (at your option) any
+# later version.
+
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+require "event-loop"
+require "fcntl"
+
+class Symbol
+  def io_state?
+    EventLoop::IO_STATES.include? self
+  end
+end
+
+module EventLoop::Watchable
+  include SignalEmitter
+
+  define_signals :readable, :writable, :exceptional
+
+  def monitor_events (*events)
+    EventLoop.monitor_io(self, *events) end
+  def ignore_events (*events)
+    EventLoop.ignore_io(self, *events) end
+
+  define_soft_aliases \
+    :monitor_event => :monitor_events,
+    :ignore_event  => :ignore_events
+
+  def close ; super
+    ignore_events end
+  def close_read ; super
+    ignore_event :readable end
+  def close_write ; super
+    ignore_event :writable end
+
+  module Automatic
+    include EventLoop::Watchable
+
+    def add_signal_handler (name, &handler) super
+      monitor_event(name) if name.io_state?
+    end
+
+    def remove_signal_handler (name, handler) super
+      if @signal_handlers[name].empty?
+        ignore_event(name) if name.io_state?
+      end
+    end
+  end
+end
+
+class IO
+  def on_readable &block
+    extend EventLoop::Watchable::Automatic
+    on_readable(&block)
+  end
+
+  def on_writable &block
+    extend EventLoop::Watchable::Automatic
+    on_writable(&block)
+  end
+
+  def on_exceptional &block
+    extend EventLoop::Watchable::Automatic
+    on_exceptional(&block)
+  end
+
+  def will_block?
+    require "fcntl"
+    fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0
+  end
+
+  def will_block= (wants_blocking)
+    require "fcntl"
+    flags = fcntl(Fcntl::F_GETFL, 0)
+    if wants_blocking
+      flags &= ~Fcntl::O_NONBLOCK
+    else
+      flags |= Fcntl::O_NONBLOCK
+    end
+    fcntl(Fcntl::F_SETFL, flags)
+  end
+end
+
+## io.rb ends here.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/signal-system.rb
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/signal-system.rb	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/signal-system.rb	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,226 @@
+## signal-system.rb --- simple intra-process signal system
+# Copyright (C) 2005, 2006  Daniel Brockman
+
+# This program is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation;
+# either version 2 of the License, or (at your option) any
+# later version.
+
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+require "event-loop/better-definers"
+
+module SignalEmitterModule
+  def self.extended (object)
+    if object.kind_of? Module and not object < SignalEmitter
+      if object.respond_to? :fcall
+        # This is the way to call private methods
+        # in Ruby 1.9 as of November 16.
+        object.fcall :include, SignalEmitter
+      else
+        object.__send__ :include, SignalEmitter
+      end
+    end
+  end
+
+  def define_signal (name, slot=:before, &body)
+    # Can't use `define_method' and take a block pre-1.9.
+    class_eval %{ def on_#{name} &block
+                    add_signal_handler(:#{name}, &block) end }
+    define_signal_handler(name, :before, &lambda {|*a|})
+    define_signal_handler(name, :after, &lambda {|*a|})
+    define_signal_handler(name, slot, &body) if block_given?
+  end
+
+  def define_signals (*names, &body)
+    names.each { |x| define_signal(x, &body) }
+  end
+
+  def define_signal_handler (name, slot=:before, &body)
+    case slot
+    when :before
+      define_protected_method "prehandle_#{name}", &body
+    when :after
+      define_protected_method "posthandle_#{name}", &body
+    else
+      raise ArgumentError, "invalid slot `#{slot.inspect}'; " +
+        "should be `:before' or `:after'", caller(1)
+    end
+  end
+end
+
+# This is an old name for the same thing.
+SignalEmitterClass = SignalEmitterModule
+
+module SignalEmitter
+  def self.included (includer)
+    if not includer.kind_of? SignalEmitterClass
+      includer.extend SignalEmitterClass
+    end
+  end
+
+  def __maybe_initialize_signal_emitter
+    @signal_handlers ||= Hash.new { |h, k| h[k] = Array.new }
+    @allow_dynamic_signals ||= false
+  end
+
+  define_accessors :allow_dynamic_signals?
+
+  def add_signal_handler (name, &handler)
+    __maybe_initialize_signal_emitter
+    @signal_handlers[name] << handler
+    return handler
+  end
+
+  define_soft_aliases [:on, :on_signal] => :add_signal_handler
+
+  def remove_signal_handler (name, handler)
+    __maybe_initialize_signal_emitter
+    @signal_handlers[name].delete(handler)
+  end
+
+  def __signal__ (name, *args, &block)
+    __maybe_initialize_signal_emitter
+    respond_to? "on_#{name}" or allow_dynamic_signals? or
+      fail "undefined signal `#{name}' for #{self}:#{self.class}"
+    __send__("prehandle_#{name}", *args, &block) if
+      respond_to? "prehandle_#{name}"
+    # This is an old name for the same thing:
+    __send__("handle_#{name}", *args, &block) if
+      respond_to? "handle_#{name}"
+    @signal_handlers[name].each { |x| x.call(*args, &block) }
+    __send__("posthandle_#{name}", *args, &block) if
+      respond_to? "posthandle_#{name}"
+    # This is an old name for the same thing:
+    __send__("after_handle_#{name}", *args, &block) if
+      respond_to? "after_handle_#{name}"
+  end
+
+  define_soft_alias :signal => :__signal__
+end
+
+# This module is indended to be a convenience mixin to be used by
+# classes whose objects need to observe foreign signals.  That is,
+# if you want to observe some signals coming from an object, *you*
+# should mix in this module.
+#
+# You cannot use this module at two different places of the same
+# inheritance chain to observe signals coming from the same object.
+#
+# XXX: This has not seen much use, and I'd like to provide a
+#      better solution for the problem in the future.
+module SignalObserver
+  def __maybe_initialize_signal_observer
+    @observed_signals ||= Hash.new do |signals, object|
+      signals[object] = Hash.new do |handlers, name|
+        handlers[name] = Array.new
+      end
+    end
+  end
+
+  def observe_signal (subject, name, &handler)
+    __maybe_initialize_signal_observer
+    @observed_signals[subject][name] << handler
+    subject.add_signal_handler(name, &handler)
+  end
+
+  def map_signals (source, pairs={})
+    pairs.each do |src_name, dst_name|
+      observe_signal(source, src_name) do |*args|
+        __signal__(dst_name, *args)
+      end
+    end
+  end
+
+  def absorb_signals (subject, *names)
+    names.each do |name|
+      observe_signal(subject, name) do |*args|
+        __signal__(name, *args)
+      end
+    end
+  end
+
+  define_soft_aliases \
+    :map_signal    => :map_signals,
+    :absorb_signal => :absorb_signals
+
+  def ignore_signal (subject, name)
+    __maybe_initialize_signal_observer
+    __ignore_signal_1(subject, name)
+    @observed_signals.delete(subject) if
+      @observed_signals[subject].empty?
+  end
+
+  def ignore_signals (subject, *names)
+    __maybe_initialize_signal_observer
+    names = @observed_signals[subject] if names.empty?
+    names.each { |x| __ignore_signal_1(subject, x) }
+  end
+
+ private
+
+  def __ignore_signal_1(subject, name)
+    @observed_signals[subject][name].each do |handler|
+      subject.remove_signal_handler(name, handler) end
+    @observed_signals[subject].delete(name)
+  end
+end
+
+if __FILE__ == $0
+  require "test/unit"
+  class SignalEmitterTest < Test::Unit::TestCase
+    class X
+      include SignalEmitter
+      define_signal :foo
+    end
+
+    def setup
+      @x = X.new
+    end
+
+    def test_on_signal
+      moomin = 0
+      @x.on_signal(:foo) { moomin = 1 }
+      @x.signal :foo
+      assert moomin == 1
+    end
+
+    def test_on_foo
+      moomin = 0
+      @x.on_foo { moomin = 1 }
+      @x.signal :foo
+      assert moomin == 1
+    end
+
+    def test_multiple_on_signal
+      moomin = 0
+      @x.on_signal(:foo) { moomin += 1 }
+      @x.on_signal(:foo) { moomin += 2 }
+      @x.on_signal(:foo) { moomin += 4 }
+      @x.on_signal(:foo) { moomin += 8 }
+      @x.signal :foo
+      assert moomin == 15
+    end
+
+    def test_multiple_on_foo
+      moomin = 0
+      @x.on_foo { moomin += 1 }
+      @x.on_foo { moomin += 2 }
+      @x.on_foo { moomin += 4 }
+      @x.on_foo { moomin += 8 }
+      @x.signal :foo
+      assert moomin == 15
+    end
+  end
+end
+
+## signal-system.rb ends here.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/timer.rb
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/timer.rb	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop/timer.rb	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,288 @@
+## timer.rb --- timer implementations for the event loop
+# Copyright (C) 2005, 2006  Daniel Brockman
+
+# This program is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation;
+# either version 2 of the License, or (at your option) any
+# later version.
+
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+require "event-loop"
+
+class EventLoop
+  def every (interval, options={}, &body)
+    options[:event_loop] ||= self
+    PeriodicTimer.new(interval, options, &body).start
+  end
+
+  def after (interval, options={}, &body)
+    options[:event_loop] ||= self
+    SporadicTimer.new(interval, options, &body).start
+  end
+
+  def repeat (&body)
+    every(0, &body)
+  end
+
+  def later (&body)
+    after(0, &body)
+  end
+end
+
+class EventLoop::Timer
+  include SignalEmitter
+
+  DEFAULT_TOLERANCE = 0.001
+
+  define_opposite_readers :stopped? => :running?
+  define_readers :interval, :tolerance, :event_loop
+  define_signal :alarm
+
+  def initialize (interval, options={}, &alarm_handler)
+    EventLoop::Utilities.validate_keyword_arguments options.keys,
+      [:tolerance, :event_loop]
+
+    @running = false
+    @start_time = nil
+
+    @interval = interval
+    @event_loop = options[:event_loop] || EventLoop.current
+    @alarm_handler = alarm_handler and
+      replace_alarm_handler(&@alarm_handler)
+
+    if options[:tolerance]
+      @tolerance = options[:tolerance].to_f
+    elsif DEFAULT_TOLERANCE < @interval
+      @tolerance = DEFAULT_TOLERANCE
+    else
+      @tolerance = 0.0
+    end
+  end
+
+  def start_time ; @start_time or
+      fail "the timer has not been started" end
+  def end_time ; start_time + @interval end
+  def time_left ; end_time - Time.now end
+  def ready? ; time_left <= @tolerance end
+
+  def interval= (new_interval)
+    old_interval = @interval
+    @interval = new_interval
+    if running? and new_interval < old_interval
+      @event_loop.check_timer(self)
+    end
+  end
+
+  def end_time= (new_end_time)
+    self.interval = new_end_time - start_time end
+  def time_left= (new_time_left)
+    self.end_time = Time.now + new_time_left end
+
+  def replace_alarm_handler (&block)
+    remove_signal_handler(:alarm, @alarm_handler) if @alarm_handler
+    add_signal_handler(:alarm, &block)
+    @alarm_handler = block
+  end
+
+  def restart (&block)
+    running? or raise "the timer is not running"
+    replace_alarm_handler(&block) if block_given?
+    returning self do
+      @start_time = Time.now
+    end
+  end
+
+  def start (&block)
+    replace_alarm_handler(&block) if block_given?
+    returning self do
+      @start_time = Time.now
+      @event_loop.monitor_timer(self)
+      @running = true
+    end
+  end
+
+  def stop
+    returning self do
+      @event_loop.ignore_timer(self)
+      @running = false
+    end
+  end
+
+  class << self
+    define_hard_alias :regular_new => :new
+
+    def new (*a, &b)
+      warn "event-loop: As of event-loop 0.3, `EventLoop::Timer.new' " +
+        "is deprecated in favor of `EventLoop#every' and " +
+        "`EventLoop#after'; see the documentation for more information."
+      new!(*a, &b)
+    end
+
+    def new! (options={}, &body)
+      if options.kind_of? Numeric
+        interval = options
+        options = {}
+      elsif options.include? :interval
+        interval = options[:interval].to_f
+        options.delete(:interval)
+      else
+        interval = 0.0
+      end
+      
+      EventLoop::Utilities.validate_keyword_arguments options.keys,
+        [:interval, :tolerance, :start?, :event_loop]
+
+      if options.include? :start?
+        start = options.delete(:start?)
+      else
+        start = block_given?
+      end
+      
+      timer = EventLoop::PeriodicTimer.new(interval, options)
+      timer.on_alarm(&body) if block_given?
+      timer.start if start
+      return timer
+    end
+  end
+end
+
+class EventLoop::PeriodicTimer < EventLoop::Timer
+  class << self
+    define_soft_alias :new => :regular_new end
+  def sound_alarm
+    signal :alarm ; restart if running? end
+end
+
+class EventLoop::SporadicTimer < EventLoop::Timer
+  class << self
+    define_soft_alias :new => :regular_new end
+  def sound_alarm
+    stop ; signal :alarm end
+end
+
+class Numeric
+  def nanoseconds ; self / 1_000_000_000.0 end
+  def microseconds ; self / 1_000_000.0 end
+  def milliseconds ; self / 1_000.0 end
+  def seconds ; self end
+  def minutes ; self * 60.seconds end
+  def hours ; self * 60.minutes end
+  def days ; self * 24.hours end
+  def weeks ; self * 7.days end
+  def years ; self * 365.24.days end
+
+  define_hard_aliases \
+    :nanosecond => :nanoseconds,
+    :microsecond => :microseconds,
+    :millisecond => :milliseconds,
+    :second => :seconds,
+    :minute => :minutes,
+    :hour => :hours,
+    :day => :days,
+    :week => :weeks,
+    :year => :years
+
+  define_hard_aliases \
+    :ns => :nanoseconds,
+    :ms => :milliseconds
+
+  def half ; self / 2.0 end
+  def quarter ; self / 4.0 end
+
+  def from_now (&block)
+    EventLoop.after(self, &block)
+  end
+
+  def from_now_and_repeat (&block)
+    EventLoop.every(self, &block)
+  end
+end
+
+class Integer
+  # It turns out whole numbers of years are
+  # always whole numbers of seconds.
+  def years ; super.to_i end
+  define_hard_alias :year => :years
+end
+
+def Time.measure
+  t0 = now ; yield ; now - t0
+end
+
+if __FILE__ == $0
+  require "test/unit"
+
+  class TimerTest < Test::Unit::TestCase
+    def setup
+      EventLoop.current = EventLoop.new
+      @timer = EventLoop::Timer.new!(:interval => 1.ms)
+    end
+
+    def test_monitor_unstarted_timer
+      assert_raise RuntimeError do
+        EventLoop.monitor_timer(@timer)
+        EventLoop.run
+      end
+    end
+
+    def test_start_monitoring_timer_while_running
+      EventLoop.later { 1.ms.from_now { EventLoop.quit } }
+      1.second.from_now { EventLoop.quit }
+      assert Time.measure { EventLoop.run } < 1.half.second
+    end
+
+    def test_start_monitoring_timer_while_running_deprecated
+      @timer.start { EventLoop::Timer.new!(1.ms) { EventLoop.quit } }
+      EventLoop::Timer.new!(1.second) { EventLoop.quit }
+      assert Time.measure { EventLoop.run } < 1.half.second
+    end
+
+    def test_timer_tolerance
+      timer = EventLoop::SporadicTimer.new(10.milliseconds) do
+        puts "[#{timer.time_left * 1000} milliseconds left on alarm]"
+        EventLoop.quit end
+      8.times do
+        dt = Time.measure { timer.start ; EventLoop.run }
+        assert(dt > timer.interval - timer.tolerance)
+      end
+    end
+  end
+
+  class SporadicTimerTest < Test::Unit::TestCase
+    def setup
+      EventLoop.current = EventLoop.new
+    end
+
+    def test_sporadicity
+      counter = 0
+      1.nanosecond.from_now { counter += 1 }
+      5.times { EventLoop.iterate(10.milliseconds) }
+      assert counter == 1
+    end
+  end
+
+  class PeriodicTimerTest < Test::Unit::TestCase
+    def setup
+      EventLoop.current = EventLoop.new
+    end
+    
+    def test_periodicity
+      counter = 0
+      EventLoop.every(1.nanosecond) { counter += 1 }
+      5.times { EventLoop.iterate(10.milliseconds) }
+      assert counter == 5
+    end
+  end
+end
+
+## timer.rb ends here.

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop.rb
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop.rb	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/lib/event-loop.rb	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1 @@
+require "event-loop/event-loop"

Added: packages-wip/libevent-loop-ruby/branches/upstream/current/setup.rb
===================================================================
--- packages-wip/libevent-loop-ruby/branches/upstream/current/setup.rb	2006-11-12 23:30:03 UTC (rev 1091)
+++ packages-wip/libevent-loop-ruby/branches/upstream/current/setup.rb	2006-11-13 13:52:29 UTC (rev 1092)
@@ -0,0 +1,1587 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
+  module Enumerable
+    alias map collect
+  end
+end
+
+unless File.respond_to?(:read)   # Ruby 1.6
+  def File.read(fname)
+    open(fname) {|f|
+      return f.read
+    }
+  end
+end
+
+unless Errno.const_defined?(:ENOTEMPTY)   # Windows?
+  module Errno
+    class ENOTEMPTY
+      # We do not raise this exception, implementation is not needed.
+    end
+  end
+end
+
+def File.binread(fname)
+  open(fname, 'rb') {|f|
+    return f.read
+  }
+end
+
+# for corrupted Windows' stat(2)
+def File.dir?(path)
+  File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class ConfigTable
+
+  include Enumerable
+
+  def initialize(rbconfig)
+    @rbconfig = rbconfig
+    @items = []
+    @table = {}
+    # options
+    @install_prefix = nil
+    @config_opt = nil
+    @verbose = true
+    @no_harm = false
+  end
+
+  attr_accessor :install_prefix
+  attr_accessor :config_opt
+
+  attr_writer :verbose
+
+  def verbose?
+    @verbose
+  end
+
+  attr_writer :no_harm
+
+  def no_harm?
+    @no_harm
+  end
+
+  def [](key)
+    lookup(key).resolve(self)
+  end
+
+  def []=(key, val)
+    lookup(key).set val
+  end
+
+  def names
+    @items.map {|i| i.name }
+  end
+
+  def each(&block)
+    @items.each(&block)
+  end
+
+  def key?(name)
+    @table.key?(name)
+  end
+
+  def lookup(name)
+    @table[name] or setup_rb_error "no such config item: #{name}"
+  end
+
+  def add(item)
+    @items.push item
+    @table[item.name] = item
+  end
+
+  def remove(name)
+    item = lookup(name)
+    @items.delete_if {|i| i.name == name }
+    @table.delete_if {|name, i| i.name == name }
+    item
+  end
+
+  def load_script(path, inst = nil)
+    if File.file?(path)
+      MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
+    end
+  end
+
+  def savefile
+    '.config'
+  end
+
+  def load_savefile
+    begin
+      File.foreach(savefile()) do |line|
+        k, v = *line.split(/=/, 2)
+        self[k] = v.strip
+      end
+    rescue Errno::ENOENT
+      setup_rb_error $!.message + "\n#{File.basename($0)} config first"
+    end
+  end
+
+  def save
+    @items.each {|i| i.value }
+    File.open(savefile(), 'w') {|f|
+      @items.each do |i|
+        f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
+      end
+    }
+  end
+
+  def load_standard_entries
+    standard_entries(@rbconfig).each do |ent|
+      add ent
+    end
+  end
+
+  def standard_entries(rbconfig)
+    c = rbconfig
+
+    rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
+
+    major = c['MAJOR'].to_i
+    minor = c['MINOR'].to_i
+    teeny = c['TEENY'].to_i
+    version = "#{major}.#{minor}"
+
+    # ruby ver. >= 1.4.4?
+    newpath_p = ((major >= 2) or
+                 ((major == 1) and
+                  ((minor >= 5) or
+                   ((minor == 4) and (teeny >= 4)))))
+
+    if c['rubylibdir']
+      # V > 1.6.3
+      libruby         = "#{c['prefix']}/lib/ruby"
+      librubyver      = c['rubylibdir']
+      librubyverarch  = c['archdir']
+      siteruby        = c['sitedir']
+      siterubyver     = c['sitelibdir']
+      siterubyverarch = c['sitearchdir']
+    elsif newpath_p
+      # 1.4.4 <= V <= 1.6.3
+      libruby         = "#{c['prefix']}/lib/ruby"
+      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
+      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+      siteruby        = c['sitedir']
+      siterubyver     = "$siteruby/#{version}"
+      siterubyverarch = "$siterubyver/#{c['arch']}"
+    else
+      # V < 1.4.4
+      libruby         = "#{c['prefix']}/lib/ruby"
+      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
+      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+      siteruby        = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
+      siterubyver     = siteruby
+      siterubyverarch = "$siterubyver/#{c['arch']}"
+    end
+    parameterize = lambda {|path|
+      path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
+    }
+
+    if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
+      makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+    else
+      makeprog = 'make'
+    end
+
+    [
+      ExecItem.new('installdirs', 'std/site/home',
+                   'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
+          {|val, table|
+            case val
+            when 'std'
+              table['rbdir'] = '$librubyver'
+              table['sodir'] = '$librubyverarch'
+            when 'site'
+              table['rbdir'] = '$siterubyver'
+              table['sodir'] = '$siterubyverarch'
+            when 'home'
+              setup_rb_error '$HOME was not set' unless ENV['HOME']
+              table['prefix'] = ENV['HOME']
+              table['rbdir'] = '$libdir/ruby'
+              table['sodir'] = '$libdir/ruby'
+            end
+          },
+      PathItem.new('prefix', 'path', c['prefix'],
+                   'path prefix of target environment'),
+      PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+                   'the directory for commands'),
+      PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
+                   'the directory for libraries'),
+      PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+                   'the directory for shared data'),
+      PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+                   'the directory for man pages'),
+      PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+                   'the directory for system configuration files'),
+      PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
+                   'the directory for local state data'),
+      PathItem.new('libruby', 'path', libruby,
+                   'the directory for ruby libraries'),
+      PathItem.new('librubyver', 'path', librubyver,
+                   'the directory for standard ruby libraries'),
+      PathItem.new('librubyverarch', 'path', librubyverarch,
+                   'the directory for standard ruby extensions'),
+      PathItem.new('siteruby', 'path', siteruby,
+          'the directory for version-independent aux ruby libraries'),
+      PathItem.new('siterubyver', 'path', siterubyver,
+                   'the directory for aux ruby libraries'),
+      PathItem.new('siterubyverarch', 'path', siterubyverarch,
+                   'the directory for aux ruby binaries'),
+      PathItem.new('rbdir', 'path', '$siterubyver',
+                   'the directory for ruby scripts'),
+      PathItem.new('sodir', 'path', '$siterubyverarch',
+                   'the directory for ruby extentions'),
+      PathItem.new('rubypath', 'path', rubypath,
+                   'the path to set to #! line'),
+      ProgramItem.new('rubyprog', 'name', rubypath,
+                      'the ruby program using for installation'),
+      ProgramItem.new('makeprog', 'name', makeprog,
+                      'the make program to compile ruby extentions'),
+      SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+                     'shebang line (#!) editing mode'),
+      BoolItem.new('without-ext', 'yes/no', 'no',
+                   'does not compile/install ruby extentions')
+    ]
+  end
+  private :standard_entries
+
+  def load_multipackage_entries
+    multipackage_entries().each do |ent|
+      add ent
+    end
+  end
+
+  def multipackage_entries
+    [
+      PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+                               'package names that you want to install'),
+      PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+                               'package names that you do not want to install')
+    ]
+  end
+  private :multipackage_entries
+
+  ALIASES = {
+    'std-ruby'         => 'librubyver',
+    'stdruby'          => 'librubyver',
+    'rubylibdir'       => 'librubyver',
+    'archdir'          => 'librubyverarch',
+    'site-ruby-common' => 'siteruby',     # For backward compatibility
+    'site-ruby'        => 'siterubyver',  # For backward compatibility
+    'bin-dir'          => 'bindir',
+    'bin-dir'          => 'bindir',
+    'rb-dir'           => 'rbdir',
+    'so-dir'           => 'sodir',
+    'data-dir'         => 'datadir',
+    'ruby-path'        => 'rubypath',
+    'ruby-prog'        => 'rubyprog',
+    'ruby'             => 'rubyprog',
+    'make-prog'        => 'makeprog',
+    'make'             => 'makeprog'
+  }
+
+  def fixup
+    ALIASES.each do |ali, name|
+      @table[ali] = @table[name]
+    end
+  end
+
+  def options_re
+    /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
+  end
+
+  def parse_opt(opt)
+    m = options_re().match(opt) or setup_rb_error "config: unknown option #{opt}"
+    m.to_a[1,2]
+  end
+
+  def dllext
+    @rbconfig['DLEXT']
+  end
+
+  def value_config?(name)
+    lookup(name).value?
+  end
+
+  class Item
+    def initialize(name, template, default, desc)
+      @name = name.freeze
+      @template = template
+      @value = default
+      @default = default
+      @description = desc
+    end
+
+    attr_reader :name
+    attr_reader :description
+
+    attr_accessor :default
+    alias help_default default
+
+    def help_opt
+      "--#{@name}=#{@template}"
+    end
+
+    def value?
+      true
+    end
+
+    def value
+      @value
+    end
+
+    def resolve(table)
+      @value.gsub(%r<\$([^/]+)>) { table[$1] }
+    end
+
+    def set(val)
+      @value = check(val)
+    end
+
+    private
+
+    def check(val)
+      setup_rb_error "config: --#{name} requires argument" unless val
+      val
+    end
+  end
+
+  class BoolItem < Item
+    def config_type
+      'bool'
+    end
+
+    def help_opt
+      "--#{@name}"
+    end
+
+    private
+
+    def check(val)
+      return 'yes' unless val
+      case val
+      when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
+      when /\An(o)?\z/i, /\Af(alse)\z/i  then 'no'
+      else
+        setup_rb_error "config: --#{@name} accepts only yes/no for argument"
+      end
+    end
+  end
+
+  class PathItem < Item
+    def config_type
+      'path'
+    end
+
+    private
+
+    def check(path)
+      setup_rb_error "config: --#{@name} requires argument"  unless path
+      path[0,1] == '$' ? path : File.expand_path(path)
+    end
+  end
+
+  class ProgramItem < Item
+    def config_type
+      'program'
+    end
+  end
+
+  class SelectItem < Item
+    def initialize(name, selection, default, desc)
+      super
+      @ok = selection.split('/')
+    end
+
+    def config_type
+      'select'
+    end
+
+    private
+
+    def check(val)
+      unless @ok.include?(val.strip)
+        setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
+      end
+      val.strip
+    end
+  end
+
+  class ExecItem < Item
+    def initialize(name, selection, desc, &block)
+      super name, selection, nil, desc
+      @ok = selection.split('/')
+      @action = block
+    end
+
+    def config_type
+      'exec'
+    end
+
+    def value?
+      false
+    end
+
+    def resolve(table)
+      setup_rb_error "$#{name()} wrongly used as option value"
+    end
+
+    undef set
+
+    def evaluate(val, table)
+      v = val.strip.downcase
+      unless @ok.include?(v)
+        setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
+      end
+      @action.call v, table
+    end
+  end
+
+  class PackageSelectionItem < Item
+    def initialize(name, template, default, help_default, desc)
+      super name, template, default, desc
+      @help_default = help_default
+    end
+
+    attr_reader :help_default
+
+    def config_type
+      'package'
+    end
+
+    private
+
+    def check(val)
+      unless File.dir?("packages/#{val}")
+        setup_rb_error "config: no such package: #{val}"
+      end
+      val
+    end
+  end
+
+  class MetaConfigEnvironment
+    def initialize(config, installer)
+      @config = config
+      @installer = installer
+    end
+
+    def config_names
+      @config.names
+    end
+
+    def config?(name)
+      @config.key?(name)
+    end
+
+    def bool_config?(name)
+      @config.lookup(name).config_type == 'bool'
+    end
+
+    def path_config?(name)
+      @config.lookup(name).config_type == 'path'
+    end
+
+    def value_config?(name)
+      @config.lookup(name).config_type != 'exec'
+    end
+
+    def add_config(item)
+      @config.add item
+    end
+
+    def add_bool_config(name, default, desc)
+      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+    end
+
+    def add_path_config(name, default, desc)
+      @config.add PathItem.new(name, 'path', default, desc)
+    end
+
+    def set_config_default(name, default)
+      @config.lookup(name).default = default
+    end
+
+    def remove_config(name)
+      @config.remove(name)
+    end
+
+    # For only multipackage
+    def packages
+      raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
+      @installer.packages
+    end
+
+    # For only multipackage
+    def declare_packages(list)
+      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
+      @installer.packages = list
+    end
+  end
+
+end   # class ConfigTable
+
+
+# This module requires: #verbose?, #no_harm?
+module FileOperations
+
+  def mkdir_p(dirname, prefix = nil)
+    dirname = prefix + File.expand_path(dirname) if prefix
+    $stderr.puts "mkdir -p #{dirname}" if verbose?
+    return if no_harm?
+
+    # Does not check '/', it's too abnormal.
+    dirs = File.expand_path(dirname).split(%r<(?=/)>)
+    if /\A[a-z]:\z/i =~ dirs[0]
+      disk = dirs.shift
+      dirs[0] = disk + dirs[0]
+    end
+    dirs.each_index do |idx|
+      path = dirs[0..idx].join('')
+      Dir.mkdir path unless File.dir?(path)
+    end
+  end
+
+  def rm_f(path)
+    $stderr.puts "rm -f #{path}" if verbose?
+    return if no_harm?
+    force_remove_file path
+  end
+
+  def rm_rf(path)
+    $stderr.puts "rm -rf #{path}" if verbose?
+    return if no_harm?
+    remove_tree path
+  end
+
+  def remove_tree(path)
+    if File.symlink?(path)
+      remove_file path
+    elsif File.dir?(path)
+      remove_tree0 path
+    else
+      force_remove_file path
+    end
+  end
+
+  def remove_tree0(path)
+    Dir.foreach(path) do |ent|
+      next if ent == '.'
+      next if ent == '..'
+      entpath = "#{path}/#{ent}"
+      if File.symlink?(entpath)
+        remove_file entpath
+      elsif File.dir?(entpath)
+        remove_tree0 entpath
+      else
+        force_remove_file entpath
+      end
+    end
+    begin
+      Dir.rmdir path
+    rescue Errno::ENOTEMPTY
+      # directory may not be empty
+    end
+  end
+
+  def move_file(src, dest)
+    force_remove_file dest
+    begin
+      File.rename src, dest
+    rescue
+      File.open(dest, 'wb') {|f|
+        f.write File.binread(src)
+      }
+      File.chmod File.stat(src).mode, dest
+      File.unlink src
+    end
+  end
+
+  def force_remove_file(path)
+    begin
+      remove_file path
+    rescue
+    end
+  end
+
+  def remove_file(path)
+    File.chmod 0777, path
+    File.unlink path
+  end
+
+  def install(from, dest, mode, prefix = nil)
+    $stderr.puts "install #{from} #{dest}" if verbose?
+    return if no_harm?
+
+    realdest = prefix ? prefix + File.expand_path(dest) : dest
+    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+    str = File.binread(from)
+    if diff?(str, realdest)
+      verbose_off {
+        rm_f realdest if File.exist?(realdest)
+      }
+      File.open(realdest, 'wb') {|f|
+        f.write str
+      }
+      File.chmod mode, realdest
+
+      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+        if prefix
+          f.puts realdest.sub(prefix, '')
+        else
+          f.puts realdest
+        end
+      }
+    end
+  end
+
+  def diff?(new_content, path)
+    return true unless File.exist?(path)
+    new_content != File.binread(path)
+  end
+
+  def command(*args)
+    $stderr.puts args.join(' ') if verbose?
+    system(*args) or raise RuntimeError,
+        "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
+  end
+
+  def ruby(*args)
+    command config('rubyprog'), *args
+  end
+  
+  def make(task = nil)
+    command(*[config('makeprog'), task].compact)
+  end
+
+  def extdir?(dir)
+    File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
+  end
+
+  def files_of(dir)
+    Dir.open(dir) {|d|
+      return d.select {|ent| File.file?("#{dir}/#{ent}") }
+    }
+  end
+
+  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
+
+  def directories_of(dir)
+    Dir.open(dir) {|d|
+      return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
+    }
+  end
+
+end
+
+
+# This module requires: #srcdir_root, #objdir_root, #relpath
+module HookScriptAPI
+
+  def get_config(key)
+    @config[key]
+  end
+
+  alias config get_config
+
+  # obsolete: use metaconfig to change configuration
+  def set_config(key, val)
+    @config[key] = val
+  end
+
+  #
+  # srcdir/objdir (works only in the package directory)
+  #
+
+  def curr_srcdir
+    "#{srcdir_root()}/#{relpath()}"
+  end
+
+  def curr_objdir
+    "#{objdir_root()}/#{relpath()}"
+  end
+
+  def srcfile(path)
+    "#{curr_srcdir()}/#{path}"
+  end
+
+  def srcexist?(path)
+    File.exist?(srcfile(path))
+  end
+
+  def srcdirectory?(path)
+    File.dir?(srcfile(path))
+  end
+  
+  def srcfile?(path)
+    File.file?(srcfile(path))
+  end
+
+  def srcentries(path = '.')
+    Dir.open("#{curr_srcdir()}/#{path}") {|d|
+      return d.to_a - %w(. ..)
+    }
+  end
+
+  def srcfiles(path = '.')
+    srcentries(path).select {|fname|
+      File.file?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+  def srcdirectories(path = '.')
+    srcentries(path).select {|fname|
+      File.dir?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+end
+
+
+class ToplevelInstaller
+
+  Version   = '3.4.1'
+  Copyright = 'Copyright (c) 2000-2006 Minero Aoki'
+
+  TASKS = [
+    [ 'all',      'do config, setup, then install' ],
+    [ 'config',   'saves your configurations' ],
+    [ 'show',     'shows current configuration' ],
+    [ 'setup',    'compiles ruby extentions and others' ],
+    [ 'install',  'installs files' ],
+    [ 'test',     'run all tests in test/' ],
+    [ 'clean',    "does `make clean' for each extention" ],
+    [ 'distclean',"does `make distclean' for each extention" ]
+  ]
+
+  def ToplevelInstaller.invoke
+    config = ConfigTable.new(load_rbconfig())
+    config.load_standard_entries
+    config.load_multipackage_entries if multipackage?
+    config.fixup
+    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
+    klass.new(File.dirname($0), config).invoke
+  end
+
+  def ToplevelInstaller.multipackage?
+    File.dir?(File.dirname($0) + '/packages')
+  end
+
+  def ToplevelInstaller.load_rbconfig
+    if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+      ARGV.delete(arg)
+      load File.expand_path(arg.split(/=/, 2)[1])
+      $".push 'rbconfig.rb'
+    else
+      require 'rbconfig'
+    end
+    ::Config::CONFIG
+  end
+
+  def initialize(ardir_root, config)
+    @ardir = File.expand_path(ardir_root)
+    @config = config
+    # cache
+    @valid_task_re = nil
+  end
+
+  def config(key)
+    @config[key]
+  end
+
+  def inspect
+    "#<#{self.class} #{__id__()}>"
+  end
+
+  def invoke
+    run_metaconfigs
+    case task = parsearg_global()
+    when nil, 'all'
+      parsearg_config
+      init_installers
+      exec_config
+      exec_setup
+      exec_install
+    else
+      case task
+      when 'config', 'test'
+        ;
+      when 'clean', 'distclean'
+        @config.load_savefile if File.exist?(@config.savefile)
+      else
+        @config.load_savefile
+      end
+      __send__ "parsearg_#{task}"
+      init_installers
+      __send__ "exec_#{task}"
+    end
+  end
+  
+  def run_metaconfigs
+    @config.load_script "#{@ardir}/metaconfig"
+  end
+
+  def init_installers
+    @installer = Installer.new(@config, @ardir, File.expand_path('.'))
+  end
+
+  #
+  # Hook Script API bases
+  #
+
+  def srcdir_root
+    @ardir
+  end
+
+  def objdir_root
+    '.'
+  end
+
+  def relpath
+    '.'
+  end
+
+  #
+  # Option Parsing
+  #
+
+  def parsearg_global
+    while arg = ARGV.shift
+      case arg
+      when /\A\w+\z/
+        setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
+        return arg
+      when '-q', '--quiet'
+        @config.verbose = false
+      when '--verbose'
+        @config.verbose = true
+      when '--help'
+        print_usage $stdout
+        exit 0
+      when '--version'
+        puts "#{File.basename($0)} version #{Version}"
+        exit 0
+      when '--copyright'
+        puts Copyright
+        exit 0
+      else
+        setup_rb_error "unknown global option '#{arg}'"
+      end
+    end
+    nil
+  end
+
+  def valid_task?(t)
+    valid_task_re() =~ t
+  end
+
+  def valid_task_re
+    @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
+  end
+
+  def parsearg_no_options
+    unless ARGV.empty?
+      task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
+      setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
+    end
+  end
+
+  alias parsearg_show       parsearg_no_options
+  alias parsearg_setup      parsearg_no_options
+  alias parsearg_test       parsearg_no_options
+  alias parsearg_clean      parsearg_no_options
+  alias parsearg_distclean  parsearg_no_options
+
+  def parsearg_config
+    evalopt = []
+    set = []
+    @config.config_opt = []
+    while i = ARGV.shift
+      if /\A--?\z/ =~ i
+        @config.config_opt = ARGV.dup
+        break
+      end
+      name, value = *@config.parse_opt(i)
+      if @config.value_config?(name)
+        @config[name] = value
+      else
+        evalopt.push [name, value]
+      end
+      set.push name
+    end
+    evalopt.each do |name, value|
+      @config.lookup(name).evaluate value, @config
+    end
+    # Check if configuration is valid
+    set.each do |n|
+      @config[n] if @config.value_config?(n)
+    end
+  end
+
+  def parsearg_install
+    @config.no_harm = false
+    @config.install_prefix = ''
+    while a = ARGV.shift
+      case a
+      when '--no-harm'
+        @config.no_harm = true
+      when /\A--prefix=/
+        path = a.split(/=/, 2)[1]
+        path = File.expand_path(path) unless path[0,1] == '/'
+        @config.install_prefix = path
+      else
+        setup_rb_error "install: unknown option #{a}"
+      end
+    end
+  end
+
+  def print_usage(out)
+    out.puts 'Typical Installation Procedure:'
+    out.puts "  $ ruby #{File.basename $0} config"
+    out.puts "  $ ruby #{File.basename $0} setup"
+    out.puts "  # ruby #{File.basename $0} install (may require root privilege)"
+    out.puts
+    out.puts 'Detailed Usage:'
+    out.puts "  ruby #{File.basename $0} <global option>"
+    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+    fmt = "  %-24s %s\n"
+    out.puts
+    out.puts 'Global options:'
+    out.printf fmt, '-q,--quiet',   'suppress message outputs'
+    out.printf fmt, '   --verbose', 'output messages verbosely'
+    out.printf fmt, '   --help',    'print this message'
+    out.printf fmt, '   --version', 'print version and quit'
+    out.printf fmt, '   --copyright',  'print copyright and quit'
+    out.puts
+    out.puts 'Tasks:'
+    TASKS.each do |name, desc|
+      out.printf fmt, name, desc
+    end
+
+    fmt = "  %-24s %s [%s]\n"
+    out.puts
+    out.puts 'Options for CONFIG or ALL:'
+    @config.each do |item|
+      out.printf fmt, item.help_opt, item.description, item.help_default
+    end
+    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+    out.puts
+    out.puts 'Options for INSTALL:'
+    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+    out.printf fmt, '--prefix=path',  'install path prefix', ''
+    out.puts
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    @installer.exec_config
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    @installer.exec_setup
+  end
+
+  def exec_install
+    @installer.exec_install
+  end
+
+  def exec_test
+    @installer.exec_test
+  end
+
+  def exec_show
+    @config.each do |i|
+      printf "%-20s %s\n", i.name, i.value if i.value?
+    end
+  end
+
+  def exec_clean
+    @installer.exec_clean
+  end
+
+  def exec_distclean
+    @installer.exec_distclean
+  end
+
+end   # class ToplevelInstaller
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+  include FileOperations
+
+  def initialize(ardir_root, config)
+    super
+    @packages = directories_of("#{@ardir}/packages")
+    raise 'no package exists' if @packages.empty?
+    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
+  end
+
+  def run_metaconfigs
+    @config.load_script "#{@ardir}/metaconfig", self
+    @packages.each do |name|
+      @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
+    end
+  end
+
+  attr_reader :packages
+
+  def packages=(list)
+    raise 'package list is empty' if list.empty?
+    list.each do |name|
+      raise "directory packages/#{name} does not exist"\
+              unless File.dir?("#{@ardir}/packages/#{name}")
+    end
+    @packages = list
+  end
+
+  def init_installers
+    @installers = {}
+    @packages.each do |pack|
+      @installers[pack] = Installer.new(@config,
+                                       "#{@ardir}/packages/#{pack}",
+                                       "packages/#{pack}")
+    end
+    with    = extract_selection(config('with'))
+    without = extract_selection(config('without'))
+    @selected = @installers.keys.select {|name|
+                  (with.empty? or with.include?(name)) \
+                      and not without.include?(name)
+                }
+  end
+
+  def extract_selection(list)
+    a = list.split(/,/)
+    a.each do |name|
+      setup_rb_error "no such package: #{name}"  unless @installers.key?(name)
+    end
+    a
+  end
+
+  def print_usage(f)
+    super
+    f.puts 'Inluded packages:'
+    f.puts '  ' + @packages.sort.join(' ')
+    f.puts
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    run_hook 'pre-config'
+    each_selected_installers {|inst| inst.exec_config }
+    run_hook 'post-config'
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    run_hook 'pre-setup'
+    each_selected_installers {|inst| inst.exec_setup }
+    run_hook 'post-setup'
+  end
+
+  def exec_install
+    run_hook 'pre-install'
+    each_selected_installers {|inst| inst.exec_install }
+    run_hook 'post-install'
+  end
+
+  def exec_test
+    run_hook 'pre-test'
+    each_selected_installers {|inst| inst.exec_test }
+    run_hook 'post-test'
+  end
+
+  def exec_clean
+    rm_f @config.savefile
+    run_hook 'pre-clean'
+    each_selected_installers {|inst| inst.exec_clean }
+    run_hook 'post-clean'
+  end
+
+  def exec_distclean
+    rm_f @config.savefile
+    run_hook 'pre-distclean'
+    each_selected_installers {|inst| inst.exec_distclean }
+    run_hook 'post-distclean'
+  end
+
+  #
+  # lib
+  #
+
+  def each_selected_installers
+    Dir.mkdir 'packages' unless File.dir?('packages')
+    @selected.each do |pack|
+      $stderr.puts "Processing the package `#{pack}' ..." if verbose?
+      Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+      Dir.chdir "packages/#{pack}"
+      yield @installers[pack]
+      Dir.chdir '../..'
+    end
+  end
+
+  def run_hook(id)
+    @root_installer.run_hook id
+  end
+
+  # module FileOperations requires this
+  def verbose?
+    @config.verbose?
+  end
+
+  # module FileOperations requires this
+  def no_harm?
+    @config.no_harm?
+  end
+
+end   # class ToplevelInstallerMulti
+
+
+class Installer
+
+  FILETYPES = %w( bin lib ext data conf man )
+
+  include FileOperations
+  include HookScriptAPI
+
+  def initialize(config, srcroot, objroot)
+    @config = config
+    @srcdir = File.expand_path(srcroot)
+    @objdir = File.expand_path(objroot)
+    @currdir = '.'
+  end
+
+  def inspect
+    "#<#{self.class} #{File.basename(@srcdir)}>"
+  end
+
+  def noop(rel)
+  end
+
+  #
+  # Hook Script API base methods
+  #
+
+  def srcdir_root
+    @srcdir
+  end
+
+  def objdir_root
+    @objdir
+  end
+
+  def relpath
+    @currdir
+  end
+
+  #
+  # Config Access
+  #
+
+  # module FileOperations requires this
+  def verbose?
+    @config.verbose?
+  end
+
+  # module FileOperations requires this
+  def no_harm?
+    @config.no_harm?
+  end
+
+  def verbose_off
+    begin
+      save, @config.verbose = @config.verbose?, false
+      yield
+    ensure
+      @config.verbose = save
+    end
+  end
+
+  #
+  # TASK config
+  #
+
+  def exec_config
+    exec_task_traverse 'config'
+  end
+
+  alias config_dir_bin noop
+  alias config_dir_lib noop
+
+  def config_dir_ext(rel)
+    extconf if extdir?(curr_srcdir())
+  end
+
+  alias config_dir_data noop
+  alias config_dir_conf noop
+  alias config_dir_man noop
+
+  def extconf
+    ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
+  end
+
+  #
+  # TASK setup
+  #
+
+  def exec_setup
+    exec_task_traverse 'setup'
+  end
+
+  def setup_dir_bin(rel)
+    files_of(curr_srcdir()).each do |fname|
+      update_shebang_line "#{curr_srcdir()}/#{fname}"
+    end
+  end
+
+  alias setup_dir_lib noop
+
+  def setup_dir_ext(rel)
+    make if extdir?(curr_srcdir())
+  end
+
+  alias setup_dir_data noop
+  alias setup_dir_conf noop
+  alias setup_dir_man noop
+
+  def update_shebang_line(path)
+    return if no_harm?
+    return if config('shebang') == 'never'
+    old = Shebang.load(path)
+    if old
+      $stderr.puts "warning: #{path}: Shebang line includes too many args.  It is not portable and your program may not work." if old.args.size > 1
+      new = new_shebang(old)
+      return if new.to_s == old.to_s
+    else
+      return unless config('shebang') == 'all'
+      new = Shebang.new(config('rubypath'))
+    end
+    $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
+    open_atomic_writer(path) {|output|
+      File.open(path, 'rb') {|f|
+        f.gets if old   # discard
+        output.puts new.to_s
+        output.print f.read
+      }
+    }
+  end
+
+  def new_shebang(old)
+    if /\Aruby/ =~ File.basename(old.cmd)
+      Shebang.new(config('rubypath'), old.args)
+    elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
+      Shebang.new(config('rubypath'), old.args[1..-1])
+    else
+      return old unless config('shebang') == 'all'
+      Shebang.new(config('rubypath'))
+    end
+  end
+
+  def open_atomic_writer(path, &block)
+    tmpfile = File.basename(path) + '.tmp'
+    begin
+      File.open(tmpfile, 'wb', &block)
+      File.rename tmpfile, File.basename(path)
+    ensure
+      File.unlink tmpfile if File.exist?(tmpfile)
+    end
+  end
+
+  class Shebang
+    def Shebang.load(path)
+      line = nil
+      File.open(path) {|f|
+        line = f.gets
+      }
+      return nil unless /\A#!/ =~ line
+      parse(line)
+    end
+
+    def Shebang.parse(line)
+      cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
+      new(cmd, args)
+    end
+
+    def initialize(cmd, args = [])
+      @cmd = cmd
+      @args = args
+    end
+
+    attr_reader :cmd
+    attr_reader :args
+
+    def to_s
+      "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
+    end
+  end
+
+  #
+  # TASK install
+  #
+
+  def exec_install
+    rm_f 'InstalledFiles'
+    exec_task_traverse 'install'
+  end
+
+  def install_dir_bin(rel)
+    install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
+  end
+
+  def install_dir_lib(rel)
+    install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
+  end
+
+  def install_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    install_files rubyextentions('.'),
+                  "#{config('sodir')}/#{File.dirname(rel)}",
+                  0555
+  end
+
+  def install_dir_data(rel)
+    install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
+  end
+
+  def install_dir_conf(rel)
+    # FIXME: should not remove current config files
+    # (rename previous file to .old/.org)
+    install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
+  end
+
+  def install_dir_man(rel)
+    install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
+  end
+
+  def install_files(list, dest, mode)
+    mkdir_p dest, @config.install_prefix
+    list.each do |fname|
+      install fname, dest, mode, @config.install_prefix
+    end
+  end
+
+  def libfiles
+    glob_reject(%w(*.y *.output), targetfiles())
+  end
+
+  def rubyextentions(dir)
+    ents = glob_select("*.#{@config.dllext}", targetfiles())
+    if ents.empty?
+      setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+    end
+    ents
+  end
+
+  def targetfiles
+    mapdir(existfiles() - hookfiles())
+  end
+
+  def mapdir(ents)
+    ents.map {|ent|
+      if File.exist?(ent)
+      then ent                         # objdir
+      else "#{curr_srcdir()}/#{ent}"   # srcdir
+      end
+    }
+  end
+
+  # picked up many entries from cvs-1.11.1/src/ignore.c
+  JUNK_FILES = %w( 
+    core RCSLOG tags TAGS .make.state
+    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+    *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+    *.org *.in .*
+  )
+
+  def existfiles
+    glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
+  end
+
+  def hookfiles
+    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+      %w( config setup install clean distclean ).map {|t| sprintf(fmt, t) }
+    }.flatten
+  end
+
+  def glob_select(pat, ents)
+    re = globs2re([pat])
+    ents.select {|ent| re =~ ent }
+  end
+
+  def glob_reject(pats, ents)
+    re = globs2re(pats)
+    ents.reject {|ent| re =~ ent }
+  end
+
+  GLOB2REGEX = {
+    '.' => '\.',
+    '$' => '\$',
+    '#' => '\#',
+    '*' => '.*'
+  }
+
+  def globs2re(pats)
+    /\A(?:#{
+      pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
+    })\z/
+  end
+
+  #
+  # TASK test
+  #
+
+  TESTDIR = 'test'
+
+  def exec_test
+    unless File.directory?('test')
+      $stderr.puts 'no test in this package' if verbose?
+      return
+    end
+    $stderr.puts 'Running tests...' if verbose?
+    begin
+      require 'test/unit'
+    rescue LoadError
+      setup_rb_error 'test/unit cannot loaded.  You need Ruby 1.8 or later to invoke this task.'
+    end
+    runner = Test::Unit::AutoRunner.new(true)
+    runner.to_run << TESTDIR
+    runner.run
+  end
+
+  #
+  # TASK clean
+  #
+
+  def exec_clean
+    exec_task_traverse 'clean'
+    rm_f @config.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  alias clean_dir_bin noop
+  alias clean_dir_lib noop
+  alias clean_dir_data noop
+  alias clean_dir_conf noop
+  alias clean_dir_man noop
+
+  def clean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'clean' if File.file?('Makefile')
+  end
+
+  #
+  # TASK distclean
+  #
+
+  def exec_distclean
+    exec_task_traverse 'distclean'
+    rm_f @config.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  alias distclean_dir_bin noop
+  alias distclean_dir_lib noop
+
+  def distclean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'distclean' if File.file?('Makefile')
+  end
+
+  alias distclean_dir_data noop
+  alias distclean_dir_conf noop
+  alias distclean_dir_man noop
+
+  #
+  # Traversing
+  #
+
+  def exec_task_traverse(task)
+    run_hook "pre-#{task}"
+    FILETYPES.each do |type|
+      if type == 'ext' and config('without-ext') == 'yes'
+        $stderr.puts 'skipping ext/* by user option' if verbose?
+        next
+      end
+      traverse task, type, "#{task}_dir_#{type}"
+    end
+    run_hook "post-#{task}"
+  end
+
+  def traverse(task, rel, mid)
+    dive_into(rel) {
+      run_hook "pre-#{task}"
+      __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+      directories_of(curr_srcdir()).each do |d|
+        traverse task, "#{rel}/#{d}", mid
+      end
+      run_hook "post-#{task}"
+    }
+  end
+
+  def dive_into(rel)
+    return unless File.dir?("#{@srcdir}/#{rel}")
+
+    dir = File.basename(rel)
+    Dir.mkdir dir unless File.dir?(dir)
+    prevdir = Dir.pwd
+    Dir.chdir dir
+    $stderr.puts '---> ' + rel if verbose?
+    @currdir = rel
+    yield
+    Dir.chdir prevdir
+    $stderr.puts '<--- ' + rel if verbose?
+    @currdir = File.dirname(rel)
+  end
+
+  def run_hook(id)
+    path = [ "#{curr_srcdir()}/#{id}",
+             "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
+    return unless path
+    $stderr.puts "invoking hook script #{path}" if verbose?
+    begin
+      instance_eval File.read(path), path, 1
+    rescue
+      raise if $DEBUG
+      setup_rb_error "hook #{path} failed:\n" + $!.message
+    end
+  end
+
+end   # class Installer
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+  raise SetupError, msg
+end
+
+if $0 == __FILE__
+  begin
+    ToplevelInstaller.invoke
+  rescue SetupError
+    raise if $DEBUG
+    $stderr.puts $!.message
+    $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+    exit 1
+  end
+end




More information about the Pkg-ruby-extras-commits mailing list