Index: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-string-ext/mrbgem.rake	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/mrbgem.rake	(revision 331)
@@ -3,3 +3,4 @@
   spec.author  = 'mruby developers'
   spec.summary = 'String class extension'
+  spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
 end
Index: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/mrblib/string.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-string-ext/mrblib/string.rb	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/mrblib/string.rb	(revision 331)
@@ -1,3 +1,22 @@
 class String
+
+  ##
+  #  call-seq:
+  #     String.try_convert(obj) -> string or nil
+  #
+  # Try to convert <i>obj</i> into a String, using to_str method.
+  # Returns converted string or nil if <i>obj</i> cannot be converted
+  # for any reason.
+  #
+  #     String.try_convert("str")     #=> "str"
+  #     String.try_convert(/re/)      #=> nil
+  #
+  def self.try_convert(obj)
+    if obj.respond_to?(:to_str)
+      obj.to_str
+    else
+      nil
+    end
+  end
 
   ##
@@ -27,5 +46,5 @@
     a = 0
     z = self.size - 1
-    a += 1 while " \f\n\r\t\v".include?(self[a]) and a <= z
+    a += 1 while a <= z and " \f\n\r\t\v".include?(self[a])
     (z >= 0) ? self[a..z] : ""
   end
@@ -44,5 +63,5 @@
     a = 0
     z = self.size - 1
-    z -= 1 while " \f\n\r\t\v\0".include?(self[z]) and a <= z
+    z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z])
     (z >= 0) ? self[a..z] : ""
   end
@@ -60,6 +79,6 @@
     a = 0
     z = self.size - 1
-    a += 1 while " \f\n\r\t\v".include?(self[a]) and a <= z
-    z -= 1 while " \f\n\r\t\v\0".include?(self[z]) and a <= z
+    a += 1 while a <= z and " \f\n\r\t\v".include?(self[a])
+    z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z])
     (z >= 0) ? self[a..z] : ""
   end
@@ -77,4 +96,5 @@
   #
   def lstrip!
+    raise RuntimeError, "can't modify frozen String" if frozen?
     s = self.lstrip
     (s == self) ? nil : self.replace(s)
@@ -93,4 +113,5 @@
   #
   def rstrip!
+    raise RuntimeError, "can't modify frozen String" if frozen?
     s = self.rstrip
     (s == self) ? nil : self.replace(s)
@@ -105,4 +126,5 @@
   #
   def strip!
+    raise RuntimeError, "can't modify frozen String" if frozen?
     s = self.strip
     (s == self) ? nil : self.replace(s)
@@ -165,4 +187,5 @@
   #
   def slice!(arg1, arg2=nil)
+    raise RuntimeError, "can't modify frozen String" if frozen?
     raise "wrong number of arguments (for 1..2)" if arg1.nil? && arg2.nil?
 
@@ -189,5 +212,5 @@
         idx = arg1
         idx += self.size if arg1 < 0
-        validated = true if idx >=0 && arg1 < self.size   
+        validated = true if idx >=0 && arg1 < self.size
       end
       if validated
@@ -236,12 +259,11 @@
   #
   def insert(idx, str)
-    pos = idx.to_i
-    pos += self.size + 1 if pos < 0
-
-    raise IndexError, "index #{idx.to_i} out of string" if pos < 0 || pos > self.size
-
-    return self + str if pos == -1
-    return str + self if pos == 0
-    return self[0..pos - 1] + str + self[pos..-1]
+    if idx == -1
+      return self << str
+    elsif idx < 0
+      idx += 1
+    end
+    self[idx, 0] = str
+    self
   end
 
@@ -258,61 +280,33 @@
   #     "hello".ljust(20, '1234')   #=> "hello123412341234123"
   def ljust(idx, padstr = ' ')
-    if idx <= self.size
-      return self
-    end
-    newstr = self.dup
-    newstr << padstr
-    while newstr.size <= idx
-      newstr << padstr
-    end
-    return newstr.slice(0,idx)
-  end
-
-  #     str.upto(other_str, exclusive=false) {|s| block }   -> str
-  #     str.upto(other_str, exclusive=false)                -> an_enumerator
-  #
-  #  Iterates through successive values, starting at <i>str</i> and
-  #  ending at <i>other_str</i> inclusive, passing each value in turn to
-  #  the block. The <code>String#succ</code> method is used to generate
-  #  each value.  If optional second argument exclusive is omitted or is false,
-  #  the last value will be included; otherwise it will be excluded.
-  #
-  #  If no block is given, an enumerator is returned instead.
-  #
-  #     "a8".upto("b6") {|s| print s, ' ' }
-  #     for s in "a8".."b6"
-  #       print s, ' '
-  #     end
-  #
-  #  <em>produces:</em>
-  #
-  #     a8 a9 b0 b1 b2 b3 b4 b5 b6
-  #     a8 a9 b0 b1 b2 b3 b4 b5 b6
-  #
-  #  If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
-  #  both are recognized as decimal numbers. In addition, the width of
-  #  string (e.g. leading zeros) is handled appropriately.
-  #
-  #     "9".upto("11").to_a   #=> ["9", "10", "11"]
-  #     "25".upto("5").to_a   #=> []
-  #     "07".upto("11").to_a  #=> ["07", "08", "09", "10", "11"]
-  #
-  def upto(other_str, excl=false, &block)
-    return to_enum :upto, other_str, excl unless block
-
-    str = self
-    n = self.<=>other_str
-    return self if n > 0 || (self == other_str && excl)
-    while true
-      block.call(str)
-      return self if !excl && str == other_str
-      str = str.succ
-      return self if excl && str == other_str
-    end
+    raise ArgumentError, 'zero width padding' if padstr == ''
+    return self if idx <= self.size
+    pad_repetitions = (idx / padstr.length).ceil
+    padding = (padstr * pad_repetitions)[0...(idx - self.length)]
+    self + padding
+  end
+
+  ##
+  #  call-seq:
+  #     str.rjust(integer, padstr=' ')   -> new_str
+  #
+  #  If <i>integer</i> is greater than the length of <i>str</i>, returns a new
+  #  <code>String</code> of length <i>integer</i> with <i>str</i> right justified
+  #  and padded with <i>padstr</i>; otherwise, returns <i>str</i>.
+  #
+  #     "hello".rjust(4)            #=> "hello"
+  #     "hello".rjust(20)           #=> "               hello"
+  #     "hello".rjust(20, '1234')   #=> "123412341234123hello"
+  def rjust(idx, padstr = ' ')
+    raise ArgumentError, 'zero width padding' if padstr == ''
+    return self if idx <= self.size
+    pad_repetitions = (idx / padstr.length).ceil
+    padding = (padstr * pad_repetitions)[0...(idx - self.length)]
+    padding + self
   end
 
   def chars(&block)
     if block_given?
-      self.split('').map do |i|
+      self.split('').each do |i|
         block.call(i)
       end
@@ -322,5 +316,13 @@
     end
   end
-  alias each_char chars
+
+  def each_char(&block)
+    return to_enum :each_char unless block
+
+    split('').each do |i|
+      block.call(i)
+    end
+    self
+  end
 
   def codepoints(&block)
@@ -328,5 +330,5 @@
 
     if block_given?
-      self.split('').map do|x|
+      self.split('').each do|x|
         block.call(x.ord)
       end
@@ -337,3 +339,17 @@
   end
   alias each_codepoint codepoints
+
+  ##
+  # call-seq:
+  #    str.prepend(other_str)  -> str
+  #
+  # Prepend---Prepend the given string to <i>str</i>.
+  #
+  #    a = "world"
+  #    a.prepend("hello ") #=> "hello world"
+  #    a                   #=> "hello world"
+  def prepend(arg)
+    self[0, 0] = arg
+    self
+  end
 end
Index: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/src/string.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-string-ext/src/string.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/src/string.c	(revision 331)
@@ -1,8 +1,8 @@
 #include <string.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/string.h"
-#include "mruby/range.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/string.h>
+#include <mruby/range.h>
 
 static mrb_value
