自転車とプログラミング

自転車メーカーに勤める会社員がプログラミングを学ぶ中で感じたことを書きます。最近サービス作りました。

人のプログラムを読解しよう カレンダープログラム編03

フィヨルドブートキャンプに所属しているYukiです。 今回はフィヨルドブートキャンプで課された「ターミナルでカレンダーを出力しよう」という課題を終了し、他の受講生の解答が見られるようになりましたので、その読解に取り組みます。 今回からフィヨルドブートキャンプのメンターが作ったプログラムの読解です。

ミュータブルとイミュータブル

# frozen_string_literal: true
#プログラム内文字列の破壊的変更をNGとする

ミュータブルは「変更可能な」という意味で、対してイミュータブルは「不変の」といった意味の言葉。 ミュータブルなオブジェクトは破壊的な変更をすることが可能ではあるけれど、破壊的な変更で意図しないバグを生み出すこともままある。イミュータブルは破壊的な変更ができないオブジェクトである。 例えばstringはミュータブルなオブジェクトなので破壊的な変更を受け付ける。文字列を大文字にするupcase!メソッドを使うなどすると処理の途中で変数内の文字列が変わってしまう、という事態は簡単に発生する。

イミュータブルなオブジェクト

  • Integerクラス
  • Floatクラス
  • Symbolクラス
  • Trueクラス/Falseクラス
  • NilClassクラス

ミュータブルなオブジェクトというとString Array Hashなどが当たる。

ミュータブルなオブジェクトのイミュータブル化

ミュータブルなオブジェクトをイミュータブル化するために存在するのがfreezeメソッド。これを使うとイミュータブルになる。 このfreezeメソッドをプログラム全体に作用させるのがこのマジックコメントである。

前回のif $0 == __FILE__と同じくおまじないの類か?このくらいのプログラムでも記述するんだと不思議に思う。

コマンドラインオプションの取得

params = ARGV.getopts('m:y:')
#コマンドラインからショートオプションを取って、ハッシュを生成する

おなじみのARGV.getoptsメソッドでコマンドラインオプションを取得している。 細かい話だけど引数は連続して記述されていても、個別にオプションとして機能してくれる。

年月の取得

month = (params['m'] || Date.today.month).to_i
year = (params['y'] || Date.today.year).to_i
# paramsに代入された値があればそちらを、なければ今日の年月を取得して整数化して代入する

paramsには先程取得したコマンドラインオプションの指定年月が代入される。そうでない場合は存在しないオブジェクトだ。 演算子式の||で左辺がfalseであれば右辺を、とされている。

ヘッダーの出力

printf "      %<month>2d月 %<year>4d     \n", month: date.month, year: date.year
puts '日 月 火 水 木 金 土'
#フォーマットを指定してハッシュmonthとyearの値を代入して出力。曜日は普通に出力

printfメソッドはprintf(format, 引数)といった形を取る。今回のフォーマットは" %2d月 %4d \n"で%記法を使って%dで十進数の数字を文字列として出力する。%dの間にある数値は文字数を表す。

日付にフォーマットを適用して出力する

(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
#ひと月の日付をeachメソッドでそれぞれブロックの処理を適用する。ブロック変数で渡した日にちオブジェクトが今日その日なら文字と背景色を反転させるフォーマットを変数formatに代入。printfメソッドでformatを使いながらブロック変数dayのdayメソッドの値を突っ込んでいく。そして土曜日に改行を加えて出力。

ここでもprintfメソッド。今回はフォーマットの中に変数は使用せず、文字色と背景色を変える手続きを入れた変数を使用している。引数にはひと月の日にちが渡される。渡された値に処理をして出力する。かならずしもformatの中で引数を受け取る必要はない。わりと便利そうな気がする。 色替えはansiカラーシーケンスが使われている。