1. 環境#
- macOS Monterey 12.4
- Ruby 3.1.0
2. カレンダープログラムの要件#
- -mで月を、-yで年を指定できる
- 引数を指定しない場合は、今年・今月のカレンダーが表示される
- macに入っているcalコマンドと同じ見た目になっている
- 今日の日付の部分の色が反転する
- どのような引数が与えられようが、cal コマンドと同じ表示結果になる
3. ソースコード#
3-1. 試作品(自作→レビュー反映)#
#!/usr/bin/env ruby
require 'date'
require 'optparse'
today = Date.today
options = ARGV.getopts("", "m:#{today.month}", "y:#{today.year}")
if options["m"].to_i >= 1 && options["m"].to_i <= 12
inputed_month = options["m"].to_i
else
puts "cal: #{options["m"]} is neither a month number (1..12) nor a name"
return
end
if options["y"].to_i >= 1 && options["y"].to_i <= 9999
inputed_year = options["y"].to_i
else
puts "cal: year `#{options["y"]}' not in range 1..9999"
return
end
first_date = Date.new(inputed_year, inputed_month, 1)
last_date = Date.new(inputed_year, inputed_month, -1)
space = " "
puts " #{inputed_month}月 #{inputed_year}"
puts "日 月 火 水 木 金 土"
print space * first_date.wday
def color_reverse(text)
"\e[30m\e[47m#{text}\e[0m"
end
(first_date..last_date).each do |full_date|
day_of_week = full_date.wday
if full_date == today
print color_reverse(full_date.day).rjust(16)
else
print full_date.day.to_s.rjust(2)
end
print " "
puts "" if day_of_week == 6
end
puts ""
3-2. 最終形(自作→レビュー反映→他の人のコードを見る)#
#!/usr/bin/env ruby
require 'date'
require 'optparse'
params = ARGV.getopts('m:y:')
month = (params['m'] || Date.today.month).to_i
year = (params['y'] || Date.today.year).to_i
if month < 1 || month > 12
puts "cal: #{params['m']} is neither a month number (1..12) nor a name"
return
end
if year < 1 || year > 9999
puts "cal: year `#{params['y']}' not in range 1..9999"
return
end
start_of_month = Date.new(year, month, 1)
end_of_month = Date.new(year, month, -1)
puts " #{month}月 #{year}"
puts "日 月 火 水 木 金 土"
print " " * 3 * start_of_month.wday
(start_of_month..end_of_month).each do |day|
format = day == Date.today ? "\e[7m%2d\e[0m " : '%2d '
printf format, day.day
puts "\n" if day.wday == 6
end
puts "\n\n"
4. ソースコード(最終形)の解説#
4-1. 主な使用メソッド#
4-2. 解説#
# 6行目
params = ARGV.getopts('m:y:')
# 引数に「-m」と「-y」をとる
# 7~8行目
month = (params['m'] || Date.today.month).to_i
year = (params['y'] || Date.today.year).to_i
# それぞれの引数が指定されなかった場合、monthに今月の月、yearに今年の年が入る
# 10~13行目
if month < 1 || month > 12
puts "cal: #{params['m']} is neither a month number (1..12) nor a name"
return
end
# -mオプションで1~12以外が指定された場合、エラーメッセージを表示して処理を終了
# 15~18行目
if year < 1 || year > 9999
puts "cal: year `#{params['y']}' not in range 1..9999"
return
end
# -yオプションで1~9999以外が指定された場合、エラーメッセージを表示して処理を終了
# 20~21行目
start_of_month = Date.new(year, month, 1)
end_of_month = Date.new(year, month, -1)
# 月の初日と最終日
# 25行目
print " " * 3 * start_of_month.wday
# 月の初日の曜日によって表示する位置を調整
# start_of_month.wdayには曜日を表す数値(日曜から0~6)が入る
# 26行目
(start_of_month..end_of_month).each do |day|
# dayに<Date: 2017-09-20 ...>の形式で月の初日から最終日までが入る
# 27~28行目
format = day == Date.today ? "\e[7m%2d\e[0m " : '%2d '
printf format, day.day
# 条件演算子によりdayが今日の日付の場合"\e[7m%2d\e[0m "が、それ以外の場合'%2d 'がformatに代入される
# printfにより、指定したフォーマットでday.day(日付)が表示される(今日の日付の場合に色を反転して表示)
# 29行目
puts "\n" if day.wday == 6
# 土曜日で改行