summaryrefslogtreecommitdiffstats
path: root/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrbgem.rake6
-rw-r--r--debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrblib/string.rb355
-rw-r--r--debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/src/string.c685
-rw-r--r--debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/test/string.rb667
4 files changed, 1713 insertions, 0 deletions
diff --git a/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrbgem.rake b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrbgem.rake
new file mode 100644
index 0000000..9812f2c
--- /dev/null
+++ b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrbgem.rake
@@ -0,0 +1,6 @@
+MRuby::Gem::Specification.new('mruby-string-ext') do |spec|
+ spec.license = 'MIT'
+ spec.author = 'mruby developers'
+ spec.summary = 'String class extension'
+ spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
+end
diff --git a/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrblib/string.rb b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrblib/string.rb
new file mode 100644
index 0000000..c3a7eb3
--- /dev/null
+++ b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -0,0 +1,355 @@
+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
+
+ ##
+ # call-seq:
+ # string.clear -> string
+ #
+ # Makes string empty.
+ #
+ # a = "abcde"
+ # a.clear #=> ""
+ #
+ def clear
+ self.replace("")
+ end
+
+ ##
+ # call-seq:
+ # str.lstrip -> new_str
+ #
+ # Returns a copy of <i>str</i> with leading whitespace removed. See also
+ # <code>String#rstrip</code> and <code>String#strip</code>.
+ #
+ # " hello ".lstrip #=> "hello "
+ # "hello".lstrip #=> "hello"
+ #
+ def lstrip
+ a = 0
+ z = self.size - 1
+ a += 1 while a <= z and " \f\n\r\t\v".include?(self[a])
+ (z >= 0) ? self[a..z] : ""
+ end
+
+ ##
+ # call-seq:
+ # str.rstrip -> new_str
+ #
+ # Returns a copy of <i>str</i> with trailing whitespace removed. See also
+ # <code>String#lstrip</code> and <code>String#strip</code>.
+ #
+ # " hello ".rstrip #=> " hello"
+ # "hello".rstrip #=> "hello"
+ #
+ def rstrip
+ a = 0
+ z = self.size - 1
+ z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z])
+ (z >= 0) ? self[a..z] : ""
+ end
+
+ ##
+ # call-seq:
+ # str.strip -> new_str
+ #
+ # Returns a copy of <i>str</i> with leading and trailing whitespace removed.
+ #
+ # " hello ".strip #=> "hello"
+ # "\tgoodbye\r\n".strip #=> "goodbye"
+ #
+ def strip
+ a = 0
+ z = self.size - 1
+ 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
+
+ ##
+ # call-seq:
+ # str.lstrip! -> self or nil
+ #
+ # Removes leading whitespace from <i>str</i>, returning <code>nil</code> if no
+ # change was made. See also <code>String#rstrip!</code> and
+ # <code>String#strip!</code>.
+ #
+ # " hello ".lstrip #=> "hello "
+ # "hello".lstrip! #=> nil
+ #
+ def lstrip!
+ raise RuntimeError, "can't modify frozen String" if frozen?
+ s = self.lstrip
+ (s == self) ? nil : self.replace(s)
+ end
+
+ ##
+ # call-seq:
+ # str.rstrip! -> self or nil
+ #
+ # Removes trailing whitespace from <i>str</i>, returning <code>nil</code> if
+ # no change was made. See also <code>String#lstrip!</code> and
+ # <code>String#strip!</code>.
+ #
+ # " hello ".rstrip #=> " hello"
+ # "hello".rstrip! #=> nil
+ #
+ def rstrip!
+ raise RuntimeError, "can't modify frozen String" if frozen?
+ s = self.rstrip
+ (s == self) ? nil : self.replace(s)
+ end
+
+ ##
+ # call-seq:
+ # str.strip! -> str or nil
+ #
+ # Removes leading and trailing whitespace from <i>str</i>. Returns
+ # <code>nil</code> if <i>str</i> was not altered.
+ #
+ def strip!
+ raise RuntimeError, "can't modify frozen String" if frozen?
+ s = self.strip
+ (s == self) ? nil : self.replace(s)
+ end
+
+ ##
+ # call-seq:
+ # str.casecmp(other_str) -> -1, 0, +1 or nil
+ #
+ # Case-insensitive version of <code>String#<=></code>.
+ #
+ # "abcdef".casecmp("abcde") #=> 1
+ # "aBcDeF".casecmp("abcdef") #=> 0
+ # "abcdef".casecmp("abcdefg") #=> -1
+ # "abcdef".casecmp("ABCDEF") #=> 0
+ #
+ def casecmp(str)
+ self.downcase <=> str.to_str.downcase
+ rescue NoMethodError
+ raise TypeError, "no implicit conversion of #{str.class} into String"
+ end
+
+ def partition(sep)
+ raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String
+ n = index(sep)
+ unless n.nil?
+ m = n + sep.size
+ [ slice(0, n), sep, slice(m, size - m) ]
+ else
+ [ self, "", "" ]
+ end
+ end
+
+ def rpartition(sep)
+ raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String
+ n = rindex(sep)
+ unless n.nil?
+ m = n + sep.size
+ [ slice(0, n), sep, slice(m, size - m) ]
+ else
+ [ "", "", self ]
+ end
+ end
+
+ ##
+ # call-seq:
+ # str.slice!(fixnum) -> new_str or nil
+ # str.slice!(fixnum, fixnum) -> new_str or nil
+ # str.slice!(range) -> new_str or nil
+ # str.slice!(other_str) -> new_str or nil
+ #
+ # Deletes the specified portion from <i>str</i>, and returns the portion
+ # deleted.
+ #
+ # string = "this is a string"
+ # string.slice!(2) #=> "i"
+ # string.slice!(3..6) #=> " is "
+ # string.slice!("r") #=> "r"
+ # string #=> "thsa sting"
+ #
+ 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?
+
+ if !arg1.nil? && !arg2.nil?
+ idx = arg1
+ idx += self.size if arg1 < 0
+ if idx >= 0 && idx <= self.size && arg2 > 0
+ str = self[idx, arg2]
+ else
+ return nil
+ end
+ else
+ validated = false
+ if arg1.kind_of?(Range)
+ beg = arg1.begin
+ ed = arg1.end
+ beg += self.size if beg < 0
+ ed += self.size if ed < 0
+ ed -= 1 if arg1.exclude_end?
+ validated = true
+ elsif arg1.kind_of?(String)
+ validated = true
+ else
+ idx = arg1
+ idx += self.size if arg1 < 0
+ validated = true if idx >=0 && arg1 < self.size
+ end
+ if validated
+ str = self[arg1]
+ else
+ return nil
+ end
+ end
+ unless str.nil? || str == ""
+ if !arg1.nil? && !arg2.nil?
+ idx = arg1 >= 0 ? arg1 : self.size+arg1
+ str2 = self[0...idx] + self[idx+arg2..-1].to_s
+ else
+ if arg1.kind_of?(Range)
+ idx = beg >= 0 ? beg : self.size+beg
+ idx2 = ed>= 0 ? ed : self.size+ed
+ str2 = self[0...idx] + self[idx2+1..-1].to_s
+ elsif arg1.kind_of?(String)
+ idx = self.index(arg1)
+ str2 = self[0...idx] + self[idx+arg1.size..-1] unless idx.nil?
+ else
+ idx = arg1 >= 0 ? arg1 : self.size+arg1
+ str2 = self[0...idx] + self[idx+1..-1].to_s
+ end
+ end
+ self.replace(str2) unless str2.nil?
+ end
+ str
+ end
+
+ ##
+ # call-seq:
+ # str.insert(index, other_str) -> str
+ #
+ # Inserts <i>other_str</i> before the character at the given
+ # <i>index</i>, modifying <i>str</i>. Negative indices count from the
+ # end of the string, and insert <em>after</em> the given character.
+ # The intent is insert <i>aString</i> so that it starts at the given
+ # <i>index</i>.
+ #
+ # "abcd".insert(0, 'X') #=> "Xabcd"
+ # "abcd".insert(3, 'X') #=> "abcXd"
+ # "abcd".insert(4, 'X') #=> "abcdX"
+ # "abcd".insert(-3, 'X') #=> "abXcd"
+ # "abcd".insert(-1, 'X') #=> "abcdX"
+ #
+ def insert(idx, str)
+ if idx == -1
+ return self << str
+ elsif idx < 0
+ idx += 1
+ end
+ self[idx, 0] = str
+ self
+ end
+
+ ##
+ # call-seq:
+ # str.ljust(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> left justified
+ # and padded with <i>padstr</i>; otherwise, returns <i>str</i>.
+ #
+ # "hello".ljust(4) #=> "hello"
+ # "hello".ljust(20) #=> "hello "
+ # "hello".ljust(20, '1234') #=> "hello123412341234123"
+ def ljust(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)]
+ 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('').each do |i|
+ block.call(i)
+ end
+ self
+ else
+ self.split('')
+ end
+ end
+
+ def each_char(&block)
+ return to_enum :each_char unless block
+
+ split('').each do |i|
+ block.call(i)
+ end
+ self
+ end
+
+ def codepoints(&block)
+ len = self.size
+
+ if block_given?
+ self.split('').each do|x|
+ block.call(x.ord)
+ end
+ self
+ else
+ self.split('').map{|x| x.ord}
+ end
+ 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
diff --git a/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/src/string.c b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/src/string.c
new file mode 100644
index 0000000..6bc035d
--- /dev/null
+++ b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/src/string.c
@@ -0,0 +1,685 @@
+#include <string.h>
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/string.h>
+#include <mruby/range.h>
+
+static mrb_value
+mrb_str_getbyte(mrb_state *mrb, mrb_value str)
+{
+ mrb_int pos;
+ mrb_get_args(mrb, "i", &pos);
+
+ if (pos < 0)
+ pos += RSTRING_LEN(str);
+ if (pos < 0 || RSTRING_LEN(str) <= pos)
+ return mrb_nil_value();
+
+ return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[pos]);
+}
+
+static mrb_value
+mrb_str_setbyte(mrb_state *mrb, mrb_value str)
+{
+ mrb_int pos, byte;
+ 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));
+ if (pos < 0)
+ pos += len;
+
+ mrb_str_modify(mrb, mrb_str_ptr(str));
+ byte &= 0xff;
+ RSTRING_PTR(str)[pos] = byte;
+ return mrb_fixnum_value((unsigned char)byte);
+}
+
+static mrb_value
+mrb_str_byteslice(mrb_state *mrb, mrb_value str)
+{
+ mrb_value a1;
+ mrb_int len;
+ int argc;
+
+ argc = mrb_get_args(mrb, "o|i", &a1, &len);
+ if (argc == 2) {
+ return mrb_str_substr(mrb, str, mrb_fixnum(a1), len);
+ }
+ switch (mrb_type(a1)) {
+ case MRB_TT_RANGE:
+ {
+ mrb_int beg;
+
+ len = RSTRING_LEN(str);
+ 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();
+ }
+ case MRB_TT_FLOAT:
+ a1 = mrb_fixnum_value((mrb_int)mrb_float(a1));
+ /* fall through */
+ case MRB_TT_FIXNUM:
+ return mrb_str_substr(mrb, str, mrb_fixnum(a1), 1);
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "wrong type of argument");
+ }
+ /* not reached */
+ return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ * str.swapcase! -> str or nil
+ *
+ * Equivalent to <code>String#swapcase</code>, but modifies the receiver in
+ * place, returning <i>str</i>, or <code>nil</code> if no changes were made.
+ * Note: case conversion is effective only in ASCII region.
+ */
+static mrb_value
+mrb_str_swapcase_bang(mrb_state *mrb, mrb_value str)
+{
+ char *p, *pend;
+ int modify = 0;
+ struct RString *s = mrb_str_ptr(str);
+
+ mrb_str_modify(mrb, s);
+ p = RSTRING_PTR(str);
+ pend = p + RSTRING_LEN(str);
+ while (p < pend) {
+ if (ISUPPER(*p)) {
+ *p = TOLOWER(*p);
+ modify = 1;
+ }
+ else if (ISLOWER(*p)) {
+ *p = TOUPPER(*p);
+ modify = 1;
+ }
+ p++;
+ }
+
+ if (modify) return str;
+ return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ * str.swapcase -> new_str
+ *
+ * Returns a copy of <i>str</i> with uppercase alphabetic characters converted
+ * to lowercase and lowercase characters converted to uppercase.
+ * Note: case conversion is effective only in ASCII region.
+ *
+ * "Hello".swapcase #=> "hELLO"
+ * "cYbEr_PuNk11".swapcase #=> "CyBeR_pUnK11"
+ */
+static mrb_value
+mrb_str_swapcase(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+
+ str = mrb_str_dup(mrb, self);
+ mrb_str_swapcase_bang(mrb, str);
+ return str;
+}
+
+static mrb_value mrb_fixnum_chr(mrb_state *mrb, mrb_value num);
+
+/*
+ * call-seq:
+ * str << integer -> str
+ * str.concat(integer) -> str
+ * str << obj -> str
+ * str.concat(obj) -> str
+ *
+ * Append---Concatenates the given object to <i>str</i>. If the object is a
+ * <code>Integer</code>, it is considered as a codepoint, and is converted
+ * to a character before concatenation.
+ *
+ * a = "hello "
+ * a << "world" #=> "hello world"
+ * a.concat(33) #=> "hello world!"
+ */
+static mrb_value
+mrb_str_concat_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value 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;
+}
+
+/*
+ * call-seq:
+ * str.start_with?([prefixes]+) -> true or false
+ *
+ * Returns true if +str+ starts with one of the +prefixes+ given.
+ *
+ * "hello".start_with?("hell") #=> true
+ *
+ * # returns true if one of the prefixes matches.
+ * "hello".start_with?("heaven", "hell") #=> true
+ * "hello".start_with?("heaven", "paradise") #=> false
+ * "h".start_with?("heaven", "hell") #=> false
+ */
+static mrb_value
+mrb_str_start_with(mrb_state *mrb, mrb_value self)
+{
+ mrb_value *argv, sub;
+ mrb_int argc, i;
+ mrb_get_args(mrb, "*", &argv, &argc);
+
+ for (i = 0; i < argc; i++) {
+ size_t len_l, len_r;
+ int ai = mrb_gc_arena_save(mrb);
+ sub = mrb_string_type(mrb, argv[i]);
+ mrb_gc_arena_restore(mrb, ai);
+ len_l = RSTRING_LEN(self);
+ len_r = RSTRING_LEN(sub);
+ if (len_l >= len_r) {
+ if (memcmp(RSTRING_PTR(self), RSTRING_PTR(sub), len_r) == 0) {
+ return mrb_true_value();
+ }
+ }
+ }
+ return mrb_false_value();
+}
+
+/*
+ * call-seq:
+ * str.end_with?([suffixes]+) -> true or false
+ *
+ * Returns true if +str+ ends with one of the +suffixes+ given.
+ */
+static mrb_value
+mrb_str_end_with(mrb_state *mrb, mrb_value self)
+{
+ mrb_value *argv, sub;
+ mrb_int argc, i;
+ mrb_get_args(mrb, "*", &argv, &argc);
+
+ for (i = 0; i < argc; i++) {
+ size_t len_l, len_r;
+ int ai = mrb_gc_arena_save(mrb);
+ sub = mrb_string_type(mrb, argv[i]);
+ mrb_gc_arena_restore(mrb, ai);
+ len_l = RSTRING_LEN(self);
+ len_r = RSTRING_LEN(sub);
+ if (len_l >= len_r) {
+ if (memcmp(RSTRING_PTR(self) + (len_l - len_r),
+ RSTRING_PTR(sub),
+ len_r) == 0) {
+ return mrb_true_value();
+ }
+ }
+ }
+ return mrb_false_value();
+}
+
+static mrb_value
+mrb_str_hex(mrb_state *mrb, mrb_value self)
+{
+ return mrb_str_to_inum(mrb, self, 16, FALSE);
+}
+
+static mrb_value
+mrb_str_oct(mrb_state *mrb, mrb_value self)
+{
+ return mrb_str_to_inum(mrb, self, 8, FALSE);
+}
+
+/*
+ * call-seq:
+ * string.chr -> string
+ *
+ * Returns a one-character string at the beginning of the string.
+ *
+ * a = "abcde"
+ * a.chr #=> "a"
+ */
+static mrb_value
+mrb_str_chr(mrb_state *mrb, mrb_value self)
+{
+ return mrb_str_substr(mrb, self, 0, 1);
+}
+
+static mrb_value
+mrb_fixnum_chr(mrb_state *mrb, mrb_value num)
+{
+ mrb_int cp = mrb_fixnum(num);
+#ifdef MRB_UTF8_STRING
+ char utf8[4];
+ mrb_int len;
+
+ if (cp < 0 || 0x10FFFF < cp) {
+ mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num);
+ }
+ if (cp < 0x80) {
+ utf8[0] = (char)cp;
+ len = 1;
+ }
+ else if (cp < 0x800) {
+ utf8[0] = (char)(0xC0 | (cp >> 6));
+ utf8[1] = (char)(0x80 | (cp & 0x3F));
+ len = 2;
+ }
+ else if (cp < 0x10000) {
+ utf8[0] = (char)(0xE0 | (cp >> 12));
+ utf8[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
+ utf8[2] = (char)(0x80 | ( cp & 0x3F));
+ len = 3;
+ }
+ else {
+ utf8[0] = (char)(0xF0 | (cp >> 18));
+ utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
+ utf8[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
+ utf8[3] = (char)(0x80 | ( cp & 0x3F));
+ len = 4;
+ }
+ return mrb_str_new(mrb, utf8, len);
+#else
+ char c;
+
+ if (cp < 0 || 0xff < cp) {
+ mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num);
+ }
+ c = (char)cp;
+ return mrb_str_new(mrb, &c, 1);
+#endif
+}
+
+/*
+ * call-seq:
+ * string.lines -> array of string
+ *
+ * Returns strings per line;
+ *
+ * a = "abc\ndef"
+ * a.lines #=> ["abc\n", "def"]
+ */
+static mrb_value
+mrb_str_lines(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ mrb_value blk;
+ int ai;
+ mrb_int len;
+ mrb_value arg;
+ 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) {
+ t = p;
+ while (p < e && *p != '\n') p++;
+ if (*p == '\n') p++;
+ len = (mrb_int) (p - t);
+ 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) {
+ t = p;
+ while (p < e && *p != '\n') p++;
+ if (*p == '\n') p++;
+ len = (mrb_int) (p - t);
+ mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return result;
+}
+
+/*
+ * call-seq:
+ * string.succ -> string
+ *
+ * Returns next sequence of the string;
+ *
+ * a = "abc"
+ * a.succ #=> "abd"
+ */
+static mrb_value
+mrb_str_succ_bang(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ unsigned char *p, *e, *b, *t;
+ const char *prepend;
+ struct RString *s = mrb_str_ptr(self);
+ mrb_int l;
+
+ if (RSTRING_LEN(self) == 0)
+ return self;
+
+ mrb_str_modify(mrb, s);
+ l = RSTRING_LEN(self);
+ b = p = (unsigned char*) RSTRING_PTR(self);
+ t = e = p + l;
+ *(e--) = 0;
+
+ // find trailing ascii/number
+ while (e >= b) {
+ if (ISALNUM(*e))
+ break;
+ e--;
+ }
+ if (e < b) {
+ e = p + l - 1;
+ result = mrb_str_new_lit(mrb, "");
+ }
+ else {
+ // find leading letter of the ascii/number
+ b = e;
+ while (b > p) {
+ if (!ISALNUM(*b) || (ISALNUM(*b) && *b != '9' && *b != 'z' && *b != 'Z'))
+ break;
+ b--;
+ }
+ if (!ISALNUM(*b))
+ b++;
+ result = mrb_str_new(mrb, (char*) p, b - p);
+ }
+
+ while (e >= b) {
+ if (!ISALNUM(*e)) {
+ if (*e == 0xff) {
+ mrb_str_cat_lit(mrb, result, "\x01");
+ (*e) = 0;
+ }
+ else
+ (*e)++;
+ break;
+ }
+ prepend = NULL;
+ if (*e == '9') {
+ if (e == b) prepend = "1";
+ *e = '0';
+ }
+ else if (*e == 'z') {
+ if (e == b) prepend = "a";
+ *e = 'a';
+ }
+ else if (*e == 'Z') {
+ if (e == b) prepend = "A";
+ *e = 'A';
+ }
+ else {
+ (*e)++;
+ break;
+ }
+ if (prepend) mrb_str_cat_cstr(mrb, result, prepend);
+ e--;
+ }
+ result = mrb_str_cat(mrb, result, (char*) b, t - b);
+ l = RSTRING_LEN(result);
+ mrb_str_resize(mrb, self, l);
+ memcpy(RSTRING_PTR(self), RSTRING_PTR(result), l);
+ return self;
+}
+
+static mrb_value
+mrb_str_succ(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+
+ str = mrb_str_dup(mrb, self);
+ mrb_str_succ_bang(mrb, str);
+ return str;
+}
+
+#ifdef MRB_UTF8_STRING
+static const char utf8len_codepage_zero[256] =
+{
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+static mrb_int
+utf8code(unsigned char* p)
+{
+ mrb_int len;
+
+ if (p[0] < 0x80)
+ return p[0];
+
+ len = utf8len_codepage_zero[p[0]];
+ if (len > 1 && (p[1] & 0xc0) == 0x80) {
+ if (len == 2)
+ return ((p[0] & 0x1f) << 6) + (p[1] & 0x3f);
+ if ((p[2] & 0xc0) == 0x80) {
+ if (len == 3)
+ return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6)
+ + (p[2] & 0x3f);
+ if ((p[3] & 0xc0) == 0x80) {
+ if (len == 4)
+ return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12)
+ + ((p[2] & 0x3f) << 6) + (p[3] & 0x3f);
+ if ((p[4] & 0xc0) == 0x80) {
+ if (len == 5)
+ return ((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18)
+ + ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6)
+ + (p[4] & 0x3f);
+ if ((p[5] & 0xc0) == 0x80 && len == 6)
+ return ((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24)
+ + ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12)
+ + ((p[4] & 0x3f) << 6) + (p[5] & 0x3f);
+ }
+ }
+ }
+ }
+ return p[0];
+}
+
+static mrb_value
+mrb_str_ord(mrb_state* mrb, mrb_value str)
+{
+ if (RSTRING_LEN(str) == 0)
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "empty string");
+ return mrb_fixnum_value(utf8code((unsigned char*) RSTRING_PTR(str)));
+}
+#else
+static mrb_value
+mrb_str_ord(mrb_state* mrb, mrb_value str)
+{
+ if (RSTRING_LEN(str) == 0)
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "empty string");
+ 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))) {
+ mrb_int min_width = RSTRING_LEN(beg);
+ 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));
+ int ai = mrb_gc_arena_save(mrb);
+
+ while (bi <= ei) {
+ mrb_value ns, str;
+
+ if (excl && bi == ei) break;
+ ns = mrb_format(mrb, "%S", mrb_fixnum_value(bi));
+ if (min_width > RSTRING_LEN(ns)) {
+ str = mrb_str_new(mrb, NULL, min_width);
+ memset(RSTRING_PTR(str), '0', min_width-RSTRING_LEN(ns));
+ memcpy(RSTRING_PTR(str)+min_width-RSTRING_LEN(ns),
+ RSTRING_PTR(ns), RSTRING_LEN(ns));
+ }
+ else {
+ str = ns;
+ }
+ mrb_yield(mrb, block, str);
+ 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
+mrb_mruby_string_ext_gem_init(mrb_state* mrb)
+{
+ struct RClass * s = mrb->string_class;
+
+ mrb_define_method(mrb, s, "dump", mrb_str_dump, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, s, "swapcase!", mrb_str_swapcase_bang, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "swapcase", mrb_str_swapcase, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "concat", mrb_str_concat_m, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "<<", mrb_str_concat_m, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "start_with?", mrb_str_start_with, MRB_ARGS_REST());
+ mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST());
+ mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "oct", mrb_str_oct, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE());
+ 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_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());
+}
+
+void
+mrb_mruby_string_ext_gem_final(mrb_state* mrb)
+{
+}
diff --git a/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/test/string.rb b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/test/string.rb
new file mode 100644
index 0000000..2a568c7
--- /dev/null
+++ b/debian/vendor-h2o/deps/mruby/mrbgems/mruby-string-ext/test/string.rb
@@ -0,0 +1,667 @@
+##
+# String(Ext) Test
+
+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
+ str1 = "hello"
+ bytes1 = [104, 101, 108, 108, 111]
+ assert_equal bytes1[0], str1.getbyte(0)
+ assert_equal bytes1[-1], str1.getbyte(-1)
+ assert_equal bytes1[6], str1.getbyte(6)
+
+ str2 = "\xFF"
+ bytes2 = [0xFF]
+ assert_equal bytes2[0], str2.getbyte(0)
+end
+
+assert('String#setbyte') do
+ str1 = "hello"
+ h = "H".getbyte(0)
+ str1.setbyte(0, h)
+ 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
+
+assert('String#byteslice') do
+ str1 = "hello"
+ assert_equal("e", str1.byteslice(1))
+ assert_equal("o", str1.byteslice(-1))
+ assert_equal("ell", str1.byteslice(1..3))
+ assert_equal("el", str1.byteslice(1...3))
+end
+
+assert('String#dump') do
+ ("\1" * 100).dump # should not raise an exception - regress #1210
+ "\0".inspect == "\"\\000\"" and
+ "foo".dump == "\"foo\""
+end
+
+assert('String#strip') do
+ s = " abc "
+ "".strip == "" and " \t\r\n\f\v".strip == "" and
+ "\0a\0".strip == "\0a" and
+ "abc".strip == "abc" and
+ " abc".strip == "abc" and
+ "abc ".strip == "abc" and
+ " abc ".strip == "abc" and
+ s == " abc "
+end
+
+assert('String#lstrip') do
+ s = " abc "
+ s.lstrip
+ "".lstrip == "" and " \t\r\n\f\v".lstrip == "" and
+ "\0a\0".lstrip == "\0a\0" and
+ "abc".lstrip == "abc" and
+ " abc".lstrip == "abc" and
+ "abc ".lstrip == "abc " and
+ " abc ".lstrip == "abc " and
+ s == " abc "
+end
+
+assert('String#rstrip') do
+ s = " abc "
+ s.rstrip
+ "".rstrip == "" and " \t\r\n\f\v".rstrip == "" and
+ "\0a\0".rstrip == "\0a" and
+ "abc".rstrip == "abc" and
+ " abc".rstrip == " abc" and
+ "abc ".rstrip == "abc" and
+ " abc ".rstrip == " abc" and
+ s == " abc "
+end
+
+assert('String#strip!') do
+ s = " abc "
+ t = "abc"
+ s.strip! == "abc" and s == "abc" and t.strip! == nil
+end
+
+assert('String#lstrip!') do
+ s = " abc "
+ t = "abc "
+ s.lstrip! == "abc " and s == "abc " and t.lstrip! == nil
+end
+
+assert('String#rstrip!') do
+ s = " abc "
+ t = " abc"
+ s.rstrip! == " abc" and s == " abc" and t.rstrip! == nil
+end
+
+assert('String#swapcase') do
+ assert_equal "hELLO", "Hello".swapcase
+ assert_equal "CyBeR_pUnK11", "cYbEr_PuNk11".swapcase
+end
+
+assert('String#swapcase!') do
+ s = "Hello"
+ t = s.clone
+ t.swapcase!
+ assert_equal s.swapcase, t
+end
+
+assert('String#concat') do
+ 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
+
+assert('String#casecmp') do
+ assert_equal 1, "abcdef".casecmp("abcde")
+ assert_equal 0, "aBcDeF".casecmp("abcdef")
+ assert_equal(-1, "abcdef".casecmp("abcdefg"))
+ assert_equal 0, "abcdef".casecmp("ABCDEF")
+ o = Object.new
+ def o.to_str
+ "ABCDEF"
+ end
+ assert_equal 0, "abcdef".casecmp(o)
+end
+
+assert('String#start_with?') do
+ assert_true "hello".start_with?("heaven", "hell")
+ assert_true !"hello".start_with?("heaven", "paradise")
+ assert_true !"h".start_with?("heaven", "hell")
+ assert_raise TypeError do "hello".start_with?(true) end
+end
+
+assert('String#end_with?') do
+ assert_true "string".end_with?("ing", "mng")
+ assert_true !"string".end_with?("str", "tri")
+ assert_true !"ng".end_with?("ing", "mng")
+ assert_raise TypeError do "hello".end_with?(true) end
+end
+
+assert('String#partition') do
+ assert_equal ["a", "x", "axa"], "axaxa".partition("x")
+ assert_equal ["aaaaa", "", ""], "aaaaa".partition("x")
+ assert_equal ["", "", "aaaaa"], "aaaaa".partition("")
+ assert_equal ["", "a", "aaaa"], "aaaaa".partition("a")
+ assert_equal ["aaaa", "b", ""], "aaaab".partition("b")
+ assert_equal ["", "b", "aaaa"], "baaaa".partition("b")
+ assert_equal ["", "", ""], "".partition("a")
+end
+
+assert('String#rpartition') do
+ assert_equal ["axa", "x", "a"], "axaxa".rpartition("x")
+ assert_equal ["", "", "aaaaa"], "aaaaa".rpartition("x")
+ assert_equal ["aaaaa", "", ""], "aaaaa".rpartition("")
+ assert_equal ["aaaa", "a", ""], "aaaaa".rpartition("a")
+ assert_equal ["aaaa", "b", ""], "aaaab".rpartition("b")
+ assert_equal ["", "b", "aaaa"], "baaaa".rpartition("b")
+ assert_equal ["", "", ""], "".rpartition("a")
+end
+
+assert('String#hex') do
+ assert_equal 16, "10".hex
+ assert_equal 255, "ff".hex
+ assert_equal 16, "0x10".hex
+ assert_equal (-16), "-0x10".hex
+ assert_equal 0, "xyz".hex
+ assert_equal 16, "10z".hex
+ assert_equal 16, "1_0".hex
+ assert_equal 0, "".hex
+end
+
+assert('String#oct') do
+ assert_equal 8, "10".oct
+ assert_equal 7, "7".oct
+ assert_equal 0, "8".oct
+ assert_equal 0, "9".oct
+ assert_equal 0, "xyz".oct
+ assert_equal 8, "10z".oct
+ assert_equal 8, "1_0".oct
+ assert_equal 8, "010".oct
+ assert_equal (-8), "-10".oct
+end
+
+assert('String#chr') do
+ assert_equal "a", "abcde".chr
+ # test Fixnum#chr as well
+ assert_equal "a", 97.chr
+end
+
+assert('String#lines') do
+ assert_equal ["Hel\n", "lo\n", "World!"], "Hel\nlo\nWorld!".lines
+ assert_equal ["Hel\n", "lo\n", "World!\n"], "Hel\nlo\nWorld!\n".lines
+ assert_equal ["\n", "\n", "\n"], "\n\n\n".lines
+ assert_equal [], "".lines
+end
+
+assert('String#clear') do
+ # embed string
+ s = "foo"
+ assert_equal("", s.clear)
+ assert_equal("", s)
+
+ # not embed string and not shared string
+ s = "foo" * 100
+ a = s
+ assert_equal("", s.clear)
+ assert_equal("", s)
+ assert_equal("", a)
+
+ # shared string
+ s = "foo" * 100
+ a = s[10, 90] # create shared string
+ assert_equal("", s.clear) # clear
+ assert_equal("", s) # s is cleared
+ assert_not_equal("", a) # a should not be affected
+end
+
+assert('String#slice!') do
+ a = "AooBar"
+ b = a.dup
+ assert_equal "A", a.slice!(0)
+ assert_equal "AooBar", b
+
+ a = "FooBar"
+ assert_equal "r", a.slice!(-1)
+ assert_equal "FooBa", a
+
+ a = "FooBar"
+ assert_nil a.slice!(6)
+ assert_nil a.slice!(-7)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_equal "Foo", a.slice!(0, 3)
+ assert_equal "Bar", a
+
+ a = "FooBar"
+ assert_equal "Bar", a.slice!(-3, 3)
+ assert_equal "Foo", a
+
+ a = "FooBar"
+ assert_equal "", a.slice!(6, 2)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_nil a.slice!(-7,10)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_equal "Foo", a.slice!(0..2)
+ assert_equal "Bar", a
+
+ a = "FooBar"
+ assert_equal "Bar", a.slice!(-3..-1)
+ assert_equal "Foo", a
+
+ a = "FooBar"
+ assert_equal "", a.slice!(6..2)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_nil a.slice!(-10..-7)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_equal "Foo", a.slice!("Foo")
+ assert_equal "Bar", a
+
+ a = "FooBar"
+ assert_nil a.slice!("xyzzy")
+ assert_equal "FooBar", a
+
+ assert_raise(ArgumentError) { "foo".slice! }
+end
+
+assert('String#succ') do
+ assert_equal "", "".succ
+ assert_equal "1", "0".succ
+ assert_equal "10", "9".succ
+ assert_equal "01", "00".succ
+ assert_equal "a1", "a0".succ
+ assert_equal "A1", "A0".succ
+ assert_equal "10", "09".succ
+ assert_equal "b0", "a9".succ
+ assert_equal "B0", "A9".succ
+
+ assert_equal "b", "a".succ
+ assert_equal "aa", "z".succ
+ assert_equal "ab", "aa".succ
+ assert_equal "Ab", "Aa".succ
+ assert_equal "0b", "0a".succ
+ assert_equal "ba", "az".succ
+ assert_equal "Ba", "Az".succ
+ assert_equal "1a", "0z".succ
+
+ assert_equal "B", "A".succ
+ assert_equal "AA", "Z".succ
+ assert_equal "AB", "AA".succ
+ assert_equal "aB", "aA".succ
+ assert_equal "0B", "0A".succ
+ assert_equal "BA", "AZ".succ
+ assert_equal "bA", "aZ".succ
+ assert_equal "1A", "0Z".succ
+
+ assert_equal ".", "-".succ
+ assert_equal "\x01\x00", "\xff".succ
+ assert_equal "-b", "-a".succ
+ assert_equal "-aa", "-z".succ
+ assert_equal "-a-b-", "-a-a-".succ
+ assert_equal "-b-", "-a-".succ
+ assert_equal "-aa-", "-z-".succ
+ assert_equal "あb", "あa".succ
+ assert_equal "あba", "あaz".succ
+
+ a = ""; a.succ!
+ assert_equal "", a
+ a = "0"; a.succ!
+ assert_equal "1", a
+ a = "9"; a.succ!
+ assert_equal "10", a
+ a = "00"; a.succ!
+ assert_equal "01", a
+ a = "a0"; a.succ!
+ assert_equal "a1", a
+ a = "A0"; a.succ!
+ assert_equal "A1", a
+ a = "09"; a.succ!
+ assert_equal "10", a
+ a = "a9"; a.succ!
+ assert_equal "b0", a
+ a = "A9"; a.succ!
+ assert_equal "B0", a
+
+ a = "a"; a.succ!
+ assert_equal "b", a
+ a = "z"; a.succ!
+ assert_equal "aa", a
+ a = "aa"; a.succ!
+ assert_equal "ab", a
+ a = "Aa"; a.succ!
+ assert_equal "Ab", a
+ a = "0a"; a.succ!
+ assert_equal "0b", a
+ a = "az"; a.succ!
+ assert_equal "ba", a
+ a = "Az"; a.succ!
+ assert_equal "Ba", a
+ a = "0z"; a.succ!
+ assert_equal "1a", a
+
+ a = "A"; a.succ!
+ assert_equal "B", a
+ a = "Z"; a.succ!
+ assert_equal "AA", a
+ a = "AA"; a.succ!
+ assert_equal "AB", a
+ a = "aA"; a.succ!
+ assert_equal "aB", a
+ a = "0A"; a.succ!
+ assert_equal "0B", a
+ a = "AZ"; a.succ!
+ assert_equal "BA", a
+ a = "aZ"; a.succ!
+ assert_equal "bA", a
+ a = "0Z"; a.succ!
+ assert_equal "1A", a
+
+ a = "-"; a.succ!
+ assert_equal ".", a
+ a = "\xff"; a.succ!
+ assert_equal "\x01\x00", a
+ a = "-a"; a.succ!
+ assert_equal "-b", a
+ a = "-z"; a.succ!
+ assert_equal "-aa", a
+ a = "-a-a-"; a.succ!
+ assert_equal "-a-b-", a
+ a = "-a-"; a.succ!
+ assert_equal "-b-", a
+ a = "-z-"; a.succ!
+ assert_equal "-aa-", a
+ a = "あb"; a.succ!
+ assert_equal "あc", a
+ a = "あaz"; a.succ!
+ assert_equal "あba", a
+end
+
+assert('String#next') do
+ assert_equal "01", "00".next
+
+ a = "00"; a.next!
+ assert_equal "01", a
+end
+
+assert('String#insert') do
+ assert_equal "Xabcd", "abcd".insert(0, 'X')
+ assert_equal "abcXd", "abcd".insert(3, 'X')
+ assert_equal "abcdX", "abcd".insert(4, 'X')
+ assert_equal "abXcd", "abcd".insert(-3, 'X')
+ assert_equal "abcdX", "abcd".insert(-1, 'X')
+ 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
+
+assert('String#prepend') do
+ a = "world"
+ assert_equal "hello world", a.prepend("hello ")
+ assert_equal "hello world", a
+end
+
+assert('String#ljust') do
+ 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"
+ count = 0
+ assert_equal("aa", a.upto("zz") {|s|
+ assert_equal(start, s)
+ start.succ!
+ count += 1
+ })
+ assert_equal(676, count)
+
+ a = "a"
+ start = "a"
+ count = 0
+ assert_equal("a", a.upto("a") {|s|
+ assert_equal(start, s)
+ start.succ!
+ count += 1
+ })
+ assert_equal(1, count)
+
+ a = "a"
+ start = "a"
+ count = 0
+ assert_equal("a", a.upto("b", true) {|s|
+ assert_equal(start, s)
+ start.succ!
+ count += 1
+ })
+ assert_equal(1, count)
+
+ a = "0"
+ start = "0"
+ count = 0
+ assert_equal("0", a.upto("0") {|s|
+ assert_equal(start, s)
+ start.succ!
+ count += 1
+ })
+ assert_equal(1, count)
+
+ a = "0"
+ start = "0"
+ count = 0
+ assert_equal("0", a.upto("-1") {|s|
+ assert_equal(start, s)
+ start.succ!
+ count += 1
+ })
+ assert_equal(0, count)
+
+ a = "-1"
+ start = "-1"
+ count = 0
+ assert_equal("-1", a.upto("-2") {|s|
+ assert_equal(start, s)
+ start.succ!
+ count += 1
+ })
+ assert_equal(2, count)
+
+ assert_raise(TypeError) { "a".upto(:c) {} }
+end
+
+assert('String#ord') do
+ 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
+
+assert('String#ord(UTF-8)') do
+ got = "こんにちは世界!".split('').map {|x| x.ord}
+ expect = [0x3053,0x3093,0x306b,0x3061,0x306f,0x4e16,0x754c,0x21]
+ assert_equal expect, got
+end if UTF8STRING
+
+assert('String#chr') do
+ assert_equal "h", "hello!".chr
+end
+assert('String#chr(UTF-8)') do
+ assert_equal "こ", "こんにちは世界!".chr
+end if UTF8STRING
+
+assert('String#chars') do
+ expect = ["h", "e", "l", "l", "o", "!"]
+ assert_equal expect, "hello!".chars
+ s = ""
+ "hello!".chars do |x|
+ s += x
+ end
+ assert_equal "hello!", s
+end
+
+assert('String#chars(UTF-8)') do
+ expect = ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!']
+ assert_equal expect, "こんにちは世界!".chars
+ s = ""
+ "こんにちは世界!".chars do |x|
+ s += x
+ end
+ assert_equal "こんにちは世界!", s
+end if UTF8STRING
+
+assert('String#each_char') do
+ s = ""
+ "hello!".each_char do |x|
+ s += x
+ end
+ assert_equal "hello!", s
+end
+
+assert('String#each_char(UTF-8)') do
+ s = ""
+ "こんにちは世界!".each_char do |x|
+ s += x
+ end
+ assert_equal "こんにちは世界!", s
+end if UTF8STRING
+
+assert('String#codepoints') do
+ expect = [104, 101, 108, 108, 111, 33]
+ assert_equal expect, "hello!".codepoints
+ cp = []
+ "hello!".codepoints do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end
+
+assert('String#codepoints(UTF-8)') do
+ expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33]
+ assert_equal expect, "こんにちは世界!".codepoints
+ cp = []
+ "こんにちは世界!".codepoints do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end if UTF8STRING
+
+assert('String#each_codepoint') do
+ expect = [104, 101, 108, 108, 111, 33]
+ cp = []
+ "hello!".each_codepoint do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end
+
+assert('String#each_codepoint(UTF-8)') do
+ expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33]
+ cp = []
+ "こんにちは世界!".each_codepoint do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end if UTF8STRING