summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-string-ext/mrblib
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2018-04-21 22:30:54 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2018-04-21 22:30:54 +0900
commit2213deeeaaa39ee28dc2d369f71fe7ffdee09e54 (patch)
tree3c4fc72486f9caecce622ca75b48e66dc72218ae /mrbgems/mruby-string-ext/mrblib
parent8b92ab5c7bfbc52934fe23075a86163f2b9fc7c3 (diff)
downloadmruby-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.rb73
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