diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2018-04-21 22:30:54 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2018-04-21 22:30:54 +0900 |
| commit | 2213deeeaaa39ee28dc2d369f71fe7ffdee09e54 (patch) | |
| tree | 3c4fc72486f9caecce622ca75b48e66dc72218ae /mrbgems/mruby-string-ext/mrblib | |
| parent | 8b92ab5c7bfbc52934fe23075a86163f2b9fc7c3 (diff) | |
| download | mruby-2213deeeaaa39ee28dc2d369f71fe7ffdee09e54.tar.gz mruby-2213deeeaaa39ee28dc2d369f71fe7ffdee09e54.zip | |
Implement `String#upto` in Ruby.
Avoid using `mrb_yield` in C code. The function is not recommended.
Because it doesn't work well with fibers.
Diffstat (limited to 'mrbgems/mruby-string-ext/mrblib')
| -rw-r--r-- | mrbgems/mruby-string-ext/mrblib/string.rb | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 39ee57419..27ca30610 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -386,4 +386,77 @@ class String end lines end + + ## + # 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"] + def upto(max, exclusive=false, &block) + return to_enum(:upto, max, exclusive) unless block + raise TypeError, "no implicit conversion of #{max.class} into String" unless max.kind_of? String + + len = self.length + maxlen = max.length + # single character + if len == 1 and maxlen == 1 + c = self.ord + e = max.ord + while c <= e + break if exclusive and c == e + yield c.chr + c += 1 + end + return self + end + # both edges are all digits + bi = self.to_i(10) + ei = max.to_i(10) + len = self.length + if (bi > 0 or bi == "0"*len) and (ei > 0 or ei == "0"*maxlen) + while bi <= ei + break if exclusive and bi == ei + s = bi.to_s + s = s.rjust(len, "0") if s.length < len + yield s + bi += 1 + end + return self + end + bs = self + while true + n = (bs <=> max) + break if n > 0 + break if exclusive and n == 0 + yield bs + break if n == 0 + bs = bs.succ + end + self + end end |
