[Pkg-ruby-extras-maintainers] r731 - in packages/libinline-ruby/trunk: . debian lib

Patrick Ringl smash-guest at costa.debian.org
Tue Aug 1 11:05:12 UTC 2006


Author: smash-guest
Date: 2006-08-01 11:05:10 +0000 (Tue, 01 Aug 2006)
New Revision: 731

Added:
   packages/libinline-ruby/trunk/CHANGELOG
   packages/libinline-ruby/trunk/README
   packages/libinline-ruby/trunk/debian/
   packages/libinline-ruby/trunk/debian/changelog
   packages/libinline-ruby/trunk/debian/compat
   packages/libinline-ruby/trunk/debian/control
   packages/libinline-ruby/trunk/debian/control.in
   packages/libinline-ruby/trunk/debian/copyright
   packages/libinline-ruby/trunk/debian/example.rb
   packages/libinline-ruby/trunk/debian/rules
   packages/libinline-ruby/trunk/debian/watch
   packages/libinline-ruby/trunk/lib/
   packages/libinline-ruby/trunk/lib/inline.rb
   packages/libinline-ruby/trunk/lib/inline_package
   packages/libinline-ruby/trunk/setup.rb
Log:
Load newtrunk into packages/libinline-ruby/trunk.


Added: packages/libinline-ruby/trunk/CHANGELOG
===================================================================
--- packages/libinline-ruby/trunk/CHANGELOG	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/CHANGELOG	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,5 @@
+--------------------------------------------------------------------------------
+26/07/2006 version 3.5.0-1
+
+o Initial release.
+--------------------------------------------------------------------------------
\ No newline at end of file

