さらなる高みへ -higher ground -

プログラミング学習の定着を狙いとしたアウトプット(独り言)をしてみるブログ

レビューを読めるようになる機能を追加する

いよいよレビューアプリの最後の項目である。
ここでは以下2点を習得する。

  • 配列に対して繰り返し処理を行えるようになる
  • 配列から要素を取り出せるようになる

配列から要素を取り出す

既に前回レビューを配列で管理することを行った。
ここではその配列から選んだ順番の要素を取得できるようにする。

配列は順番でオブジェクトを管理していることは前回行った通り。
配列は順番を指定することでオブジェクトを取得することができる
以下の書き方で配列オブジェクトから指定した順番の要素を取得できる。

配列オブジェクト[順番(数値)]

配列オブジェクトに続けて[](大括弧)とその中に取得したいオブジェクトの順番を指定する。

以下の配列オブジェクトplayersから「山田」を取り出してputsメソッドで表示してみる。

players = ["山田", "青木", "村上"]

配列の順番は0から始まる
つまりplayers[1]は配列playersの2番目のオブジェクトを取得しているということになる。
よって「山田」を取得する正解はplayers[0]となる。

  players = ["山田", "青木", "村上"]
  puts players[0]                    # => "山田"

 

指定した順番のレビューを表示させるようにする

では、実際に「レビューを読む」を実装していく。
レビューを読むのメソッドread_reviewsに書き足していく。ここで作る機能は以下の通り。

  1. 見たいレビューの番号を入力させる

    メニューで[1]:レビューを読むを入力後

    1
    2
      見たいレビューの番号を入力してください:
      # 入力待ち

     

  2. その番号のレビューのジャンル、タイトル、感想を表示する

    レビューの番号を入力後

    1
    2
    3
    4
    5
    6
    ジャンル : マンガ
    ---------------------------
    タイトル : るろうに剣心
    ---------------------------
    感想 : 映画もいいけどやっぱりマンガが最高!
    ---------------------------

     

     

レビューの一覧の表示をするには配列オブジェクトpostsの要素すべてに表示の処理を行う必要がある。

配列オブジェクトの要素すべてに共通の処理を行う

配列の要素すべてに対して共通の処理を行うには配列の繰り返しを使う。
繰り返しのためのメソッドはeachメソッドである。

eachメソッド

配列オブジェクトに対してeachメソッドを実行すると、配列に含まれる要素を順に取り出して繰り返し処理が行われる。
すなわち、配列の要素の数だけ処理が行われる
eachメソッドの使い方は以下のように配列オブジェクトに使う。

配列オブジェクト.each do |変数|
  # 処理
end

変数には繰り返しごとに配列の要素が代入されていく。
試しに以下のソースコードを実行してみよう。

players = ["山田", "青木", "村上"]
players.each do |player|
  puts player
end

上のコードでは配列オブジェクトの要素を1つずつ変数playerに入れてputs playerの処理を行っている。
配列の要素は選手の名前なので、その共通項をとって変数名をplayerにしている。
配列の要素["山田", "青木", "村上"]のすべてが出力されていることが確認できる。

きちんと要素の数だけ繰り返されているかも、以下のプログラムで確認してみよう。

players = ["山田", "青木", "村上"]
number = 0
players.each do |player|
  puts player
  number = number + 1
end
puts "#{number}回繰り返しました"

解説動画1
https://www.youtube.com/watch?v=x-ADKbjaE-I&feature=youtu.be

解説動画2
https://www.youtube.com/watch?v=wXKBBhGx1Ts&feature=youtu.be

「レビューを読む」を入力したらレビューの一覧を表示させよう

メニューで"[1]レビューを読む"を入力したらレビューの一覧を表示させてから見たいレビューの番号を入力させるようにしてみよう。

レビューの一覧は以下のように
[順番]:"タイトル"のレビュー
というフォーマットで表示させる。

1
2
3
4
5
6
[0]:時をかける少女のレビュー
[1]:トレモロのレビュー
[2]:るろうに剣心のレビュー

見たいレビューの番号を入力してください:
# 入力待ち

 

 問題17:メニューで"[1]レビューを読む"を入力したら「レビューの一覧を表示させてから」見たいレビューの番号を入力させるようにしましょう

 

1
2
3
4
5
6
[0]:時をかける少女のレビュー
[1]:トレモロのレビュー
[2]:るろうに剣心のレビュー

見たいレビューの番号を入力してください:
# 入力待ち
作業ファイル:reviewApp.rb
ヒント:配列オブジェクトpostsにeachメソッドを使って繰り返し処理を行い、全ての要素を表示させましょう

完成ソースコード

# メソッドの定義
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(posts)
  # リストの表示
  number = 0
  posts.each do |post|
    puts "[#{number}]:#{post[:title]}のレビュー"
    number += 1
  end

  puts "\n見たいレビューの番号を入力してください:"
  input = gets.to_i

  # レビューの取得
  post = posts[input]

  # レビューの描画
  line   = "---------------------------"
  puts "ジャンル : #{post[:genre]}\n#{line}"
  puts "タイトル : #{post[:title]}\n#{line}"
  puts "感想 :\n#{post[:review]}\n#{line}"
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(posts) # read_reviewsメソッドの呼び出し
  elsif input == 2 then
    end_program         # end_programメソッドの呼び出し
  else
    exception           # exceptionメソッドの呼び出し
  end
