[前][次][番号順一覧][スレッド一覧][生データ]

yarv-diff:419

From: ko1 atdot.net
Date: 31 Dec 2006 17:05:23 +0900
Subject: [yarv-diff:419] r588 - in trunk: . lib lib/date sample

Author: ko1
Date: 2006-12-31 17:05:21 +0900 (Sun, 31 Dec 2006)
New Revision: 588

Removed:
   trunk/lib/date2.rb
Modified:
   trunk/ChangeLog
   trunk/Makefile.in
   trunk/array.c
   trunk/configure.in
   trunk/dir.c
   trunk/enum.c
   trunk/eval.c
   trunk/file.c
   trunk/instruby.rb
   trunk/intern.h
   trunk/io.c
   trunk/lib/README
   trunk/lib/date.rb
   trunk/lib/date/format.rb
   trunk/object.c
   trunk/ruby.h
   trunk/rubytest.rb
   trunk/sample/test.rb
   trunk/string.c
   trunk/variable.c
Log:
	* catch up ruby/trunk 11437

	* eval_intern.h : reorder tag initialization

	* eval.c : fix to support __send!, funcall and prohibit funcall as
	send

	* eval_error.h, eval_jump.h, eval_safe.h : fix prototypes

	* eval_method.h, vm.c : check re-definition at rb_add_method()

	* yarvcore.h : fix typo

	* compile.c : fix white spaces

	* lib/delegate.rb : fix to support __send, ...

	* lib/getoptlong.rb : fix to work on YARV

	* lib/rss/parser.rb : use __send! instead of __send__

	* sample/test.rb : comment out codes which use |&b| type block parameter

	* ext/ripper/extconf.rb : turn off

	* test/ripper/test_files.rb, test_parser_events.rb,
	test_scanner_events.rb : fix to check it has ripper module

	* vm_dump.c : remove showing file path length limitation

	* yarvtest/test_eval.rb : use __send! instead of __send__



Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/ChangeLog	2006-12-31 08:05:21 UTC (rev 588)
@@ -6,6 +6,8 @@
 
 2006-12-30(Sat) 07:59:26 +0900  Koichi Sasada  <ko1 atdot.net>
 
+	* catch up ruby/trunk 11437
+
 	* eval_intern.h : reorder tag initialization
 
 	* eval.c : fix to support __send!, funcall and prohibit funcall as

Modified: trunk/Makefile.in
===================================================================
--- trunk/Makefile.in	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/Makefile.in	2006-12-31 08:05:21 UTC (rev 588)
@@ -1,4 +1,5 @@
 SHELL = /bin/sh
+NULLCMD = :
 
 #### Start of system configuration section. ####
 

Modified: trunk/array.c
===================================================================
--- trunk/array.c	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/array.c	2006-12-31 08:05:21 UTC (rev 588)
@@ -39,7 +39,15 @@
     }
 }
 
-#define ARY_TMPLOCK  FL_USER1
+#define ARY_ITERLOCK FL_USER1
+static void
+ary_iter_check(VALUE ary)
+{
+    if (FL_TEST(ary, ARY_ITERLOCK)) {
+      rb_raise(rb_eRuntimeError, "can't modify array during iteration");
+    }
+}
+#define ARY_SORTLOCK FL_USER3
 #define ARY_SHARED_P(a) FL_TEST(a, ELTS_SHARED)
 
 #define ARY_SET_LEN(ary, n) do { \
@@ -52,6 +60,11 @@
     RARRAY(ary)->aux.capa = (capacity);\
 } while (0)
 
+#define ITERATE(func, ary) do { \
+    FL_SET(ary, ARY_ITERLOCK); \
+    return rb_ensure(func, (ary), each_unlock, (ary));\
+} while (0)
+
 static VALUE *
 rb_ary_ptr(VALUE ary)
 {
@@ -62,8 +75,8 @@
 rb_ary_modify_check(VALUE ary)
 {
     if (OBJ_FROZEN(ary)) rb_error_frozen("array");
-    if (FL_TEST(ary, ARY_TMPLOCK))
-	rb_raise(rb_eRuntimeError, "can't modify array during iteration");
+    if (FL_TEST(ary, ARY_SORTLOCK))
+	rb_raise(rb_eRuntimeError, "can't modify array during sort");
     if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify array");
 }
@@ -101,7 +114,7 @@
 rb_ary_frozen_p(VALUE ary)
 {
     if (OBJ_FROZEN(ary)) return Qtrue;
-    if (FL_TEST(ary, ARY_TMPLOCK)) return Qtrue;
+    if (FL_TEST(ary, ARY_SORTLOCK)) return Qtrue;
     return Qfalse;
 }
 
@@ -282,6 +295,7 @@
     VALUE size, val;
 
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     if (rb_scan_args(argc, argv, "02", &size, &val) == 0) {
 	if (RARRAY_PTR(ary) && !ARY_SHARED_P(ary)) {
 	    free(RARRAY(ary)->ptr);
@@ -522,6 +536,7 @@
     VALUE top;
 
     rb_ary_modify_check(ary);
+    ary_iter_check(ary);
     if (RARRAY_LEN(ary) == 0) return Qnil;
     top = RARRAY_PTR(ary)[0];
     if (!ARY_SHARED_P(ary)) {
@@ -567,6 +582,7 @@
     }
 
     rb_ary_modify_check(ary);
+    ary_iter_check(ary);
     result = ary_shared_first(argc, argv, ary, Qfalse);
     n = RARRAY_LEN(result);
     if (ARY_SHARED_P(ary)) {
@@ -600,6 +616,7 @@
 
     if (argc == 0) return ary;
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     if (RARRAY(ary)->aux.capa <= RARRAY_LEN(ary)+argc) {
 	RESIZE_CAPA(ary, RARRAY(ary)->aux.capa + ARY_DEFAULT_SIZE);
     }
@@ -912,8 +929,8 @@
     long i = RARRAY_LEN(ary);
 
     if (rb_scan_args(argc, argv, "01", &val) == 0) {
+	    RETURN_ENUMERATOR(ary, 0, 0);
 	while (i--) {
-	    RETURN_ENUMERATOR(ary, 0, 0);
 	    if (RTEST(rb_yield(RARRAY_PTR(ary)[i])))
 		return LONG2NUM(i);
 	    if (i > RARRAY_LEN(ary)) {
@@ -970,6 +987,7 @@
 	rlen = RARRAY_LEN(rpl);
     }
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     if (beg >= RARRAY_LEN(ary)) {
 	len = beg + rlen;
 	if (len >= ARY_CAPA(ary)) {
@@ -1092,6 +1110,24 @@
     return ary;
 }
 
+static VALUE
+each_unlock(VALUE ary)
+{
+    FL_UNSET(ary, ARY_ITERLOCK);
+    return ary;
+}
+
+static VALUE
+each_i(VALUE ary)
+{
+    long i;
+
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+	rb_yield(RARRAY_PTR(ary)[i]);
+    }
+    return ary;
+}
+
 /*
  *  call-seq:
  *     array.each {|item| block }   ->   array
@@ -1122,8 +1158,17 @@
 	return val;
     }
 
+    ITERATE(each_i, ary);
+    return ary;
+}
+
+static VALUE
+each_index_i(VALUE ary)
+{
+    long i;
+
     for (i=0; i<RARRAY_LEN(ary); i++) {
-	rb_yield(RARRAY_PTR(ary)[i]);
+      rb_yield(LONG2NUM(i));
     }
     return ary;
 }
@@ -1146,11 +1191,20 @@
 static VALUE
 rb_ary_each_index(VALUE ary)
 {
-    long i;
+    RETURN_ENUMERATOR(ary, 0, 0);
+    ITERATE(each_index_i, ary);
+}
 
-    RETURN_ENUMERATOR(ary, 0, 0);
-    for (i=0; i<RARRAY_LEN(ary); i++) {
-	rb_yield(LONG2NUM(i));
+static VALUE
+reverse_each_i(VALUE ary)
+{
+    long len = RARRAY_LEN(ary);
+
+    while (len--) {
+	rb_yield(RARRAY_PTR(ary)[len]);
+	if (RARRAY_LEN(ary) < len) {
+	    len = RARRAY_LEN(ary);
+	}
     }
     return ary;
 }
@@ -1173,16 +1227,8 @@
 static VALUE
 rb_ary_reverse_each(VALUE ary)
 {
-    long len = RARRAY_LEN(ary);
-
     RETURN_ENUMERATOR(ary, 0, 0);
-    while (len--) {
-	rb_yield(RARRAY_PTR(ary)[len]);
-	if (RARRAY_LEN(ary) < len) {
-	    len = RARRAY_LEN(ary);
-	}
-    }
-    return ary;
+    ITERATE(reverse_each_i, ary);
 }
 
 /*
@@ -1390,6 +1436,7 @@
     VALUE tmp;
 
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     if (RARRAY_LEN(ary) > 1) {
 	p1 = RARRAY_PTR(ary);
 	p2 = p1 + RARRAY_LEN(ary) - 1;	/* points last item */
@@ -1486,7 +1533,7 @@
 }
 
 static VALUE
-sort_internal(VALUE ary)
+sort_i(VALUE ary)
 {
     struct ary_sort_data data;
 
@@ -1500,7 +1547,7 @@
 static VALUE
 sort_unlock(VALUE ary)
 {
-    FL_UNSET(ary, ARY_TMPLOCK);
+    FL_UNSET(ary, ARY_SORTLOCK);
     return ary;
 }
 
@@ -1524,9 +1571,10 @@
 rb_ary_sort_bang(VALUE ary)
 {
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     if (RARRAY_LEN(ary) > 1) {
-	FL_SET(ary, ARY_TMPLOCK);	/* prohibit modification during sort */
-	rb_ensure(sort_internal, ary, sort_unlock, ary);
+	FL_SET(ary, ARY_SORTLOCK);	/* prohibit modification during sort */
+	rb_ensure(sort_i, ary, sort_unlock, ary);
     }
     return ary;
 }
@@ -1555,6 +1603,20 @@
     return ary;
 }
 
+
+static VALUE
+collect_i(VALUE ary)
+{
+    long i;
+    VALUE collect;
+
+    collect = rb_ary_new2(RARRAY_LEN(ary));
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+	rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
+    }
+    return collect;
+}
+
 /*
  *  call-seq:
  *     array.collect {|item| block }  -> an_array
@@ -1572,15 +1634,21 @@
 static VALUE
 rb_ary_collect(VALUE ary)
 {
+    RETURN_ENUMERATOR(ary, 0, 0);
+    ITERATE(collect_i, ary);
+}
+
+
+static VALUE
+collect_bang_i(VALUE ary)
+{
     long i;
-    VALUE collect;
 
-    RETURN_ENUMERATOR(ary, 0, 0);
-    collect = rb_ary_new2(RARRAY_LEN(ary));
+    rb_ary_modify(ary);
     for (i = 0; i < RARRAY_LEN(ary); i++) {
-	rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
+	RARRAY_PTR(ary)[i] = rb_yield(RARRAY_PTR(ary)[i]);
     }
-    return collect;
+    return ary;
 }
 
 /* 
@@ -1600,14 +1668,8 @@
 static VALUE
 rb_ary_collect_bang(VALUE ary)
 {
-    long i;
-
     RETURN_ENUMERATOR(ary, 0, 0);
-    rb_ary_modify(ary);
-    for (i = 0; i < RARRAY_LEN(ary); i++) {
-	rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i]));
-    }
-    return ary;
+    ITERATE(collect_bang_i, ary);
 }
 
 VALUE
@@ -1660,6 +1722,22 @@
     return rb_get_values_at(ary, RARRAY_LEN(ary), argc, argv, rb_ary_entry);
 }
 
+
+static VALUE
+select_i(VALUE ary)
+{
+    VALUE result;
+    long i;
+
+    result = rb_ary_new2(RARRAY_LEN(ary));
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+	if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
+	    rb_ary_push(result, rb_ary_elt(ary, i));
+	}
+    }
+    return result;
+}
+
 /*
  *  call-seq:
  *     array.select {|item| block } -> an_array
@@ -1675,17 +1753,8 @@
 static VALUE
 rb_ary_select(VALUE ary)
 {
-    VALUE result;
-    long i;
-
     RETURN_ENUMERATOR(ary, 0, 0);
-    result = rb_ary_new2(RARRAY_LEN(ary));
-    for (i = 0; i < RARRAY_LEN(ary); i++) {
-	if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
-	    rb_ary_push(result, rb_ary_elt(ary, i));
-	}
-    }
-    return result;
+    ITERATE(select_i, ary);
 }
 
 /*
@@ -1727,6 +1796,7 @@
     }
 
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     if (RARRAY_LEN(ary) > i2) {
 	RARRAY(ary)->len = i2;
 	if (i2 * 2 < ARY_CAPA(ary) &&
@@ -1751,6 +1821,7 @@
     }
 
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     del = RARRAY_PTR(ary)[pos];
     MEMMOVE(RARRAY_PTR(ary)+pos, RARRAY_PTR(ary)+pos+1, VALUE,
 	    RARRAY_LEN(ary)-pos-1);
@@ -1829,22 +1900,11 @@
     return rb_ary_delete_at(ary, NUM2LONG(arg1));
 }
 
-/*
- *  call-seq:
- *     array.reject! {|item| block }  -> array or nil
- *  
- *  Equivalent to <code>Array#delete_if</code>, deleting elements from
- *  _self_ for which the block evaluates to true, but returns
- *  <code>nil</code> if no changes were made. Also see
- *  <code>Enumerable#reject</code>.
- */
-
 static VALUE
-rb_ary_reject_bang(VALUE ary)
+reject_bang_i(VALUE ary)
 {
     long i1, i2;
 
-    RETURN_ENUMERATOR(ary, 0, 0);
     rb_ary_modify(ary);
     for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
 	VALUE v = RARRAY_PTR(ary)[i1];
@@ -1854,15 +1914,33 @@
 	}
 	i2++;
     }
+
     if (RARRAY_LEN(ary) == i2) return Qnil;
     if (i2 < RARRAY_LEN(ary))
 	RARRAY(ary)->len = i2;
-
     return ary;
 }
 
 /*
  *  call-seq:
+ *     array.reject! {|item| block }  -> array or nil
+ *  
+ *  Equivalent to <code>Array#delete_if</code>, deleting elements from
+ *  _self_ for which the block evaluates to true, but returns
+ *  <code>nil</code> if no changes were made. Also see
+ *  <code>Enumerable#reject</code>.
+ */
+
+static VALUE
+rb_ary_reject_bang(VALUE ary)
+{
+    RETURN_ENUMERATOR(ary, 0, 0);
+    ary_iter_check(ary);
+    ITERATE(reject_bang_i, ary);
+}
+
+/*
+ *  call-seq:
  *     array.reject {|item| block }  -> an_array
  *  
  *  Returns a new array containing the items in _self_
@@ -1925,6 +2003,7 @@
     long len;
     VALUE result;
 
+    RETURN_ENUMERATOR(ary, argc, argv);
     for (i=0; i<argc; i++) {
 	argv[i] = to_a(argv[i]);
     }
@@ -2012,6 +2091,7 @@
     VALUE *ptr;
 
     rb_ary_modify(copy);
+    ary_iter_check(copy);
     orig = to_ary(orig);
     if (copy == orig) return copy;
     shared = ary_make_shared(orig);
@@ -2039,6 +2119,7 @@
 rb_ary_clear(VALUE ary)
 {
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     RARRAY(ary)->len = 0;
     if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
 	RESIZE_CAPA(ary, ARY_DEFAULT_SIZE * 2);
@@ -2106,6 +2187,7 @@
 	break;
     }
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     end = beg + len;
     if (end > RARRAY_LEN(ary)) {
 	if (end >= ARY_CAPA(ary)) {
@@ -2587,6 +2669,7 @@
     VALUE hash, v, vv;
     long i, j;
 
+    ary_iter_check(ary);
     hash = ary_make_hash(ary, 0);
 
     if (RARRAY_LEN(ary) == RHASH(hash)->tbl->num_entries) {
@@ -2639,6 +2722,7 @@
     long n;
 
     rb_ary_modify(ary);
+    ary_iter_check(ary);
     p = t = RARRAY_PTR(ary);
     end = p + RARRAY_LEN(ary);
     
@@ -2832,6 +2916,8 @@
 {
     long i = RARRAY_LEN(ary);
 
+    rb_ary_modify(ary);
+    ary_iter_check(ary);
     while (i) {
 	long j = genrand_real()*i;
 	VALUE tmp = RARRAY_PTR(ary)[--i];

Modified: trunk/configure.in
===================================================================
--- trunk/configure.in	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/configure.in	2006-12-31 08:05:21 UTC (rev 588)
@@ -1534,7 +1534,7 @@
 	    [  --with-sitedir=DIR      site libraries in DIR [PREFIX/lib/ruby/site_ruby]],
             [sitedir=$withval],
             [sitedir='${prefix}/lib/ruby/site_ruby'])
-SITE_DIR="`eval \"echo ${sitedir}\"`"
+SITE_DIR=`eval echo \\"${sitedir}\\"`
 case "$target_os" in
   cygwin*|mingw*|*djgpp*|os2-emx*)
     RUBY_SITE_LIB_PATH="`expr "$SITE_DIR" : "$prefix\(/.*\)"`" ||

Modified: trunk/dir.c
===================================================================
--- trunk/dir.c	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/dir.c	2006-12-31 08:05:21 UTC (rev 588)
@@ -1896,6 +1896,7 @@
 
     rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
     rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
+    rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1); /* in file.c */
 
     rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
     rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);

Modified: trunk/enum.c
===================================================================
--- trunk/enum.c	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/enum.c	2006-12-31 08:05:21 UTC (rev 588)
@@ -335,13 +335,14 @@
 }
 
 static VALUE
-inject_i(VALUE i, VALUE *memo)
+inject_i(VALUE i, VALUE memo)
 {
-    if (*memo == Qundef) {
-        *memo = i;
+    if (RARRAY_PTR(memo)[0] == Qundef) {
+        RARRAY_PTR(memo)[0] = i;
     }
     else {
-        *memo = rb_yield_values(2, *memo, i);
+	RARRAY_PTR(memo)[1] = i;
+        RARRAY_PTR(memo)[0] = rb_yield(memo);
     }
     return Qnil;
 }
@@ -380,13 +381,18 @@
 static VALUE
 enum_inject(int argc, VALUE *argv, VALUE obj)
 {
-    VALUE memo = Qundef;
+    VALUE memo, tmp;
 
-    if (rb_scan_args(argc, argv, "01", &memo) == 0)
-	memo = Qundef;
-    rb_block_call(obj, id_each, 0, 0, inject_i, (VALUE)&memo);
-    if (memo == Qundef) return Qnil;
-    return memo;
+    if (rb_scan_args(argc, argv, "01", &tmp) == 0) {
+	memo = rb_ary_new3(2, Qundef, Qnil);
+    }
+    else {
+	memo = rb_ary_new3(2, tmp, Qnil);
+    }
+    rb_block_call(obj, id_each, 0, 0, inject_i, (VALUE)memo);
+    tmp = RARRAY_PTR(memo)[0];
+    if (tmp == Qundef) return Qnil;
+    return tmp;
 }
 
 static VALUE
@@ -881,7 +887,10 @@
 	*memo = i;
     }
     else {
-	cmp = rb_yield_values(2, i, *memo);
+	VALUE ary = memo[1];
+	RARRAY_PTR(ary)[0] = i;
+	RARRAY_PTR(ary)[1] = *memo;
+	cmp = rb_yield(ary);
 	if (rb_cmpint(cmp, i, *memo) < 0) {
 	    *memo = i;
 	}
@@ -907,11 +916,18 @@
 static VALUE
 enum_min(VALUE obj)
 {
-    VALUE result = Qundef;
+    VALUE result[2];
 
-    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? min_ii : min_i, (VALUE)&result);
-    if (result == Qundef) return Qnil;
-    return result;
+    result[0] = Qundef;
+    if (rb_block_given_p()) {
+	result[1] = rb_ary_new3(2, Qnil, Qnil);
+	rb_block_call(obj, id_each, 0, 0, min_ii, (VALUE)result);
+    }
+    else {
+	rb_block_call(obj, id_each, 0, 0, min_i, (VALUE)result);
+    }
+    if (result[0] == Qundef) return Qnil;
+    return result[0];
 }
 
 static VALUE
