optparseってなに?
optparseというのはRubyのライブラリで、 ターミナル側へ入力したオプションを処理してくれるものです。 これに使うことでcalで呼び出せるカレンダーを作ることができます
全体のコードは以下のようになります
# frozen_string_literal: true require 'date' require 'optparse' option = {} opt = OptionParser.new opt.on('-m MONTH', Integer) do |month| option[:month] = month end opt.parse!(ARGV) if option[:month] && (option[:month] < 1 || option[:month] > 12) puts "#{option[:month]} is neither a month number (1..12) nor a name" exit end year = Date.today.year month = option[:month] || Date.today.month first_day = Date.new(year, month, 1) last_day = Date.new(year, month, -1) puts "#{year}年 #{month}月".center(20) puts '月 火 水 木 金 土 日' print ' ' * ((first_day.wday + 6) % 7) (first_day..last_day).each do |day| day = if day.sunday? "#{day.day.to_s.rjust(2)}\n" else "#{day.day.to_s.rjust(2)} " end print day end
詳しく解説します
ライブラリの呼び出し
require 'date' require 'optparse'
これは、デフォルトではdateとoptparseのライブラリを使えないので、呼び出しています。 dateは日付関係のライブラリです。 optparseは、この記事のメインのテーマのライブラリで、引数でオプションを受け取って、処理するためのものです。
オプションを受けれるようにする
option = {} opt = OptionParser.new opt.on('-m MONTH', Integer) do |month| option[:month] = month end opt.parse!(ARGV)
optionというハッシュを初期化します。
OptionParserのインスタンスを作り、optに入れます。
onメソッドはルールを定義するものであり、parse!をすることによって実行されます。
optのonメソッドを使って-mとその引数を、整数でMONTHとして受取り、
更にそれをmonthとして、ブロックに渡します。
ブロックの中で、monthをさっき作ったoptionというハッシュに、キーは:monthとして入れます。
そうすると、optionの中が{ month: 9 }のようになります
opt.parse!(ARGV)により、
ターミナルで引き受けた["-m", "9"]のような配列を、onで定義した通りに実行します。
これで-mと月を書くことで、月を指定できるようになりました。
1~12月以外が入らないようにする
if option[:month] && (option[:month] < 1 || option[:month] > 12) puts "#{option[:month]} is neither a month number (1..12) nor a name" exit end
optionの:monthの値が存在し、かつ1から12以外の場合に、エラーのメッセージを出力し、終了させます
日付を定義する
year = Date.today.year month = option[:month] || Date.today.month first_day = Date.new(year, month, 1) last_day = Date.new(year, month, -1)
1から12の月が入力されたことを想定して、
まず今日の日付から、年を出します。
次に、もし引数として、月を受けた場合はそれを使い、なければ今月をmonthに代入します。
月の初めの日をfirst_dayに入れます。
月の最後の日をlast_dayに入れます。
年と月と曜日の文字を出力する
puts "#{year}年 #{month}月".center(20) puts '月 火 水 木 金 土 日'
ここから出力する部分を作っていきます。 最初に、中央揃えで、先ほど定義した年と月を出力します。
最初の空白を揃える
print ' ' * ((first_day.wday + 6) % 7)
これは、最初の日の曜日を揃えるために空白を出しています。
今回は、月曜日から始まるので、このように書きます。
wdayは日曜日なら0、月曜日なら1を返します。
(wday + 6)を7でわって余った分だけ、半角スペース3つ与えるときれいに並びます。
最初の日が月曜日の場合、(1 + 6) % 7 = 0なので、きれいに左に並びます。
実際に日付を出力する
(first_day..last_day).each do |day| day = if day.sunday? "#{day.day.to_s.rjust(2)}\n" else "#{day.day.to_s.rjust(2)} " end print day end
(first_day..last_day)と書くことによって、この範囲を、末尾を含むレンジオブジェクトとします。
eachにブロックを渡し、先程のレンジオブジェクトの中身をdayとして、if文を書きます。
day.day.to_s.rjust(2)というのは、レンジメソッドのアイテムをdayとして、その中の日の値を取って、文字列に変換し、2文字になるようにスペースで埋めます。
カレンダーは月曜日から日曜日まで並ぶので、日曜日のdayの後ろに改行文字をつけて、それ以外の日の後ろに半角スペースを付けます。 dayを再定義します。
そしてprintを使ってdayを一つずつ出力します
まとめ
複数の基礎的な操作を組み合わせることによって、カレンダーを作ることができました。 わからないことあったら、基礎に戻って復習しましょう。 今回のポイントは、OptionParserを初期化して、onメソッドで定義して、parse!メソッドでそれを実行することでした。