end

 

処理の流れ

最後に全体の処理の流れをおさらいする。

  • まず2行目から52行目

ースコードの開始である、2行目から52行目まででプログラムで使用するメソッドをすべて定義する。

これで52行目以降で、いま定義したメソッドを自由に使うことができる。

  • 54行目
54
  posts = []

メニューの表示やレビューの投稿、表示といったメインの処理があるwhile文より前で、複数のレビューを管理するための配列オブジェクトpostsを定義する。

  • 56行目
56
  while true do
  • 58行目から61行目

アプリケーションのメインの処理である
「メニューの表示」 → 「ターミナルからの入力」 → 「入力に応じた処理」 という流れは「プログラムを終了」するまで繰り返し続ける。
そのためこれらの処理のかたまりをwhile文で囲み、条件式をtrueにすることでexitメソッドが呼ばれるまで繰り返し続けるようにする。

exitメソッドはメニューで「2」を入力(プログラムの終了を選択)すると呼ばれる。

reviewApp.rb

58
59
60
61
  puts "レビュー数:#{posts.length}"
  puts "[0]レビューを書く"
  puts "[1]レビューを読む"
  puts "[2]アプリを終了する"

メニューの表示を行う。また、今まで投稿したレビューの数を配列のlengthメソッドを使って表示する。

  • 62行目
62
  input = gets.to_i

メニューのうち、どれを選択するかをgetsメソッドを使ってターミナルから入力させる。

  • 64行目から72行目

ターミナルから入力した値によって処理を分岐させる。処理の分岐にはif文を使う。

2を入力したときはend_programメソッドを呼び出し、その中でexitメソッドを使いプログラムを終了させる。

46
47
48
  def end_program
    exit
  end

無効な値の場合はexceptionメソッドを呼び出し、無効な値であることを知らせる。

50
51
52
  def exception
    puts "入力された値は無効な値です"
  end
  • 65行目
65
  posts = post_review(posts)

ターミナルで「0」を入力した場合、レビューを書くためのメソッドpost_reviewを呼び出す。
このとき引数としてレビューを管理する配列オブジェクトpostsを渡す。

  • 2行目から23行目

post_reviewメソッドが呼ばれた場合、ターミナルからユーザーに対して新しくレビューを書くように促す。

 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  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}"

作成されたレビューは引数として渡された配列オブジェクトの最後に追加される。

19
  posts << post

新しく書いたレビューが追加された配列オブジェクトをメソッドの呼び出し元に返す。
メソッドの呼び出し元では変数postsにこの返り値を代入する。

これにより新しいレビューが追加された配列オブジェクトをpostsに代入することができる。

22
  return posts
 
65
  posts = post_review(posts)
  • 67行目
67
  read_reviews(posts)

ターミナルで「1」を入力した場合、レビューを閲覧するためのメソッドread_reviewsを呼び出す。
このとき引数としてレビューを管理する配列オブジェクトpostsを渡す。

  • 25行目から44行目

read_reviewsメソッドが呼び出されると、まず引数として渡した配列オブジェクトに入っているすべてのレビューを一覧で表示する。

25
26
27
28
29
30
31
  def read_reviews(posts)
    # リストの表示
    number = 0
    posts.each do |post|
      puts "[#{number}]:#{post[:title]}のレビュー"
      number += 1
    end

何番目に書いたレビューかわかるように番号用の変数numberを定義する。
配列オブジェクトのすべての要素に対して繰り返し処理を行うにはeachメソッドを使う。

1
2
3
  配列オブジェクト.each do |要素|
    # 要素を一つずつ取り出して処理を行う
  end

次に、詳細を見たいレビューの番号をターミナルから入力させる。

33
34
  puts "\n見たいレビューの番号を入力してください:"
  input = gets.to_i

入力された値の順番のレビューを配列オブジェクトから取り出す。
配列オブジェクトから特定の順番の要素を取り出すのは配列オブジェクト[順番]という書き方をする。

38
  post = posts[input]

これで変数postには指定した番号のレビューのハッシュオブジェクトが代入されている。あとは詳細を表示させるだけ。

40
41
42
43
  line   = "---------------------------"
  puts "ジャンル : #{post[:genre]}\n#{line}"
  puts "タイトル : #{post[:title]}\n#{line}"
  puts "感想 :\n#{post[:review]}\n#{line}"

これですべての処理の流れは終了である。


以上ですべての実装が完了。

70行程度のソースコードの量で立派にアプリケーションとして機能している。

アプリケーションが完成した後

これで一応は完成しましたが、まだまだこのアプリケーションには改善の余地がある。
例を挙げると以下のような部分である。

  • 入力する項目を増やす。
  • レビューが1つも書かれていないときに「レビューを読む」を選べなくする。
  • 「見たいレビューの番号を入力してください:」で書いたレビュー数より大きい番号を入力したら再入力させる。
  • レビューの描画を別メソッドとして分ける。

もちろんこれらの改善をすべて行う必要はない。
しかし自分で考えてプログラムを組むことは非常にレベルアップに繋がるため今後挑戦していきたい。