1#! /usr/bin/env ruby 2 3# cal.rb: Written by Tadayoshi Funaba 1998-2004,2006,2008 4# $Id: cal.rb,v 2.11 2008-01-06 08:42:17+09 tadf Exp $ 5 6require 'date' 7 8class Cal 9 10 START = 11 { 12 'cn' => Date::GREGORIAN, # China 13 'de' => 2342032, # Germany (protestant states) 14 'dk' => 2342032, # Denmark 15 'es' => 2299161, # Spain 16 'fi' => 2361390, # Finland 17 'fr' => 2299227, # France 18 'gb' => 2361222, # United Kingdom 19 'gr' => 2423868, # Greece 20 'hu' => 2301004, # Hungary 21 'it' => 2299161, # Italy 22 'jp' => Date::GREGORIAN, # Japan 23 'no' => 2342032, # Norway 24 'pl' => 2299161, # Poland 25 'pt' => 2299161, # Portugal 26 'ru' => 2421639, # Russia 27 'se' => 2361390, # Sweden 28 'us' => 2361222, # United States 29 'os' => Date::JULIAN, # (old style) 30 'ns' => Date::GREGORIAN # (new style) 31 } 32 33 DEFAULT_START = 'gb' 34 35 def initialize 36 opt_j; opt_m; opt_t; opt_y; opt_c 37 end 38 39 def opt_j(flag=false) @opt_j = flag end 40 def opt_m(flag=false) @opt_m = flag end 41 def opt_t(flag=false) @opt_t = flag end 42 def opt_y(flag=false) @opt_y = flag end 43 44 def opt_c(arg=DEFAULT_START) @start = START[arg] end 45 46 def set_params 47 @dw = if @opt_j then 3 else 2 end 48 @mw = (@dw + 1) * 7 - 1 49 @mn = if @opt_j then 2 else 3 end 50 @tw = (@mw + 2) * @mn - 2 51 @k = if @opt_m then 1 else 0 end 52 @da = if @opt_j then :yday else :mday end 53 end 54 55 def pict(y, m) 56 d = (1..31).detect{|x| Date.valid_date?(y, m, x, @start)} 57 fi = Date.new(y, m, d, @start) 58 fi -= (fi.jd - @k + 1) % 7 59 60 ve = (fi..fi + 6).collect{|cu| 61 %w(S M Tu W Th F S)[cu.wday] 62 } 63 ve += (fi..fi + 41).collect{|cu| 64 if cu.mon == m then cu.send(@da) end.to_s 65 } 66 67 ve = ve.collect{|e| e.rjust(@dw)} 68 69 gr = group(ve, 7) 70 gr = trans(gr) if @opt_t 71 ta = gr.collect{|xs| xs.join(' ')} 72 73 ca = %w(January February March April May June July 74 August September October November December)[m - 1] 75 ca = ca + ' ' + y.to_s if !@opt_y 76 ca = ca.center(@mw) 77 78 ta.unshift(ca) 79 end 80 81 def group(xs, n) 82 (0..xs.size / n - 1).collect{|i| xs[i * n, n]} 83 end 84 85 def trans(xs) 86 (0..xs[0].size - 1).collect{|i| xs.collect{|x| x[i]}} 87 end 88 89 def stack(xs) 90 if xs.empty? then [] else xs[0] + stack(xs[1..-1]) end 91 end 92 93 def block(xs, n) 94 stack(group(xs, n).collect{|ys| trans(ys).collect{|zs| zs.join(' ')}}) 95 end 96 97 def unlines(xs) 98 xs.collect{|x| x + "\n"}.join 99 end 100 101 def monthly(y, m) 102 unlines(pict(y, m)) 103 end 104 105 def addmon(y, m, n) 106 y, m = (y * 12 + (m - 1) + n).divmod(12) 107 return y, m + 1 108 end 109 110 def yearly(y) 111 y.to_s.center(@tw) + "\n\n" + 112 unlines(block((0..11).collect{|n| pict(*addmon(y, 1, n))}, @mn)) + "\n" 113 end 114 115 def print(y, m) 116 set_params 117 if @opt_y then yearly(y) else monthly(y, m) end 118 end 119 120end 121 122if __FILE__ == $0 123 124 require 'getoptlong' 125 126 def usage 127 warn 'usage: cal [-c iso3166] [-jmty] [[month] year]' 128 exit 1 129 end 130 131 cal = Cal.new 132 133 begin 134 GetoptLong.new(['-c', GetoptLong::REQUIRED_ARGUMENT], 135 ['-j', GetoptLong::NO_ARGUMENT], 136 ['-m', GetoptLong::NO_ARGUMENT], 137 ['-t', GetoptLong::NO_ARGUMENT], 138 ['-y', GetoptLong::NO_ARGUMENT]). 139 each do |opt, arg| 140 case opt 141 when '-c'; cal.opt_c(arg) || raise 142 when '-j'; cal.opt_j(true) 143 when '-m'; cal.opt_m(true) 144 when '-t'; cal.opt_t(true) 145 when '-y'; cal.opt_y(true) 146 end 147 end 148 rescue 149 usage 150 end 151 152 y, m = ARGV.values_at(1, 0).compact.collect{|x| x.to_i} 153 cal.opt_y(true) if y && !m 154 155 to = Date.today 156 y ||= to.year 157 m ||= to.mon 158 159 usage unless m >= 1 && m <= 12 160 usage unless y >= -4712 161 162 print cal.print(y, m) 163 164end 165 166# See Bird & Wadler's Introduction to functional programming 4.5. 167