Added: packages/libinline-ruby/trunk/README
===================================================================
--- packages/libinline-ruby/trunk/README	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/README	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,152 @@
+** Ruby Inline
+
+    http://www.zenspider.com/ZSS/Products/RubyInline/
+    http://rubyforge.org/projects/rubyinline/
+    support at zenspider.com
+
+** DESCRIPTION:
+
+Ruby Inline is an analog to Perl's Inline::C. Out of the box, it
+allows you to embed C/++ external module code in your ruby script
+directly. By writing simple builder classes, you can teach how to cope
+with new languages (fortran, perl, whatever). The code is compiled and
+run on the fly when needed.
+
+Using the package_inline tool Inline now allows you to package up
+your inlined object code for distribution to systems without a
+compiler (read: windows)!
+
+### HELLO WORLD EXAMPLE ###
+
+#!/usr/bin/ruby -w
+
+require 'inline'
+
+class Hello
+  inline do |builder|
+    builder.include "<stdio.h>"
+    builder.c 'void hello() { puts("hello world"); }'
+  end
+end
+
+Hello.new.hello
+
+##############################
+
+
+
+
+** FEATURES/PROBLEMS:
+
++ Quick and easy inlining of your C or C++ code embedded in your ruby script.
++ Extendable to work with other languages.
++ Automatic conversion between ruby and C basic types
+	+ char, unsigned, unsigned int, char *, int, long, unsigned long
++ inline_c_raw exists for when the automatic conversion isn't sufficient.
++ Only recompiles if the inlined code has changed.
++ Pretends to be secure.
++ Only requires standard ruby libraries, nothing extra to download.
++ Can generate a basic Rakefile and package up built extensions for distribution.
+
+** SYNOPSYS:
+
+  require "inline"
+  class MyTest
+    inline do |builder|
+      builder.c "
+        long factorial(int max) {
+          int i=max, result=1;
+          while (i >= 2) { result *= i--; }
+          return result;
+        }"
+  end
+  t = MyTest.new()
+  factorial_5 = t.factorial(5)
+
+** SYNOPSYS (C++):
+
+  require 'inline'
+  class MyTest
+    inline(:C) do |builder|
+      builder.include '<iostream>'
+      builder.add_compile_flags '-x c++', '-lstdc++'
+      builder.c '
+        void hello(int i) {
+          while (i-- > 0) {
+            std::cout << "hello" << std::endl;
+          }
+        }'
+    end
+  end
+  t = MyTest.new()
+  t.hello(3)
+
+** SYNOPSYS (packaging):
+
+  rm -rf ~/.ruby_inline
+  make test
+  inline_package packagename 1.0.0
+  ls lib/inline
+
+** (PSEUDO)BENCHMARKS:
+
+  > make bench
+
+  Running native
+  Type = Native   , Iter = 1000000, T = 28.70058100 sec, 0.00002870 sec / iter
+  Running primer - preloads the compiler and stuff
+  With full builds
+  Type = Inline C , Iter = 1000000, T = 7.55118600 sec, 0.00000755 sec / iter
+  Type = InlineRaw, Iter = 1000000, T = 7.54488300 sec, 0.00000754 sec / iter
+  Type = Alias    , Iter = 1000000, T = 7.53243100 sec, 0.00000753 sec / iter
+  Without builds
+  Type = Inline C , Iter = 1000000, T = 7.59543300 sec, 0.00000760 sec / iter
+  Type = InlineRaw, Iter = 1000000, T = 7.54097200 sec, 0.00000754 sec / iter
+  Type = Alias    , Iter = 1000000, T = 7.53654000 sec, 0.00000754 sec / iter
+
+** PROFILING STRATEGY:
+
+0) Always keep a log of your progress and changes.
+1) Run code with 'time' and large dataset.
+2) Run code with '-rprofile' and smaller dataset, large enough to get good #s.
+3) Examine profile output and translate 1 bottleneck to C.
+4) Run new code with 'time' and large dataset. Repeat 2-3 if unsatisfied.
+5) Run final code with 'time' and compare to the first run.
+
+** REQUIREMENTS:
+
++ Ruby - 1.8.2 has been used on FreeBSD 4.6+ and MacOSX.
++ POSIX compliant system (ie pretty much any UNIX, or Cygwin on MS platforms).
++ A C/C++ compiler (the same one that compiled your ruby interpreter).
++ test::unit for running tests ( http://testunit.talbott.ws/ ).
++ rubygems & rake if you'd like - these are used by inline_package.
+
+** INSTALL:
+
++ make test  (optional)
++ make install
+
+** LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2001-2005 Ryan Davis, Zen Spider Software
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: packages/libinline-ruby/trunk/debian/changelog
===================================================================
--- packages/libinline-ruby/trunk/debian/changelog	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/changelog	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,6 @@
+libinline-ruby (3.5.0-1) unstable; urgency=low
+
+  * Initial release
+
+ -- Patrick Ringl <patrick_ at freenet.de>  Wed, 26 Jul 2006 04:38:15 +0200
+

Added: packages/libinline-ruby/trunk/debian/compat
===================================================================
--- packages/libinline-ruby/trunk/debian/compat	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/compat	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1 @@
+5

Added: packages/libinline-ruby/trunk/debian/control
===================================================================
--- packages/libinline-ruby/trunk/debian/control	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/control	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,35 @@
+Source: libinline-ruby
+Section: interpreters
+Priority: optional
+Maintainer: Patrick Ringl <patrick_ at freenet.de>
+Uploaders: Debian Ruby Extras Maintainers <pkg-ruby-extras-maintainers at lists.alioth.debian.org>, Antonio S. de A. Terceiro <asaterceiro at inf.ufrgs.br>, David Moreno Garza <damog at debian.org>, David Nusinow <dnusinow at debian.org>, Paul van Tilburg <paulvt at debian.org>, Esteban Manchado Velázquez <zoso at debian.org>, Arnaud Cornet <arnaud.cornet at gmail.com>, Lucas Nussbaum <lucas at lucas-nussbaum.net>, Thierry Reding <thierry at doppeltgemoppelt.de>, Marc Dequènes (Duck) <Duck at DuckCorp.org>, Ari Pollak <ari at debian.org>, Daigo Moriwaki <daigo at debian.org>
+Build-Depends: ruby-pkg-tools (>= 0.8), cdbs, debhelper (>= 5.0.0), ruby1.8, ruby1.8-dev
+Build-Depends-Indep: ruby-pkg-tools (>= 0.8), cdbs, debhelper (>= 5.0.0), ruby1.8, ruby1.8-dev
+Standards-Version: 3.7.2
+
+Package: libinline-ruby
+Architecture: all
+Depends: libinline-ruby1.8
+Description: Ruby library for embedding C/++ external module code
+ Ruby Inline is an analog to Perl's Inline::C. Out of the box,
+ it allows you to embed C/++ external module code in your ruby script
+ directly. By writing simple builder classes, you can teach how to cope with
+ new languages (fortran, perl, whatever).
+ .
+ This package is part of the Ruby library extras, a supplement to Ruby's
+ standard library.
+ .
+ This is a dummy package depending on the library for the current default
+ version of Ruby.
+
+Package: libinline-ruby1.8
+Architecture: all
+Depends: ruby1.8, ruby1.8-dev
+Description: Ruby library for embedding C/++ external module code
+ Ruby Inline is an analog to Perl's Inline::C. Out of the box,
+ it allows you to embed C/++ external module code in your ruby script
+ directly. By writing simple builder classes, you can teach how to cope with
+ new languages (fortran, perl, whatever).
+ .
+ This package is part of the Ruby library extras, a supplement to Ruby's
+ standard library.

Added: packages/libinline-ruby/trunk/debian/control.in
===================================================================
--- packages/libinline-ruby/trunk/debian/control.in	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/control.in	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,35 @@
+Source: libinline-ruby
+Section: interpreters
+Priority: optional
+Maintainer: Patrick Ringl <patrick_ at freenet.de>
+Uploaders: @RUBY_EXTRAS_TEAM@
+Build-Depends: ruby-pkg-tools (>= 0.8), cdbs, debhelper (>= 5.0.0), ruby1.8, ruby1.8-dev
+Build-Depends-Indep: ruby-pkg-tools (>= 0.8), cdbs, debhelper (>= 5.0.0), ruby1.8, ruby1.8-dev
+Standards-Version: 3.7.2
+
+Package: libinline-ruby
+Architecture: all
+Depends: libinline-ruby1.8
+Description: Ruby library for embedding C/++ external module code
+ Ruby Inline is an analog to Perl's Inline::C. Out of the box,
+ it allows you to embed C/++ external module code in your ruby script
+ directly. By writing simple builder classes, you can teach how to cope with
+ new languages (fortran, perl, whatever).
+ .
+ This package is part of the Ruby library extras, a supplement to Ruby's
+ standard library.
+ .
+ This is a dummy package depending on the library for the current default
+ version of Ruby.
+
+Package: libinline-ruby1.8
+Architecture: all
+Depends: ruby1.8, ruby1.8-dev
+Description: Ruby library for embedding C/++ external module code
+ Ruby Inline is an analog to Perl's Inline::C. Out of the box,
+ it allows you to embed C/++ external module code in your ruby script
+ directly. By writing simple builder classes, you can teach how to cope with
+ new languages (fortran, perl, whatever).
+ .
+ This package is part of the Ruby library extras, a supplement to Ruby's
+ standard library.

Added: packages/libinline-ruby/trunk/debian/copyright
===================================================================
--- packages/libinline-ruby/trunk/debian/copyright	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/copyright	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,35 @@
+This package was debianized by Patrick Ringl <patrick_ at freenet.de> on
+Wed, 26 Jul 2006 04:38:15 +0200.
+
+It was downloaded from http://rubyforge.org/frs/download.php/6475/RubyInline-3.5.0.tar.gz
+
+Upstream Author: Ryan Davis <support at zenspider.com>
+
+Copyright: Copyright (c) 2001-2006 Ryan Davis, Zen Spider Software
+
+License: The MIT License
+
+Copyright (c) 2001-2005 Ryan Davis, Zen Spider Software
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+The Debian packaging is (C) 2006, Patrick Ringl <patrick_ at freenet.de> and
+is licensed under the GPL, see `/usr/share/common-licenses/GPL'.

Added: packages/libinline-ruby/trunk/debian/example.rb
===================================================================
--- packages/libinline-ruby/trunk/debian/example.rb	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/example.rb	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,12 @@
+#!/usr/bin/ruby -w
+
+require 'inline'
+
+class Hello
+  inline do |builder|
+    builder.include "<stdio.h>"
+    builder.c 'void hello() { puts("hello world"); }'
+  end
+end
+
+Hello.new.hello
\ No newline at end of file

Added: packages/libinline-ruby/trunk/debian/rules
===================================================================
--- packages/libinline-ruby/trunk/debian/rules	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/rules	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,11 @@
+#!/usr/bin/make -f
+#
+# CDBS file to build the Daemonize package.
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/ruby-pkg-tools/1/class/ruby-setup-rb.mk
+
+include /usr/share/ruby-pkg-tools/1/rules/uploaders.mk
+
+# Include the upstream ChangeLog:
+DEB_INSTALL_CHANGELOGS_ALL = CHANGELOG


Property changes on: packages/libinline-ruby/trunk/debian/rules
___________________________________________________________________
Name: svn:executable
   + *

Added: packages/libinline-ruby/trunk/debian/watch
===================================================================
--- packages/libinline-ruby/trunk/debian/watch	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/debian/watch	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,2 @@
+version=2
+http://rubyforge.org/frs/download.php/6475/RubyInline-(.*)\.tar\.gz
\ No newline at end of file

Added: packages/libinline-ruby/trunk/lib/inline.rb
===================================================================
--- packages/libinline-ruby/trunk/lib/inline.rb	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/lib/inline.rb	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,651 @@
+#!/usr/bin/ruby -w
+
+##
+# Ruby Inline is a framework for writing ruby extensions in foreign
+# languages.
+#
+# = SYNOPSIS
+#
+#   require 'inline'
+#   class MyClass
+#     inline do |builder|
+#       builder.include "<math.h>"
+#       builder.c %q{
+#         long factorial(int max) {
+#           int i=max, result=1;
+#           while (i >= 2) { result *= i--; }
+#           return result;
+#         }
+#       }
+#     end
+#   end
+# 
+# = DESCRIPTION
+# 
+# Inline allows you to write foreign code within your ruby code. It
+# automatically determines if the code in question has changed and
+# builds it only when necessary. The extensions are then automatically
+# loaded into the class/module that defines it.
+#
+# Using the package_inline tool Inline now allows you to package up
+# your inlined object code for distribution to systems without a
+# compiler (read: windows)!
+#
+# You can even write extra builders that will allow you to write
+# inlined code in any language. Use Inline::C as a template and look
+# at Module#inline for the required API.
+
+require "rbconfig"
+require "digest/md5"
+require 'ftools'
+require 'fileutils'
+
+$TESTING = false unless defined? $TESTING
+
+class CompilationError < RuntimeError; end
+
+##
+# The Inline module is the top-level module used. It is responsible
+# for instantiating the builder for the right language used,
+# compilation/linking when needed, and loading the inlined code into
+# the current namespace.
+
+module Inline
+  VERSION = '3.5.0'
+
+  $stderr.puts "RubyInline v #{VERSION}" if $DEBUG
+
+  protected
+
+  def self.rootdir
+    env = ENV['INLINEDIR'] || ENV['HOME']
+    unless defined? @@rootdir and env == @@rootdir and test ?d, @@rootdir then
+      rootdir = ENV['INLINEDIR'] || ENV['HOME']
+      Dir.mkdir rootdir, 0700 unless test ?d, rootdir
+      Dir.assert_secure rootdir
+      @@rootdir = rootdir
+    end
+
+    @@rootdir
+  end
+
+  def self.directory
+    directory = File.join(rootdir, ".ruby_inline")
+    unless defined? @@directory and directory == @@directory and test ?d, @@directory then
+      unless File.directory? directory then
+	$stderr.puts "NOTE: creating #{directory} for RubyInline" if $DEBUG
+	Dir.mkdir directory, 0700
+      end
+      Dir.assert_secure directory
+      @@directory = directory
+    end
+    @@directory
+  end
+
+  # Inline::C is the default builder used and the only one provided by
+  # Inline. It can be used as a template to write builders for other
+  # languages. It understands type-conversions for the basic types and
+  # can be extended as needed.
+  
+  class C 
+
+    protected unless $TESTING
+
+    MAGIC_ARITY_THRESHOLD = 2
+    MAGIC_ARITY = -1
+
+    @@type_map = {
+      'char'          => [ 'NUM2CHR',  'CHR2FIX' ],
+      'char *'        => [ 'STR2CSTR', 'rb_str_new2' ],
+      'double'        => [ 'NUM2DBL',  'rb_float_new' ],
+      'int'           => [ 'FIX2INT',  'INT2FIX' ],
+      'long'          => [ 'NUM2INT',  'INT2NUM' ],
+      'unsigned int'  => [ 'NUM2UINT', 'UINT2NUM' ],
+      'unsigned long' => [ 'NUM2UINT', 'UINT2NUM' ],
+      'unsigned'      => [ 'NUM2UINT', 'UINT2NUM' ],
+      # Can't do these converters because they conflict with the above:
+      # ID2SYM(x), SYM2ID(x), NUM2DBL(x), FIX2UINT(x)
+    }
+
+    def ruby2c(type)
+      raise ArgumentError, "Unknown type #{type}" unless @@type_map.has_key? type
+      @@type_map[type].first
+    end
+
+    def c2ruby(type)
+      raise ArgumentError, "Unknown type #{type}" unless @@type_map.has_key? type
+      @@type_map[type].last
+    end
+
+    def strip_comments(src)
+      # strip c-comments
+      src = src.gsub(/\s*(?:(?:\/\*)(?:(?:(?!\*\/)[\s\S])*)(?:\*\/))/, '')
+      # strip cpp-comments
+      src.gsub!(/\s*(?:\/\*(?:(?!\*\/)[\s\S])*\*\/|\/\/[^\n]*\n)/, '')
+      src
+    end
+    
+    def parse_signature(src, raw=false)
+
+      sig = self.strip_comments(src)
+      # strip preprocessor directives
+      sig.gsub!(/^\s*\#.*(\\\n.*)*/, '')
+      # strip {}s
+      sig.gsub!(/\{[^\}]*\}/, '{ }')
+      # clean and collapse whitespace
+      sig.gsub!(/\s+/, ' ')
+
+      types = 'void|VALUE|' + @@type_map.keys.map{|x| Regexp.escape(x)}.join('|')
+
+      if /(#{types})\s*(\w+)\s*\(([^)]*)\)/ =~ sig then
+	return_type, function_name, arg_string = $1, $2, $3
+	args = []
+	arg_string.split(',').each do |arg|
+
+	  # helps normalize into 'char * varname' form
+	  arg = arg.gsub(/\s*\*\s*/, ' * ').strip
+
+	  # if /(#{types})\s+(\w+)\s*$/ =~ arg
+	  if /(((#{types})\s*\*?)+)\s+(\w+)\s*$/ =~ arg then
+	    args.push([$4, $1])
+	  elsif arg != "void" then
+	    $stderr.puts "WARNING: '#{arg}' not understood"
+	  end
+	end
+
+	arity = args.size
+	arity = -1 if arity > MAGIC_ARITY_THRESHOLD or raw
+
+	return {
+	  'return' => return_type,
+	    'name' => function_name,
+	    'args' => args,
+	   'arity' => arity
+	}
+      end
+
+      raise SyntaxError, "Can't parse signature: #{sig}"
+    end # def parse_signature
+
+    def generate(src, options={})
+
+      if not Hash === options then
+        options = {:expand_types=>options}
+      end
+
+      expand_types = options[:expand_types]
+      singleton = options[:singleton]
+      result = self.strip_comments(src)
+
+      signature = parse_signature(src, !expand_types)
+      function_name = signature['name']
+      return_type = signature['return']
+      arity = signature['arity']
+
+      if expand_types then
+	prefix = "static VALUE #{function_name}("
+	if arity == MAGIC_ARITY then
+	  prefix += "int argc, VALUE *argv, VALUE self"
+	else
+	  prefix += "VALUE self"
+	  signature['args'].each do |arg, type|
+	    prefix += ", VALUE _#{arg}"
+	  end
+	end
+	prefix += ") {\n"
+	if arity == MAGIC_ARITY then
+	  count = 0
+	  signature['args'].each do |arg, type|
+	    prefix += "  #{type} #{arg} = #{ruby2c(type)}(argv[#{count}]);\n"
+	    count += 1
+	  end
+	else
+	  signature['args'].each do |arg, type|
+	    prefix += "  #{type} #{arg} = #{ruby2c(type)}(_#{arg});\n"
+	  end
+	end
+	# replace the function signature (hopefully) with new sig (prefix)
+	result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
+	result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
+	unless return_type == "void" then
+	  raise SyntaxError, "Couldn't find return statement for #{function_name}" unless 
+	    result =~ /return/ 
+	  result.gsub!(/return\s+([^\;\}]+)/) do
+	    "return #{c2ruby(return_type)}(#{$1})"
+	  end
+	else
+	  result.sub!(/\s*\}\s*\Z/, "\nreturn Qnil;\n}")
+	end
+      else
+	prefix = "static #{return_type} #{function_name}("
+	result.sub!(/[^;\/\"\>]+#{function_name}\s*\(/, prefix)
+	result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
+      end
+
+      delta = if result =~ /\A(static.*?\{)/m then
+                $1.split(/\n/).size
+              else
+                warn "WARNING: Can't find signature in #{result.inspect}\n" unless $TESTING
+                0
+              end
+
+      file, line = caller[1].split(/:/)
+      result = "# line #{line.to_i + delta} \"#{file}\"\n" + result unless $DEBUG
+
+      @src << result
+      @sig[function_name] = [arity,singleton]
+
+      return result if $TESTING
+    end # def generate
+
+    def module_name
+      unless defined? @module_name then
+        module_name = @mod.name.gsub('::','__')
+        md5 = Digest::MD5.new
+        @sig.keys.sort_by{|x| x.to_s}.each { |m| md5 << m.to_s }
+        @module_name = "Inline_#{module_name}_#{md5.to_s[0,4]}"
+      end
+      @module_name
+    end
+
+    def so_name
+      unless defined? @so_name then
+        @so_name = "#{Inline.directory}/#{module_name}.#{Config::CONFIG["DLEXT"]}"
+      end
+      @so_name
+    end
+
+    attr_reader :rb_file, :mod
+    attr_accessor :mod, :src, :sig, :flags, :libs if $TESTING
+
+    public
+
+    def initialize(mod)
+      raise ArgumentError, "Class/Module arg is required" unless Module === mod
+      # new (but not on some 1.8s) -> inline -> real_caller|eval
+      stack = caller
+      meth = stack.shift until meth =~ /in .(inline|test_)/ or stack.empty?
+      raise "Couldn't discover caller" if stack.empty?
+      real_caller = stack.first
+      real_caller = stack[3] if real_caller =~ /\(eval\)/
+      @real_caller = real_caller.split(/:/).first
+      @rb_file = File.expand_path(@real_caller)
+
+      @mod = mod
+      @src = []
+      @sig = {}
+      @flags = []
+      @libs = []
+      @init_extra = []
+    end
+
+    ##
+    # Attempts to load pre-generated code returning true if it succeeds.
+
+    def load_cache
+      begin
+        file = File.join("inline", File.basename(so_name))
+        if require file then
+          dir = Inline.directory
+          warn "WARNING: #{dir} exists but is not being used" if test ?d, dir
+          return true
+        end
+      rescue LoadError
+      end
+      return false
+    end
+
+    ##
+    # Loads the generated code back into ruby
+
+    def load
+      require "#{so_name}" or raise LoadError, "require on #{so_name} failed"
+    end
+
+    ##
+    # Builds the source file, if needed, and attempts to compile it.
+
+    def build
+      so_name = self.so_name
+      so_exists = File.file? so_name
+
+      unless so_exists and File.mtime(rb_file) < File.mtime(so_name)
+	
+	src_name = "#{Inline.directory}/#{module_name}.c"
+	old_src_name = "#{src_name}.old"
+	should_compare = File.write_with_backup(src_name) do |io|
+	  io.puts
+	  io.puts "#include \"ruby.h\""
+	  io.puts
+	  io.puts @src.join("\n\n")
+	  io.puts
+	  io.puts
+	  io.puts "#ifdef __cplusplus"
+	  io.puts "extern \"C\" {"
+	  io.puts "#endif"
+	  io.puts "  void Init_#{module_name}() {"
+          io.puts "    VALUE c = rb_cObject;"
+          # TODO: use rb_class2path
+          @mod.name.split("::").each do |n|
+            io.puts "    c = rb_const_get_at(c,rb_intern(\"#{n}\"));"
+          end
+	  @sig.keys.sort.each do |name|
+	    arity, singleton = @sig[name]
+            if singleton then
+              io.print "    rb_define_singleton_method(c, \"#{name}\", "
+            else
+	      io.print "    rb_define_method(c, \"#{name}\", "
+            end
+	    io.puts  "(VALUE(*)(ANYARGS))#{name}, #{arity});"
+	  end
+
+          io.puts @init_extra.join("\n") unless @init_extra.empty?
+
+	  io.puts
+	  io.puts "  }"
+	  io.puts "#ifdef __cplusplus"
+	  io.puts "}"
+	  io.puts "#endif"
+	  io.puts
+	end
+
+	# recompile only if the files are different
+	recompile = true
+	if so_exists and should_compare and
+            File::compare(old_src_name, src_name, $DEBUG) then
+	  recompile = false
+
+	  # Updates the timestamps on all the generated/compiled files.
+	  # Prevents us from entering this conditional unless the source
+	  # file changes again.
+          t = Time.now
+	  File.utime(t, t, src_name, old_src_name, so_name)
+	end
+
+	if recompile then
+
+	  # extracted from mkmf.rb
+	  srcdir  = Config::CONFIG["srcdir"]
+	  archdir = Config::CONFIG["archdir"]
+	  if File.exist? archdir + "/ruby.h" then
+	    hdrdir = archdir
+	  elsif File.exist? srcdir + "/ruby.h" then
+	    hdrdir = srcdir
+	  else
+	    $stderr.puts "ERROR: Can't find header files for ruby. Exiting..."
+	    exit 1
+	  end
+
+	  flags = @flags.join(' ')
+	  flags += " #{$INLINE_FLAGS}" if defined? $INLINE_FLAGS# DEPRECATE
+	  libs  = @libs.join(' ')
+	  libs += " #{$INLINE_LIBS}" if defined? $INLINE_LIBS	# DEPRECATE
+
+	  cmd = "#{Config::CONFIG['LDSHARED']} #{flags} #{Config::CONFIG['CFLAGS']} -I #{hdrdir} -o #{so_name} #{src_name} #{libs}"
+	  
+          case RUBY_PLATFORM
+          when /mswin32/ then
+	    cmd += " -link /INCREMENTAL:no /EXPORT:Init_#{module_name}"
+          when /i386-cygwin/ then
+            cmd += ' -L/usr/local/lib -lruby.dll'
+          end
+
+          cmd += " 2> /dev/null" if $TESTING and not $DEBUG
+	  
+	  $stderr.puts "Building #{so_name} with '#{cmd}'" if $DEBUG
+          `#{cmd}`
+          if $? != 0 then
+            bad_src_name = src_name + ".bad"
+            File.rename src_name, bad_src_name
+            raise CompilationError, "error executing #{cmd}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
+          end
+	  $stderr.puts "Built successfully" if $DEBUG
+	end
+
+      else
+	$stderr.puts "#{so_name} is up to date" if $DEBUG
+      end # unless (file is out of date)
+    end # def build
+      
+    ##
+    # Adds compiler options to the compiler command line.  No
+    # preprocessing is done, so you must have all your dashes and
+    # everything.
+    
+    def add_compile_flags(*flags)
+      @flags.push(*flags)
+    end
+
+    ##
+    # Adds linker flags to the link command line.  No preprocessing is
+    # done, so you must have all your dashes and everything.
+    
+    def add_link_flags(*flags)
+      @libs.push(*flags)
+    end
+
+    ##
+    # Adds custom content to the end of the init function.
+
+    def add_to_init(*src)
+      @init_extra.push(*src)
+    end
+
+    ##
+    # Registers C type-casts +r2c+ and +c2r+ for +type+.
+    
+    def add_type_converter(type, r2c, c2r)
+      $stderr.puts "WARNING: overridding #{type}" if @@type_map.has_key? type
+      @@type_map[type] = [r2c, c2r]
+    end
+
+    ##
+    # Adds an include to the top of the file. Don't forget to use
+    # quotes or angle brackets.
+    
+    def include(header)
+      @src << "#include #{header}"
+    end
+
+    ##
+    # Adds any amount of text/code to the source
+    
+    def prefix(code)
+      @src << code
+    end
+
+    ##
+    # Adds a C function to the source, including performing automatic
+    # type conversion to arguments and the return value. Unknown type
+    # conversions can be extended by using +add_type_converter+.
+    
+    def c src
+      self.generate(src,:expand_types=>true)
+    end
+
+    ##
+    # Same as +c+, but adds a class function.
+    
+    def c_singleton src
+      self.generate(src,:expand_types=>true,:singleton=>true)
+    end
+    
+    ##
+    # Adds a raw C function to the source. This version does not
+    # perform any type conversion and must conform to the ruby/C
+    # coding conventions.
+    
+    def c_raw src
+      self.generate(src)
+    end
+
+    ##
+    # Same as +c_raw+, but adds a class function.
+    
+    def c_raw_singleton src
+      self.generate(src, :singleton=>true)
+    end
+
+  end # class Inline::C
+
+  class Packager
+    attr_accessor :name, :version, :summary, :libs_copied, :inline_dir
+
+    def initialize(name, version, summary = '')
+      @name = name
+      @version = version
+      @summary = summary
+      @libs_copied = false
+      @ext = Config::CONFIG['DLEXT']
+
+      # TODO (maybe) put libs in platform dir
+      @inline_dir = File.join "lib", "inline"
+    end
+
+    def package
+      copy_libs
+      generate_rakefile
+      build_gem
+    end
+
+    def copy_libs
+      unless @libs_copied then
+        FileUtils.mkdir_p @inline_dir
+        built_libs = Dir.glob File.join(Inline.directory, "*.#{@ext}")
+        FileUtils.cp built_libs, @inline_dir
+        @libs_copied = true
+      end
+    end
+
+    def generate_rakefile
+      if File.exists? 'Rakefile' then
+        unless $TESTING then
+          STDERR.puts "Hrm, you already have a Rakefile, so I didn't touch it."
+          STDERR.puts "You might have to add the following files to your gemspec's files list:"
+          STDERR.puts "\t#{gem_libs.join "\n\t"}"
+        end
+        return
+      end
+
+      rakefile = eval RAKEFILE_TEMPLATE 
+
+      STDERR.puts "==> Generating Rakefile" unless $TESTING
+      File.open 'Rakefile', 'w' do |fp|
+        fp.puts rakefile
+      end
+    end
+
+    def build_gem
+      STDERR.puts "==> Running rake" unless $TESTING
+
+      cmd = "rake package"
+      cmd += "> /dev/null 2> /dev/null" if $TESTING
+      system cmd
+
+      STDERR.puts unless $TESTING
+      STDERR.puts "Ok, you now have a gem in ./pkg, enjoy!" unless $TESTING
+    end
+
+    def gem_libs
+      unless defined? @gem_libs then
+        @gem_libs = Dir.glob File.join(@inline_dir, "*.#{@ext}")
+        files = Dir.glob(File.join('lib', '*')).select { |f| test ?f, f }
+        
+        @gem_libs.push(*files)
+        @gem_libs.sort!
+      end
+      @gem_libs
+    end
+
+    RAKEFILE_TEMPLATE = '%[require "rake"\nrequire "rake/gempackagetask"\n\nsummary = #{summary.inspect}\n\nif summary.empty? then\n  STDERR.puts "*************************************"\n  STDERR.puts "*** Summary not filled in, SHAME! ***"\n  STDERR.puts "*************************************"\nend\n\nspec = Gem::Specification.new do |s|\n  s.name = #{name.inspect}\n  s.version = #{version.inspect}\n  s.summary = summary\n\n  s.has_rdoc = false\n  s.files = #{gem_libs.inspect}\n  s.add_dependency "RubyInline", ">= 3.3.0"\n  s.require_path = "lib"\nend\n\ndesc "Builds a gem with #{name} in it"\nRake::GemPackageTask.new spec do |pkg|\n  pkg.need_zip = false\n  pkg.need_tar = false\nend\n]'
+  end # class Packager
+end # module Inline
+
+class Module
+
+  ##
+  # options is a hash that allows you to pass extra data to your
+  # builder.  The only key that is guaranteed to exist is :testing.
+
+  attr_reader :options
+
+  ##
+  # Extends the Module class to have an inline method. The default
+  # language/builder used is C, but can be specified with the +lang+
+  # parameter.
+  
+  def inline(lang = :C, options={})
+    case options
+    when TrueClass, FalseClass then
+      warn "WARNING: 2nd argument to inline is now a hash, changing to {:testing=>#{options}}" unless options
+      options = { :testing => options  }
+    when Hash
+      options[:testing] ||= false
+    else
+      raise ArgumentError, "BLAH"
+    end
+
+    builder_class = begin
+                      Inline.const_get(lang)
+                    rescue NameError
+                      require "inline/#{lang}"
+                      Inline.const_get(lang)
+                    end
+
+    @options = options
+    builder = builder_class.new self
+
+    yield builder
+
+    unless options[:testing] then
+      unless builder.load_cache then
+        builder.build
+        builder.load
+      end
+    end
+  end
+end
+
+class File
+
+  ##
+  # Equivalent to +File::open+ with an associated block, but moves
+  # any existing file with the same name to the side first.
+  
+  def self.write_with_backup(path) # returns true if file already existed
+    
+    # move previous version to the side if it exists
+    renamed = false
+    if test ?f, path then
+      renamed = true
+      File.rename path, path + ".old"
+    end
+
+    File.open(path, "w") do |io|
+      yield(io)
+    end
+
+    return renamed
+  end
+end # class File
+
+class Dir
+
+  ##
+  # +assert_secure+ checks to see that +path+ exists and has minimally
+  # writable permissions. If not, it prints an error and exits. It
+  # only works on +POSIX+ systems. Patches for other systems are
+  # welcome.
+  
+  def self.assert_secure(path)
+    mode = File.stat(path).mode
+    unless ((mode % 01000) & 0022) == 0 then
+      if $TESTING then
+	raise SecurityError, "Directory #{path} is insecure"
+      else
+	$stderr.puts "#{path} is insecure (#{sprintf('%o', mode)}), needs 0700 for perms. Exiting."
+	exit 1
+      end
+    end
+  end
+end

Added: packages/libinline-ruby/trunk/lib/inline_package
===================================================================
--- packages/libinline-ruby/trunk/lib/inline_package	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/lib/inline_package	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,15 @@
+#!/usr/bin/ruby -w
+
+require 'inline'
+
+name = ARGV.shift
+version = ARGV.shift
+summary = ARGV.shift || ""
+
+if version.nil? then # TODO better usage
+  STDERR.puts "Usage: #{$0} NAME VERSION [SUMMARY]"
+  exit 1
+end
+
+packager = Inline::Packager.new name, version, summary
+packager.package

Added: packages/libinline-ruby/trunk/setup.rb
===================================================================
--- packages/libinline-ruby/trunk/setup.rb	2006-08-01 11:04:28 UTC (rev 730)
+++ packages/libinline-ruby/trunk/setup.rb	2006-08-01 11:05:10 UTC (rev 731)
@@ -0,0 +1,1360 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2004 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
+  module Enumerable
+    alias map collect
+  end
+end
+
+unless File.respond_to?(:read)   # Ruby 1.6
+  def File.read(fname)
+    open(fname) {|f|
+      return f.read
+    }
+  end
+end
+
+def File.binread(fname)
+  open(fname, 'rb') {|f|
+    return f.read
+  }
+end
+
+# for corrupted windows stat(2)
+def File.dir?(path)
+  File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+  raise SetupError, msg
+end
+
+#
+# Config
+#
+
+if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+  ARGV.delete(arg)
+  require arg.split(/=/, 2)[1]
+  $".push 'rbconfig.rb'
+else
+  require 'rbconfig'
+end
+
+def multipackage_install?
+  FileTest.directory?(File.dirname($0) + '/packages')
+end
+
+
+class ConfigItem
+  def initialize(name, template, default, desc)
+    @name = name.freeze
+    @template = template
+    @value = default
+    @default = default.dup.freeze
+    @description = desc
+  end
+
+  attr_reader :name
+  attr_reader :description
+
+  attr_accessor :default
+  alias help_default default
+
+  def help_opt
+    "--#{@name}=#{@template}"
+  end
+
+  def value
+    @value
+  end
+
+  def eval(table)
+    @value.gsub(%r<\$([^/]+)>) { table[$1] }
+  end
+
+  def set(val)
+    @value = check(val)
+  end
+
+  private
+
+  def check(val)
+    setup_rb_error "config: --#{name} requires argument" unless val
+    val
+  end
+end
+
+class BoolItem < ConfigItem
+  def config_type
+    'bool'
+  end
+
+  def help_opt
+    "--#{@name}"
+  end
+
+  private
+
+  def check(val)
+    return 'yes' unless val
+    unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
+      setup_rb_error "config: --#{@name} accepts only yes/no for argument"
+    end
+    (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
+  end
+end
+
+class PathItem < ConfigItem
+  def config_type
+    'path'
+  end
+
+  private
+
+  def check(path)
+    setup_rb_error "config: --#{@name} requires argument"  unless path
+    path[0,1] == '$' ? path : File.expand_path(path)
+  end
+end
+
+class ProgramItem < ConfigItem
+  def config_type
+    'program'
+  end
+end
+
+class SelectItem < ConfigItem
+  def initialize(name, template, default, desc)
+    super
+    @ok = template.split('/')
+  end
+
+  def config_type
+    'select'
+  end
+
+  private
+
+  def check(val)
+    unless @ok.include?(val.strip)
+      setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
+    end
+    val.strip
+  end
+end
+
+class PackageSelectionItem < ConfigItem
+  def initialize(name, template, default, help_default, desc)
+    super name, template, default, desc
+    @help_default = help_default
+  end
+
+  attr_reader :help_default
+
+  def config_type
+    'package'
+  end
+
+  private
+
+  def check(val)
+    unless File.dir?("packages/#{val}")
+      setup_rb_error "config: no such package: #{val}"
+    end
+    val
+  end
+end
+
+class ConfigTable_class
+
+  def initialize(items)
+    @items = items
+    @table = {}
+    items.each do |i|
+      @table[i.name] = i
+    end
+    ALIASES.each do |ali, name|
+      @table[ali] = @table[name]
+    end
+  end
+
+  include Enumerable
+
+  def each(&block)
+    @items.each(&block)
+  end
+
+  def key?(name)
+    @table.key?(name)
+  end
+
+  def lookup(name)
+    @table[name] or raise ArgumentError, "no such config item: #{name}"
+  end
+
+  def add(item)
+    @items.push item
+    @table[item.name] = item
+  end
+
+  def remove(name)
+    item = lookup(name)
+    @items.delete_if {|i| i.name == name }
+    @table.delete_if {|name, i| i.name == name }
+    item
+  end
+
+  def new
+    dup()
+  end
+
+  def savefile
+    '.config'
+  end
+
+  def load
+    begin
+      t = dup()
+      File.foreach(savefile()) do |line|
+        k, v = *line.split(/=/, 2)
+        t[k] = v.strip
+      end
+      t
+    rescue Errno::ENOENT
+      setup_rb_error $!.message + "#{File.basename($0)} config first"
+    end
+  end
+
+  def save
+    @items.each {|i| i.value }
+    File.open(savefile(), 'w') {|f|
+      @items.each do |i|
+        f.printf "%s=%s\n", i.name, i.value if i.value
+      end
+    }
+  end
+
+  def [](key)
+    lookup(key).eval(self)
+  end
+
+  def []=(key, val)
+    lookup(key).set val
+  end
+
+end
+
+c = ::Config::CONFIG
+
+rubypath = c['bindir'] + '/' + c['ruby_install_name']
+
+major = c['MAJOR'].to_i
+minor = c['MINOR'].to_i
+teeny = c['TEENY'].to_i
+version = "#{major}.#{minor}"
+
+# ruby ver. >= 1.4.4?
+newpath_p = ((major >= 2) or
+             ((major == 1) and
+              ((minor >= 5) or
+               ((minor == 4) and (teeny >= 4)))))
+
+if c['rubylibdir']
+  # V < 1.6.3
+  _stdruby         = c['rubylibdir']
+  _siteruby        = c['sitedir']
+  _siterubyver     = c['sitelibdir']
+  _siterubyverarch = c['sitearchdir']
+elsif newpath_p
+  # 1.4.4 <= V <= 1.6.3
+  _stdruby         = "$prefix/lib/ruby/#{version}"
+  _siteruby        = c['sitedir']
+  _siterubyver     = "$siteruby/#{version}"
+  _siterubyverarch = "$siterubyver/#{c['arch']}"
+else
+  # V < 1.4.4
+  _stdruby         = "$prefix/lib/ruby/#{version}"
+  _siteruby        = "$prefix/lib/ruby/#{version}/site_ruby"
+  _siterubyver     = _siteruby
+  _siterubyverarch = "$siterubyver/#{c['arch']}"
+end
+libdir = '-* dummy libdir *-'
+stdruby = '-* dummy rubylibdir *-'
+siteruby = '-* dummy site_ruby *-'
+siterubyver = '-* dummy site_ruby version *-'
+parameterize = lambda {|path|
+  path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
+      .sub(/\A#{Regexp.quote(libdir)}/,      '$libdir')\
+      .sub(/\A#{Regexp.quote(stdruby)}/,     '$stdruby')\
+      .sub(/\A#{Regexp.quote(siteruby)}/,    '$siteruby')\
+      .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
+}
+libdir          = parameterize.call(c['libdir'])
+stdruby         = parameterize.call(_stdruby)
+siteruby        = parameterize.call(_siteruby)
+siterubyver     = parameterize.call(_siterubyver)
+siterubyverarch = parameterize.call(_siterubyverarch)
+
+if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
+  makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+else
+  makeprog = 'make'
+end
+
+common_conf = [
+  PathItem.new('prefix', 'path', c['prefix'],
+               'path prefix of target environment'),
+  PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+               'the directory for commands'),
+  PathItem.new('libdir', 'path', libdir,
+               'the directory for libraries'),
+  PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+               'the directory for shared data'),
+  PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+               'the directory for man pages'),
+  PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+               'the directory for man pages'),
+  PathItem.new('stdruby', 'path', stdruby,
+               'the directory for standard ruby libraries'),
+  PathItem.new('siteruby', 'path', siteruby,
+      'the directory for version-independent aux ruby libraries'),
+  PathItem.new('siterubyver', 'path', siterubyver,
+               'the directory for aux ruby libraries'),
+  PathItem.new('siterubyverarch', 'path', siterubyverarch,
+               'the directory for aux ruby binaries'),
+  PathItem.new('rbdir', 'path', '$siterubyver',
+               'the directory for ruby scripts'),
+  PathItem.new('sodir', 'path', '$siterubyverarch',
+               'the directory for ruby extentions'),
+  PathItem.new('rubypath', 'path', rubypath,
+               'the path to set to #! line'),
+  ProgramItem.new('rubyprog', 'name', rubypath,
+                  'the ruby program using for installation'),
+  ProgramItem.new('makeprog', 'name', makeprog,
+                  'the make program to compile ruby extentions'),
+  SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+                 'shebang line (#!) editing mode'),
+  BoolItem.new('without-ext', 'yes/no', 'no',
+               'does not compile/install ruby extentions')
+]
+class ConfigTable_class   # open again
+  ALIASES = {
+    'std-ruby'         => 'stdruby',
+    'site-ruby-common' => 'siteruby',     # For backward compatibility
+    'site-ruby'        => 'siterubyver',  # For backward compatibility
+    'bin-dir'          => 'bindir',
+    'bin-dir'          => 'bindir',
+    'rb-dir'           => 'rbdir',
+    'so-dir'           => 'sodir',
+    'data-dir'         => 'datadir',
+    'ruby-path'        => 'rubypath',
+    'ruby-prog'        => 'rubyprog',
+    'ruby'             => 'rubyprog',
+    'make-prog'        => 'makeprog',
+    'make'             => 'makeprog'
+  }
+end
+multipackage_conf = [
+  PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+                           'package names that you want to install'),
+  PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+                           'package names that you do not want to install')
+]
+if multipackage_install?
+  ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
+else
+  ConfigTable = ConfigTable_class.new(common_conf)
+end
+
+
+module MetaConfigAPI
+
+  def eval_file_ifexist(fname)
+    instance_eval File.read(fname), fname, 1 if File.file?(fname)
+  end
+
+  def config_names
+    ConfigTable.map {|i| i.name }
+  end
+
+  def config?(name)
+    ConfigTable.key?(name)
+  end
+
+  def bool_config?(name)
+    ConfigTable.lookup(name).config_type == 'bool'
+  end
+
+  def path_config?(name)
+    ConfigTable.lookup(name).config_type == 'path'
+  end
+
+  def value_config?(name)
+    case ConfigTable.lookup(name).config_type
+    when 'bool', 'path'
+      true
+    else
+      false
+    end
+  end
+
+  def add_config(item)
+    ConfigTable.add item
+  end
+
+  def add_bool_config(name, default, desc)
+    ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+  end
+
+  def add_path_config(name, default, desc)
+    ConfigTable.add PathItem.new(name, 'path', default, desc)
+  end
+
+  def set_config_default(name, default)
+    ConfigTable.lookup(name).default = default
+  end
+
+  def remove_config(name)
+    ConfigTable.remove(name)
+  end
+
+end
+
+
+#
+# File Operations
+#
+
+module FileOperations
+
+  def mkdir_p(dirname, prefix = nil)
+    dirname = prefix + File.expand_path(dirname) if prefix
+    $stderr.puts "mkdir -p #{dirname}" if verbose?
+    return if no_harm?
+
+    # does not check '/'... it's too abnormal case
+    dirs = File.expand_path(dirname).split(%r<(?=/)>)
+    if /\A[a-z]:\z/i =~ dirs[0]
+      disk = dirs.shift
+      dirs[0] = disk + dirs[0]
+    end
+    dirs.each_index do |idx|
+      path = dirs[0..idx].join('')
+      Dir.mkdir path unless File.dir?(path)
+    end
+  end
+
+  def rm_f(fname)
+    $stderr.puts "rm -f #{fname}" if verbose?
+    return if no_harm?
+
+    if File.exist?(fname) or File.symlink?(fname)
+      File.chmod 0777, fname
+      File.unlink fname
+    end
+  end
+
+  def rm_rf(dn)
+    $stderr.puts "rm -rf #{dn}" if verbose?
+    return if no_harm?
+
+    Dir.chdir dn
+    Dir.foreach('.') do |fn|
+      next if fn == '.'
+      next if fn == '..'
+      if File.dir?(fn)
+        verbose_off {
+          rm_rf fn
+        }
+      else
+        verbose_off {
+          rm_f fn
+        }
+      end
+    end
+    Dir.chdir '..'
+    Dir.rmdir dn
+  end
+
+  def move_file(src, dest)
+    File.unlink dest if File.exist?(dest)
+    begin
+      File.rename src, dest
+    rescue
+      File.open(dest, 'wb') {|f| f.write File.binread(src) }
+      File.chmod File.stat(src).mode, dest
+      File.unlink src
+    end
+  end
+
+  def install(from, dest, mode, prefix = nil)
+    $stderr.puts "install #{from} #{dest}" if verbose?
+    return if no_harm?
+
+    realdest = prefix ? prefix + File.expand_path(dest) : dest
+    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+    str = File.binread(from)
+    if diff?(str, realdest)
+      verbose_off {
+        rm_f realdest if File.exist?(realdest)
+      }
+      File.open(realdest, 'wb') {|f|
+        f.write str
+      }
+      File.chmod mode, realdest
+
+      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+        if prefix
+          f.puts realdest.sub(prefix, '')
+        else
+          f.puts realdest
+        end
+      }
+    end
+  end
+
+  def diff?(new_content, path)
+    return true unless File.exist?(path)
+    new_content != File.binread(path)
+  end
+
+  def command(str)
+    $stderr.puts str if verbose?
+    system str or raise RuntimeError, "'system #{str}' failed"
+  end
+
+  def ruby(str)
+    command config('rubyprog') + ' ' + str
+  end
+  
+  def make(task = '')
+    command config('makeprog') + ' ' + task
+  end
+
+  def extdir?(dir)
+    File.exist?(dir + '/MANIFEST')
+  end
+
+  def all_files_in(dirname)
+    Dir.open(dirname) {|d|
+      return d.select {|ent| File.file?("#{dirname}/#{ent}") }
+    }
+  end
+
+  REJECT_DIRS = %w(
+    CVS SCCS RCS CVS.adm .svn
+  )
+
+  def all_dirs_in(dirname)
+    Dir.open(dirname) {|d|
+      return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
+    }
+  end
+
+end
+
+
+#
+# Main Installer
+#
+
+module HookUtils
+
+  def run_hook(name)
+    try_run_hook "#{curr_srcdir()}/#{name}" or
+    try_run_hook "#{curr_srcdir()}/#{name}.rb"
+  end
+
+  def try_run_hook(fname)
+    return false unless File.file?(fname)
+    begin
+      instance_eval File.read(fname), fname, 1
+    rescue
+      setup_rb_error "hook #{fname} failed:\n" + $!.message
+    end
+    true
+  end
+
+end
+
+
+module HookScriptAPI
+
+  def get_config(key)
+    @config[key]
+  end
+
+  alias config get_config
+
+  def set_config(key, val)
+    @config[key] = val
+  end
+
+  #
+  # srcdir/objdir (works only in the package directory)
+  #
+
+  #abstract srcdir_root
+  #abstract objdir_root
+  #abstract relpath
+
+  def curr_srcdir
+    "#{srcdir_root()}/#{relpath()}"
+  end
+
+  def curr_objdir
+    "#{objdir_root()}/#{relpath()}"
+  end
+
+  def srcfile(path)
+    "#{curr_srcdir()}/#{path}"
+  end
+
+  def srcexist?(path)
+    File.exist?(srcfile(path))
+  end
+
+  def srcdirectory?(path)
+    File.dir?(srcfile(path))
+  end
+  
+  def srcfile?(path)
+    File.file? srcfile(path)
+  end
+
+  def srcentries(path = '.')
+    Dir.open("#{curr_srcdir()}/#{path}") {|d|
+      return d.to_a - %w(. ..)
+    }
+  end
+
+  def srcfiles(path = '.')
+    srcentries(path).select {|fname|
+      File.file?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+  def srcdirectories(path = '.')
+    srcentries(path).select {|fname|
+      File.dir?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+end
+
+
+class ToplevelInstaller
+
+  Version   = '3.3.1'
+  Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
+
+  TASKS = [
+    [ 'all',      'do config, setup, then install' ],
+    [ 'config',   'saves your configurations' ],
+    [ 'show',     'shows current configuration' ],
+    [ 'setup',    'compiles ruby extentions and others' ],
+    [ 'install',  'installs files' ],
+    [ 'clean',    "does `make clean' for each extention" ],
+    [ 'distclean',"does `make distclean' for each extention" ]
+  ]
+
+  def ToplevelInstaller.invoke
+    instance().invoke
+  end
+
+  @singleton = nil
+
+  def ToplevelInstaller.instance
+    @singleton ||= new(File.dirname($0))
+    @singleton
+  end
+
+  include MetaConfigAPI
+
+  def initialize(ardir_root)
+    @config = nil
+    @options = { 'verbose' => true }
+    @ardir = File.expand_path(ardir_root)
+  end
+
+  def inspect
+    "#<#{self.class} #{__id__()}>"
+  end
+
+  def invoke
+    run_metaconfigs
+    case task = parsearg_global()
+    when nil, 'all'
+      @config = load_config('config')
+      parsearg_config
+      init_installers
+      exec_config
+      exec_setup
+      exec_install
+    else
+      @config = load_config(task)
+      __send__ "parsearg_#{task}"
+      init_installers
+      __send__ "exec_#{task}"
+    end
+  end
+  
+  def run_metaconfigs
+    eval_file_ifexist "#{@ardir}/metaconfig"
+  end
+
+  def load_config(task)
+    case task
+    when 'config'
+      ConfigTable.new
+    when 'clean', 'distclean'
+      if File.exist?(ConfigTable.savefile)
+      then ConfigTable.load
+      else ConfigTable.new
+      end
+    else
+      ConfigTable.load
+    end
+  end
+
+  def init_installers
+    @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
+  end
+
+  #
+  # Hook Script API bases
+  #
+
+  def srcdir_root
+    @ardir
+  end
+
+  def objdir_root
+    '.'
+  end
+
+  def relpath
+    '.'
+  end
+
+  #
+  # Option Parsing
+  #
+
+  def parsearg_global
+    valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
+
+    while arg = ARGV.shift
+      case arg
+      when /\A\w+\z/
+        setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
+        return arg
+
+      when '-q', '--quiet'
+        @options['verbose'] = false
+
+      when       '--verbose'
+        @options['verbose'] = true
+
+      when '-h', '--help'
+        print_usage $stdout
+        exit 0
+
+      when '-v', '--version'
+        puts "#{File.basename($0)} version #{Version}"
+        exit 0
+      
+      when '--copyright'
+        puts Copyright
+        exit 0
+
+      else
+        setup_rb_error "unknown global option '#{arg}'"
+      end
+    end
+
+    nil
+  end
+
+
+  def parsearg_no_options
+    unless ARGV.empty?
+      setup_rb_error "#{task}:  unknown options: #{ARGV.join ' '}"
+    end
+  end
+
+  alias parsearg_show       parsearg_no_options
+  alias parsearg_setup      parsearg_no_options
+  alias parsearg_clean      parsearg_no_options
+  alias parsearg_distclean  parsearg_no_options
+
+  def parsearg_config
+    re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
+    @options['config-opt'] = []
+
+    while i = ARGV.shift
+      if /\A--?\z/ =~ i
+        @options['config-opt'] = ARGV.dup
+        break
+      end
+      m = re.match(i)  or setup_rb_error "config: unknown option #{i}"
+      name, value = *m.to_a[1,2]
+      @config[name] = value
+    end
+  end
+
+  def parsearg_install
+    @options['no-harm'] = false
+    @options['install-prefix'] = ''
+    while a = ARGV.shift
+      case a
+      when /\A--no-harm\z/
+        @options['no-harm'] = true
+      when /\A--prefix=(.*)\z/
+        path = $1
+        path = File.expand_path(path) unless path[0,1] == '/'
+        @options['install-prefix'] = path
+      else
+        setup_rb_error "install: unknown option #{a}"
+      end
+    end
+  end
+
+  def print_usage(out)
+    out.puts 'Typical Installation Procedure:'
+    out.puts "  $ ruby #{File.basename $0} config"
+    out.puts "  $ ruby #{File.basename $0} setup"
+    out.puts "  # ruby #{File.basename $0} install (may require root privilege)"
+    out.puts
+    out.puts 'Detailed Usage:'
+    out.puts "  ruby #{File.basename $0} <global option>"
+    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+    fmt = "  %-24s %s\n"
+    out.puts
+    out.puts 'Global options:'
+    out.printf fmt, '-q,--quiet',   'suppress message outputs'
+    out.printf fmt, '   --verbose', 'output messages verbosely'
+    out.printf fmt, '-h,--help',    'print this message'
+    out.printf fmt, '-v,--version', 'print version and quit'
+    out.printf fmt, '   --copyright',  'print copyright and quit'
+    out.puts
+    out.puts 'Tasks:'
+    TASKS.each do |name, desc|
+      out.printf fmt, name, desc
+    end
+
+    fmt = "  %-24s %s [%s]\n"
+    out.puts
+    out.puts 'Options for CONFIG or ALL:'
+    ConfigTable.each do |item|
+      out.printf fmt, item.help_opt, item.description, item.help_default
+    end
+    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+    out.puts
+    out.puts 'Options for INSTALL:'
+    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+    out.printf fmt, '--prefix=path',  'install path prefix', '$prefix'
+    out.puts
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    @installer.exec_config
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    @installer.exec_setup
+  end
+
+  def exec_install
+    @installer.exec_install
+  end
+
+  def exec_show
+    ConfigTable.each do |i|
+      printf "%-20s %s\n", i.name, i.value
+    end
+  end
+
+  def exec_clean
+    @installer.exec_clean
+  end
+
+  def exec_distclean
+    @installer.exec_distclean
+  end
+
+end
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+  include HookUtils
+  include HookScriptAPI
+  include FileOperations
+
+  def initialize(ardir)
+    super
+    @packages = all_dirs_in("#{@ardir}/packages")
+    raise 'no package exists' if @packages.empty?
+  end
+
+  def run_metaconfigs
+    eval_file_ifexist "#{@ardir}/metaconfig"
+    @packages.each do |name|
+      eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
+    end
+  end
+
+  def init_installers
+    @installers = {}
+    @packages.each do |pack|
+      @installers[pack] = Installer.new(@config, @options,
+                                       "#{@ardir}/packages/#{pack}",
+                                       "packages/#{pack}")
+    end
+
+    with    = extract_selection(config('with'))
+    without = extract_selection(config('without'))
+    @selected = @installers.keys.select {|name|
+                  (with.empty? or with.include?(name)) \
+                      and not without.include?(name)
+                }
+  end
+
+  def extract_selection(list)
+    a = list.split(/,/)
+    a.each do |name|
+      setup_rb_error "no such package: #{name}"  unless @installers.key?(name)
+    end
+    a
+  end
+
+  def print_usage(f)
+    super
+    f.puts 'Inluded packages:'
+    f.puts '  ' + @packages.sort.join(' ')
+    f.puts
+  end
+
+  #
+  # multi-package metaconfig API
+  #
+
+  attr_reader :packages
+
+  def declare_packages(list)
+    raise 'package list is empty' if list.empty?
+    list.each do |name|
+      raise "directory packages/#{name} does not exist"\
+              unless File.dir?("#{@ardir}/packages/#{name}")
+    end
+    @packages = list
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    run_hook 'pre-config'
+    each_selected_installers {|inst| inst.exec_config }
+    run_hook 'post-config'
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    run_hook 'pre-setup'
+    each_selected_installers {|inst| inst.exec_setup }
+    run_hook 'post-setup'
+  end
+
+  def exec_install
+    run_hook 'pre-install'
+    each_selected_installers {|inst| inst.exec_install }
+    run_hook 'post-install'
+  end
+
+  def exec_clean
+    rm_f ConfigTable.savefile
+    run_hook 'pre-clean'
+    each_selected_installers {|inst| inst.exec_clean }
+    run_hook 'post-clean'
+  end
+
+  def exec_distclean
+    rm_f ConfigTable.savefile
+    run_hook 'pre-distclean'
+    each_selected_installers {|inst| inst.exec_distclean }
+    run_hook 'post-distclean'
+  end
+
+  #
+  # lib
+  #
+
+  def each_selected_installers
+    Dir.mkdir 'packages' unless File.dir?('packages')
+    @selected.each do |pack|
+      $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
+      Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+      Dir.chdir "packages/#{pack}"
+      yield @installers[pack]
+      Dir.chdir '../..'
+    end
+  end
+
+  def verbose?
+    @options['verbose']
+  end
+
+  def no_harm?
+    @options['no-harm']
+  end
+
+end
+
+
+class Installer
+
+  FILETYPES = %w( bin lib ext data )
+
+  include HookScriptAPI
+  include HookUtils
+  include FileOperations
+
+  def initialize(config, opt, srcroot, objroot)
+    @config = config
+    @options = opt
+    @srcdir = File.expand_path(srcroot)
+    @objdir = File.expand_path(objroot)
+    @currdir = '.'
+  end
+
+  def inspect
+    "#<#{self.class} #{File.basename(@srcdir)}>"
+  end
+
+  #
+  # Hook Script API base methods
+  #
+
+  def srcdir_root
+    @srcdir
+  end
+
+  def objdir_root
+    @objdir
+  end
+
+  def relpath
+    @currdir
+  end
+
+  #
+  # configs/options
+  #
+
+  def no_harm?
+    @options['no-harm']
+  end
+
+  def verbose?
+    @options['verbose']
+  end
+
+  def verbose_off
+    begin
+      save, @options['verbose'] = @options['verbose'], false
+      yield
+    ensure
+      @options['verbose'] = save
+    end
+  end
+
+  #
+  # TASK config
+  #
+
+  def exec_config
+    exec_task_traverse 'config'
+  end
+
+  def config_dir_bin(rel)
+  end
+
+  def config_dir_lib(rel)
+  end
+
+  def config_dir_ext(rel)
+    extconf if extdir?(curr_srcdir())
+  end
+
+  def extconf
+    opt = @options['config-opt'].join(' ')
+    command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
+  end
+
+  def config_dir_data(rel)
+  end
+
+  #
+  # TASK setup
+  #
+
+  def exec_setup
+    exec_task_traverse 'setup'
+  end
+
+  def setup_dir_bin(rel)
+    all_files_in(curr_srcdir()).each do |fname|
+      adjust_shebang "#{curr_srcdir()}/#{fname}"
+    end
+  end
+
+  def adjust_shebang(path)
+    return if no_harm?
+    tmpfile = File.basename(path) + '.tmp'
+    begin
+      File.open(path, 'rb') {|r|
+        first = r.gets
+        return unless File.basename(config('rubypath')) == 'ruby'
+        return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
+        $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
+        File.open(tmpfile, 'wb') {|w|
+          w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
+          w.write r.read
+        }
+        move_file tmpfile, File.basename(path)
+      }
+    ensure
+      File.unlink tmpfile if File.exist?(tmpfile)
+    end
+  end
+
+  def setup_dir_lib(rel)
+  end
+
+  def setup_dir_ext(rel)
+    make if extdir?(curr_srcdir())
+  end
+
+  def setup_dir_data(rel)
+  end
+
+  #
+  # TASK install
+  #
+
+  def exec_install
+    rm_f 'InstalledFiles'
+    exec_task_traverse 'install'
+  end
+
+  def install_dir_bin(rel)
+    install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
+  end
+
+  def install_dir_lib(rel)
+    install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
+  end
+
+  def install_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    install_files ruby_extentions('.'),
+                  "#{config('sodir')}/#{File.dirname(rel)}",
+                  0555
+  end
+
+  def install_dir_data(rel)
+    install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
+  end
+
+  def install_files(list, dest, mode)
+    mkdir_p dest, @options['install-prefix']
+    list.each do |fname|
+      install fname, dest, mode, @options['install-prefix']
+    end
+  end
+
+  def ruby_scripts
+    collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
+  end
+  
+  # picked up many entries from cvs-1.11.1/src/ignore.c
+  reject_patterns = %w( 
+    core RCSLOG tags TAGS .make.state
+    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+    *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+    *.org *.in .*
+  )
+  mapping = {
+    '.' => '\.',
+    '$' => '\$',
+    '#' => '\#',
+    '*' => '.*'
+  }
+  REJECT_PATTERNS = Regexp.new('\A(?:' +
+                               reject_patterns.map {|pat|
+                                 pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
+                               }.join('|') +
+                               ')\z')
+
+  def collect_filenames_auto
+    mapdir((existfiles() - hookfiles()).reject {|fname|
+             REJECT_PATTERNS =~ fname
+           })
+  end
+
+  def existfiles
+    all_files_in(curr_srcdir()) | all_files_in('.')
+  end
+
+  def hookfiles
+    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+      %w( config setup install clean ).map {|t| sprintf(fmt, t) }
+    }.flatten
+  end
+
+  def mapdir(filelist)
+    filelist.map {|fname|
+      if File.exist?(fname)   # objdir
+        fname
+      else                    # srcdir
+        File.join(curr_srcdir(), fname)
+      end
+    }
+  end
+
+  def ruby_extentions(dir)
+    Dir.open(dir) {|d|
+      ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
+      if ents.empty?
+        setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+      end
+      return ents
+    }
+  end
+
+  #
+  # TASK clean
+  #
+
+  def exec_clean
+    exec_task_traverse 'clean'
+    rm_f ConfigTable.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  def clean_dir_bin(rel)
+  end
+
+  def clean_dir_lib(rel)
+  end
+
+  def clean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'clean' if File.file?('Makefile')
+  end
+
+  def clean_dir_data(rel)
+  end
+
+  #
+  # TASK distclean
+  #
+
+  def exec_distclean
+    exec_task_traverse 'distclean'
+    rm_f ConfigTable.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  def distclean_dir_bin(rel)
+  end
+
+  def distclean_dir_lib(rel)
+  end
+
+  def distclean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'distclean' if File.file?('Makefile')
+  end
+
+  #
+  # lib
+  #
+
+  def exec_task_traverse(task)
+    run_hook "pre-#{task}"
+    FILETYPES.each do |type|
+      if config('without-ext') == 'yes' and type == 'ext'
+        $stderr.puts 'skipping ext/* by user option' if verbose?
+        next
+      end
+      traverse task, type, "#{task}_dir_#{type}"
+    end
+    run_hook "post-#{task}"
+  end
+
+  def traverse(task, rel, mid)
+    dive_into(rel) {
+      run_hook "pre-#{task}"
+      __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+      all_dirs_in(curr_srcdir()).each do |d|
+        traverse task, "#{rel}/#{d}", mid
+      end
+      run_hook "post-#{task}"
+    }
+  end
+
+  def dive_into(rel)
+    return unless File.dir?("#{@srcdir}/#{rel}")
+
+    dir = File.basename(rel)
+    Dir.mkdir dir unless File.dir?(dir)
+    prevdir = Dir.pwd
+    Dir.chdir dir
+    $stderr.puts '---> ' + rel if verbose?
+    @currdir = rel
+    yield
+    Dir.chdir prevdir
+    $stderr.puts '<--- ' + rel if verbose?
+    @currdir = File.dirname(rel)
+  end
+
+end
+
+
+if $0 == __FILE__
+  begin
+    if multipackage_install?
+      ToplevelInstallerMulti.invoke
+    else
+      ToplevelInstaller.invoke
+    end
+  rescue SetupError
+    raise if $DEBUG
+    $stderr.puts $!.message
+    $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+    exit 1
+  end
+end




More information about the pkg-ruby-extras-maintainers mailing list