プログラミングと洋服と

プログラミングや洋服など、好きなことを自由に書き綴ります。

Ruby修行日記 カレンダープログラムを作る(とりあえず作成編)

いっぱしのプログラマーになるべく、プログラミングの修行をしています。(主にRuby) 今日はその修行のひとつ、カレンダープログラムを作る をやってみましたので試行錯誤の流れを残したいと思います。(日記です) この回は仕様を実直に(実直すぎるほど)プログラミングしたのでツッコミどころ満載プログラムとなります。(もちろんその後リファクタリングもします)

Rubyでカレンダープログラムを作る

●カレンダープログラムとは? 要件まとめ

<必須要件>

  • Macのターミナルで動かすcalコマンドと同じような見た目にすること

ytakegawa_—_yuudai_tk2-261-40040____—_-zsh_—_100×35.png

こんなやつ

  • コマンドのオプションとして-m-yを設定-mは月を指定でき、-yは年を指定できる
  • オプションを指定しない場合は、現在の月、年が表示される。
  • 1970〜2100年まで正しく表示される。

<あるとなお良い>

  • 今日の日付の部分の色が反転する
  • どのような引数が与えられようが、cal コマンドと同じ表示結果になる

●カレンダープログラムってどんなものか仕様を細かく分けてみる

<基本仕様>

  • 日曜日から土曜日まで数字が7つ順番に並ぶ
  • 土曜日で次の行に改行する
  • 月によって日数が変わる(30日、31日)

<オプション>

  • 月と年を指定できるオプションを実装する
  • 今日の日付の色を反転させてわかるようにする

●カレンダープログラムの仕様を作り込んでいく

1.日曜日から土曜日まで数字が7つ順番に並ぶ

これを作っていく。

まずはカレンダーもどきを作ってみる。

Cursor_and_calendar_rb_—_02_calendar.png

calendar_rb_—_02_calendar.png

カレンダーっぽいものが表示された(あたりまえ)

次に数字を自動で表示させたい。 プログラムを呼び出したときに入力したときの月のカレンダーとしたいので、 まずは入力時の月の日付を並べるプログラムを作ってみる。

calendar_rb_—_02_calendar.png ライブラリからDateクラスを呼び込み、メソッドを使って、year、month、dayに入力したときの年、月、日にちを代入する。 その月の最初の日と最後の日を指定したいので、month_start_dayとmonth_last_dayを作る。 とりあえず、ここでmonth_start_dayからmonth_last_dayを配列で表示させてみる。

calendar_rb_—_02_calendar.png 年月日、その他情報が並んでしまった。 日付だけを並べるようにしないと。 .dayを使うとdateから日にちだけを抽出できるようなので、繰り返し処理で.dayをくっつけて出力させてみよう。

calendar_rb_—_02_calendar.png

calendar_rb_—_02_calendar.png 横並びができた。

土曜日で改行してカレンダーっぽくする 横並びを土曜日で改行してカレンダーっぽい見た目にしたい。 Dataクラスにsaturday?という、レシーバが土曜日だったらtrueを返すメソッドがあるようなので、これを条件分岐に入れてみる。

Cursor_and_calendar_rb_—_02_calendar.png

calendar_rb_—_02_calendar.png おっ ちょっとカレンダーぽくなってきた 見た目が悪いので、日にちの間と、日にちが一桁だったときに数字の前にスペースを入れるプログラムを追加してみる。(ネスト深い?) あとついでに年月と曜日も表示させてみる。(putsで入れただけ)

calendar_rb_—_02_calendar.png

calendar_rb_—_02_calendar.png

だいぶ見た目は良くなってきた。 あとは月の最初の週をうまく表示させたいところ。

2.月の最初の週の見た目を整える

しかし、どうやるんだこれ??🤔 1日の位置が重要だけど、1日をどうやって動かすか…。 理屈としては、1日の曜日ごとに位置を指定するイメージでいいのかな…。 であれば…。Dataクラスに.cwdayというレシーバの曜日を数字として返す(例:月曜の場合1を返す)メソッドがあったから、そのメソッドを使って1日の曜日ごとに位置を変更する条件分岐の構文を書いてみる。 こんな感じ

test_rb_—_02_calendar.png

…。 なーんか、あまりかっこよくない感じ。。 とりあえず動きを見てみる。

calendar_rb_—_02_calendar.png

ぐはっ! カレンダーを貫いた🤤 あー、土曜日以外はprintで横並びにしているから1日がちょうど土曜日だと折り返すプログラムにひっかからないのか…。 なら無理やりこうやって!😠

calendar_rb_—_02_calendar.png

test_rb_—_02_calendar.png

修正はされた…が… だんだん、対処療法的なプログラムになってきている。やばいか…? ・・・ しかし、いいプログラムが思いつかないのでとりあえずこれで走ってみる。 他の年月でも動きを確認。 2021.10月

calendar_rb_—_02_calendar.png 2020.4月

calendar_rb_—_02_calendar.png 良さそう。

3.オプション機能をつけていく

月と年を指定できるオプションを実装する -y 数字の入力で年の指定を、-m 数字の入力で月の指定をできるようにしたい。

optparseライブラリを使うとコマンドラインのオプションが実装できるとのこと。 リファレンスを読むと、

ARGV の機能 optparse を require すると ARGV に OptionParser::Arguable の機能が加わります。以下の書き方ができるようになります。 OptionParser::Arguable#getopts はオプションを保持した Hash を返します。

# sample.rb の内容
require 'optparse'
params = ARGV.getopts("a:b:", "foo", "bar:")
p params

この sample.rb を実行すると

$ ruby sample.rb -a 1 --foo --bar xxx
{"a"=>"1", "b"=>nil, "foo"=>true, "bar"=>"xxx"}

とのことで、ARGV.getoptsにy:m:を引数に設定すればオプションにできそう。 続きは次回!!