Skip to content

カレンダープログラムを作成しました。#2

Open
s-tone-gs wants to merge 12 commits intomainfrom
my-calendar
Open

カレンダープログラムを作成しました。#2
s-tone-gs wants to merge 12 commits intomainfrom
my-calendar

Conversation

@s-tone-gs
Copy link
Copy Markdown
Owner

コマンドライン上で表示されるカレンダープログラムを作成しました。
レビューをお願いします。

def check_inputs(inputs)
year = inputs['y']
month = inputs['m']
raise '-yの引数には1873以上の数値を入力してください' if !year.nil? && year.to_i < 1873
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

コマンドを作るときは raiseで終わるのはダメじゃないですが、ちょっと乱暴です。
エラーメッセージを出力して、プロセスを終わる用のメソッドを使うと良いですね。調べてみてください。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

プロセスを終了するという意図を明確に示すために修正にて反映しました。

理解の確認をさせてください。
今回の修正はコミット名に記載した目的のためだと理解しました。
raiseは発生させたエラーをキャッチして何らかの処理を行うことが前提であるため、今回の場面で使用するのは少し乱暴。exitはプロセスを終了するというメソッドでより意図が明確になるという理解です。あっておりますでしょうか?

「コマンドを作るときは」という部分が分かりませんでした。私は「コマンドを作るときはWebシステムなどを作るときとは勝手が違うから」という意味で解釈したのですが、その「勝手」が何かわかりませんでした。

Copy link
Copy Markdown

@u1tnk u1tnk Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raiseは発生させたエラーをキャッチして何らかの処理を行うことが前提であるため、今回の場面で使用するのは少し乱暴。exitはプロセスを終了するというメソッドでより意図が明確になるという理解です。あっておりますでしょうか?

はい、大丈夫です。
補足するとraiseしたときはエラーメッセージも例外名など本来のコマンドで不要なメッセージも出力されているので、そこも良くないですね。

「コマンドを作るときは」

すみません、分かりづらかったですね 🙏
「コマンドを作るときは」 というのは その後に買いてる通り、 「Webシステムではなく、ターミナル上のCLIコマンドを作るときは」という意図でした。

その「勝手」が何かわかりませんでした。

「勝手」の文脈にもよりますが、一般的な話で言うと return code、STDOUT/STDERR に一般的なunixiコマンドの作法に応じた出力を行うことかなと思いました。
今回については例外を出したことで、 return codeはエラー時のものになっていて、STDERRに出力しているがエラーメッセージが意図したものになっていないし、例外を投げてしまうと制御できないのでやめた方が良い。
となります。
ちなみに質問されたので細かく答えましたが、このプラクティスの時点ではちょっと難しいので、そこまで細かく(STDOUT/STDERRなど)はチェックしていません。とりあえず出力の見た目がcalコマンドと大体一緒であれば大丈夫です。

# カレンダーのデータを作成
def make_calendar_data(year, month, calendar)
week_number = 1
first_day = Date.new(year, month, 1).day
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちょっと早いアドバイスですが、
せっかく オブジェクトという色々できるものを作っているのですぐに dayを読んでintにしてしまうのではなく、オブジェクトをそのまま使って、出力などするときにdayを呼ぶと良いですよ。

Copy link
Copy Markdown
Owner Author

@s-tone-gs s-tone-gs Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dateオブジェクトの再利用性を上げるために修正にて反映しました。

これもコミットに記載した目的で合っておりますでしょうか?後々新たな機能を付け加えたくなったとき、メソッドを簡単に利用できるようにオブジェクトのまま保持しておくという理解です。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

はい、その理解であっています。
後にやるオブジェクト指向プラクティスのときは必須になります。

week_number = 1
first_day = Date.new(year, month, 1).day
last_day = Date.new(year, month, -1).day
(first_day..last_day).to_a.each do |day|
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to_aは無くても動くと思いますがどうでしょうか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

動きました。
冗長だったため削除にて削除しました。

end

# カレンダーデータをもとにカレンダーを表示
def make_calendar(year, months, month, calendar)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make_calendar_dataと make_calendar というメソッド名は差がわかりません。
メソッド名だけで何をしているか想像できるような名前をつけましょう。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def make_calendar(year, months, month, calendar)
printf('%8s', months[month])
printf("%8s\n", year)
calendar.each do |x|
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

数行なのでxとyでも良いレベルではありますが、何が入っているかわかるシンプルな名前が付けられるならそっちの方が良いですね。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

year = inputs['y'].nil? ? Date.today.year : inputs['y'].to_i
month = inputs['m'].nil? ? Date.today.month : inputs['m'].to_i
# ネストされた配列の値を呼び出す際にエラーが起こらないように空配列をセットしてある
calendar = [%w[Su Mo Tu We Th Fr Sa], []]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calendarは変更が入るので良いとして、変更の無い部分は定数にした方が良いです

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

意図しない再代入が起こらないように修正

というのも正しいのですが、プログラムの可読性の向上の為というのが大きいですね。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

%w[Su Mo Tu We Th Fr Sa]

この部分も定数にして欲しいです。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

メソッドを単一責任にするため修正にて反映しました

可読性向上、なるほどです!確かに変化する部分としない部分が視覚的に分かるだけで読みやすさが違いますね🙌

year = inputs['y'].nil? ? Date.today.year : inputs['y'].to_i
month = inputs['m'].nil? ? Date.today.month : inputs['m'].to_i
# ネストされた配列の値を呼び出す際にエラーが起こらないように空配列をセットしてある
calendar = [%w[Su Mo Tu We Th Fr Sa], []]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

%w[Su Mo Tu We Th Fr Sa]

この部分も定数にして欲しいです。

12 => 'December' }

# カレンダーのデータを作成
def generate_calendar_data(year, month, calendar)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

細かいですが、 _dataのところはあまり良く無い名称です。理由は私が以前に書いたブログで 解説していますので参考にしてください。

https://u1tnk.github.io/blog/2022/12/04/naming_variable/#%E6%8A%BD%E8%B1%A1%E7%9A%84%E9%81%8E%E3%81%8E%E3%82%8B%E5%8D%98%E8%AA%9E%E3%82%92%E4%BD%BF%E3%81%86infodata%E3%81%AA%E3%81%A9

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

メソッドを単一責任にするため修正にて反映しました。

かなり変更を入れております。
命名を考える際に実装してあるメソッドの役割も同時に考えたのですが、役割以上のことをしているなと感じました。そのため、命名を変更すると同時に、メソッドが単一責任になるように修正を加えました。

# 出力する際に週と日付が同じ配列にあったほうが出力が楽であるため週と日を一緒にしてある
calendar = {:year => YEAR, :month => MONTHS[MONTH], :weeks_and_days => []}

def get_days(year, month)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

修正不要ですが、 ruby/rails界隈は get_xxx だと get_ 無くして xxx にする慣習があります。
とはいえ、その場合は取得するだけの簡単な場合に使う名前なので…僕だったら build_daysぐらいにするかなーと思います。前のgenerateでも良いと思います。

end

calendar[:weeks_and_days] = get_days(YEAR, MONTH)
calendar[:weeks_and_days].unshift(WEEKS)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これも修正するほどじゃないですが、何かを入れてunshiftするより、先頭にWEEKS代入して、daysを追加する方が自然に読めます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants