ここでもともと作業をしていたreviewApp.rbに戻る。
今実現したいことは、配列オブジェクトpostsに個別のレビューのハッシュオブジェクトpostを保存するということだった。
前投稿で確認した引数を使って配列オブジェクトpostsを、レビューを書くメソッドのpost_review内で扱えるようにしたい。
def post_review # ここで引数を受け取るようにする # 変数の定義 post = {} puts "ジャンルを入力してください:" post[:genre] = gets.chomp puts "タイトルを入力してください:" post[:title] = gets.chomp puts "感想を入力してください:" post[:review] = gets.chomp line = "---------------------------" # レビューの描画 puts "ジャンル : #{post[:genre]}\n#{line}" puts "タイトル : #{post[:title]}\n#{line}" puts "感想 :\n#{post[:review]}\n#{line}" # 引数で受け取った配列オブジェクトにpostを追加 ## コードを書く # postを追加した配列オブジェクトを返り値として返す ## コードを書く end def read_reviews # レビューを読む end def end_program exit end def exception puts "入力された値は無効な値です" end posts = [] # 配列オブジェクトpostsの生成 #以下省略
メソッドの呼び出し元は配列オブジェクトpostsを渡すようにする。
メソッドpost_reviewではpostsという名前の仮引数で、本引数である配列オブジェクトpostsを受け取るようにする。
# メソッドの定義 def post_review(posts) # 変数の定義 post = {} puts "ジャンルを入力してください:" post[:genre] = gets.chomp puts "タイトルを入力してください:" post[:title] = gets.chomp puts "感想を入力してください:" post[:review] = gets.chomp line = "---------------------------" # レビューの描画 puts "ジャンル : #{post[:genre]}\n#{line}" puts "タイトル : #{post[:title]}\n#{line}" puts "感想 :\n#{post[:review]}\n#{line}" # 配列オブジェクトに追加 posts << post # postsをメソッドの呼び出し元に返す return posts end def read_reviews # レビューを読む end def end_program exit end def exception puts "入力された値は無効な値です" end posts = [] # 配列オブジェクトpostsの生成 while true do # メニューの表示 puts "レビュー数:0" puts "[0]レビューを書く" puts "[1]レビューを読む" puts "[2]アプリを終了する" input = gets.to_i if input == 0 then posts = post_review(posts) # post_reviewメソッドの呼び出し elsif input == 1 then read_reviews # read_reviewsメソッドの呼び出し elsif input == 2 then end_program # end_programメソッドの呼び出し else exception # exceptionメソッドの呼び出し end end
書いたレビューの数を表示する
配列オブジェクトに要素を追加しても、今は中身を出力をしていないのできちんと追加されているかわからない。
そこでメニュー画面に「書いたレビューの数」を表示する。
今までレビュー数:0と表示していたが、ここの0を書き換える。
レビュー数 = 配列オブジェクトpostsの要素数である。
この要素数を0の代わりに表示する。
完成ソースコード
# メソッドの定義 def post_review(posts) # 変数の定義 post = {} puts "ジャンルを入力してください:" post[:genre] = gets.chomp puts "タイトルを入力してください:" post[:title] = gets.chomp puts "感想を入力してください:" post[:review] = gets.chomp line = "---------------------------" # レビューの描画 puts "ジャンル : #{post[:genre]}\n#{line}" puts "タイトル : #{post[:title]}\n#{line}" puts "感想 :\n#{post[:review]}\n#{line}" # 配列オブジェクトに追加 posts << post # postsをメソッドの呼び出し元に返す return posts end def read_reviews # レビューを読む end def end_program exit end def exception puts "入力された値は無効な値です" end posts = [] # 配列オブジェクトpostsの生成 while true do # メニューの表示 puts "レビュー数:#{posts.length}" puts "[0]レビューを書く" puts "[1]レビューを読む" puts "[2]アプリを終了する" input = gets.to_i if input == 0 then posts = post_review(posts) # post_reviewメソッドの呼び出し elsif input == 1 then read_reviews # read_reviewsメソッドの呼び出し elsif input == 2 then end_program # end_programメソッドの呼び出し else exception # exceptionメソッドの呼び出し end end
def post_reviewからdef exception putsまででこれまで通りメソッドの定義をしている。
今回post_reviewメソッドだけ大幅に処理の内容が変わったが、このメソッドについては後述する。
posts = []
でレビューの内容を保存するための配列オブジェクトpostsを定義する。
ここでポイントとなるのは定義する場所である。
各メソッドの中でも、while文の中でも、while文のあとでもない。
その理由は、
- 各メソッドの中で定義すると、使えるのがそのメソッドの中のみになってしまう。今回は様々なメソッドやその外側で使用したいので各メソッドの中では定義しない。
- while文の中で定義すると繰り返すたびに配列が初期化(最初の何も入っていない状態)されてしまうため、while文の中でも定義できない。
- while文のあとだと、そもそもすべての処理が終わっているので定義しても意味がない。
というものである。
そこで、定義するのは各メソッド内ではなく、かつwhile文のブロックより前ということになる。
def exception puts "入力された値は無効な値です" end posts = [] while true do
↑ココ!
while true do # メニューの表示 puts "レビュー数:#{posts.length}" puts "[0]レビューを書く" puts "[1]レビューを読む" puts "[2]アプリを終了する" input = gets.to_i
その後の処理であるが、基本的な処理は変わらない。
「メニューの表示」 → 「ターミナルからの入力」 → 「入力に応じた処理」 という流れをwhile文の中で繰り返している。
ただし、メニューで「【0】レビューを書く」を選択したときだけ処理が変わる。
if input == 0 then posts = post_review(posts)
メニューで「【0】レビューを書く」を選択すると条件分岐によって48行目のpost_reviewメソッドの呼び出しが行われる。
このとき引数で配列オブジェクトの変数postsをpost_reviewメソッドに渡す。
posts = post_review(posts) # postsを引数としてpost_reviewメソッドに渡す
引数として渡された配列オブジェクトpostsはpost_reviewメソッドの変数に代入される。
⇒2行目
再び、2行目に処理が戻ってくる。
定義したpost_reviewメソッドが呼ばれたためである。
def post_review(posts)
post_reviewメソッドは引数を受け取る。
先ほど、48行目でこのpost_reviewメソッドが呼ばれたときに、引数として変数postsが渡された。
この変数postsの中にはレビューを管理するための配列オブジェクトが入っている。
引数として渡された変数postsの中に入っていた、レビューを管理するための配列オブジェクトはpost_reviewメソッドの変数postsに代入され、メソッド内で使用できるようになる。
48行目
posts = post_review(posts) # postsを引数としてpost_reviewメソッドに渡す
2行目
def post_review(posts) # 渡されたpostsの中の配列オブジェクトが変数a_postに代入される # 変数postsとして、引数の配列オブジェクトをメソッド内で使える
4行目から16行目では今までと同様にレビューの情報を持つハッシュオブジェクトを生成し、ターミナルからレビューを入力させる処理を行う。
また、入力が終わったレビュー情報をターミナルに表示させる。
19行目
posts << post
19行目では、生成したレビューのハッシュオブジェクトpostを引数で受け取った配列オブジェクトpostsに追加する。
これで配列postsの最後にいま入力したレビューのハッシュオブジェクトが入った。
図で表すと、以下のようになる。
22行目
return posts
変数postsには入力したレビューのハッシュオブジェクトが新しく追加された配列オブジェクトが入っている。
これをメソッドの呼び出し元に返す。
メソッドの最後で、メソッドの呼び出し元に値を返すときにはreturnを使う。
return メソッドの呼び出し元に返す値
今回は新しく書いたレビューを追加した配列オブジェクトであるpostsをreturnで返すようにする。
このreturnで返す値を返り値という。
48行目
メソッド内の処理がすべて終わると、プログラムではメソッドを呼び出した部分に処理が戻る。
post_reviewメソッドを呼び出したのは48行目。
posts = post_review(posts)
post_reviewメソッドは返り値を返すので、変数postsにはその返り値が代入される。
posts = post_reviewの返り値
post_reviewメソッドの返り値は、新しく書いたレビューを追加した配列オブジェクトであった。
この配列オブジェクトは元は変数postsに代入されていたものなので、結果としてpostsには新しく書いたレビューが1つ追加された配列オブジェクトが代入されることになる。
具体的な例として、すでに「るろうに剣心」と「君に届け」のレビューを書いたあとの状態で、新しく「アバター」のレビューを書く処理の流れを追ってみる。
最初の段階では配列オブジェクトの変数postsには「るろうに剣心」と「君に届け」のレビューのハッシュオブジェクトが入っている。
- post_reviewメソッドの呼び出し
# 元のpostsには「るろうに剣心」と「君に届け」のレビューのハッシュオブジェクトが入っていた posts = post_review(posts)
- post_reviewメソッド
def post_review(posts) # postsは「るろうに剣心」と「君に届け」の入っている配列オブジェクト # (48行目で引数として渡された変数postsに代入されていた配列オブジェクト) # 新たに「アバター」のレビューを投稿 # 「アバター」のレビューを配列オブジェクトに追加 posts << post # メソッドの呼び出し元に新しく書いたレビューを追加した配列オブジェクトを返す return posts
- post_reviewメソッドの返り値を代入
posts = post_review(posts) # 「アバター」のレビューが新しく追加された配列オブジェクトを変数postsに代入 # postsには「るろうに剣心」と「君に届け」と「アバター」のレビュー情報が入った
こうして、結果として変数postsに新しくレビューのハッシュオブジェクトを追加することができた。