@@ -24,8 +24,9 @@
 {
   mrb_int pos, byte;
-  long len = RSTRING_LEN(str);
+  long len;
 
   mrb_get_args(mrb, "ii", &pos, &byte);
 
+  len = RSTRING_LEN(str);
   if (pos < -len || len <= pos)
     mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos));
@@ -56,6 +57,12 @@
 
       len = RSTRING_LEN(str);
-      if (mrb_range_beg_len(mrb, a1, &beg, &len, len)) {
+      switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) {
+      case 0:                   /* not range */
+        break;
+      case 1:                   /* range */
         return mrb_str_substr(mrb, str, beg, len);
+      case 2:                   /* out of range */
+        mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1);
+        break;
       }
       return mrb_nil_value();
@@ -128,4 +135,6 @@
 }
 
+static mrb_value mrb_fixnum_chr(mrb_state *mrb, mrb_value num);
+
 /*
  *  call-seq:
@@ -147,5 +156,10 @@
 {
   mrb_value str;
-  mrb_get_args(mrb, "S", &str);
+
+  mrb_get_args(mrb, "o", &str);
+  if (mrb_fixnum_p(str))
+    str = mrb_fixnum_chr(mrb, str);
+  else
+    str = mrb_string_type(mrb, str);
   mrb_str_concat(mrb, self, str);
   return self;
@@ -308,11 +322,12 @@
   mrb_int len;
   mrb_value arg;
-  char *p = RSTRING_PTR(self), *t;
-  char *e = p + RSTRING_LEN(self);
+  char *b = RSTRING_PTR(self);
+  char *p = b, *t;
+  char *e = b + RSTRING_LEN(self);
 
   mrb_get_args(mrb, "&", &blk);
 
   result = mrb_ary_new(mrb);
-
+  ai = mrb_gc_arena_save(mrb);
   if (!mrb_nil_p(blk)) {
     while (p < e) {
@@ -323,9 +338,15 @@
       arg = mrb_str_new(mrb, t, len);
       mrb_yield_argv(mrb, blk, 1, &arg);
+      mrb_gc_arena_restore(mrb, ai);
+      if (b != RSTRING_PTR(self)) {
+        ptrdiff_t diff = p - b;
+        b = RSTRING_PTR(self);
+        p = b + diff;
+      }
+      e = b + RSTRING_LEN(self);
     }
     return self;
   }
   while (p < e) {
-    ai = mrb_gc_arena_save(mrb);
     t = p;
     while (p < e && *p != '\n') p++;
@@ -354,5 +375,5 @@
   const char *prepend;
   struct RString *s = mrb_str_ptr(self);
-  size_t l;
+  mrb_int l;
 
   if (RSTRING_LEN(self) == 0)
@@ -374,5 +395,6 @@
     e = p + l - 1;
     result = mrb_str_new_lit(mrb, "");
-  } else {
+  }
+  else {
     // find leading letter of the ascii/number
     b = e;
@@ -392,5 +414,6 @@
         mrb_str_cat_lit(mrb, result, "\x01");
         (*e) = 0;
-      } else
+      }
+      else
         (*e)++;
       break;
@@ -400,11 +423,14 @@
       if (e == b) prepend = "1";
       *e = '0';
-    } else if (*e == 'z') {
+    }
+    else if (*e == 'z') {
       if (e == b) prepend = "a";
       *e = 'a';
-    } else if (*e == 'Z') {
+    }
+    else if (*e == 'Z') {
       if (e == b) prepend = "A";
       *e = 'A';
-    } else {
+    }
+    else {
       (*e)++;
       break;
@@ -428,42 +454,4 @@
   mrb_str_succ_bang(mrb, str);
   return str;
-}
-
-/*
- *  call-seq:
- *     str.prepend(other_str)  -> str
- *
- *  Prepend---Prepend the given string to <i>str</i>.
- *
- *     a = "world"
- *     a.prepend("hello ") #=> "hello world"
- *     a                   #=> "hello world"
- */
-static mrb_value
-mrb_str_prepend(mrb_state *mrb, mrb_value self)
-{
-  struct RString *s1 = mrb_str_ptr(self), *s2, *temp_s;
-  mrb_int len;
-  mrb_value other, temp_str;
-
-  mrb_get_args(mrb, "S", &other);
-
-  mrb_str_modify(mrb, s1);
-  if (!mrb_string_p(other)) {
-    other = mrb_str_to_str(mrb, other);
-  }
-  s2 = mrb_str_ptr(other);
-  len = RSTR_LEN(s1) + RSTR_LEN(s2);
-  temp_str = mrb_str_new(mrb, NULL, RSTR_LEN(s1));
-  temp_s = mrb_str_ptr(temp_str);
-  memcpy(RSTR_PTR(temp_s), RSTR_PTR(s1), RSTR_LEN(s1));
-  if (RSTRING_CAPA(self) < len) {
-    mrb_str_resize(mrb, self, len);
-  }
-  memcpy(RSTR_PTR(s1), RSTR_PTR(s2), RSTR_LEN(s2));
-  memcpy(RSTR_PTR(s1) + RSTR_LEN(s2), RSTR_PTR(temp_s), RSTR_LEN(temp_s));
-  RSTR_SET_LEN(s1, len);
-  RSTR_PTR(s1)[len] = '\0';
-  return self;
 }
 
