1日1行カレンダーの機能強化版を作りました.
さっそくですがソースです.
#!/usr/bin/env ruby # -*- coding: utf-8 -*- # slad.rb : Simple Line-A-Day Calendar require "date" require "optparse" class Slad FORMAT = { :j => { :pattern => '%Y年%m月%d日', :week => %w(日 月 火 水 木 金 土) }, :e => { :pattern => '%Y-%m-%d', :week => %w(Sun Mon Tue Wed Thu Fri Sat) } } def initialize(opt = {}) @from = opt[:from] || Time.now @to = opt[:to] || 6 @sep = opt[:sep] || "" @lang = opt[:lang] || get_lang @dir = opt[:dir] end def get_lang (/ja/ =~ ENV["LANG"]) ? :j : :e end def get_date(param, base_date = nil) case param when Date param when Time Date.new(param.year, param.mon, param.mday) when Array Date.new(*param) when /(\d\d\d\d)\D*(\d\d)\D*(\d\d)/ Date.new($1.to_i, $2.to_i, $3.to_i) when Fixnum, /^[-+]?\d+$/ plus = param.to_i if Date === base_date base_date + plus * (@dir == :b ? -1 : 1) else raise end else raise end end def init_dates @d_from = get_date(@from) @d_to = get_date(@to, @d_from) end def setup_order if @d_from > @d_to @d_from, @d_to = @d_to, @d_from if @dir == :r @dir = :f elsif @dir.nil? @dir = :b end else if @dir == :r @dir = :b elsif @dir.nil? @dir = :f end end # Note: @d_from <= @d_to is always true. end def get_date_array fmt = FORMAT[@lang] d_array = [] @d_from.upto(@d_to) do |d| str = d.strftime(fmt[:pattern]) + "(#{fmt[:week][d.wday]})" + @sep d_array << str end d_array.reverse! if @dir == :b d_array end def start init_dates setup_order puts get_date_array end def self.setup(opt = {}) s = self.new(opt) s.init_dates s.setup_order s end def self.generate(opt = {}) self.setup(opt).get_date_array end end if __FILE__ == $0 op = OptionParser.new opt = {} op.on("-f", "--from=VAL", "\"from\" date") {|v| opt[:from] = v} op.on("-t", "--to=VAL", "\"to\" date or interval") {|v| opt[:to] = v} op.on("-a", "--after=VAL", "interval days (0 origin)") {|v| opt[:to] = v.to_i} op.on("-A", "--After=VAL", "number of days (1 origin)") {|v| num = v.to_i opt[:to] = num - (num > 0 ? 1 : 0) + (num < 0 ? 1 : 0) } op.on("-s", "--sep=VAL", "separator") {|v| opt[:sep] = v} op.on("-:", "--colon", "colon as separator") {opt[:sep] = ': '} op.on("-.", "--Colon", "zenkaku colon as separator") {opt[:sep] = ':'} op.on("-l", "--lang=VAL", "language (j or e)") {|v| opt[:lang] = v.split(//).first.to_sym} op.on("-j", "--japanese", "Japanese") {|v| opt[:lang] = :j} op.on("-e", "--english", "English") {|v| opt[:lang] = :e} op.on("-o", "--fore", "print foreword") {opt[:dir] = :f} op.on("-b", "--back", "print backword") {opt[:dir] = :b} op.on("-r", "--rev", "print reversely") {opt[:dir] = :r} op.parse!(ARGV) Slad.new(opt).start end
ソフトウェア名を決めるにあたり,辞書を引いたところ,page-a-day calendarという言葉が載っていました.「日めくりカレンダー」のことです.なるほど,page a dayは「1日につき1枚」ですね.
1日につき1行なら,line a day.ladでは分かりにくいのでsimpleをつけて,Simple Line-A-Day (Slad) Calendarとした次第です.
入力に応じて,さまざまな形で,1日1行カレンダーを出力します.前回からの変更点として,開始日・終了日はコマンドライン上で指定でき,「いつまで」は日付でなくても日数でもよく,さらに,日付をさかのぼった出力も可能になっています.いくつか実行例を示します.
$ ruby slad.rb -f 2010-12-03 2010年12月03日(金) 2010年12月04日(土) 2010年12月05日(日) 2010年12月06日(月) 2010年12月07日(火) 2010年12月08日(水) 2010年12月09日(木)
$ ruby slad.rb -f 20101203 -a 2 2010年12月03日(金) 2010年12月04日(土) 2010年12月05日(日)
$ ruby slad.rb -f 20101203 -a -2 2010年12月03日(金) 2010年12月02日(木) 2010年12月01日(水)
$ ruby slad.rb -f 20101203 -a -2 --fore 2010年12月01日(水) 2010年12月02日(木) 2010年12月03日(金)
$ ruby slad.rb -f 20101203 -A 3 2010年12月03日(金) 2010年12月04日(土) 2010年12月05日(日)
$ ruby slad.rb --from=2010-12-03 --After=3 --english --colon 2010-12-03(Fri): 2010-12-04(Sat): 2010-12-05(Sun):
$ ruby slad.rb --help Usage: slad [options] -f, --from=VAL "from" date -t, --to=VAL "to" date or interval -a, --after=VAL interval days (0 origin) -A, --After=VAL number of days (1 origin) -s, --sep=VAL separator -:, --colon colon as separator -., --Colon zenkaku colon as separator -l, --lang=VAL language (j or e) -j, --japanese Japanese -e, --english English -o, --fore print foreword -b, --back print backword -r, --rev print reversely
言語については日本語と英語の2種類から選べます.コマンドでの指定がなければ,環境変数LANGの値が"ja"を含むか否かで判断しています.
オプションの-s, -:, -.ほかは,行の右にイベントや実施した内容を書けるようにするための,境界線を指定するものです.
単独のRubyスクリプトですが,別途Test::Unitでテストを通して,かなりのバグ退治をしています.既知の問題として,ファイルに出力するオプションはありません.リダイレクション(コマンドの後ろに「> ファイル名」)で保存してください.
今後の予定ですが…考えてみると,Ruby処理系がなくても生成できそうです.具体的には,開始日終了日その他もろもろを,HTMLのインタフェースで指定し,ボタンを押せば,内部でJavaScriptのプログラムが計算し,画面上に表示するという形です.もちろんWebサーバもいりません.暇を見つけて検討したいと思います.あとそのうち,GitHubに登録します.