#!/usr/bin/ruby # range STOP | START STOP | START STOP INCREMENT - print a sequence of numbers # # START and INCREMENT default to 1. # Prefix START with leading spaces or zeroes as wanted. # Increment can be "/NUMBER" to use (STOP-START)/NUMBER as INCREMENT. # Increment can be "NUM/DENOM" for a rational increment. start = 1.to_r start_pre = 0 start_post = 0 incr = 1.to_r incr_pre = 0 incr_post = 0 pad = "0" class Rational def to_decimal(pre, post, pad="0") digits = (((10**post) * numerator + denominator/2) / denominator). abs.to_i.to_s digits = digits.rjust(post + (abs < 1 ? 1 : 0), "0") digits = digits.rjust(pre + post, pad) digits.insert(-post-1, '.') if post > 0 if self < 0 if pad == "0" digits.insert(0, '-') else digits.sub!(/(.*)#{pad}/, '\1-') or digits.insert(0, '-') end end digits end end def parse(s) case s when /\A(\s*)-?(\d+)\z/ [Rational(s), \$1.size + \$2.size, 0] when /\A(\s*)-?(\d*)\.(\d+)\z/ [Rational(s), \$1.size + \$2.size, \$3.size] when /\A-?\d+\/\d+\z/ [Rational(s), 0, 0] else raise ArgumentError, "can't parse #{s}" end end case ARGV.size when 1 stop, stop_pre, stop_post = parse(ARGV[0]) when 2, 3 start, start_pre, start_post = parse(ARGV[0]) stop, stop_pre, stop_post = parse(ARGV[1]) pad = " " if ARGV[0].start_with?(" ") if ARGV.size == 3 if ARGV[2].start_with?("/") n = parse(ARGV[2][1..-1]).first incr = Rational(stop - start, n) else incr, incr_pre, incr_post = parse(ARGV[2]) end end else abort "Usage: range STOP | START STOP | START STOP INCREMENT" end # pre = [start_pre, incr_pre, stop_pre].max pre = start_pre post = [start_post, incr_post, stop_post].max start.step(stop, incr) { |val| puts val.to_decimal(pre, post, pad) }