@@ -530,7 +518,128 @@
   if (RSTRING_LEN(str) == 0)
     mrb_raise(mrb, E_ARGUMENT_ERROR, "empty string");
-  return mrb_fixnum_value(RSTRING_PTR(str)[0]);
+  return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[0]);
 }
 #endif
+
+static mrb_bool
+all_digits_p(const char *s, mrb_int len)
+{
+  while (len-- > 0) {
+    if (!ISDIGIT(*s)) return FALSE;
+    s++;
+  }
+  return TRUE;
+}
+
+/*
+ *  call-seq:
+ *     str.upto(other_str, exclusive=false) {|s| block }   -> str
+ *     str.upto(other_str, exclusive=false)                -> an_enumerator
+ *
+ *  Iterates through successive values, starting at <i>str</i> and
+ *  ending at <i>other_str</i> inclusive, passing each value in turn to
+ *  the block. The <code>String#succ</code> method is used to generate
+ *  each value.  If optional second argument exclusive is omitted or is false,
+ *  the last value will be included; otherwise it will be excluded.
+ *
+ *  If no block is given, an enumerator is returned instead.
+ *
+ *     "a8".upto("b6") {|s| print s, ' ' }
+ *     for s in "a8".."b6"
+ *       print s, ' '
+ *     end
+ *
+ *  <em>produces:</em>
+ *
+ *     a8 a9 b0 b1 b2 b3 b4 b5 b6
+ *     a8 a9 b0 b1 b2 b3 b4 b5 b6
+ *
+ *  If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
+ *  both are recognized as decimal numbers. In addition, the width of
+ *  string (e.g. leading zeros) is handled appropriately.
+ *
+ *     "9".upto("11").to_a   #=> ["9", "10", "11"]
+ *     "25".upto("5").to_a   #=> []
+ *     "07".upto("11").to_a  #=> ["07", "08", "09", "10", "11"]
+ */
+static mrb_value
+mrb_str_upto(mrb_state *mrb, mrb_value beg)
+{
+  mrb_value end;
+  mrb_value exclusive = mrb_false_value();
+  mrb_value block = mrb_nil_value();
+  mrb_value current, after_end;
+  mrb_int n;
+  mrb_bool excl;
+
+  mrb_get_args(mrb, "o|o&", &end, &exclusive, &block);
+
+  if (mrb_nil_p(block)) {
+    return mrb_funcall(mrb, beg, "to_enum", 3, mrb_symbol_value(mrb_intern_lit(mrb, "upto")), end, exclusive);
+  }
+  end = mrb_string_type(mrb, end);
+  excl = mrb_test(exclusive);
+
+  /* single character */
+  if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 &&
+  ISASCII(RSTRING_PTR(beg)[0]) && ISASCII(RSTRING_PTR(end)[0])) {
+    char c = RSTRING_PTR(beg)[0];
+    char e = RSTRING_PTR(end)[0];
+    int ai = mrb_gc_arena_save(mrb);
+
+    if (c > e || (excl && c == e)) return beg;
+    for (;;) {
+      mrb_yield(mrb, block, mrb_str_new(mrb, &c, 1));
+      mrb_gc_arena_restore(mrb, ai);
+      if (!excl && c == e) break;
+      c++;
+      if (excl && c == e) break;
+    }
+    return beg;
+  }
+  /* both edges are all digits */
+  if (ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
+      all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
+      all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
+    int ai = mrb_gc_arena_save(mrb);
+    mrb_int min_width = RSTRING_LEN(beg);
+    mrb_int max_width = RSTRING_LEN(end);
+    mrb_int bi = mrb_int(mrb, mrb_str_to_inum(mrb, beg, 10, FALSE));
+    mrb_int ei = mrb_int(mrb, mrb_str_to_inum(mrb, end, 10, FALSE));
+    mrb_value str = mrb_str_new(mrb, NULL, max_width);
+    char *buf = RSTRING_PTR(str);
+
+    while (bi <= ei) {
+      if (excl && bi == ei) break;
+      snprintf(buf, max_width+1, "%.*" MRB_PRId, (int)min_width, bi);
+      mrb_yield(mrb, block, mrb_str_new(mrb, buf, strlen(buf)));
+      mrb_gc_arena_restore(mrb, ai);
+      bi++;
+    }
+
+    return beg;
+  }
+  /* normal case */
+  n = mrb_int(mrb, mrb_funcall(mrb, beg, "<=>", 1, end));
+  if (n > 0 || (excl && n == 0)) return beg;
+
+  after_end = mrb_funcall(mrb, end, "succ", 0);
+  current = mrb_str_dup(mrb, beg);
+  while (!mrb_str_equal(mrb, current, after_end)) {
+    int ai = mrb_gc_arena_save(mrb);
+    mrb_value next = mrb_nil_value();
+    if (excl || !mrb_str_equal(mrb, current, end))
+      next = mrb_funcall(mrb, current, "succ", 0);
+    mrb_yield(mrb, block, current);
+    if (mrb_nil_p(next)) break;
+    current = mrb_str_to_str(mrb, next);
+    if (excl && mrb_str_equal(mrb, current, end)) break;
+    if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
+      break;
+    mrb_gc_arena_restore(mrb, ai);
+  }
+
+  return beg;
+}
 
 void
@@ -555,8 +664,8 @@
   mrb_define_method(mrb, s, "succ",            mrb_str_succ,            MRB_ARGS_NONE());
   mrb_define_method(mrb, s, "succ!",           mrb_str_succ_bang,       MRB_ARGS_NONE());
-  mrb_define_method(mrb, s, "prepend",         mrb_str_prepend,         MRB_ARGS_REQ(1));
   mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ"));
   mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!"));
   mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE());
+  mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY());
 
   mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE());
Index: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/test/string.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-string-ext/test/string.rb	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/test/string.rb	(revision 331)
@@ -3,4 +3,11 @@
 
 UTF8STRING = ("\343\201\202".size == 1)
+
+assert('String.try_convert') do
+  assert_nil String.try_convert(nil)
+  assert_nil String.try_convert(:foo)
+  assert_equal "", String.try_convert("")
+  assert_equal "1,2,3", String.try_convert("1,2,3")
+end
 
 assert('String#getbyte') do
@@ -22,4 +29,16 @@
   assert_equal(h, str1.getbyte(0))
   assert_equal("Hello", str1)
+end
+
+assert("String#setbyte raises IndexError if arg conversion resizes String") do
+  $s = "01234\n"
+  class Tmp
+      def to_i
+          $s.chomp! ''
+          95
+      end
+  end
+  tmp = Tmp.new
+  assert_raise(IndexError) { $s.setbyte(5, tmp) }
 end
 
@@ -104,10 +123,14 @@
 
 assert('String#concat') do
-  s = "Hello "
-  s.concat "World!"
-  t = "Hello "
-  t << "World!"
-  assert_equal "Hello World!", t
-  assert_equal "Hello World!", s
+  assert_equal "Hello World!", "Hello " << "World" << 33
+  assert_equal "Hello World!", "Hello ".concat("World").concat(33)
+
+  o = Object.new
+  def o.to_str
+    "to_str"
+  end
+  assert_equal "hi to_str", "hi " << o
+
+  assert_raise(TypeError) { "".concat(Object.new) }
 end
 
