* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / sample / cal.rb
blob387657490f071d6b02b6ffa5ec945774ad323425
1 #! /usr/bin/env ruby
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 $
6 require 'date'
8 class Cal
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   }
33   DEFAULT_START = 'gb'
35   def initialize
36     opt_j; opt_m; opt_t; opt_y; opt_c
37   end
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
44   def opt_c(arg=DEFAULT_START) @start = START[arg] end
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
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
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     }
67     ve = ve.collect{|e| e.rjust(@dw)}
69     gr = group(ve, 7)
70     gr = trans(gr) if @opt_t
71     ta = gr.collect{|xs| xs.join(' ')}
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)
78     ta.unshift(ca)
79   end
81   def group(xs, n)
82     (0..xs.size / n - 1).collect{|i| xs[i * n, n]}
83   end
85   def trans(xs)
86     (0..xs[0].size - 1).collect{|i| xs.collect{|x| x[i]}}
87   end
89   def stack(xs)
90     if xs.empty? then [] else xs[0] + stack(xs[1..-1]) end
91   end
93   def block(xs, n)
94     stack(group(xs, n).collect{|ys| trans(ys).collect{|zs| zs.join('  ')}})
95   end
97   def unlines(xs)
98     xs.collect{|x| x + "\n"}.join
99   end
101   def monthly(y, m)
102     unlines(pict(y, m))
103   end
105   def addmon(y, m, n)
106     y, m = (y * 12 + (m - 1) + n).divmod(12)
107     return y, m + 1
108   end
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
115   def print(y, m)
116     set_params
117     if @opt_y then yearly(y) else monthly(y, m) end
118   end
122 if __FILE__ == $0
124   require 'getoptlong'
126   def usage
127     warn 'usage: cal [-c iso3166] [-jmty] [[month] year]'
128     exit 1
129   end
131   cal = Cal.new
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
152   y, m = ARGV.values_at(1, 0).compact.collect{|x| x.to_i}
153   cal.opt_y(true) if y && !m
155   to = Date.today
156   y ||= to.year
157   m ||= to.mon
159   usage unless m >= 1 && m <= 12
160   usage unless y >= -4712
162   print cal.print(y, m)
166 # See Bird & Wadler's Introduction to functional programming 4.5.