質問: %w(日 月 火 水 木 金 土 日)[d.cwday] while day < 31 puts "#{year}年#{month}月#{day}日は#{week}曜日です" day += 1 week += 1 end ``` お詳しい方ご教授お願い致します。
回答: 問題点がいくつかあります。 ###### 一つ目 まずそのままのコードで動かそうとすると`week += 1`でエラーが出ているのがわかると思います。 エラーメッセージ:`test.rb:16:in '+': no implicit conversion of Fixnum into String (TypeError) from test.rb:16:in ''` 今`day`には10行目で入れられた曜日の名前が入っています。 そこに数字である1を足そうとするとStringとFixnumを足すことになるのでエラーが起きます。 ###### 二つめ 一ヶ月の日数は月によって違うので31にしてしまうと2月とかがうまく行かなくなってしまいます。 while文を回すには**何月なので一ヶ月は何日**という情報が必要になってきます。なので普通にdayを加算していくとifなどで分岐処理を書く必要が出てしまいめんどくさいです。 そこで、Dateクラスには便利なものがあって、dateクラスのメソッドのnextを叩くと次の日の情報に更新してくれます。 ###### 三つめ weekをに代入している部分って何をしているかわかりにくいと思います。 `week = %w(日 月 火 水 木 金 土 日)[d.cwday]`が何をしているかというと `%w(日 月 火 水 木 金 土 日)`配列を作る `[d.cwday]`その日が何曜日かを調べて配列からとってくる と言う風になっていて `%W()`は配列を作るメソッドで、配列の要素をスペースで並べる `d.cwday`は月〜日曜日を1〜7で表した数字を教えてくれる なのでやっていることは以下と同じです。 ``` week_name = ["日", "月", "火", "水", "木", "金", "土", "日"] week = week_name[d.cwday] ``` またここで二つめと関わってくるのですが、一番最初のコードのようにweekを一回とってしまうと次の曜日っていうのが難しいので上のコードのようにweek_nameとweekで分けておいたほうがいいです。 ちなみにですが、cwdayは月から日を1~7なので配列からとってくる場合、一番最初の要素に空きが出てしまい、今回の場合日が二つあるみたいな状況になってしまいます。 そこで同じようなやつにwdayっていうのがあってこっちは日から土を0~6でとってくるので今回みたいな配列にアクセスするときには使いやすいです。 コード ==== 以上のことと本来実装したかったものをまとめて僕なりに書いてみました。 ``` require 'date' puts "年を入力してください:" year = gets.to_i puts "月を入力してください:" month = gets.to_i d = Date.new(year, month, 1) week_name = %w[日 月 火 水 木 金 土] while d.month == month // 入力された月を超えたらやめる str = "#{d.month}/#{d.day}#{week_name[d.wday]}曜日" // 土か日曜日だったら(休)をつける if d.wday == 0 || d.wday == 6 str += "(休)" end puts str d = d.next end ``` ###### 変更点 * 入力を月までにしました * Dateの`d`にはその月の情報をとってきたいので、1日にしてしまいます * while文の条件は入力された月と進めていった月が等しいにしています * if文でwdayが0か6(土か日曜日)だったらの時の処理をつけています 以上でどうでしょうか? ###### おまけ もっと短くすることはできますので短くしてみてください。