@@ -400,4 +423,8 @@
   assert_raise(IndexError) { "abcd".insert(5, 'X') }
   assert_raise(IndexError) { "abcd".insert(-6, 'X') }
+
+  a = "abcd"
+  a.insert(0, 'X')
+  assert_equal "Xabcd", a
 end
 
@@ -411,9 +438,73 @@
   assert_equal "hello", "hello".ljust(4)
   assert_equal "hello               ", "hello".ljust(20)
+  assert_equal 20, "hello".ljust(20).length
   assert_equal "hello123412341234123", "hello".ljust(20, '1234')
   assert_equal "hello", "hello".ljust(-3)
 end
 
+assert('String#rjust') do
+  assert_equal "hello", "hello".rjust(4)
+  assert_equal "               hello", "hello".rjust(20)
+  assert_equal 20, "hello".rjust(20).length
+  assert_equal "123412341234123hello", "hello".rjust(20, '1234')
+  assert_equal "hello", "hello".rjust(-3)
+end
+
+if UTF8STRING
+  assert('String#ljust with UTF8') do
+    assert_equal "helloん              ", "helloん".ljust(20)
+    assert_equal "helloó                            ", "helloó".ljust(34)
+    assert_equal 34, "helloó".ljust(34).length
+    assert_equal "helloんんんんんんんんんんんんんん", "hello".ljust(19, 'ん')
+    assert_equal "helloんんんんんんんんんんんんんんん", "hello".ljust(20, 'ん')
+  end
+
+  assert('String#rjust with UTF8') do
+    assert_equal "              helloん", "helloん".rjust(20)
+    assert_equal "                            helloó", "helloó".rjust(34)
+    # assert_equal 34, "helloó".rjust(34).length
+    assert_equal "んんんんんんんんんんんんんんhello", "hello".rjust(19, 'ん')
+    assert_equal "んんんんんんんんんんんんんんんhello", "hello".rjust(20, 'ん')
+  end
+
+  assert('UTF8 byte counting') do
+    ret = '                                  '
+    ret[-6..-1] = "helloó"
+    assert_equal 34, ret.length
+  end
+end
+
+assert('String#ljust should not change string') do
+  a = "hello"
+  a.ljust(20)
+  assert_equal "hello", a
+end
+
+assert('String#rjust should not change string') do
+  a = "hello"
+  a.rjust(20)
+  assert_equal "hello", a
+end
+
+assert('String#ljust should raise on zero width padding') do
+  assert_raise(ArgumentError) { "foo".ljust(10, '') }
+end
+
+assert('String#rjust should raise on zero width padding') do
+  assert_raise(ArgumentError) { "foo".rjust(10, '') }
+end
+
 assert('String#upto') do
+  assert_equal %w(a8 a9 b0 b1 b2 b3 b4 b5 b6), "a8".upto("b6").to_a
+  assert_equal ["9", "10", "11"], "9".upto("11").to_a
+  assert_equal [], "25".upto("5").to_a
+  assert_equal ["07", "08", "09", "10", "11"], "07".upto("11").to_a
+
+if UTF8STRING
+  assert_equal ["あ", "ぃ", "い", "ぅ", "う", "ぇ", "え", "ぉ", "お"], "あ".upto("お").to_a
+end
+
+  assert_equal ["9", ":", ";", "<", "=", ">", "?", "@", "A"], "9".upto("A").to_a
+
   a     = "aa"
   start = "aa"
@@ -475,4 +566,6 @@
   })
   assert_equal(2, count)
+
+  assert_raise(TypeError) { "a".upto(:c) {} }
 end
 
@@ -480,4 +573,8 @@
   got = "hello!".split('').map {|x| x.ord}
   expect = [104, 101, 108, 108, 111, 33]
+  unless UTF8STRING
+    got << "\xff".ord
+    expect << 0xff
+  end
   assert_equal expect, got
 end