@@ -940,7 +956,10 @@
 	*memo = i;
     }
     else {
-	cmp = rb_yield_values(2, i, *memo);
+	VALUE ary = memo[1];
+	RARRAY_PTR(ary)[0] = i;
+	RARRAY_PTR(ary)[1] = *memo;
+	cmp = rb_yield(ary);
 	if (rb_cmpint(cmp, i, *memo) > 0) {
 	    *memo = i;
 	}
@@ -965,11 +984,18 @@
 static VALUE
 enum_max(VALUE obj)
 {
-    VALUE result = Qundef;
+    VALUE result[2];
 
-    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? max_ii : max_i, (VALUE)&result);
-    if (result == Qundef) return Qnil;
-    return result;
+    result[0] = Qundef;
+    if (rb_block_given_p()) {
+	result[1] = rb_ary_new3(2, Qnil, Qnil);
+	rb_block_call(obj, id_each, 0, 0, max_ii, (VALUE)result);
+    }
+    else {
+	rb_block_call(obj, id_each, 0, 0, max_i, (VALUE)result);
+    }
+    if (result[0] == Qundef) return Qnil;
+    return result[0];
 }
 
 static VALUE
@@ -1089,10 +1115,16 @@
 }
 
 static VALUE
-each_with_index_i(VALUE val, VALUE *memo)
+each_with_index_i(VALUE val, VALUE memo)
 {
-    rb_yield_values(2, val, INT2FIX(*memo));
-    ++*memo;
+    long n;
+
+    RARRAY_PTR(memo)[0] = val;
+    rb_yield(memo);
+    val = RARRAY_PTR(memo)[1];
+    n = NUM2LONG(val);
+    n++;
+    RARRAY_PTR(memo)[1] = INT2NUM(n);
     return Qnil;
 }
 
@@ -1114,11 +1146,12 @@
 static VALUE
 enum_each_with_index(VALUE obj)
 {
-    VALUE memo = 0;
+    VALUE memo;
 
     RETURN_ENUMERATOR(obj, 0, 0);
 
-    rb_block_call(obj, id_each, 0, 0, each_with_index_i, (VALUE)&memo);
+    memo = rb_ary_new3(2, Qnil, INT2FIX(0));
+    rb_block_call(obj, id_each, 0, 0, each_with_index_i, memo);
     return obj;
 }
 

Modified: trunk/eval.c
===================================================================
--- trunk/eval.c	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/eval.c	2006-12-31 08:05:21 UTC (rev 588)
@@ -405,13 +405,17 @@
  */
 
 static VALUE
-rb_mod_s_constants(void)
+rb_mod_s_constants(int argc, VALUE *argv, VALUE mod)
 {
     NODE *cref = ruby_cref();
     VALUE klass;
     VALUE cbase = 0;
     void *data = 0;
 
+    if (argc > 0) {
+	return rb_mod_constants(argc, argv, rb_cModule);
+    }
+
     while (cref) {
 	klass = cref->nd_clss;
 	if (!NIL_P(klass)) {
@@ -2893,27 +2897,19 @@
     rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1);
     rb_define_method(rb_mKernel, "instance_exec", rb_obj_instance_exec, -1);
 
-    rb_define_private_method(rb_cModule, "append_features",
-			     rb_mod_append_features, 1);
-    rb_define_private_method(rb_cModule, "extend_object",
-			     rb_mod_extend_object, 1);
+    rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
+    rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
     rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
     rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
     rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
     rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
-    rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc,
-			     -1);
+    rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
     rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
-    rb_define_method(rb_cModule, "public_method_defined?",
-		     rb_mod_public_method_defined, 1);
-    rb_define_method(rb_cModule, "private_method_defined?",
-		     rb_mod_private_method_defined, 1);
-    rb_define_method(rb_cModule, "protected_method_defined?",
-		     rb_mod_protected_method_defined, 1);
-    rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method,
-		     -1);
-    rb_define_method(rb_cModule, "private_class_method",
-		     rb_mod_private_method, -1);
+    rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
+    rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
+    rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
+    rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
+    rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
     rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
     rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
     rb_define_method(rb_cModule, "module_exec", rb_mod_module_exec, -1);
@@ -2921,16 +2917,12 @@
 
     rb_undef_method(rb_cClass, "module_function");
 
-    rb_define_private_method(rb_cModule, "remove_method",
-			     rb_mod_remove_method, -1);
-    rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method,
-			     -1);
-    rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method,
-			     2);
+    rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
+    rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
+    rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
 
     rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
-    rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants,
-			       0);
+    rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, -1);
 
     rb_define_singleton_method(ruby_top_self, "include", top_include, -1);
     rb_define_singleton_method(ruby_top_self, "public", top_public, -1);

Modified: trunk/file.c
===================================================================
--- trunk/file.c	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/file.c	2006-12-31 08:05:21 UTC (rev 588)
@@ -789,7 +789,7 @@
 group_member(GETGROUPS_T gid)
 {
 #ifndef _WIN32
-    if (getgid() ==  gid)
+    if (getgid() == gid || getegid() == gid)
 	return Qtrue;
 
 # ifdef HAVE_GETGROUPS
@@ -849,7 +849,7 @@
 
     if (st.st_uid == euid)        /* owner */
 	mode <<= 6;
-    else if (getegid() == st.st_gid || group_member(st.st_gid))
+    else if (group_member(st.st_gid))
 	mode <<= 3;
 
     if ((st.st_mode & mode) == mode) return 0;
@@ -877,7 +877,30 @@
 
 
 /*
+ *   File.directory?(file_name)   =>  true or false
+ *   File.directory?(file_name)   =>  true or false
+ *
+ * Returns <code>true</code> if the named file is a directory,
+ * <code>false</code> otherwise.
+ *
+ *    File.directory?(".")
+ */
+
+/*
+ * Document-method: exist?
+ *
  * call-seq:
+ *   Dir.exist?(file_name)   =>  true or false
+ *
+ * Returns <code>true</code> if the named file is a directory,
+ * <code>false</code> otherwise.
+ *
+ */
+
+/*
+ * Document-method: directory?
+ *
+ * call-seq:
  *   File.directory?(file_name)   =>  true or false
  *
  * Returns <code>true</code> if the named file is a directory,
@@ -886,8 +909,8 @@
  *    File.directory?(".")
  */
 
-static VALUE
-test_d(VALUE obj, VALUE fname)
+VALUE
+rb_file_directory_p(VALUE obj, VALUE fname)
 {
 #ifndef S_ISDIR
 #   define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
@@ -900,6 +923,7 @@
     return Qfalse;
 }
 
+
 /*
  * call-seq:
  *   File.pipe?(file_name)   =>  true or false
@@ -908,7 +932,7 @@
  */
 
 static VALUE
-test_p(VALUE obj, VALUE fname)
+rb_file_pipe_p(VALUE obj, VALUE fname)
 {
 #ifdef S_IFIFO
 #  ifndef S_ISFIFO
@@ -932,7 +956,7 @@
  */
 
 static VALUE
-test_l(VALUE obj, VALUE fname)
+rb_file_symlink_p(VALUE obj, VALUE fname)
 {
 #ifndef S_ISLNK
 #  ifdef _S_ISLNK
@@ -968,7 +992,7 @@
  */
 
 static VALUE
-test_S(VALUE obj, VALUE fname)
+rb_file_socket_p(VALUE obj, VALUE fname)
 {
 #ifndef S_ISSOCK
 #  ifdef _S_ISSOCK
@@ -1002,7 +1026,7 @@
  */
 
 static VALUE
-test_b(VALUE obj, VALUE fname)
+rb_file_blockdev_p(VALUE obj, VALUE fname)
 {
 #ifndef S_ISBLK
 #   ifdef S_IFBLK
@@ -1029,7 +1053,7 @@
  * Returns <code>true</code> if the named file is a character device.
  */
 static VALUE
-test_c(VALUE obj, VALUE fname)
+rb_file_chardev_p(VALUE obj, VALUE fname)
 {
 #ifndef S_ISCHR
 #   define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
@@ -1053,7 +1077,7 @@
  */
 
 static VALUE
-test_e(VALUE obj, VALUE fname)
+rb_file_exist_p(VALUE obj, VALUE fname)
 {
     struct stat st;
 
@@ -1070,7 +1094,7 @@
  */
 
 static VALUE
-test_r(VALUE obj, VALUE fname)
+rb_file_readable_p(VALUE obj, VALUE fname)
 {
     rb_secure(2);
     FilePathValue(fname);
@@ -1087,7 +1111,7 @@
  */
 
 static VALUE
-test_R(VALUE obj, VALUE fname)
+rb_file_readable_real_p(VALUE obj, VALUE fname)
 {
     rb_secure(2);
     FilePathValue(fname);
@@ -1118,7 +1142,7 @@
  */
 
 static VALUE
-test_wr(VALUE obj, VALUE fname)
+rb_file_world_readable_p(VALUE obj, VALUE fname)
 {
 #ifdef S_IROTH
     struct stat st;
@@ -1140,7 +1164,7 @@
  */
 
 static VALUE
-test_w(VALUE obj, VALUE fname)
+rb_file_writable_p(VALUE obj, VALUE fname)
 {
     rb_secure(2);
     FilePathValue(fname);
@@ -1157,7 +1181,7 @@
  */
 
 static VALUE
-test_W(VALUE obj, VALUE fname)
+rb_file_writable_real_p(VALUE obj, VALUE fname)
 {
     rb_secure(2);
     FilePathValue(fname);
@@ -1180,7 +1204,7 @@
  */
 
 static VALUE
-test_ww(VALUE obj, VALUE fname)
+rb_file_world_writable_p(VALUE obj, VALUE fname)
 {
 #ifdef S_IWOTH
     struct stat st;
@@ -1202,7 +1226,7 @@
  */
 
 static VALUE
-test_x(VALUE obj, VALUE fname)
+rb_file_executable_p(VALUE obj, VALUE fname)
 {
     rb_secure(2);
     FilePathValue(fname);
@@ -1219,7 +1243,7 @@
  */
 
 static VALUE
-test_X(VALUE obj, VALUE fname)
+rb_file_executable_real_p(VALUE obj, VALUE fname)
 {
     rb_secure(2);
     FilePathValue(fname);
@@ -1240,7 +1264,7 @@
  */
 
 static VALUE
-test_f(VALUE obj, VALUE fname)
+rb_file_file_p(VALUE obj, VALUE fname)
 {
     struct stat st;
 
@@ -1258,7 +1282,7 @@
  */
 
 static VALUE
-test_z(VALUE obj, VALUE fname)
+rb_file_zero_p(VALUE obj, VALUE fname)
 {
     struct stat st;
 
@@ -1276,7 +1300,7 @@
  */
 
 static VALUE
-test_s(VALUE obj, VALUE fname)
+rb_file_size_p(VALUE obj, VALUE fname)
 {
     struct stat st;
 
@@ -1295,7 +1319,7 @@
  */
 
 static VALUE
-test_owned(VALUE obj, VALUE fname)
+rb_file_owned_p(VALUE obj, VALUE fname)
 {
     struct stat st;
 
@@ -1305,7 +1329,7 @@
 }
 
 static VALUE
-test_rowned(VALUE obj, VALUE fname)
+rb_file_rowned_p(VALUE obj, VALUE fname)
 {
     struct stat st;
 
@@ -1324,13 +1348,13 @@
  */
 
 static VALUE
-test_grpowned(VALUE obj, VALUE fname)
+rb_file_grpowned_p(VALUE obj, VALUE fname)
 {
 #ifndef _WIN32
     struct stat st;
 
     if (rb_stat(fname, &st) < 0) return Qfalse;
-    if (st.st_gid == getegid()) return Qtrue;
+    if (group_member(st.st_gid)) return Qtrue;
 #endif
     return Qfalse;
 }
@@ -1357,7 +1381,7 @@
  */
 
 static VALUE
-test_suid(VALUE obj, VALUE fname)
+rb_file_suid_p(VALUE obj, VALUE fname)
 {
 #ifdef S_ISUID
     return check3rdbyte(fname, S_ISUID);
@@ -1374,7 +1398,7 @@
  */
 
 static VALUE
-test_sgid(VALUE obj, VALUE fname)
+rb_file_sgid_p(VALUE obj, VALUE fname)
 {
 #ifdef S_ISGID
     return check3rdbyte(fname, S_ISGID);
@@ -1391,7 +1415,7 @@
  */
 
 static VALUE
-test_sticky(VALUE obj, VALUE fname)
+rb_file_sticky_p(VALUE obj, VALUE fname)
 {
 #ifdef S_ISVTX
     return check3rdbyte(fname, S_ISVTX);
@@ -1418,7 +1442,7 @@
  */
 
 static VALUE
-test_identical(VALUE obj, VALUE fname1, VALUE fname2)
+rb_file_identical_p(VALUE obj, VALUE fname1, VALUE fname2)
 {
 #ifndef DOSISH
     struct stat st1, st2;
@@ -3262,71 +3286,71 @@
 	CHECK(1);
 	switch (cmd) {
 	  case 'b':
-	    return test_b(0, argv[1]);
+	    return rb_file_blockdev_p(0, argv[1]);
 
 	  case 'c':
-	    return test_c(0, argv[1]);
+	    return rb_file_chardev_p(0, argv[1]);
 
 	  case 'd':
-	    return test_d(0, argv[1]);
+	    return rb_file_directory_p(0, argv[1]);
 
 	  case 'a':
 	  case 'e':
-	    return test_e(0, argv[1]);
+	    return rb_file_exist_p(0, argv[1]);
 
 	  case 'f':
-	    return test_f(0, argv[1]);
+	    return rb_file_file_p(0, argv[1]);
 
 	  case 'g':
-	    return test_sgid(0, argv[1]);
+	    return rb_file_sgid_p(0, argv[1]);
 
 	  case 'G':
-	    return test_grpowned(0, argv[1]);
+	    return rb_file_grpowned_p(0, argv[1]);
 
 	  case 'k':
-	    return test_sticky(0, argv[1]);
+	    return rb_file_sticky_p(0, argv[1]);
 
 	  case 'l':
-	    return test_l(0, argv[1]);
+	    return rb_file_symlink_p(0, argv[1]);
 
 	  case 'o':
-	    return test_owned(0, argv[1]);
+	    return rb_file_owned_p(0, argv[1]);
 
 	  case 'O':
-	    return test_rowned(0, argv[1]);
+	    return rb_file_rowned_p(0, argv[1]);
 
 	  case 'p':
-	    return test_p(0, argv[1]);
+	    return rb_file_pipe_p(0, argv[1]);
 
 	  case 'r':
-	    return test_r(0, argv[1]);
+	    return rb_file_readable_p(0, argv[1]);
 
 	  case 'R':
-	    return test_R(0, argv[1]);
+	    return rb_file_readable_real_p(0, argv[1]);
 
 	  case 's':
-	    return test_s(0, argv[1]);
+	    return rb_file_size_p(0, argv[1]);
 
 	  case 'S':
-	    return test_S(0, argv[1]);
+	    return rb_file_socket_p(0, argv[1]);
 
 	  case 'u':
-	    return test_suid(0, argv[1]);
+	    return rb_file_suid_p(0, argv[1]);
 
 	  case 'w':
-	    return test_w(0, argv[1]);
+	    return rb_file_writable_p(0, argv[1]);
 
 	  case 'W':
-	    return test_W(0, argv[1]);
+	    return rb_file_world_writable_p(0, argv[1]);
 
 	  case 'x':
-	    return test_x(0, argv[1]);
+	    return rb_file_executable_p(0, argv[1]);
 
 	  case 'X':
-	    return test_X(0, argv[1]);
+	    return rb_file_executable_real_p(0, argv[1]);
 
 	  case 'z':
-	    return test_z(0, argv[1]);
+	    return rb_file_zero_p(0, argv[1]);
 	}
     }
 
@@ -3350,7 +3374,7 @@
 
     if (cmd == '-') {
 	CHECK(2);
-	return test_identical(0, argv[1], argv[2]);
+	return rb_file_identical_p(0, argv[1], argv[2]);
     }
 
     if (strchr("=<>", cmd)) {
@@ -3651,7 +3675,7 @@
 rb_stat_grpowned(VALUE obj)
 {
 #ifndef _WIN32
-    if (get_stat(obj)->st_gid == getegid()) return Qtrue;
+    if (group_member(get_stat(obj)->st_gid)) return Qtrue;
 #endif
     return Qfalse;
 }
@@ -4332,36 +4356,35 @@
     rb_mFileTest = rb_define_module("FileTest");
     rb_cFile = rb_define_class("File", rb_cIO);
 
-    define_filetest_function("directory?", test_d, 1);
-    define_filetest_function("exist?", test_e, 1);
-    define_filetest_function("exists?", test_e, 1); /* temporary */
-    define_filetest_function("readable?", test_r, 1);
-    define_filetest_function("readable_real?", test_R, 1);
-    define_filetest_function("world_readable?", test_wr, 1);
-    define_filetest_function("writable?", test_w, 1);
-    define_filetest_function("writable_real?", test_W, 1);
-    define_filetest_function("world_writable?", test_ww, 1);
-    define_filetest_function("executable?", test_x, 1);
-    define_filetest_function("executable_real?", test_X, 1);
-    define_filetest_function("file?", test_f, 1);
-    define_filetest_function("zero?", test_z, 1);
-    define_filetest_function("size?", test_s, 1);
+    define_filetest_function("directory?", rb_file_directory_p, 1);
+    define_filetest_function("exist?", rb_file_exist_p, 1);
+    define_filetest_function("readable?", rb_file_readable_p, 1);
+    define_filetest_function("readable_real?", rb_file_readable_real_p, 1);
+    define_filetest_function("world_readable?", rb_file_world_writable_p, 1);
+    define_filetest_function("writable?", rb_file_writable_p, 1);
+    define_filetest_function("writable_real?", rb_file_world_writable_p, 1);
+    define_filetest_function("world_writable?", rb_file_world_writable_p, 1);
+    define_filetest_function("executable?", rb_file_executable_p, 1);
+    define_filetest_function("executable_real?", rb_file_executable_real_p, 1);
+    define_filetest_function("file?", rb_file_file_p, 1);
+    define_filetest_function("zero?", rb_file_zero_p, 1);
+    define_filetest_function("size?", rb_file_size_p, 1);
     define_filetest_function("size", rb_file_s_size, 1);
-    define_filetest_function("owned?", test_owned, 1);
-    define_filetest_function("grpowned?", test_grpowned, 1);
+    define_filetest_function("owned?", rb_file_owned_p, 1);
+    define_filetest_function("grpowned?", rb_file_grpowned_p, 1);
 
-    define_filetest_function("pipe?", test_p, 1);
-    define_filetest_function("symlink?", test_l, 1);
-    define_filetest_function("socket?", test_S, 1);
+    define_filetest_function("pipe?", rb_file_pipe_p, 1);
+    define_filetest_function("symlink?", rb_file_symlink_p, 1);
+    define_filetest_function("socket?", rb_file_socket_p, 1);
 
-    define_filetest_function("blockdev?", test_b, 1);
-    define_filetest_function("chardev?", test_c, 1);
+    define_filetest_function("blockdev?", rb_file_blockdev_p, 1);
+    define_filetest_function("chardev?", rb_file_chardev_p, 1);
 
-    define_filetest_function("setuid?", test_suid, 1);
-    define_filetest_function("setgid?", test_sgid, 1);
-    define_filetest_function("sticky?", test_sticky, 1);
+    define_filetest_function("setuid?", rb_file_suid_p, 1);
+    define_filetest_function("setgid?", rb_file_sgid_p, 1);
+    define_filetest_function("sticky?", rb_file_sticky_p, 1);
 
-    define_filetest_function("identical?", test_identical, 2);
+    define_filetest_function("identical?", rb_file_identical_p, 2);
 
     rb_define_singleton_method(rb_cFile, "stat",  rb_file_s_stat, 1);
     rb_define_singleton_method(rb_cFile, "lstat", rb_file_s_lstat, 1);

Modified: trunk/instruby.rb
===================================================================
--- trunk/instruby.rb	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/instruby.rb	2006-12-31 08:05:21 UTC (rev 588)
@@ -122,10 +122,10 @@
   super(dirs, :mode => 0755) unless dirs.empty?
 end
 
-def install_recursive(src, dest, options = {})
+def install_recursive(srcdir, dest, options = {})
   noinst = options.delete(:no_install)
-  subpath = src.size..-1
-  Dir.glob("#{src}/**/*", File::FNM_DOTMATCH) do |src|
+  subpath = srcdir.size..-1
+  Dir.glob("#{srcdir}/**/*", File::FNM_DOTMATCH) do |src|
     next if /\A\.{1,2}\z/ =~ (base = File.basename(src))
     next if noinst and File.fnmatch?(noinst, File.basename(src))
     d = dest + src[subpath]

Modified: trunk/intern.h
===================================================================
--- trunk/intern.h	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/intern.h	2006-12-31 08:05:21 UTC (rev 588)
@@ -295,6 +295,7 @@
 char *rb_path_skip_prefix(const char *);
 char *rb_path_last_separator(const char *);
 char *rb_path_end(const char *);
+VALUE rb_file_directory_p(VALUE,VALUE);
 /* gc.c */
 void ruby_set_stack_size(size_t);
 NORETURN(void rb_memerror(void));
@@ -564,7 +565,7 @@
 void *rb_mod_const_at(VALUE, void*);
 void *rb_mod_const_of(VALUE, void*);
 VALUE rb_const_list(void*);
-VALUE rb_mod_constants(VALUE);
+VALUE rb_mod_constants(int, VALUE *, VALUE);
 VALUE rb_mod_remove_const(VALUE, VALUE);
 int rb_const_defined(VALUE, ID);
 int rb_const_defined_at(VALUE, ID);
@@ -573,7 +574,6 @@
 VALUE rb_const_get_at(VALUE, ID);
 VALUE rb_const_get_from(VALUE, ID);
 void rb_const_set(VALUE, ID, VALUE);
-VALUE rb_mod_constants(VALUE);
 VALUE rb_mod_const_missing(VALUE,VALUE);
 VALUE rb_cvar_defined(VALUE, ID);
 #define RB_CVAR_SET_4ARGS 1

Modified: trunk/io.c
===================================================================
--- trunk/io.c	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/io.c	2006-12-31 08:05:21 UTC (rev 588)
@@ -1535,17 +1535,21 @@
 }
 
 static int
-appendline(OpenFile *fptr, int delim, VALUE *strp)
+appendline(OpenFile *fptr, int delim, VALUE *strp, long *lp)
 {
     VALUE str = *strp;
     int c = EOF;
+    long limit = *lp;
 
     do {
 	long pending = READ_DATA_PENDING_COUNT(fptr);
 	if (pending > 0) {
 	    const char *p = READ_DATA_PENDING_PTR(fptr);
-	    const char *e = memchr(p, delim, pending);
+	    const char *e;
 	    long last = 0, len = (c != EOF);
+
+	    if (limit > 0 && pending > limit) pending = limit;
+	    e = memchr(p, delim, pending);
 	    if (e) pending = e - p + 1;
 	    len += pending;
 	    if (!NIL_P(str)) {
@@ -1560,6 +1564,9 @@
 		RSTRING_PTR(str)[last++] = c;
 	    }
 	    read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
+	    limit -= pending;
+	    *lp = limit;
+	    if (limit == 0) return RSTRING_PTR(str)[RSTRING_LEN(str)-1];
 	    if (e) return delim;
 	}
 	else if (c != EOF) {
@@ -1576,7 +1583,9 @@
 	rb_thread_wait_fd(fptr->fd);
 	rb_io_check_closed(fptr);
 	c = io_getc(fptr);
+	limit--;
 	if (c < 0) {
+	    *lp = limit;
 	    return c;
 	}
     } while (c != delim);
@@ -1624,16 +1633,21 @@
 }
 
 static VALUE
-rb_io_getline_fast(OpenFile *fptr, unsigned char delim)
+rb_io_getline_fast(OpenFile *fptr, unsigned char delim, long limit)
 {
     VALUE str = Qnil;
     int c;
 
-    while ((c = appendline(fptr, delim, &str)) != EOF && c != delim);
+    for (;;) {
+	c = appendline(fptr, delim, &str, &limit);
+	if (c == EOF || c == delim || limit == 0) break;
+    }
 
     if (!NIL_P(str)) {
+	if (limit > 0) {
 	fptr->lineno++;
 	lineno = INT2FIX(fptr->lineno);
+	}
 	OBJ_TAINT(str);
     }
 
@@ -1649,19 +1663,43 @@
 }
 
 static VALUE
-rb_io_getline(VALUE rs, VALUE io)
+rb_io_getline(int argc, VALUE *argv, VALUE io)
 {
-    VALUE str = Qnil;
+    VALUE rs, lim, str = Qnil;
     OpenFile *fptr;
+    long limit;
 
+    if (argc == 0) {
+	rs = rb_rs;
+	lim = Qnil;
+    }
+    else {
+	rb_scan_args(argc, argv, "11", &rs, &lim);
+	if (NIL_P(lim) && !NIL_P(rs) && TYPE(rs) != T_STRING) {
+	    VALUE tmp = rb_check_string_type(rs);
+
+	    if (NIL_P(tmp)) {
+		lim = rs;
+		rs = rb_rs;
+	    }
+	    else {
+		rs = tmp;
+	    }
+	}
+    }
+    limit = NIL_P(lim) ? 0 : NUM2LONG(lim);
+
     GetOpenFile(io, fptr);
     rb_io_check_readable(fptr);
     if (NIL_P(rs)) {
 	str = read_all(fptr, 0, Qnil);
 	if (RSTRING_LEN(str) == 0) return Qnil;
     }
+    else if (!NIL_P(lim) && limit == 0) {
+	return rb_str_new(0,0);
+    }
     else if (rs == rb_default_rs) {
-	return rb_io_getline_fast(fptr, '\n');
+	return rb_io_getline_fast(fptr, '\n', limit);
     }
     else {
 	int c, newline;
@@ -1677,20 +1715,21 @@
 	    swallow(fptr, '\n');
 	}
 	else if (rslen == 1) {
-	    return rb_io_getline_fast(fptr, (unsigned char)RSTRING_PTR(rs)[0]);
+	    return rb_io_getline_fast(fptr, (unsigned char)RSTRING_PTR(rs)[0], limit);
 	}
 	else {
 	    rsptr = RSTRING_PTR(rs);
 	}
 	newline = rsptr[rslen - 1];
 
-	while ((c = appendline(fptr, newline, &str)) != EOF) {
+	while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
 	    if (c == newline) {
 		if (RSTRING_LEN(str) < rslen) continue;
 		if (!rspara) rscheck(rsptr, rslen, rs);
 		if (memcmp(RSTRING_PTR(str) + RSTRING_LEN(str) - rslen,
 			   rsptr, rslen) == 0) break;
 	    }
+	    if (limit == 0) break;
 	}
 
 	if (rspara) {
@@ -1701,8 +1740,10 @@
     }
 
     if (!NIL_P(str)) {
+	if (limit > 0) {
 	fptr->lineno++;
 	lineno = INT2FIX(fptr->lineno);
+	}
 	OBJ_TAINT(str);
     }
 
@@ -1716,21 +1757,25 @@
 
     GetOpenFile(io, fptr);
     rb_io_check_readable(fptr);
-    return rb_io_getline_fast(fptr, '\n');
+    return rb_io_getline_fast(fptr, '\n', 0);
 }
 
 /*
  *  call-seq:
- *     ios.gets(sep_string=$/)   => string or nil
+ *     ios.gets(sep=$/)     => string or nil
+ *     ios.gets(limit)      => string or nil
+ *     ios.gets(sep, limit) => string or nil
  *
  *  Reads the next ``line'' from the I/O stream; lines are separated by
- *  <i>sep_string</i>. A separator of <code>nil</code> reads the entire
+ *  <i>sep</i>. A separator of <code>nil</code> reads the entire
  *  contents, and a zero-length separator reads the input a paragraph at
  *  a time (two successive newlines in the input separate paragraphs).
  *  The stream must be opened for reading or an <code>IOError</code>
  *  will be raised. The line read in will be returned and also assigned
  *  to <code>$_</code>. Returns <code>nil</code> if called at end of
- *  file.
+ *  file.  If the first argument is an integer, or optional second
+ *  argument is given, the returning string would not be longer than the
+ *  given value.
  *
  *     File.new("testfile").gets   #=> "This is line one\n"
  *     $_                          #=> "This is line one\n"
@@ -1739,16 +1784,9 @@
 static VALUE
 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
 {
-    VALUE rs, str;
+    VALUE str;
 
-    if (argc == 0) {
-	rs = rb_rs;
-    }
-    else {
-	rb_scan_args(argc, argv, "1", &rs);
-	if (!NIL_P(rs)) StringValue(rs);
-    }
-    str = rb_io_getline(rs, io);
+    str = rb_io_getline(argc, argv, io);
     rb_lastline_set(str);
 
     return str;
@@ -1834,7 +1872,9 @@
 
 /*
  *  call-seq:
- *     ios.readline(sep_string=$/)   => string
+ *     ios.readline(sep=$/)     => string
+ *     ios.readline(limit)      => string
+ *     ios.readline(sep, limit) => string
  *
  *  Reads a line as with <code>IO#gets</code>, but raises an
  *  <code>EOFError</code> on end of file.
@@ -1853,14 +1893,17 @@
 
 /*
  *  call-seq:
- *     ios.readlines(sep_string=$/)  =>   array
+ *     ios.readlines(sep=$/)     => array
+ *     ios.readlines(limit)      => array
+ *     ios.readlines(sep, limit) => array
  *
  *  Reads all of the lines in <em>ios</em>, and returns them in
- *  <i>anArray</i>. Lines are separated by the optional
- *  <i>sep_string</i>. If <i>sep_string</i> is <code>nil</code>, the
- *  rest of the stream is returned as a single record.
- *  The stream must be opened for reading or an
- *  <code>IOError</code> will be raised.
+ *  <i>anArray</i>. Lines are separated by the optional <i>sep</i>. If
+ *  <i>sep</i> is <code>nil</code>, the rest of the stream is returned
+ *  as a single record.  If the first argument is an integer, or
+ *  optional second argument is given, the returning string would not be
+ *  longer than the given value. The stream must be opened for reading
+ *  or an <code>IOError</code> will be raised.
  *
  *     f = File.new("testfile")
  *     f.readlines[0]   #=> "This is line one\n"
@@ -1870,17 +1913,9 @@
 rb_io_readlines(int argc, VALUE *argv, VALUE io)
 {
     VALUE line, ary;
-    VALUE rs;
 
-    if (argc == 0) {
-	rs = rb_rs;
-    }
-    else {
-	rb_scan_args(argc, argv, "1", &rs);
-	if (!NIL_P(rs)) StringValue(rs);
-    }
     ary = rb_ary_new();
-    while (!NIL_P(line = rb_io_getline(rs, io))) {
+    while (!NIL_P(line = rb_io_getline(argc, argv, io))) {
 	rb_ary_push(ary, line);
     }
     return ary;
@@ -1888,11 +1923,15 @@
 
 /*
  *  call-seq:
- *     ios.each(sep_string=$/)      {|line| block }  => ios
- *     ios.each_line(sep_string=$/) {|line| block }  => ios
+ *     ios.each(sep=$/) {|line| block }         => ios
+ *     ios.each(limit) {|line| block }          => ios
+ *     ios.each(sep,limit) {|line| block }      => ios
+ *     ios.each_line(sep=$/) {|line| block }    => ios
+ *     ios.each_line(limit) {|line| block }     => ios
+ *     ios.each_line(sep,limit) {|line| block } => ios
  *
  *  Executes the block for every line in <em>ios</em>, where lines are
- *  separated by <i>sep_string</i>. <em>ios</em> must be opened for
+ *  separated by <i>sep</i>. <em>ios</em> must be opened for
  *  reading or an <code>IOError</code> will be raised.
  *
  *     f = File.new("testfile")
@@ -1910,17 +1949,9 @@
 rb_io_each_line(int argc, VALUE *argv, VALUE io)
 {
     VALUE str;
-    VALUE rs;
 
     RETURN_ENUMERATOR(io, argc, argv);
-    if (argc == 0) {
-	rs = rb_rs;
-    }
-    else {
-	rb_scan_args(argc, argv, "1", &rs);
-	if (!NIL_P(rs)) StringValue(rs);
-    }
-    while (!NIL_P(str = rb_io_getline(rs, io))) {
+    while (!NIL_P(str = rb_io_getline(argc, argv, io))) {
 	rb_yield(str);
     }
     return io;
@@ -1963,7 +1994,9 @@
 
 /*
  *  call-seq:
- *     str.lines(separator=$/)   => anEnumerator
++  *     str.lines(sep=$/)     => anEnumerator
++  *     str.lines(limit)      => anEnumerator
++  *     str.lines(sep, limit) => anEnumerator
  *
  *  Returns an enumerator that gives each line in the string.
  *
@@ -4371,16 +4404,7 @@
 	line = rb_io_gets(current_file);
     }
     else {
-	VALUE rs;
-
-	if (argc == 0) {
-	    rs = rb_rs;
-	}
-	else {
-	    rb_scan_args(argc, argv, "1", &rs);
-	    if (!NIL_P(rs)) StringValue(rs);
-	}
-	line = rb_io_getline(rs, current_file);
+	line = rb_io_getline(argc, argv, current_file);
     }
     if (NIL_P(line) && next_p != -1) {
 	argf_close(current_file);
@@ -4396,18 +4420,22 @@
 
 /*
  *  call-seq:
- *     gets(separator=$/)    => string or nil
+ *     gets(sep=$/)    => string or nil
+ *     gets(limit)     => string or nil
+ *     gets(sep,limit) => string or nil
  *
  *  Returns (and assigns to <code>$_</code>) the next line from the list
- *  of files in +ARGV+ (or <code>$*</code>), or from standard
- *  input if no files are present on the command line. Returns
- *  +nil+ at end of file. The optional argument specifies the
- *  record separator. The separator is included with the contents of
- *  each record. A separator of +nil+ reads the entire
- *  contents, and a zero-length separator reads the input one paragraph
- *  at a time, where paragraphs are divided by two consecutive newlines.
- *  If multiple filenames are present in +ARGV+,
- *  +gets(nil)+ will read the contents one file at a time.
+ *  of files in +ARGV+ (or <code>$*</code>), or from standard input if
+ *  no files are present on the command line. Returns +nil+ at end of
+ *  file. The optional argument specifies the record separator. The
+ *  separator is included with the contents of each record. A separator
+ *  of +nil+ reads the entire contents, and a zero-length separator
+ *  reads the input one paragraph at a time, where paragraphs are
+ *  divided by two consecutive newlines.  If the first argument is an
+ *  integer, or optional second argument is given, the returning string
+ *  would not be longer than the given value.  If multiple filenames are
+ *  present in +ARGV+, +gets(nil)+ will read the contents one file at a
+ *  time.
  *
  *     ARGV << "testfile"
  *     print while gets
@@ -4467,7 +4495,9 @@
 
 /*
  *  call-seq:
- *     readline(separator=$/)   => string
+ *     readline(sep=$/)     => string
+ *     readline(limit)      => string
+ *     readline(sep, limit) => string
  *
  *  Equivalent to <code>Kernel::gets</code>, except
  *  +readline+ raises +EOFError+ at end of file.
@@ -4503,10 +4533,12 @@
 
 /*
  *  call-seq:
- *     readlines(separator=$/)    => array
+ *     readlines(sep=$/)    => array
+ *     readlines(limit)     => array
+ *     readlines(sep,limit) => array
  *
  *  Returns an array containing the lines returned by calling
- *  <code>Kernel.gets(<i>separator</i>)</code> until the end of file.
+ *  <code>Kernel.gets(<i>sep</i>)</code> until the end of file.
  */
 
 static VALUE
@@ -5079,7 +5111,7 @@
 
 struct foreach_arg {
     int argc;
-    VALUE sep;
+    VALUE *argv;
     VALUE io;
 };
 
@@ -5088,7 +5120,7 @@
 {
     VALUE str;
 
-    while (!NIL_P(str = rb_io_getline(arg->sep, arg->io))) {
+    while (!NIL_P(str = rb_io_gets_m(arg->argc, arg->argv, arg->io))) {
 	rb_yield(str);
     }
     return Qnil;
@@ -5096,10 +5128,12 @@
 
 /*
  *  call-seq:
- *     IO.foreach(name, sep_string=$/) {|line| block }   => nil
+ *     IO.foreach(name, sep=$/) {|line| block }     => nil
+ *     IO.foreach(name, limit) {|line| block }      => nil
+ *     IO.foreach(name, sep, limit) {|line| block } => nil
  *
  *  Executes the block for every line in the named I/O port, where lines
- *  are separated by <em>sep_string</em>.
+ *  are separated by <em>sep</em>.
  *
  *     IO.foreach("testfile") {|x| print "GOT ", x }
  *
@@ -5118,33 +5152,30 @@
     struct foreach_arg arg;
 
     RETURN_ENUMERATOR(self, argc, argv);
-    rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+    rb_scan_args(argc, argv, "12", &fname, NULL, NULL);
     FilePathValue(fname);
-    if (argc == 1) {
-	arg.sep = rb_default_rs;
-    }
-    else if (!NIL_P(arg.sep)) {
-	StringValue(arg.sep);
-    }
     arg.io = rb_io_open(RSTRING_PTR(fname), "r");
     if (NIL_P(arg.io)) return Qnil;
-
+    arg.argc = argc - 1;
+    arg.argv = argv + 1;
     return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
 }
 
 static VALUE
 io_s_readlines(struct foreach_arg *arg)
 {
-    return rb_io_readlines(arg->argc, &arg->sep, arg->io);
+    return rb_io_readlines(arg->argc, arg->argv, arg->io);
 }
 
 /*
  *  call-seq:
- *     IO.readlines(name, sep_string=$/)   => array
+ *     IO.readlines(name, sep=$/)     => array
+ *     IO.readlines(name, limit)      => array
+ *     IO.readlines(name, sep, limit) => array
  *
  *  Reads the entire file specified by <i>name</i> as individual
  *  lines, and returns those lines in an array. Lines are separated by
- *  <i>sep_string</i>.
+ *  <i>sep</i>.
  *
  *     a = IO.readlines("testfile")
  *     a[0]   #=> "This is line one\n"
@@ -5157,18 +5188,19 @@
     VALUE fname;
     struct foreach_arg arg;
 
-    rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+    rb_scan_args(argc, argv, "12", &fname, NULL, NULL);
     FilePathValue(fname);
-    arg.argc = argc - 1;
     arg.io = rb_io_open(RSTRING_PTR(fname), "r");
     if (NIL_P(arg.io)) return Qnil;
+    arg.argc = argc - 1;
+    arg.argv = argv + 1;
     return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
 }
 
 static VALUE
 io_s_read(struct foreach_arg *arg)
 {
-    return io_read(arg->argc, &arg->sep, arg->io);
+    return io_read(arg->argc, arg->argv, arg->io);
 }
 
 /*
@@ -5190,9 +5222,10 @@
     VALUE fname, offset;
     struct foreach_arg arg;
 
-    rb_scan_args(argc, argv, "12", &fname, &arg.sep, &offset);
+    rb_scan_args(argc, argv, "12", &fname, NULL, &offset);
     FilePathValue(fname);
-    arg.argc = argc ? 1 : 0;
+    arg.argc = argc > 1 ? 1 : 0;
+    arg.argv = argv + 1;
     arg.io = rb_io_open(RSTRING_PTR(fname), "r");
     if (NIL_P(arg.io)) return Qnil;
     if (!NIL_P(offset)) {
@@ -5278,7 +5311,7 @@
     VALUE tmp, str, length;
     long len = 0;
 
-    rb_scan_args(argc, argv, "02", &length, &str);
+    rb_scan_args(argc, argv, "11", &length, &str);
     if (!NIL_P(length)) {
 	len = NUM2LONG(argv[0]);
     }

Modified: trunk/lib/README
===================================================================
--- trunk/lib/README	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/lib/README	2006-12-31 08:05:21 UTC (rev 588)
@@ -10,7 +10,6 @@
 csv.rb		CSV parser/generator
 date.rb		date object
 date/format.rb	date parsing and formatting
-date2.rb	date object (obsolete; use date)
 debug.rb	ruby debugger
 delegate.rb	delegates messages to other object
 drb.rb		distributed Ruby

Modified: trunk/lib/date/format.rb
===================================================================
--- trunk/lib/date/format.rb	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/lib/date/format.rb	2006-12-31 08:05:21 UTC (rev 588)
@@ -1,1086 +1,1061 @@
-# format.rb: Written by Tadayoshi Funaba 1999-2006
-# $Id: format.rb,v 2.28 2006-10-25 06:45:12+09 tadf Exp $
-
-require 'rational'
-
-class Date
-
-  module Format # :nodoc:
-
-  MONTHS = {
-    'january'  => 1, 'february' => 2, 'march'    => 3, 'april'    => 4,
-    'may'      => 5, 'june'     => 6, 'july'     => 7, 'august'   => 8,
-    'september'=> 9, 'october'  =>10, 'november' =>11, 'december' =>12
-  }
-
-  DAYS = {
-    'sunday'   => 0, 'monday'   => 1, 'tuesday'  => 2, 'wednesday'=> 3,
-    'thursday' => 4, 'friday'   => 5, 'saturday' => 6
-  }
-
-  ABBR_MONTHS = {
-    'jan'      => 1, 'feb'      => 2, 'mar'      => 3, 'apr'      => 4,
-    'may'      => 5, 'jun'      => 6, 'jul'      => 7, 'aug'      => 8,
-    'sep'      => 9, 'oct'      =>10, 'nov'      =>11, 'dec'      =>12
-  }
-
-  ABBR_DAYS = {
-    'sun'      => 0, 'mon'      => 1, 'tue'      => 2, 'wed'      => 3,
-    'thu'      => 4, 'fri'      => 5, 'sat'      => 6
-  }
-
-  ZONES = {
-    'ut'  =>  0*3600, 'gmt' =>  0*3600, 'est' => -5*3600, 'edt' => -4*3600,
-    'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
-    'pst' => -8*3600, 'pdt' => -7*3600,
-    'a'   =>  1*3600, 'b'   =>  2*3600, 'c'   =>  3*3600, 'd'   =>  4*3600,
-    'e'   =>  5*3600, 'f'   =>  6*3600, 'g'   =>  7*3600, 'h'   =>  8*3600,
-    'i'   =>  9*3600, 'k'   => 10*3600, 'l'   => 11*3600, 'm'   => 12*3600,
-    'n'   => -1*3600, 'o'   => -2*3600, 'p'   => -3*3600, 'q'   => -4*3600,
-    'r'   => -5*3600, 's'   => -6*3600, 't'   => -7*3600, 'u'   => -8*3600,
-    'v'   => -9*3600, 'w'   =>-10*3600, 'x'   =>-11*3600, 'y'   =>-12*3600,
-    'z'   =>  0*3600,
-    'utc' =>  0*3600, 'wet' =>  0*3600, 'bst' =>  1*3600, 'wat' => -1*3600,
-    'at'  => -2*3600, 'ast' => -4*3600, 'adt' => -3*3600, 'yst' => -9*3600,
-    'ydt' => -8*3600, 'hst' =>-10*3600, 'hdt' => -9*3600, 'cat' =>-10*3600,
-    'ahst'=>-10*3600, 'nt'  =>-11*3600, 'idlw'=>-12*3600, 'cet' =>  1*3600,
-    'met' =>  1*3600, 'mewt'=>  1*3600, 'mest'=>  2*3600, 'mesz'=>  2*3600,
-    'swt' =>  1*3600, 'sst' =>  2*3600, 'fwt' =>  1*3600, 'fst' =>  2*3600,
-    'eet' =>  2*3600, 'bt'  =>  3*3600, 'zp4' =>  4*3600, 'zp5' =>  5*3600,
-    'zp6' =>  6*3600, 'wast'=>  7*3600, 'wadt'=>  8*3600, 'cct' =>  8*3600,
-    'jst' =>  9*3600, 'east'=> 10*3600, 'eadt'=> 11*3600, 'gst' => 10*3600,
-      'nzt' => 12*3600, 'nzst'=> 12*3600, 'nzdt'=> 13*3600, 'idle'=> 12*3600,
-
-      'afghanistan'           =>   16200, 'alaskan'               =>  -32400,
-      'arab'                  =>   10800, 'arabian'               =>   14400,
-      'arabic'                =>   10800, 'atlantic'              =>  -14400,
-      'aus central'           =>   34200, 'aus eastern'           =>   36000,
-      'azores'                =>   -3600, 'canada central'        =>  -21600,
-      'cape verde'            =>   -3600, 'caucasus'              =>   14400,
-      'cen. australia'        =>   34200, 'central america'       =>  -21600,
-      'central asia'          =>   21600, 'central europe'        =>    3600,
-      'central european'      =>    3600, 'central pacific'       =>   39600,
-      'central'               =>  -21600, 'china'                 =>   28800,
-      'dateline'              =>  -43200, 'e. africa'             =>   10800,
-      'e. australia'          =>   36000, 'e. europe'             =>    7200,
-      'e. south america'      =>  -10800, 'eastern'               =>  -18000,
-      'egypt'                 =>    7200, 'ekaterinburg'          =>   18000,
-      'fiji'                  =>   43200, 'fle'                   =>    7200,
-      'greenland'             =>  -10800, 'greenwich'             =>       0,
-      'gtb'                   =>    7200, 'hawaiian'              =>  -36000,
-      'india'                 =>   19800, 'iran'                  =>   12600,
-      'jerusalem'             =>    7200, 'korea'                 =>   32400,
-      'mexico'                =>  -21600, 'mid-atlantic'          =>   -7200,
-      'mountain'              =>  -25200, 'myanmar'               =>   23400,
-      'n. central asia'       =>   21600, 'nepal'                 =>   20700,
-      'new zealand'           =>   43200, 'newfoundland'          =>  -12600,
-      'north asia east'       =>   28800, 'north asia'            =>   25200,
-      'pacific sa'            =>  -14400, 'pacific'               =>  -28800,
-      'romance'               =>    3600, 'russian'               =>   10800,
-      'sa eastern'            =>  -10800, 'sa pacific'            =>  -18000,
-      'sa western'            =>  -14400, 'samoa'                 =>  -39600,
-      'se asia'               =>   25200, 'malay peninsula'       =>   28800,
-      'south africa'          =>    7200, 'sri lanka'             =>   21600,
-      'taipei'                =>   28800, 'tasmania'              =>   36000,
-      'tokyo'                 =>   32400, 'tonga'                 =>   46800,
-      'us eastern'            =>  -18000, 'us mountain'           =>  -25200,
-      'vladivostok'           =>   36000, 'w. australia'          =>   28800,
-      'w. central africa'     =>    3600, 'w. europe'             =>    3600,
-      'west asia'             =>   18000, 'west pacific'          =>   36000,
-      'yakutsk'               =>   32400
-  }
-
-    [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x|
-      x.freeze
-    end
-
-    class Bag # :nodoc:
-
-      def method_missing(t, *args, &block)
-	t = t.to_s
-	set = t.chomp!('=')
-	t = '@' + t
-	if set
-	  instance_variable_set(t, *args)
-	else
-	  if instance_variables.include?(t)
-	    instance_variable_get(t)
-	  end
-	end
-      end
-
-      def to_hash
-	instance_variables.
-	  select{|n| !instance_variable_get(n).nil?}.grep(/\A@[^_]/).
-	  inject({}){|r, n| r[n[1..-1].intern] = instance_variable_get(n); r}
-      end
-
-    end
-
-  end
-
-  def emit(e, f) # :nodoc:
-    case e
-    when Numeric
-      sign = %w(+ + -)[e <=> 0]
-      e = e.abs
-    end
-
-    s = e.to_s
-
-    if f[:s] && f[:p] == '0'
-      f[:w] -= 1
-    end
-
-    if f[:s] && f[:p] == "\s"
-      s[0,0] = sign
-    end
-
-    if f[:p] != '-'
-      s = s.rjust(f[:w], f[:p])
-    end
-
-    if f[:s] && f[:p] != "\s"
-      s[0,0] = sign
-    end
-
-    s = s.upcase if f[:u]
-    s = s.downcase if f[:d]
-    s
-  end
-
-  def emit_w(e, w, f) # :nodoc:
-    f[:w] = [f[:w], w].compact.max
-    emit(e, f)
-  end
-
-  def emit_n(e, w, f) # :nodoc:
-    f[:p] ||= '0'
-    emit_w(e, w, f)
-  end
-
-  def emit_sn(e, w, f) # :nodoc:
-    if e < 0
-      w += 1
-      f[:s] = true
-    end
-    emit_n(e, w, f)
-  end
-
-  def emit_z(e, w, f) # :nodoc:
-    w += 1
-    f[:s] = true
-    emit_n(e, w, f)
-  end
-
-  def emit_a(e, w, f) # :nodoc:
-    f[:p] ||= "\s"
-    emit_w(e, w, f)
-  end
-
-  def emit_ad(e, w, f) # :nodoc:
-    if f[:x]
-      f[:u] = true
-      f[:d] = false
-    end
-    emit_a(e, w, f)
-  end
-
-  def emit_au(e, w, f) # :nodoc:
-    if f[:x]
-      f[:u] = false
-      f[:d] = true
-    end
-    emit_a(e, w, f)
-  end
-
-  private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
-	  :emit_a, :emit_ad, :emit_au
-
-  def strftime(fmt='%F')
-    fmt.gsub(/%([-_0^#]+)?(\d+)?[EO]?(:{1,3}z|.)/m) do |m|
-      f = {}
-      s, w, c = $1, $2, $3
-      if s
-	s.scan(/./) do |k|
-	  case k
-	  when '-'; f[:p] = '-'
-	  when '_'; f[:p] = "\s"
-	  when '0'; f[:p] = '0'
-	  when '^'; f[:u] = true
-	  when '#'; f[:x] = true
-	  end
-	end
-      end
-      if w
-	f[:w] = w.to_i
-      end
-      case c
-      when 'A'; emit_ad(DAYNAMES[wday], 0, f)
-      when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
-      when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
-      when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
-      when 'C'; emit_sn((year / 100).floor, 2, f)
-      when 'c'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
-      when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
-      when 'd'; emit_n(mday, 2, f)
-      when 'e'; emit_a(mday, 2, f)
-      when 'F'
-	if m == '%F'
-	  format('%.4d-%02d-%02d', year, mon, mday) # 4p
-	else
-	  emit_a(strftime('%Y-%m-%d'), 0, f)
-	end
-      when 'G'; emit_sn(cwyear, 4, f)
-      when 'g'; emit_n(cwyear % 100, 2, f)
-      when 'H'; emit_n(hour, 2, f)
-      when 'h'; emit_ad(strftime('%b'), 0, f)
-      when 'I'; emit_n((hour % 12).nonzero? || 12, 2, f)
-      when 'j'; emit_n(yday, 3, f)
-      when 'k'; emit_a(hour, 2, f)
-      when 'L'
-	emit_n((sec_fraction / (1.to_r/86400/(10**3))).round, 3, f)
-      when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
-      when 'M'; emit_n(min, 2, f)
-      when 'm'; emit_n(mon, 2, f)
-      when 'N'
-	emit_n((sec_fraction / (1.to_r/86400/(10**9))).round, 9, f)
-      when 'n'; "\n"
-      when 'P'; emit_ad(strftime('%p').downcase, 0, f)
-      when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
-      when 'Q'
-	d = ajd - self.class.jd_to_ajd(self.class::UNIXEPOCH, 0)
-	s = (d * 86400*10**3).to_i
-	emit_sn(s, 1, f)
-      when 'R'; emit_a(strftime('%H:%M'), 0, f)
-      when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
-      when 'S'; emit_n(sec, 2, f)
-      when 's'
-	d = ajd - self.class.jd_to_ajd(self.class::UNIXEPOCH, 0)
-	s = (d * 86400).to_i
-	emit_sn(s, 1, f)
-      when 'T'
-	if m == '%T'
-	  format('%02d:%02d:%02d', hour, min, sec) # 4p
-	else
-	  emit_a(strftime('%H:%M:%S'), 0, f)
-	end
-      when 't'; "\t"
-      when 'U', 'W'
-	emit_n(if c == 'U' then wnum0 else wnum1 end, 2, f)
-      when 'u'; emit_n(cwday, 1, f)
-      when 'V'; emit_n(cweek, 2, f)
-      when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
-      when 'w'; emit_n(wday, 1, f)
-      when 'X'; emit_a(strftime('%H:%M:%S'), 0, f)
-      when 'x'; emit_a(strftime('%m/%d/%y'), 0, f)
-      when 'Y'; emit_sn(year, 4, f)
-      when 'y'; emit_n(year % 100, 2, f)
-      when 'Z'; emit_au(strftime('%:z'), 0, f)
-      when /\A(:{0,3})z/
-	t = $1.size
-	sign = if offset < 0 then -1 else +1 end
-	fr = offset.abs
-	hh, fr = fr.divmod(1.to_r/24)
-	mm, fr = fr.divmod(1.to_r/1440)
-	ss, fr = fr.divmod(1.to_r/86400)
-	if t == 3
-	  if    ss.nonzero? then t =  2
-	  elsif mm.nonzero? then t =  1
-	  else                   t = -1
-	  end
-	end
-	case t
-	when -1
-	  tail = []
-	  sep = ''
-	when 0
-	  f[:w] -= 2 if f[:w]
-	  tail = ['%02d' % mm]
-	  sep = ''
-	when 1
-	  f[:w] -= 3 if f[:w]
-	  tail = ['%02d' % mm]
-	  sep = ':'
-	when 2
-	  f[:w] -= 6 if f[:w]
-	  tail = ['%02d' % mm, '%02d' % ss]
-	  sep = ':'
-	end
-	([emit_z(sign * hh, 2, f)] + tail).join(sep)
-      when '%'; emit_a('%', 0, f)
-      when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
-      when '1'
-	if $VERBOSE
-	  warn("warning: strftime: %1 is deprecated; forget this")
-	end
-	emit_n(jd, 1, f)
-      when '2'
-	if $VERBOSE
-	  warn("warning: strftime: %2 is deprecated; use '%Y-%j'")
-	end
-	emit_a(strftime('%Y-%j'), 0, f)
-      when '3'
-	if $VERBOSE
-	  warn("warning: strftime: %3 is deprecated; use '%F'")
-	end
-	emit_a(strftime('%F'), 0, f)
-      else
-	c
-      end
-    end
-  end
-
-# alias_method :format, :strftime
-
-  def asctime() strftime('%c') end
-
-  alias_method :ctime, :asctime
-
-=begin
-  def iso8601() strftime('%F') end
-
-  def rfc3339() iso8601 end
-
-  def rfc2822() strftime('%a, %-d %b %Y %T %z') end
-
-  alias_method :rfc822, :rfc2822
-
-  def jisx0301
-    if jd < 2405160
-      iso8601
-    else
-      case jd
-      when 2405160...2419614
-	g = 'M%02d' % (year - 1867)
-      when 2419614...2424875
-	g = 'T%02d' % (year - 1911)
-      when 2424875...2447535
-	g = 'S%02d' % (year - 1925)
-      else
-	g = 'H%02d' % (year - 1988)
-      end
-      g + strftime('.%m.%d')
-    end
-  end
-
-  def beat(n=0)
-    i, f = (new_offset(1.to_r/24).day_fraction * 1000).divmod(1)
-    ('@%03d' % i) +
-      if n < 1
-	''
-      else
-	'.%0*d' % [n, (f / (1.to_r/(10**n))).round]
-      end
-  end
-=end
-
-  def self.num_pattern? (s) # :nodoc:
-    /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s
-  end
-
-  private_class_method :num_pattern?
-
-  def self._strptime_i(str, fmt, e) # :nodoc:
-    fmt.scan(/%[EO]?(:{1,3}z|.)|(.)/m) do |s, c|
-      if s
-	case s
-	when 'A', 'a'
-	  return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') ||
-			str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '')
-	  val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase]
-	return unless val
-	  e.wday = val
-	when 'B', 'b', 'h'
-	  return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') ||
-			str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '')
-	  val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase]
-	return unless val
-	  e.mon = val
-	when 'C'
-	  return unless str.sub!(if num_pattern?($')
-				 then /\A([-+]?\d{1,2})/
-				 else /\A([-+]?\d{1,})/
-				 end, '')
-	  val = $1.to_i
-	  e._cent = val
-	when 'c'
-	  return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e)
-	when 'D'
-	  return unless _strptime_i(str, '%m/%d/%y', e)
-	when 'd', 'e'
-	  return unless str.sub!(/\A( \d|\d{1,2})/, '')
-	val = $1.to_i
-	return unless (1..31) === val
-	  e.mday = val
-	when 'F'
-	  return unless _strptime_i(str, '%Y-%m-%d', e)
-	when 'G'
-	  return unless str.sub!(if num_pattern?($')
-				 then /\A([-+]?\d{1,4})/
-				 else /\A([-+]?\d{1,})/
-				 end, '')
-	  val = $1.to_i
-	  e.cwyear = val
-	when 'g'
-	  return unless str.sub!(/\A(\d{1,2})/, '')
-	val = $1.to_i
-	return unless (0..99) === val
-	  e.cwyear = val
-	  e._cent ||= if val >= 69 then 19 else 20 end
-	when 'H', 'k'
-	  return unless str.sub!(/\A( \d|\d{1,2})/, '')
-	val = $1.to_i
-	return unless (0..24) === val
-	  e.hour = val
-	when 'I', 'l'
-	  return unless str.sub!(/\A( \d|\d{1,2})/, '')
-	val = $1.to_i
-	return unless (1..12) === val
-	  e.hour = val
-	when 'j'
-	  return unless str.sub!(/\A(\d{1,3})/, '')
-	val = $1.to_i
-	return unless (1..366) === val
-	  e.yday = val
-	when 'L'
-	  return unless str.sub!(if num_pattern?($')
-				 then /\A([-+]?\d{1,3})/
-				 else /\A([-+]?\d{1,})/
-				 end, '')
-#	  val = $1.to_i.to_r / (10**3)
-	  val = $1.to_i.to_r / (10**$1.size)
-	  e.sec_fraction = val
-	when 'M'
-	  return unless str.sub!(/\A(\d{1,2})/, '')
-	val = $1.to_i
-	return unless (0..59) === val
-	  e.min = val
-	when 'm'
-	  return unless str.sub!(/\A(\d{1,2})/, '')
-	val = $1.to_i
-	return unless (1..12) === val
-	  e.mon = val
-	when 'N'
-	  return unless str.sub!(if num_pattern?($')
-				 then /\A([-+]?\d{1,9})/
-				 else /\A([-+]?\d{1,})/
-				 end, '')
-#	  val = $1.to_i.to_r / (10**9)
-	  val = $1.to_i.to_r / (10**$1.size)
-	  e.sec_fraction = val
-	when 'n', 't'
-	  return unless _strptime_i(str, "\s", e)
-	when 'P', 'p'
-	  return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '')
-	  e._merid = if $1.downcase == 'a' then 0 else 12 end
-	when 'Q'
-	  return unless str.sub!(/\A(-?\d{1,})/, '')
-	  val = $1.to_i.to_r / 10**3
-	  e.seconds = val
-	when 'R'
-	  return unless _strptime_i(str, '%H:%M', e)
-	when 'r'
-	  return unless _strptime_i(str, '%I:%M:%S %p', e)
-	when 'S'
-	  return unless str.sub!(/\A(\d{1,2})/, '')
-	val = $1.to_i
-	return unless (0..60) === val
-	  e.sec = val
-	when 's'
-	  return unless str.sub!(/\A(-?\d{1,})/, '')
-	  val = $1.to_i
-	  e.seconds = val
-	when 'T'
-	  return unless _strptime_i(str, '%H:%M:%S', e)
-	when 'U', 'W'
-	  return unless str.sub!(/\A(\d{1,2})/, '')
-	val = $1.to_i
-	return unless (0..53) === val
-	  e.__send__(if s == 'U' then :wnum0= else :wnum1= end, val)
-	when 'u'
-	  return unless str.sub!(/\A(\d{1})/, '')
-	val = $1.to_i
-	return unless (1..7) === val
-	  e.cwday = val
-	when 'V'
-	  return unless str.sub!(/\A(\d{1,2})/, '')
-	val = $1.to_i
-	return unless (1..53) === val
-	  e.cweek = val
-	when 'v'
-	  return unless _strptime_i(str, '%e-%b-%Y', e)
-	when 'w'
-	  return unless str.sub!(/\A(\d{1})/, '')
-	val = $1.to_i
-	return unless (0..6) === val
-	  e.wday = val
-	when 'X'
-	  return unless _strptime_i(str, '%H:%M:%S', e)
-	when 'x'
-	  return unless _strptime_i(str, '%m/%d/%y', e)
-	when 'Y'
-	  return unless str.sub!(if num_pattern?($')
-				 then /\A([-+]?\d{1,4})/
-				 else /\A([-+]?\d{1,})/
-				 end, '')
-	  val = $1.to_i
-	  e.year = val
-	when 'y'
-	  return unless str.sub!(/\A(\d{1,2})/, '')
-	val = $1.to_i
-	return unless (0..99) === val
-	  e.year = val
-	  e._cent ||= if val >= 69 then 19 else 20 end
-	when 'Z', /\A:{0,3}z/
-	  return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
-				    |[a-z.\s]+(?:standard|daylight)\s+time\b
-				    |[a-z]+(?:\s+dst)?\b
-				    )/ix, '')
-	val = $1
-	  e.zone = val
-	offset = zone_to_diff(val)
-	  e.offset = offset
-	when '%'
-	  return unless str.sub!(/\A%/, '')
-	when '+'
-	  return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e)
-	when '1'
-	if $VERBOSE
-	    warn("warning: strptime: %1 is deprecated; forget this")
-	end
-	  return unless str.sub!(/\A(\d+)/, '')
-	val = $1.to_i
-	  e.jd = val
-	when '2'
-	if $VERBOSE
-	    warn("warning: strptime: %2 is deprecated; use '%Y-%j'")
-	end
-	  return unless _strptime_i(str, '%Y-%j', e)
-	when '3'
-	if $VERBOSE
-	    warn("warning: strptime: %3 is deprecated; use '%F'")
-	  end
-	  return unless _strptime_i(str, '%F', e)
-	else
-	  return unless str.sub!(Regexp.new('\\A' + Regexp.quote(s)), '')
-	end
-      else
-	case c
-	when /\A[\s\v]/
-	  str.sub!(/\A[\s\v]+/, '')
-      else
-	return unless str.sub!(Regexp.new('\\A' + Regexp.quote(c)), '')
-      end
-    end
-    end
-  end
-
-  private_class_method :_strptime_i
-
-  def self._strptime(str, fmt='%F')
-    e = Format::Bag.new
-    return unless _strptime_i(str.dup, fmt, e)
-
-    if e._cent
-      if e.cwyear
-	e.cwyear += e._cent * 100
-      end
-      if e.year
-	e.  year += e._cent * 100
-      end
-    end
-
-    if e._merid
-      if e.hour
-	e.hour %= 12
-	e.hour += e._merid
-      end
-    end
-
-    e.to_hash
-  end
-
-  def self.s3e(e, y, m, d, bc=false)
-    unless String === m
-      m = m.to_s
-    end
-
-    if y == nil
-      if d && d.size > 2
-	y = d
-	d = nil
-      end
-      if d && d[0,1] == "'"
-	y = d
-	d = nil
-      end
-  end
-
-    if y
-      y.scan(/(\d+)(.+)?/)
-      if $2
-	y, d = d, $1
-      end
-    end
-
-    if m
-      if m[0,1] == "'" || m.size > 2
-	y, m, d = m, d, y # us -> be
-      end
-    end
-
-    if d
-      if d[0,1] == "'" || d.size > 2
-	y, d = d, y
-      end
-    end
-
-    if y
-      y =~ /([-+])?(\d+)/
-      if $1 || $2.size > 2
-	c = false
-      end
-      iy = $&.to_i
-      if bc
-	iy = -iy + 1
-      end
-      e.year = iy
-    end
-
-    if m
-      m =~ /\d+/
-      e.mon = $&.to_i
-    end
-
-    if d
-      d =~ /\d+/
-      e.mday = $&.to_i
-    end
-
-    if c != nil
-      e._comp = c
-    end
-
-  end
-
-  private_class_method :s3e
-
-  def self._parse_day(str, e) # :nodoc:
-    if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/ino, ' ')
-      e.wday = Format::ABBR_DAYS[$1.downcase]
-      true
-=begin
-    elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/in, ' ')
-      e.wday = %w(su mo tu we th fr sa).index($1.downcase)
-      true
-=end
-    end
-    end
-
-  def self._parse_time(str, e) # :nodoc:
-    if str.sub!(
-		/(
-		 (?:
-		     \d+\s*:\s*\d+
-		     (?:
-		       \s*:\s*\d+(?:[,.]\d*)?
-		 )?
-		   |
-		     \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
-		   )
-		 (?:
-		   \s*
-		     [ap](?:m\b|\.m\.)
-		 )?
-		 |
-		   \d+\s*[ap](?:m\b|\.m\.)
-		 )
-		 (?:
-		   \s*
-		   (
-		     (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
-		   |
-		     [a-z.\s]+(?:standard|daylight)\stime\b
-		   |
-		     [a-z]+(?:\sdst)?\b
-		   )
-		 )?
-		/inx,
-		' ')
-
-      t = $1
-      e.zone = $2 if $2
-
-      t =~ /\A(\d+)h?
-	      (?:\s*:?\s*(\d+)m?
-		(?:
-		  \s*:?\s*(\d+)(?:[,.](\d+))?s?
-		)?
-	      )?
-	    (?:\s*([ap])(?:m\b|\.m\.))?/inx
-
-      e.hour = $1.to_i
-      e.min = $2.to_i if $2
-      e.sec = $3.to_i if $3
-      e.sec_fraction = $4.to_i.to_r / (10**$4.size) if $4
-
-      if $5
-	e.hour %= 12
-	if $5.downcase == 'p'
-	  e.hour += 12
-	end
-      end
-      true
-	end
-      end
-
-  def self._parse_beat(str, e) # :nodoc:
-    if str.sub!(/ \s*(\d+)(?:[,.](\d*))?/, ' ')
-      beat = $1.to_i.to_r
-      beat += $2.to_i.to_r / (10**$2.size) if $2
-      secs = beat.to_r / 1000
-      h, min, s, fr = self.day_fraction_to_time(secs)
-      e.hour = h
-      e.min = min
-      e.sec = s
-      e.sec_fraction = fr * 86400
-      e.zone = '+01:00'
-      true
-      end
-    end
-
-  def self._parse_eu(str, e) # :nodoc:
-    if str.sub!(
-		/'?(\d+)[^-\d\s]*
-		 \s*
-		 (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
-		 (?:
-		   \s*
-		   (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
-		   \s*
-		   ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
-		 )?
-		/inox,
-		' ') # '
-      s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
-	  $3 && $3[0,1].downcase == 'b')
-      true
-	end
-      end
-
-  def self._parse_us(str, e) # :nodoc:
-    if str.sub!(
-		/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
-		 \s*
-		 ('?\d+)[^-\d\s']*
-		    (?:
-		   \s*
-		   (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
-		   \s*
-		   ('?-?\d+)
-		    )?
-		   /inox,
-		' ') # '
-      s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
-	  $3 && $3[0,1].downcase == 'b')
-      true
-	end
-      end
-
-  def self._parse_iso(str, e) # :nodoc:
-    if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/n, ' ')
-      s3e(e, $1, $2, $3)
-      true
-    end
-  end
-
-  def self._parse_iso2(str, e) # :nodoc:
-    if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d+))?/in, ' ')
-      e.cwyear = $1.to_i if $1
-      e.cweek = $2.to_i
-      e.cwday = $3.to_i if $3
-      true
-    elsif str.sub!(/--(\d{2})-(\d{2})\b/n, ' ')
-      e.mon = $1.to_i
-      e.mday = $2.to_i
-      true
-    elsif str.sub!(/\b(\d{2}|\d{4})-(\d{2,3})\b/n, ' ')
-      e.year = $1.to_i
-      if $2.size < 3
-	e.mon = $2.to_i
-      else
-	e.yday = $2.to_i
-      end
-      true
-    end
-      end
-
-  def self._parse_jis(str, e) # :nodoc:
-    if str.sub!(/\b([MTSH])(\d+)\.(\d+)\.(\d+)/in, ' ')
-      era = { 'm'=>1867,
-	    't'=>1911,
-	    's'=>1925,
-	    'h'=>1988
-	  }[$1.downcase]
-      e.year = $2.to_i + era
-      e.mon = $3.to_i
-      e.mday = $4.to_i
-      true
-    end
-  end
-
-  def self._parse_vms(str, e) # :nodoc:
-    if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
-		-('?-?\d+)/inox, ' ')
-      s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
-      true
-    elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
-		-('?-?\d+)(?:-('?-?\d+))?/inox, ' ')
-      s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
-      true
-	end
-      end
-
-  def self._parse_sla_ja(str, e) # :nodoc:
-    if str.sub!(%r|('?-?\d+)[/.]\s*('?\d+)(?:[^\d]\s*('?-?\d+))?|n, ' ') # '
-      s3e(e, $1, $2, $3)
-      true
-    end
-      end
-
-  def self._parse_sla_eu(str, e) # :nodoc:
-    if str.sub!(%r|('?-?\d+)[/.]\s*('?\d+)(?:[^\d]\s*('?-?\d+))?|n, ' ') # '
-      s3e(e, $3, $2, $1)
-      true
-    end
-  end
-
-  def self._parse_sla_us(str, e) # :nodoc:
-    if str.sub!(%r|('?-?\d+)[/.]\s*('?\d+)(?:[^\d]\s*('?-?\d+))?|n, ' ') # '
-      s3e(e, $3, $1, $2)
-      true
-    end
-  end
-
-  def self._parse_year(str, e) # :nodoc:
-    if str.sub!(/'(\d+)\b/in, ' ')
-      e.year = $1.to_i
-      true
-    end
-  end
-
-  def self._parse_mon(str, e) # :nodoc:
-    if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/ino, ' ')
-      e.mon = Format::ABBR_MONTHS[$1.downcase]
-      true
-    end
-  end
-
-  def self._parse_mday(str, e) # :nodoc:
-    if str.sub!(/(\d+)(st|nd|rd|th)\b/in, ' ')
-      e.mday = $1.to_i
-      true
-    end
-  end
-
-  def self._parse_ddd(str, e) # :nodoc:
-    if str.sub!(
-		/([-+]?)(\d{2,14})
-		    (?:
-		      \s*
-		      T?
-		      \s*
-		      (\d{2,6})(?:[,.](\d*))?
-		    )?
-		    (?:
-		      \s*
-		      (
-			Z
-		      |
-		      [-+]\d{1,4}
-		      )
-		      \b
-		    )?
-		/inx,
-		   ' ')
-      case $2.size
-      when 2
-	e.mday = $2[ 0, 2].to_i
-      when 4
-	e.mon  = $2[ 0, 2].to_i
-	e.mday = $2[ 2, 2].to_i
-      when 6
-	e.year = ($1 + $2[ 0, 2]).to_i
-	e.mon  = $2[ 2, 2].to_i
-	e.mday = $2[ 4, 2].to_i
-      when 8, 10, 12, 14
-	e.year = ($1 + $2[ 0, 4]).to_i
-	e.mon  = $2[ 4, 2].to_i
-	e.mday = $2[ 6, 2].to_i
-	e.hour = $2[ 8, 2].to_i if $2.size >= 10
-	e.min  = $2[10, 2].to_i if $2.size >= 12
-	e.sec  = $2[12, 2].to_i if $2.size >= 14
-	e._comp = false
-      when 3
-	e.yday = $2[ 0, 3].to_i
-      when 5
-	e.year = ($1 + $2[ 0, 2]).to_i
-	e.yday = $2[ 2, 3].to_i
-      when 7
-	e.year = ($1 + $2[ 0, 4]).to_i
-	e.yday = $2[ 4, 3].to_i
-      end
-      if $3
-	case $3.size
-	when 2, 4, 6
-	  e.hour = $3[ 0, 2].to_i
-	  e.min  = $3[ 2, 2].to_i if $3.size >= 4
-	  e.sec  = $3[ 4, 2].to_i if $3.size >= 6
-	end
-      end
-      if $4
-	e.sec_fraction = $4.to_i.to_r / (10**$4.size)
-      end
-      if $5
-	e.zone = $5
-      end
-      true
-    end
-  end
-
-  private_class_method :_parse_day, :_parse_time, :_parse_beat,
-	:_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
-	:_parse_jis, :_parse_vms,
-	:_parse_sla_ja, :_parse_sla_eu, :_parse_sla_us,
-	:_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
-
-  def self._parse(str, comp=false)
-    str = str.dup
-
-    e = Format::Bag.new
-
-    e._comp = comp
-
-    str.gsub!(/[^-+',.\/:0-9@a-z\x80-\xff]+/in, ' ')
-
-    _parse_time(str, e) # || _parse_beat(str, e)
-    _parse_day(str, e)
-
-    _parse_eu(str, e)     ||
-    _parse_us(str, e)     ||
-    _parse_iso(str, e)    ||
-    _parse_jis(str, e)    ||
-    _parse_vms(str, e)    ||
-    _parse_sla_us(str, e) ||
-    _parse_iso2(str, e)   ||
-    _parse_year(str, e)   ||
-    _parse_mon(str, e)    ||
-    _parse_mday(str, e)   ||
-    _parse_ddd(str, e)
-
-    if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/in, ' ')
-      if e.year
-	e.year = -e.year + 1
-      end
-    end
-
-    if str.sub!(/\A\s*(\d{1,2})\s*\z/n, ' ')
-      if e.hour && !e.mday
-	v = $1.to_i
-	if (1..31) === v
-	  e.mday = v
-	end
-      end
-      if e.mday && !e.hour
-	v = $1.to_i
-	if (0..24) === v
-	  e.hour = v
-	end
-    end
-  end
-
-    if e._comp and e.year
-      if e.year >= 0 and e.year <= 99
-	if e.year >= 69
-	  e.year += 1900
-	else
-	  e.year += 2000
-	end
-    end
-  end
-
-    e.offset ||= zone_to_diff(e.zone) if e.zone
-
-    e.to_hash
-	end
-
-  def self.zone_to_diff(zone) # :nodoc:
-    zone = zone.downcase
-    if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
-      dst = $1 == 'daylight'
-    else
-      dst = zone.sub!(/\s+dst\z/, '')
-	end
-    if Format::ZONES.include?(zone)
-      offset = Format::ZONES[zone]
-      offset += 3600 if dst
-    elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
-      sign = $1
-      if zone.include?(':')
-	hour, min, sec, = zone.split(':')
-      elsif zone.include?(',') || zone.include?('.')
-	hour, fr, = zone.split(/[,.]/)
-	min = fr.to_i.to_r / (10**fr.size) * 60
-      else
-	case zone.size
-	when 3
-	  hour = zone[0,1]
-	  min = zone[1,2]
-	else
-	  hour = zone[0,2]
-	  min = zone[2,2]
-	  sec = zone[4,2]
-	end
-      end
-      offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
-      offset *= -1 if sign == '-'
-    end
-    offset
-  end
-
-end
-
-class DateTime < Date
-
-  def strftime(fmt='%FT%T%:z')
-    super(fmt)
-  end
-
-  def self._strptime(str, fmt='%FT%T%z')
-    super(str, fmt)
-  end
-
-=begin
-  def iso8601_timediv(n) # :nodoc:
-    strftime('T%T' +
-	     if n < 1
-	       ''
-	     else
-	       '.%0*d' % [n, (sec_fraction / (1.to_r/86400/(10**n))).round]
-	     end +
-	     '%:z')
-  end
-
-  private :iso8601_timediv
-
-  def iso8601(n=0)
-    super() + iso8601_timediv(n)
-  end
-
-  def jisx0301(n=0)
-    super() + iso8601_timediv(n)
-  end
-=end
-
-end
+# format.rb: Written by Tadayoshi Funaba 1999-2006
+# $Id: format.rb,v 2.29 2006-12-30 21:43:41+09 tadf Exp $
+
+require 'rational'
+
+class Date
+
+  module Format # :nodoc:
+
+    MONTHS = {
+      'january'  => 1, 'february' => 2, 'march'    => 3, 'april'    => 4,
+      'may'      => 5, 'june'     => 6, 'july'     => 7, 'august'   => 8,
+      'september'=> 9, 'october'  =>10, 'november' =>11, 'december' =>12
+    }
+
+    DAYS = {
+      'sunday'   => 0, 'monday'   => 1, 'tuesday'  => 2, 'wednesday'=> 3,
+      'thursday' => 4, 'friday'   => 5, 'saturday' => 6
+    }
+
+    ABBR_MONTHS = {
+      'jan'      => 1, 'feb'      => 2, 'mar'      => 3, 'apr'      => 4,
+      'may'      => 5, 'jun'      => 6, 'jul'      => 7, 'aug'      => 8,
+      'sep'      => 9, 'oct'      =>10, 'nov'      =>11, 'dec'      =>12
+    }
+
+    ABBR_DAYS = {
+      'sun'      => 0, 'mon'      => 1, 'tue'      => 2, 'wed'      => 3,
+      'thu'      => 4, 'fri'      => 5, 'sat'      => 6
+    }
+
+    ZONES = {
+      'ut'  =>  0*3600, 'gmt' =>  0*3600, 'est' => -5*3600, 'edt' => -4*3600,
+      'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
+      'pst' => -8*3600, 'pdt' => -7*3600,
+      'a'   =>  1*3600, 'b'   =>  2*3600, 'c'   =>  3*3600, 'd'   =>  4*3600,
+      'e'   =>  5*3600, 'f'   =>  6*3600, 'g'   =>  7*3600, 'h'   =>  8*3600,
+      'i'   =>  9*3600, 'k'   => 10*3600, 'l'   => 11*3600, 'm'   => 12*3600,
+      'n'   => -1*3600, 'o'   => -2*3600, 'p'   => -3*3600, 'q'   => -4*3600,
+      'r'   => -5*3600, 's'   => -6*3600, 't'   => -7*3600, 'u'   => -8*3600,
+      'v'   => -9*3600, 'w'   =>-10*3600, 'x'   =>-11*3600, 'y'   =>-12*3600,
+      'z'   =>  0*3600,
+      'utc' =>  0*3600, 'wet' =>  0*3600, 'bst' =>  1*3600, 'wat' => -1*3600,
+      'at'  => -2*3600, 'ast' => -4*3600, 'adt' => -3*3600, 'yst' => -9*3600,
+      'ydt' => -8*3600, 'hst' =>-10*3600, 'hdt' => -9*3600, 'cat' =>-10*3600,
+      'ahst'=>-10*3600, 'nt'  =>-11*3600, 'idlw'=>-12*3600, 'cet' =>  1*3600,
+      'met' =>  1*3600, 'mewt'=>  1*3600, 'mest'=>  2*3600, 'mesz'=>  2*3600,
+      'swt' =>  1*3600, 'sst' =>  2*3600, 'fwt' =>  1*3600, 'fst' =>  2*3600,
+      'eet' =>  2*3600, 'bt'  =>  3*3600, 'zp4' =>  4*3600, 'zp5' =>  5*3600,
+      'zp6' =>  6*3600, 'wast'=>  7*3600, 'wadt'=>  8*3600, 'cct' =>  8*3600,
+      'jst' =>  9*3600, 'east'=> 10*3600, 'eadt'=> 11*3600, 'gst' => 10*3600,
+      'nzt' => 12*3600, 'nzst'=> 12*3600, 'nzdt'=> 13*3600, 'idle'=> 12*3600,
+
+      'afghanistan'           =>   16200, 'alaskan'               =>  -32400,
+      'arab'                  =>   10800, 'arabian'               =>   14400,
+      'arabic'                =>   10800, 'atlantic'              =>  -14400,
+      'aus central'           =>   34200, 'aus eastern'           =>   36000,
+      'azores'                =>   -3600, 'canada central'        =>  -21600,
+      'cape verde'            =>   -3600, 'caucasus'              =>   14400,
+      'cen. australia'        =>   34200, 'central america'       =>  -21600,
+      'central asia'          =>   21600, 'central europe'        =>    3600,
+      'central european'      =>    3600, 'central pacific'       =>   39600,
+      'central'               =>  -21600, 'china'                 =>   28800,
+      'dateline'              =>  -43200, 'e. africa'             =>   10800,
+      'e. australia'          =>   36000, 'e. europe'             =>    7200,
+      'e. south america'      =>  -10800, 'eastern'               =>  -18000,
+      'egypt'                 =>    7200, 'ekaterinburg'          =>   18000,
+      'fiji'                  =>   43200, 'fle'                   =>    7200,
+      'greenland'             =>  -10800, 'greenwich'             =>       0,
+      'gtb'                   =>    7200, 'hawaiian'              =>  -36000,
+      'india'                 =>   19800, 'iran'                  =>   12600,
+      'jerusalem'             =>    7200, 'korea'                 =>   32400,
+      'mexico'                =>  -21600, 'mid-atlantic'          =>   -7200,
+      'mountain'              =>  -25200, 'myanmar'               =>   23400,
+      'n. central asia'       =>   21600, 'nepal'                 =>   20700,
+      'new zealand'           =>   43200, 'newfoundland'          =>  -12600,
+      'north asia east'       =>   28800, 'north asia'            =>   25200,
+      'pacific sa'            =>  -14400, 'pacific'               =>  -28800,
+      'romance'               =>    3600, 'russian'               =>   10800,
+      'sa eastern'            =>  -10800, 'sa pacific'            =>  -18000,
+      'sa western'            =>  -14400, 'samoa'                 =>  -39600,
+      'se asia'               =>   25200, 'malay peninsula'       =>   28800,
+      'south africa'          =>    7200, 'sri lanka'             =>   21600,
+      'taipei'                =>   28800, 'tasmania'              =>   36000,
+      'tokyo'                 =>   32400, 'tonga'                 =>   46800,
+      'us eastern'            =>  -18000, 'us mountain'           =>  -25200,
+      'vladivostok'           =>   36000, 'w. australia'          =>   28800,
+      'w. central africa'     =>    3600, 'w. europe'             =>    3600,
+      'west asia'             =>   18000, 'west pacific'          =>   36000,
+      'yakutsk'               =>   32400
+    }
+
+    [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x|
+      x.freeze
+    end
+
+    class Bag # :nodoc:
+
+      def method_missing(t, *args, &block)
+	t = t.to_s
+	set = t.chomp!('=')
+	t = '@' + t
+	if set
+	  instance_variable_set(t, *args)
+	else
+	  if instance_variables.include?(t)
+	    instance_variable_get(t)
+	  end
+	end
+      end
+
+      def to_hash
+	instance_variables.
+	  select{|n| !instance_variable_get(n).nil?}.grep(/\A@[^_]/).
+	  inject({}){|r, n| r[n[1..-1].intern] = instance_variable_get(n); r}
+      end
+
+    end
+
+  end
+
+  def emit(e, f) # :nodoc:
+    case e
+    when Numeric
+      sign = %w(+ + -)[e <=> 0]
+      e = e.abs
+    end
+
+    s = e.to_s
+
+    if f[:s] && f[:p] == '0'
+      f[:w] -= 1
+    end
+
+    if f[:s] && f[:p] == "\s"
+      s[0,0] = sign
+    end
+
+    if f[:p] != '-'
+      s = s.rjust(f[:w], f[:p])
+    end
+
+    if f[:s] && f[:p] != "\s"
+      s[0,0] = sign
+    end
+
+    s = s.upcase if f[:u]
+    s = s.downcase if f[:d]
+    s
+  end
+
+  def emit_w(e, w, f) # :nodoc:
+    f[:w] = [f[:w], w].compact.max
+    emit(e, f)
+  end
+
+  def emit_n(e, w, f) # :nodoc:
+    f[:p] ||= '0'
+    emit_w(e, w, f)
+  end
+
+  def emit_sn(e, w, f) # :nodoc:
+    if e < 0
+      w += 1
+      f[:s] = true
+    end
+    emit_n(e, w, f)
+  end
+
+  def emit_z(e, w, f) # :nodoc:
+    w += 1
+    f[:s] = true
+    emit_n(e, w, f)
+  end
+
+  def emit_a(e, w, f) # :nodoc:
+    f[:p] ||= "\s"
+    emit_w(e, w, f)
+  end
+
+  def emit_ad(e, w, f) # :nodoc:
+    if f[:x]
+      f[:u] = true
+      f[:d] = false
+    end
+    emit_a(e, w, f)
+  end
+
+  def emit_au(e, w, f) # :nodoc:
+    if f[:x]
+      f[:u] = false
+      f[:d] = true
+    end
+    emit_a(e, w, f)
+  end
+
+  private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
+	  :emit_a, :emit_ad, :emit_au
+
+  def strftime(fmt='%F')
+    fmt.gsub(/%([-_0^#]+)?(\d+)?[EO]?(:{1,3}z|.)/m) do |m|
+      f = {}
+      s, w, c = $1, $2, $3
+      if s
+	s.scan(/./) do |k|
+	  case k
+	  when '-'; f[:p] = '-'
+	  when '_'; f[:p] = "\s"
+	  when '0'; f[:p] = '0'
+	  when '^'; f[:u] = true
+	  when '#'; f[:x] = true
+	  end
+	end
+      end
+      if w
+	f[:w] = w.to_i
+      end
+      case c
+      when 'A'; emit_ad(DAYNAMES[wday], 0, f)
+      when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
+      when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
+      when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
+      when 'C'; emit_sn((year / 100).floor, 2, f)
+      when 'c'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
+      when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
+      when 'd'; emit_n(mday, 2, f)
+      when 'e'; emit_a(mday, 2, f)
+      when 'F'
+	if m == '%F'
+	  format('%.4d-%02d-%02d', year, mon, mday) # 4p
+	else
+	  emit_a(strftime('%Y-%m-%d'), 0, f)
+	end
+      when 'G'; emit_sn(cwyear, 4, f)
+      when 'g'; emit_n(cwyear % 100, 2, f)
+      when 'H'; emit_n(hour, 2, f)
+      when 'h'; emit_ad(strftime('%b'), 0, f)
+      when 'I'; emit_n((hour % 12).nonzero? || 12, 2, f)
+      when 'j'; emit_n(yday, 3, f)
+      when 'k'; emit_a(hour, 2, f)
+      when 'L'
+	emit_n((sec_fraction / (1.to_r/(10**3))).round, 3, f)
+      when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
+      when 'M'; emit_n(min, 2, f)
+      when 'm'; emit_n(mon, 2, f)
+      when 'N'
+	emit_n((sec_fraction / (1.to_r/(10**9))).round, 9, f)
+      when 'n'; "\n"
+      when 'P'; emit_ad(strftime('%p').downcase, 0, f)
+      when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
+      when 'Q'
+	d = ajd - jd_to_ajd(self.class::UNIXEPOCH, 0)
+	s = (d * 86400*10**3).to_i
+	emit_sn(s, 1, f)
+      when 'R'; emit_a(strftime('%H:%M'), 0, f)
+      when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
+      when 'S'; emit_n(sec, 2, f)
+      when 's'
+	d = ajd - jd_to_ajd(self.class::UNIXEPOCH, 0)
+	s = (d * 86400).to_i
+	emit_sn(s, 1, f)
+      when 'T'
+	if m == '%T'
+	  format('%02d:%02d:%02d', hour, min, sec) # 4p
+	else
+	  emit_a(strftime('%H:%M:%S'), 0, f)
+	end
+      when 't'; "\t"
+      when 'U', 'W'
+	emit_n(if c == 'U' then wnum0 else wnum1 end, 2, f)
+      when 'u'; emit_n(cwday, 1, f)
+      when 'V'; emit_n(cweek, 2, f)
+      when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
+      when 'w'; emit_n(wday, 1, f)
+      when 'X'; emit_a(strftime('%H:%M:%S'), 0, f)
+      when 'x'; emit_a(strftime('%m/%d/%y'), 0, f)
+      when 'Y'; emit_sn(year, 4, f)
+      when 'y'; emit_n(year % 100, 2, f)
+      when 'Z'; emit_au(strftime('%:z'), 0, f)
+      when /\A(:{0,3})z/
+	t = $1.size
+	sign = if offset < 0 then -1 else +1 end
+	fr = offset.abs
+	hh, fr = fr.divmod(1.to_r/24)
+	mm, fr = fr.divmod(1.to_r/1440)
+	ss, fr = fr.divmod(1.to_r/86400)
+	if t == 3
+	  if    ss.nonzero? then t =  2
+	  elsif mm.nonzero? then t =  1
+	  else                   t = -1
+	  end
+	end
+	case t
+	when -1
+	  tail = []
+	  sep = ''
+	when 0
+	  f[:w] -= 2 if f[:w]
+	  tail = ['%02d' % mm]
+	  sep = ''
+	when 1
+	  f[:w] -= 3 if f[:w]
+	  tail = ['%02d' % mm]
+	  sep = ':'
+	when 2
+	  f[:w] -= 6 if f[:w]
+	  tail = ['%02d' % mm, '%02d' % ss]
+	  sep = ':'
+	end
+	([emit_z(sign * hh, 2, f)] + tail).join(sep)
+      when '%'; emit_a('%', 0, f)
+      when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
+      else
+	c
+      end
+    end
+  end
+
+# alias_method :format, :strftime
+
+  def asctime() strftime('%c') end
+
+  alias_method :ctime, :asctime
+
+  def iso8601() strftime('%F') end
+
+  def rfc3339() iso8601 end
+
+  def rfc2822() strftime('%a, %-d %b %Y %T %z') end
+
+  alias_method :rfc822, :rfc2822
+
+  def jisx0301
+    if jd < 2405160
+      iso8601
+    else
+      case jd
+      when 2405160...2419614
+	g = 'M%02d' % (year - 1867)
+      when 2419614...2424875
+	g = 'T%02d' % (year - 1911)
+      when 2424875...2447535
+	g = 'S%02d' % (year - 1925)
+      else
+	g = 'H%02d' % (year - 1988)
+      end
+      g + strftime('.%m.%d')
+    end
+  end
+
+=begin
+  def beat(n=0)
+    i, f = (new_offset(1.to_r/24).day_fraction * 1000).divmod(1)
+    ('@%03d' % i) +
+      if n < 1
+	''
+      else
+	'.%0*d' % [n, (f / (1.to_r/(10**n))).round]
+      end
+  end
+=end
+
+  def self.num_pattern? (s) # :nodoc:
+    /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s
+  end
+
+  private_class_method :num_pattern?
+
+  def self._strptime_i(str, fmt, e) # :nodoc:
+    fmt.scan(/%[EO]?(:{1,3}z|.)|(.)/m) do |s, c|
+      if s
+	case s
+	when 'A', 'a'
+	  return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') ||
+			str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '')
+	  val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase]
+	  return unless val
+	  e.wday = val
+	when 'B', 'b', 'h'
+	  return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') ||
+			str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '')
+	  val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase]
+	  return unless val
+	  e.mon = val
+	when 'C'
+	  return unless str.sub!(if num_pattern?($')
+				 then /\A([-+]?\d{1,2})/
+				 else /\A([-+]?\d{1,})/
+				 end, '')
+	  val = $1.to_i
+	  e._cent = val
+	when 'c'
+	  return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e)
+	when 'D'
+	  return unless _strptime_i(str, '%m/%d/%y', e)
+	when 'd', 'e'
+	  return unless str.sub!(/\A( \d|\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (1..31) === val
+	  e.mday = val
+	when 'F'
+	  return unless _strptime_i(str, '%Y-%m-%d', e)
+	when 'G'
+	  return unless str.sub!(if num_pattern?($')
+				 then /\A([-+]?\d{1,4})/
+				 else /\A([-+]?\d{1,})/
+				 end, '')
+	  val = $1.to_i
+	  e.cwyear = val
+	when 'g'
+	  return unless str.sub!(/\A(\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (0..99) === val
+	  e.cwyear = val
+	  e._cent ||= if val >= 69 then 19 else 20 end
+	when 'H', 'k'
+	  return unless str.sub!(/\A( \d|\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (0..24) === val
+	  e.hour = val
+	when 'I', 'l'
+	  return unless str.sub!(/\A( \d|\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (1..12) === val
+	  e.hour = val
+	when 'j'
+	  return unless str.sub!(/\A(\d{1,3})/, '')
+	  val = $1.to_i
+	  return unless (1..366) === val
+	  e.yday = val
+	when 'L'
+	  return unless str.sub!(if num_pattern?($')
+				 then /\A([-+]?\d{1,3})/
+				 else /\A([-+]?\d{1,})/
+				 end, '')
+#	  val = $1.to_i.to_r / (10**3)
+	  val = $1.to_i.to_r / (10**$1.size)
+	  e.sec_fraction = val
+	when 'M'
+	  return unless str.sub!(/\A(\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (0..59) === val
+	  e.min = val
+	when 'm'
+	  return unless str.sub!(/\A(\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (1..12) === val
+	  e.mon = val
+	when 'N'
+	  return unless str.sub!(if num_pattern?($')
+				 then /\A([-+]?\d{1,9})/
+				 else /\A([-+]?\d{1,})/
+				 end, '')
+#	  val = $1.to_i.to_r / (10**9)
+	  val = $1.to_i.to_r / (10**$1.size)
+	  e.sec_fraction = val
+	when 'n', 't'
+	  return unless _strptime_i(str, "\s", e)
+	when 'P', 'p'
+	  return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '')
+	  e._merid = if $1.downcase == 'a' then 0 else 12 end
+	when 'Q'
+	  return unless str.sub!(/\A(-?\d{1,})/, '')
+	  val = $1.to_i.to_r / 10**3
+	  e.seconds = val
+	when 'R'
+	  return unless _strptime_i(str, '%H:%M', e)
+	when 'r'
+	  return unless _strptime_i(str, '%I:%M:%S %p', e)
+	when 'S'
+	  return unless str.sub!(/\A(\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (0..60) === val
+	  e.sec = val
+	when 's'
+	  return unless str.sub!(/\A(-?\d{1,})/, '')
+	  val = $1.to_i
+	  e.seconds = val
+	when 'T'
+	  return unless _strptime_i(str, '%H:%M:%S', e)
+	when 'U', 'W'
+	  return unless str.sub!(/\A(\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (0..53) === val
+	  e.__send__(if s == 'U' then :wnum0= else :wnum1= end, val)
+	when 'u'
+	  return unless str.sub!(/\A(\d{1})/, '')
+	  val = $1.to_i
+	  return unless (1..7) === val
+	  e.cwday = val
+	when 'V'
+	  return unless str.sub!(/\A(\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (1..53) === val
+	  e.cweek = val
+	when 'v'
+	  return unless _strptime_i(str, '%e-%b-%Y', e)
+	when 'w'
+	  return unless str.sub!(/\A(\d{1})/, '')
+	  val = $1.to_i
+	  return unless (0..6) === val
+	  e.wday = val
+	when 'X'
+	  return unless _strptime_i(str, '%H:%M:%S', e)
+	when 'x'
+	  return unless _strptime_i(str, '%m/%d/%y', e)
+	when 'Y'
+	  return unless str.sub!(if num_pattern?($')
+				 then /\A([-+]?\d{1,4})/
+				 else /\A([-+]?\d{1,})/
+				 end, '')
+	  val = $1.to_i
+	  e.year = val
+	when 'y'
+	  return unless str.sub!(/\A(\d{1,2})/, '')
+	  val = $1.to_i
+	  return unless (0..99) === val
+	  e.year = val
+	  e._cent ||= if val >= 69 then 19 else 20 end
+	when 'Z', /\A:{0,3}z/
+	  return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
+				    |[a-z.\s]+(?:standard|daylight)\s+time\b
+				    |[a-z]+(?:\s+dst)?\b
+				    )/ix, '')
+	  val = $1
+	  e.zone = val
+	  offset = zone_to_diff(val)
+	  e.offset = offset
+	when '%'
+	  return unless str.sub!(/\A%/, '')
+	when '+'
+	  return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e)
+	else
+	  return unless str.sub!(Regexp.new('\\A' + Regexp.quote(s)), '')
+	end
+      else
+	case c
+	when /\A[\s\v]/
+	  str.sub!(/\A[\s\v]+/, '')
+	else
+	  return unless str.sub!(Regexp.new('\\A' + Regexp.quote(c)), '')
+	end
+      end
+    end
+  end
+
+  private_class_method :_strptime_i
+
+  def self._strptime(str, fmt='%F')
+    e = Format::Bag.new
+    return unless _strptime_i(str.dup, fmt, e)
+
+    if e._cent
+      if e.cwyear
+	e.cwyear += e._cent * 100
+      end
+      if e.year
+	e.  year += e._cent * 100
+      end
+    end
+
+    if e._merid
+      if e.hour
+	e.hour %= 12
+	e.hour += e._merid
+      end
+    end
+
+    e.to_hash
+  end
+
+  def self.s3e(e, y, m, d, bc=false)
+    unless String === m
+      m = m.to_s
+    end
+
+    if y == nil
+      if d && d.size > 2
+	y = d
+	d = nil
+      end
+      if d && d[0,1] == "'"
+	y = d
+	d = nil
+      end
+    end
+
+    if y
+      y.scan(/(\d+)(.+)?/)
+      if $2
+	y, d = d, $1
+      end
+    end
+
+    if m
+      if m[0,1] == "'" || m.size > 2
+	y, m, d = m, d, y # us -> be
+      end
+    end
+
+    if d
+      if d[0,1] == "'" || d.size > 2
+	y, d = d, y
+      end
+    end
+
+    if y
+      y =~ /([-+])?(\d+)/
+      if $1 || $2.size > 2
+	c = false
+      end
+      iy = $&.to_i
+      if bc
+	iy = -iy + 1
+      end
+      e.year = iy
+    end
+
+    if m
+      m =~ /\d+/
+      e.mon = $&.to_i
+    end
+
+    if d
+      d =~ /\d+/
+      e.mday = $&.to_i
+    end
+
+    if c != nil
+      e._comp = c
+    end
+
+  end
+
+  private_class_method :s3e
+
+  def self._parse_day(str, e) # :nodoc:
+    if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/ino, ' ')
+      e.wday = Format::ABBR_DAYS[$1.downcase]
+      true
+=begin
+    elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/in, ' ')
+      e.wday = %w(su mo tu we th fr sa).index($1.downcase)
+      true
+=end
+    end
+  end
+
+  def self._parse_time(str, e) # :nodoc:
+    if str.sub!(
+		/(
+		   (?:
+		     \d+\s*:\s*\d+
+		     (?:
+		       \s*:\s*\d+(?:[,.]\d*)?
+		     )?
+		   |
+		     \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
+		   )
+		   (?:
+		     \s*
+		     [ap](?:m\b|\.m\.)
+		   )?
+		 |
+		   \d+\s*[ap](?:m\b|\.m\.)
+		 )
+		 (?:
+		   \s*
+		   (
+		     (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
+		   |
+		     [a-z.\s]+(?:standard|daylight)\stime\b
+		   |
+		     [a-z]+(?:\sdst)?\b
+		   )
+		 )?
+		/inx,
+		' ')
+
+      t = $1
+      e.zone = $2 if $2
+
+      t =~ /\A(\d+)h?
+	      (?:\s*:?\s*(\d+)m?
+		(?:
+		  \s*:?\s*(\d+)(?:[,.](\d+))?s?
+		)?
+	      )?
+	    (?:\s*([ap])(?:m\b|\.m\.))?/inx
+
+      e.hour = $1.to_i
+      e.min = $2.to_i if $2
+      e.sec = $3.to_i if $3
+      e.sec_fraction = $4.to_i.to_r / (10**$4.size) if $4
+
+      if $5
+	e.hour %= 12
+	if $5.downcase == 'p'
+	  e.hour += 12
+	end
+      end
+      true
+    end
+  end
+
+  def self._parse_beat(str, e) # :nodoc:
+    if str.sub!(/ \s*(\d+)(?:[,.](\d*))?/, ' ')
+      beat = $1.to_i.to_r
+      beat += $2.to_i.to_r / (10**$2.size) if $2
+      secs = beat.to_r / 1000
+      h, min, s, fr = self.day_fraction_to_time(secs)
+      e.hour = h
+      e.min = min
+      e.sec = s
+      e.sec_fraction = fr * 86400
+      e.zone = '+01:00'
+      true
+    end
+  end
+
+  def self._parse_eu(str, e) # :nodoc:
+    if str.sub!(
+		/'?(\d+)[^-\d\s]*
+		 \s*
+		 (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
+		 (?:
+		   \s*
+		   (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
+		   \s*
+		   ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
+		 )?
+		/inox,
+		' ') # '
+      s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
+	  $3 && $3[0,1].downcase == 'b')
+      true
+    end
+  end
+
+  def self._parse_us(str, e) # :nodoc:
+    if str.sub!(
+		/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
+		 \s*
+		 ('?\d+)[^-\d\s']*
+		 (?:
+		   \s*
+		   (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
+		   \s*
+		   ('?-?\d+)
+		 )?
+		/inox,
+		' ') # '
+      s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
+	  $3 && $3[0,1].downcase == 'b')
+      true
+    end
+  end
+
+  def self._parse_iso(str, e) # :nodoc:
+    if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/n, ' ')
+      s3e(e, $1, $2, $3)
+      true
+    end
+  end
+
+  def self._parse_iso2(str, e) # :nodoc:
+    if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d+))?/in, ' ')
+      e.cwyear = $1.to_i if $1
+      e.cweek = $2.to_i
+      e.cwday = $3.to_i if $3
+      true
+    elsif str.sub!(/--(\d{2})-(\d{2})\b/n, ' ')
+      e.mon = $1.to_i
+      e.mday = $2.to_i
+      true
+    elsif str.sub!(/\b(\d{2}|\d{4})-(\d{2,3})\b/n, ' ')
+      e.year = $1.to_i
+      if $2.size < 3
+	e.mon = $2.to_i
+      else
+	e.yday = $2.to_i
+      end
+      true
+    end
+  end
+
+  def self._parse_jis(str, e) # :nodoc:
+    if str.sub!(/\b([MTSH])(\d+)\.(\d+)\.(\d+)/in, ' ')
+      era = { 'm'=>1867,
+	      't'=>1911,
+	      's'=>1925,
+	      'h'=>1988
+	  }[$1.downcase]
+      e.year = $2.to_i + era
+      e.mon = $3.to_i
+      e.mday = $4.to_i
+      true
+    end
+  end
+
+  def self._parse_vms(str, e) # :nodoc:
+    if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
+		-('?-?\d+)/inox, ' ')
+      s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
+      true
+    elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
+		-('?-?\d+)(?:-('?-?\d+))?/inox, ' ')
+      s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
+      true
+    end
+  end
+
+  def self._parse_sla_ja(str, e) # :nodoc:
+    if str.sub!(%r|('?-?\d+)[/.]\s*('?\d+)(?:[^\d]\s*('?-?\d+))?|n, ' ') # '
+      s3e(e, $1, $2, $3)
+      true
+    end
+  end
+
+  def self._parse_sla_eu(str, e) # :nodoc:
+    if str.sub!(%r|('?-?\d+)[/.]\s*('?\d+)(?:[^\d]\s*('?-?\d+))?|n, ' ') # '
+      s3e(e, $3, $2, $1)
+      true
+    end
+  end
+
+  def self._parse_sla_us(str, e) # :nodoc:
+    if str.sub!(%r|('?-?\d+)[/.]\s*('?\d+)(?:[^\d]\s*('?-?\d+))?|n, ' ') # '
+      s3e(e, $3, $1, $2)
+      true
+    end
+  end
+
+  def self._parse_year(str, e) # :nodoc:
+    if str.sub!(/'(\d+)\b/in, ' ')
+      e.year = $1.to_i
+      true
+    end
+  end
+
+  def self._parse_mon(str, e) # :nodoc:
+    if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/ino, ' ')
+      e.mon = Format::ABBR_MONTHS[$1.downcase]
+      true
+    end
+  end
+
+  def self._parse_mday(str, e) # :nodoc:
+    if str.sub!(/(\d+)(st|nd|rd|th)\b/in, ' ')
+      e.mday = $1.to_i
+      true
+    end
+  end
+
+  def self._parse_ddd(str, e) # :nodoc:
+    if str.sub!(
+		/([-+]?)(\d{2,14})
+		  (?:
+		    \s*
+		    T?
+		    \s*
+		    (\d{2,6})(?:[,.](\d*))?
+		  )?
+		  (?:
+		    \s*
+		    (
+		      Z
+		    |
+		      [-+]\d{1,4}
+		    )
+		    \b
+		  )?
+		/inx,
+		' ')
+      case $2.size
+      when 2
+	e.mday = $2[ 0, 2].to_i
+      when 4
+	e.mon  = $2[ 0, 2].to_i
+	e.mday = $2[ 2, 2].to_i
+      when 6
+	e.year = ($1 + $2[ 0, 2]).to_i
+	e.mon  = $2[ 2, 2].to_i
+	e.mday = $2[ 4, 2].to_i
+      when 8, 10, 12, 14
+	e.year = ($1 + $2[ 0, 4]).to_i
+	e.mon  = $2[ 4, 2].to_i
+	e.mday = $2[ 6, 2].to_i
+	e.hour = $2[ 8, 2].to_i if $2.size >= 10
+	e.min  = $2[10, 2].to_i if $2.size >= 12
+	e.sec  = $2[12, 2].to_i if $2.size >= 14
+	e._comp = false
+      when 3
+	e.yday = $2[ 0, 3].to_i
+      when 5
+	e.year = ($1 + $2[ 0, 2]).to_i
+	e.yday = $2[ 2, 3].to_i
+      when 7
+	e.year = ($1 + $2[ 0, 4]).to_i
+	e.yday = $2[ 4, 3].to_i
+      end
+      if $3
+	case $3.size
+	when 2, 4, 6
+	  e.hour = $3[ 0, 2].to_i
+	  e.min  = $3[ 2, 2].to_i if $3.size >= 4
+	  e.sec  = $3[ 4, 2].to_i if $3.size >= 6
+	end
+      end
+      if $4
+	e.sec_fraction = $4.to_i.to_r / (10**$4.size)
+      end
+      if $5
+	e.zone = $5
+      end
+      true
+    end
+  end
+
+  private_class_method :_parse_day, :_parse_time, :_parse_beat,
+	:_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
+	:_parse_jis, :_parse_vms,
+	:_parse_sla_ja, :_parse_sla_eu, :_parse_sla_us,
+	:_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
+
+  def self._parse(str, comp=false)
+    str = str.dup
+
+    e = Format::Bag.new
+
+    e._comp = comp
+
+    str.gsub!(/[^-+',.\/:0-9@a-z\x80-\xff]+/in, ' ')
+
+    _parse_time(str, e) # || _parse_beat(str, e)
+    _parse_day(str, e)
+
+    _parse_eu(str, e)     ||
+    _parse_us(str, e)     ||
+    _parse_iso(str, e)    ||
+    _parse_jis(str, e)    ||
+    _parse_vms(str, e)    ||
+    _parse_sla_us(str, e) ||
+    _parse_iso2(str, e)   ||
+    _parse_year(str, e)   ||
+    _parse_mon(str, e)    ||
+    _parse_mday(str, e)   ||
+    _parse_ddd(str, e)
+
+    if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/in, ' ')
+      if e.year
+	e.year = -e.year + 1
+      end
+    end
+
+    if str.sub!(/\A\s*(\d{1,2})\s*\z/n, ' ')
+      if e.hour && !e.mday
+	v = $1.to_i
+	if (1..31) === v
+	  e.mday = v
+	end
+      end
+      if e.mday && !e.hour
+	v = $1.to_i
+	if (0..24) === v
+	  e.hour = v
+	end
+      end
+    end
+
+    if e._comp and e.year
+      if e.year >= 0 and e.year <= 99
+	if e.year >= 69
+	  e.year += 1900
+	else
+	  e.year += 2000
+	end
+      end
+    end
+
+    e.offset ||= zone_to_diff(e.zone) if e.zone
+
+    e.to_hash
+  end
+
+  t = Module.new do
+
+    private
+
+    def zone_to_diff(zone) # :nodoc:
+      zone = zone.downcase
+      if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
+	dst = $1 == 'daylight'
+      else
+	dst = zone.sub!(/\s+dst\z/, '')
+      end
+      if Format::ZONES.include?(zone)
+	offset = Format::ZONES[zone]
+	offset += 3600 if dst
+      elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
+	sign = $1
+	if zone.include?(':')
+	  hour, min, sec, = zone.split(':')
+	elsif zone.include?(',') || zone.include?('.')
+	  hour, fr, = zone.split(/[,.]/)
+	  min = fr.to_i.to_r / (10**fr.size) * 60
+	else
+	  case zone.size
+	  when 3
+	    hour = zone[0,1]
+	    min = zone[1,2]
+	  else
+	    hour = zone[0,2]
+	    min = zone[2,2]
+	    sec = zone[4,2]
+	  end
+	end
+	offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
+	offset *= -1 if sign == '-'
+      end
+      offset
+    end
+
+  end
+
+  extend  t
+  include t
+
+end
+
+class DateTime < Date
+
+  def strftime(fmt='%FT%T%:z')
+    super(fmt)
+  end
+
+  def self._strptime(str, fmt='%FT%T%z')
+    super(str, fmt)
+  end
+
+  def iso8601_timediv(n) # :nodoc:
+    strftime('T%T' +
+	     if n < 1
+	       ''
+	     else
+	       '.%0*d' % [n, (sec_fraction / (1.to_r/(10**n))).round]
+	     end +
+	     '%:z')
+  end
+
+  private :iso8601_timediv
+
+  def iso8601(n=0)
+    super() + iso8601_timediv(n)
+  end
+
+  def jisx0301(n=0)
+    super() + iso8601_timediv(n)
+  end
+
+end

Modified: trunk/lib/date.rb
===================================================================
--- trunk/lib/date.rb	2006-12-29 23:13:35 UTC (rev 587)
+++ trunk/lib/date.rb	2006-12-31 08:05:21 UTC (rev 588)
@@ -1,1656 +1,1713 @@
-#
-# date.rb - date and time library
-#
-# Author: Tadayoshi Funaba 1998-2006
-#
-# Documentation: William Webber <william williamwebber.com>
-#
-#--
-# $Id: date.rb,v 2.29 2006-11-05 18:21:29+09 tadf Exp $
-#++
-#
-# == Overview
-#
-# This file provides two classes for working with
-# dates and times.
-#
-# The first class, Date, represents dates. 
-# It works with years, months, weeks, and days.
-# See the Date class documentation for more details.
-#
-# The second, DateTime, extends Date to include hours,
-# minutes, seconds, and fractions of a second.  It
-# provides basic support for time zones.  See the
-# DateTime class documentation for more details.
-#
-# === Ways of calculating the date.
-#
-# In common usage, the date is reckoned in years since or
-# before the Common Era (CE/BCE, also known as AD/BC), then
-# as a month and day-of-the-month within the current year.
-# This is known as the *Civil* *Date*, and abbreviated
-# as +civil+ in the Date class.
-#
-# Instead of year, month-of-the-year,  and day-of-the-month,
-# the date can also be reckoned in terms of year and
-# day-of-the-year.  This is known as the *Ordinal* *Date*,
-# and is abbreviated as +ordinal+ in the Date class.  (Note
-# that referring to this as the Julian date is incorrect.)
-#
-# The date can also be reckoned in terms of year, week-of-the-year,
-# and day-of-the-week.  This is known as the *Commercial*
-# *Date*, and is abbreviated as +commercial+ in the
-# Date class.  The commercial week runs Monday (day-of-the-week
-# 1) to Sunday (day-of-the-week 7), in contrast to the civil
-# week which runs Sunday (day-of-the-week 0) to Saturday
-# (day-of-the-week 6).  The first week of the commercial year
-# starts on the Monday on or before January 1, and the commercial
-# year itself starts on this Monday, not January 1.
-#
-# For scientific purposes, it is convenient to refer to a date
-# simply as a day count, counting from an arbitrary initial
-# day.  The date first chosen for this was January 1, 4713 BCE.
-# A count of days from this date is the *Julian* *Day* *Number*
-# or *Julian* *Date*, which is abbreviated as +jd+ in the
-# Date class.  This is in local time, and counts from midnight
-# on the initial day.  The stricter usage is in UTC, and counts
-# from midday on the initial day.  This is referred to in the
-# Date class as the *Astronomical* *Julian* *Day* *Number*, and
-# abbreviated as +ajd+.  In the Date class, the Astronomical
-# Julian Day Number includes fractional days.
-#
-# Another absolute day count is the *Modified* *Julian* *Day*
-# *Number*, which takes November 17, 1858 as its initial day.
-# This is abbreviated as +mjd+ in the Date class.  There
-# is also an *Astronomical* *Modified* *Julian* *Day* *Number*,
-# which is in UTC and includes fractional days.  This is
-# abbreviated as +amjd+ in the Date class.  Like the Modified
-# Julian Day Number (and unlike the Astronomical Julian
-# Day Number), it counts from midnight.
-#
-# Alternative calendars such as the Chinese Lunar Calendar,
-# the Islamic Calendar, or the French Revolutionary Calendar
-# are not supported by the Date class; nor are calendars that
-# are based on an Era different from the Common Era, such as
-# the Japanese Imperial Calendar or the Republic of China
-# Calendar.
-#
-# === Calendar Reform
-#
-# The standard civil year is 365 days long.  However, the
-# solar year is fractionally longer than this.  To account
-# for this, a *leap* *year* is occasionally inserted.  This
-# is a year with 366 days, the extra day falling on February 29. 
-# In the early days of the civil calendar, every fourth
-# year without exception was a leap year.  This way of
-# reckoning leap years is the *Julian* *Calendar*.
-#
-# However, the solar year is marginally shorter than 365 1/4
-# days, and so the *Julian* *Calendar* gradually ran slow
-# over the centuries.  To correct this, every 100th year
-# (but not every 400th year) was excluded as a leap year.
-# This way of reckoning leap years, which we use today, is
-# the *Gregorian* *Calendar*.
-#
-# The Gregorian Calendar was introduced at different times
-# in different regions.  The day on which it was introduced
-# for a particular region is the *Day* *of* *Calendar*
-# *Reform* for that region.  This is abbreviated as +sg+
-# (for Start of Gregorian calendar) in the Date class.
-#
-# Two such days are of particular
-# significance.  The first is October 15, 1582, which was
-# the Day of Calendar Reform for Italy and most Catholic
-# countries.  The second is September 14, 1752, which was
-# the Day of Calendar Reform for England and its colonies
-# (including what is now the United States).  These two
-# dates are available as the constants Date::ITALY and
-# Date::ENGLAND, respectively.  (By comparison, Germany and
-# Holland, less Catholic than Italy but less stubborn than
-# England, changed over in 1698; Sweden in 1753; Russia not
-# till 1918, after the Revolution; and Greece in 1923.  Many
-# Orthodox churches still use the Julian Calendar.  A complete
-# list of Days of Calendar Reform can be found at
-# http://www.polysyllabic.com/GregConv.html.)
-#
-# Switching from the Julian to the Gregorian calendar
-# involved skipping a number of days to make up for the
-# accumulated lag, and the later the switch was (or is)
-# done, the more days need to be skipped.  So in 1582 in Italy,
-# 4th October was followed by 15th October, skipping 10 days; in 1752
-# in England, 2nd September was followed by 14th September, skipping
-# 11 days; and if I decided to switch from Julian to Gregorian
-# Calendar this midnight, I would go from 27th July 2003 (Julian)
-# today to 10th August 2003 (Gregorian) tomorrow, skipping
-# 13 days.  The Date class is aware of this gap, and a supposed
-# date that would fall in the middle of it is regarded as invalid.
-#
-# The Day of Calendar Reform is relevant to all date representations
-# involving years.  It is not relevant to the Julian Day Numbers,
-# except for converting between them and year-based representations.
-#
-# In the Date and DateTime classes, the Day of Calendar Reform or
-# +sg+ can be specified a number of ways.  First, it can be as
-# the Julian Day Number of the Day of Calendar Reform.  Second,
-# it can be using the constants Date::ITALY or Date::ENGLAND; these
-# are in fact the Julian Day Numbers of the Day of Calendar Reform
-# of the respective regions.  Third, it can be as the constant
-# Date::JULIAN, which means to always use the Julian Calendar.
-# Finally, it can be as the constant Date::GREGORIAN, which means
-# to always use the Gregorian Calendar.
-#
-# Note: in the Julian Calendar, New Years Day was March 25.  The
-# Date class does not follow this convention.
-#
-# === Time Zones
-#
-# DateTime objects support a simple representation
-# of time zones.  Time zones are represented as an offset
-# from UTC, as a fraction of a day.  This offset is the
-# how much local time is later (or earlier) than UTC.
-# UTC offset 0 is centred on England (also known as GMT). 
-# As you travel east, the offset increases until you
-# reach the dateline in the middle of the Pacific Ocean;
-# as you travel west, the offset decreases.  This offset
-# is abbreviated as +of+ in the Date class.
-#
-# This simple representation of time zones does not take
-# into account the common practice of Daylight Savings
-# Time or Summer Time.
-#
-# Most DateTime methods return the date and the
-# time in local time.  The two exceptions are
-# #ajd() and #amjd(), which return the date and time
-# in UTC time, including fractional days.
-#
-# The Date class does not support time zone offsets, in that
-# there is no way to create a Date object with a time zone.
-# However, methods of the Date class when used by a
-# DateTime instance will use the time zone offset of this
-# instance.
-#
-# == Examples of use
-#
-# === Print out the date of every Sunday between two dates.
-#
-#     def print_sundays(d1, d2)
-#         d1 +=1 while (d1.wday != 0)
-#         d1.step(d2, 7) do |date|
-#             puts "#{Date::MONTHNAMES[date.mon]} #{date.day}"
-#         end
-#     end
-#
-#     print_sundays(Date::civil(2003, 4, 8), Date::civil(2003, 5, 23))
-#
-# === Calculate how many seconds to go till midnight on New Year's Day.
-#
-#     def secs_to_new_year(now = DateTime::now())
-#         new_year = DateTime.new(now.year + 1, 1, 1)
-#         dif = new_year - now
-#         hours, mins, secs, ignore_fractions = Date::day_fraction_to_time(dif)
-#         return hours * 60 * 60 + mins * 60 + secs
-#     end
-#
-#     puts secs_to_new_year()
-
-require 'rational'
-require 'date/format'
-
-# Class representing a date.
-#
-# See the documentation to the file date.rb for an overview.
-#
-# Internally, the date is represented as an Astronomical
-# Julian Day Number, +ajd+.  The Day of Calendar Reform, +sg+, is
-# also stored, for conversions to other date formats.  (There
-# is also an +of+ field for a time zone offset, but this
-# is only for the use of the DateTime subclass.)
-#
-# A new Date object is created using one of the object creation
-# class methods named after the corresponding date format, and the
-# arguments appropriate to that date format; for instance,
-# Date::civil() (aliased to Date::new()) with year, month,
-# and day-of-month, or Date::ordinal() with year and day-of-year.
-# All of these object creation class methods also take the
-# Day of Calendar Reform as an optional argument.
-#
-# Date objects are immutable once created.
-#
-# Once a Date has been created, date values
-# can be retrieved for the different date formats supported
-# using instance methods.  For instance, #mon() gives the
-# Civil month, #cwday() gives the Commercial day of the week,
-# and #yday() gives the Ordinal day of the year.  Date values
-# can be retrieved in any format, regardless of what format
-# was used to create the Date instance.
-#
-# The Date class includes the Comparable module, allowing
-# date objects to be compared and sorted, ranges of dates
-# to be created, and so forth.
-class Date
-
-  include Comparable
-
-  # Full month names, in English.  Months count from 1 to 12; a
-  # month's numerical representation indexed into this array
-  # gives the name of that month (hence the first element is nil).
-  MONTHNAMES = [nil] + %w(January February March April May June July
-			  August September October November December)
-
-  # Full names of days of the week, in English.  Days of the week
-  # count from 0 to 6 (except in the commercial week); a day's numerical
-  # representation indexed into this array gives the name of that day.
-  DAYNAMES = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
-
-  # Abbreviated month names, in English.
-  ABBR_MONTHNAMES = [nil] + %w(Jan Feb Mar Apr May Jun
-			       Jul Aug Sep Oct Nov Dec)
-
-  # Abbreviated day names, in English.
-  ABBR_DAYNAMES = %w(Sun Mon Tue Wed Thu Fri Sat)
-
-  [MONTHNAMES, DAYNAMES, ABBR_MONTHNAMES, ABBR_DAYNAMES].each do |xs|
-    xs.each{|x| x.freeze}.freeze
-  end
-
-  class Infinity < Numeric # :nodoc:
-
-    include Comparable
-
-    def initialize(d=1) @d = d <=> 0 end
-
-    def d() @d end
-
-    protected :d
-
-    def zero? () false end
-    def finite? () false end
-    def infinite? () d.nonzero? end
-    def nan? () d.zero? end
-
-    def abs() self.class.new end
-
-    def -@ () self.class.new(-d) end
-    def +@ () self.class.new(+d) end
-
-    def <=> (other)
-      case other
-      when Infinity; d <=> other.d
-      when Numeric; d
-      else
-	begin
-	  l, r = other.coerce(self)
-	  return l <=> r
-	rescue NoMethodError
-	end
-      end
-      nil
-    end
-
-    def coerce(other)
-      case other
-      when Numeric; return -d, d
-      else
-	super
-      end
-    end
-
-  end
-
-  # The Julian Day Number of the Day of Calendar Reform for Italy
-  # and the Catholic countries.
-  ITALY     = 2299161 # 1582-10-15
-
-  # The Julian Day Number of the Day of Calendar Reform for England
-  # and her Colonies.
-  ENGLAND   = 2361222 # 1752-09-14
-
-  # A constant used to indicate that a Date should always use the
-  # Julian calendar.
-  JULIAN    =  Infinity.new
-
-  # A constant used to indicate that a Date should always use the
-  # Gregorian calendar.
-  GREGORIAN = -Infinity.new
-
-  UNIXEPOCH = 2440588 # 1970-01-01 :nodoc:
-
-  # Does a given Julian Day Number fall inside the old-style (Julian)
-  # calendar?
-  #
-  # +jd+ is the Julian Day Number in question. +sg+ may be Date::GREGORIAN,
-  # in which case the answer is false; it may be Date::JULIAN, in which case
-  # the answer is true; or it may a number representing the Day of
-  # Calendar Reform. Date::ENGLAND and Date::ITALY are two possible such
-  # days.
-  def self.julian? (jd, sg)
-    case sg
-    when Numeric
-      jd < sg
-    else
-      if $VERBOSE
-	warn("#{caller.shift.sub(/:in .*/, '')}: " \
-"warning: do not use non-numerical object as julian day number anymore")
-      end
-      not sg
-    end
-  end
-
-  # Does a given Julian Day Number fall inside the new-style (Gregorian)
-  # calendar?
-  #
-  # The reverse of self.os?  See the documentation for that method for
-  # more details.
-  def self.gregorian? (jd, sg) not julian?(jd, sg) end
-
-  def self.fix_style(jd, sg) # :nodoc:
-    if julian?(jd, sg)
-    then JULIAN
-    else GREGORIAN end
-  end
-
-  private_class_method :fix_style
-
-  # Convert a Civil Date to a Julian Day Number.
-  # +y+, +m+, and +d+ are the year, month, and day of the
-  # month.  +sg+ specifies the Day of Calendar Reform.
-  #
-  # Returns the corresponding Julian Day Number.
-  def self.civil_to_jd(y, m, d, sg=GREGORIAN)
-    if m <= 2
-      y -= 1
-      m += 12
-    end
-    a = (y / 100.0).floor
-    b = 2 - a + (a / 4.0).floor
-    jd = (365.25 * (y + 4716)).floor +
-      (30.6001 * (m + 1)).floor +
-      d + b - 1524
-    if julian?(jd, sg)
-      jd -= b
-    end
-    jd
-  end
-
-  # Convert a Julian Day Number to a Civil Date.  +jd+ is
-  # the Julian Day Number. +sg+ specifies the Day of
-  # Calendar Reform.
-  #
-  # Returns the corresponding [year, month, day_of_month]
-  # as a three-element array.
-  def self.jd_to_civil(jd, sg=GREGORIAN)
-    if julian?(jd, sg)
-      a = jd
-    else
-      x = ((jd - 1867216.25) / 36524.25).floor
-      a = jd + 1 + x - (x / 4.0).floor
-    end
-    b = a + 1524
-    c = ((b - 122.1) / 365.25).floor
-    d = (365.25 * c).floor
-    e = ((b - d) / 30.6001).floor
-    dom = b - d - (30.6001 * e).floor
-    if e <= 13
-      m = e - 1
-      y = c - 4716
-    else
-      m = e - 13
-      y = c - 4715
-    end
-    return y, m, dom
-  end
-
-  # Convert a Julian Day Number to an Ordinal Date.
-  #
-  # +jd+ is the Julian Day Number to convert.
-  # +sg+ specifies the Day of Calendar Reform.
-  #
-  # Returns the corresponding Ordinal Date as
-  # [year, day_of_year]
-  def self.jd_to_ordinal(jd, sg=GREGORIAN)
-    y = jd_to_civil(jd, sg)[0]
-    doy = jd - civil_to_jd(y - 1, 12, 31, fix_style(jd, sg))
-    return y, doy
-  end
-
-  # Convert an Ordinal Date to a Julian Day Number.
-  #
-  # +y+ and +d+ are the year and day-of-year to convert.
-  # +sg+ specifies the Day of Calendar Reform.
-  #
-  # Returns the corresponding Julian Day Number.
-  def self.ordinal_to_jd(y, d, sg=GREGORIAN)
-    civil_to_jd(y, 1, d, sg)
-  end
-
-  # Convert a Julian Day Number to a Commercial Date
-  #
-  # +jd+ is the Julian Day Number to convert.
-  # +sg+ specifies the Day of Calendar Reform.
-  #
-  # Returns the corresponding Commercial Date as
-  # [commercial_year, week_of_year, day_of_week]
-  def self.jd_to_commercial(jd, sg=GREGORIAN)
-    ns = fix_style(jd, sg)
-    a = jd_to_civil(jd - 3, ns)[0]
-    y = if jd >= commercial_to_jd(a + 1, 1, 1, ns) then a + 1 else a end
-    w = 1 + ((jd - commercial_to_jd(y, 1, 1, ns)) / 7).floor
-    d = (jd + 1) % 7
-    if d.zero? then d = 7 end
-    return y, w, d
-  end
-
-  # Convert a Commercial Date to a Julian Day Number.
-  #
-  # +y+, +w+, and +d+ are the (commercial) year, week of the year,
-  # and day of the week of the Commercial Date to convert.
-  # +sg+ specifies the Day of Calendar Reform.
-  def self.commercial_to_jd(y, w, d, ns=GREGORIAN)
-    jd = civil_to_jd(y, 1, 4, ns)
-    (jd - (((jd - 1) + 1) % 7)) +
-      7 * (w - 1) +
-      (d - 1)
-  end
-
-  def self.jd_to_weeknum(jd, k=0, sg=GREGORIAN) # :nodoc:
-    ns = fix_style(jd, sg)
-    y, m, d = jd_to_civil(jd, ns)
-    a = civil_to_jd(y, 1, 1, ns) + 6
-    w, d = (jd - (a - ((a - k) + 1) % 7) + 7).divmod(7)
-    return y, w, d
-  end
-
-  def self.weeknum_to_jd(y, w, d, k=0, ns=GREGORIAN) # :nodoc:
-    a = civil_to_jd(y, 1, 1, ns) + 6
-    (a - ((a - k) + 1) % 7 - 7) + 7 * w + d
-  end
-
-  # Convert an Astronomical Julian Day Number to a (civil) Julian
-  # Day Number.
-  #
-  # +ajd+ is the Astronomical Julian Day Number to convert. 
-  # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
-  #
-  # Returns the (civil) Julian Day Number as [day_number,
-  # fraction] where +fraction+ is always 1/2.
-  def self.ajd_to_jd(ajd, of=0) (ajd + of + 1.to_r/2).divmod(1) end
-
-  # Convert a (civil) Julian Day Number to an Astronomical Julian
-  # Day Number.
-  #
-  # +jd+ is the Julian Day Number to convert, and +fr+ is a
-  # fractional day. 
-  # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
-  #
-  # Returns the Astronomical Julian Day Number as a single
-  # numeric value.
-  def self.jd_to_ajd(jd, fr, of=0) jd + fr - of - 1.to_r/2 end
-
-  # Convert a fractional day +fr+ to [hours, minutes, seconds,
-  # fraction_of_a_second]
-  def self.day_fraction_to_time(fr)
-    h,   fr = fr.divmod(1.to_r/24)
-    min, fr = fr.divmod(1.to_r/1440)
-    s,   fr = fr.divmod(1.to_r/86400)
-    return h, min, s, fr
-  end
-
-  # Convert an +h+ hour, +min+ minutes, +s+ seconds period
-  # to a fractional day.
-  def self.time_to_day_fraction(h, min, s)
-    h.to_r/24 + min.to_r/1440 + s.to_r/86400
-  end
-
-  # Convert an Astronomical Modified Julian Day Number to an
-  # Astronomical Julian Day Number.
-  def self.amjd_to_ajd(amjd) amjd + 4800001.to_r/2 end
-
-  # Convert an Astronomical Julian Day Number to an
-  # Astronomical Modified Julian Day Number.
-  def self.ajd_to_amjd(ajd) ajd - 4800001.to_r/2 end
-
-  # Convert a Modified Julian Day Number to a Julian
-  # Day Number.
-  def self.mjd_to_jd(mjd) mjd + 2400001 end
-
-  # Convert a Julian Day Number to a Modified Julian Day
-  # Number.
-  def self.jd_to_mjd(jd) jd - 2400001 end
-
-  # Convert a count of the number of days since the adoption
-  # of the Gregorian Calendar (in Italy) to a Julian Day Number.
-  def self.ld_to_jd(ld) ld + 2299160 end
-
-  # Convert a Julian Day Number to the number of days since
-  # the adoption of the Gregorian Calendar (in Italy).
-  def self.jd_to_ld(jd) jd - 2299160 end
-
-  # Convert a Julian Day Number to the day of the week.
-  #
-  # Sunday is day-of-week 0; Saturday is day-of-week 6.
-  def self.jd_to_wday(jd) (jd + 1) % 7 end
-
-  # Is a year a leap year in the Julian calendar?
-  #
-  # All years divisible by 4 are leap years in the Julian calendar.
-  def self.julian_leap? (y) y % 4 == 0 end
-
-  # Is a year a leap year in the Gregorian calendar?
-  #
-  # All years divisible by 4 are leap years in the Gregorian calendar,
-  # except for years divisible by 100 and not by 400.
-  def self.gregorian_leap? (y) y % 4 == 0 and y % 100 != 0 or y % 400 == 0 end
-
-  class << self; alias_method :leap?, :gregorian_leap? end
-  class << self; alias_method :new0, :new end
-
-  # Is +jd+ a valid Julian Day Number?
-  #
-  # If it is, returns it.  In fact, any value is treated as a valid
-  # Julian Day Number.
-  def self.valid_jd? (jd, sg=ITALY) jd end
-
-  # Create a new Date object from a Julian Day Number.
-  #
-  # +jd+ is the Julian Day Number; if not specified, it defaults to
-  # 0. 
-  # +sg+ specifies the Day of Calendar Reform.
-  def self.jd(jd=0, sg=ITALY)
-    jd = valid_jd?(jd, sg)
-    new0(jd_to_ajd(jd, 0, 0), 0, sg)
-  end
-
-  # Do t