初学者によるプログラミングMemo #5-1 実行順序・配列


はじめに

今回はスクールの後輩受講生(コピペ星人)から解説を頼まれた時のことを元に、同じ悩みがある人の一助になればと思い、記述します
なお、本記述はMacにおいて、Railsでの開発を前提としています
また、まだまだひよっこですので、不備等ございましたらご指摘いただけると幸いです

目次

  • 第1章 コピペしてきたから実行順序がわからない
  • 第2章 変数がよくかわからない
  • 第3章 メソッドが何してるかわからない
  • 第4章以降 => 次回
  • まとめ

第1章 コピペしてきたから実行順序がわからない

まずはじめに言います
コピペは理解しているところだけにしましょう
じゃないと理解できません
さて、本題ですが、泣きついてきた時の実アプリの中身をまず貼ります
映画のレビューアプリの簡易版です

# メソッドの定義
def movie_review(a_movies)
  # 変数の定義
  movie = {}
  puts "ジャンルを入力してください:"
  movie[:genre]  = gets.chomp
  puts "タイトルを入力してください:"
  movie[:title]  = gets.chomp
  puts "感想を入力してください:"
  movie[:review] = gets.chomp
  line   = "---------------------------"

  # レビューの描画
  puts "ジャンル : #{movie[:genre]}\n#{line}"
  puts "タイトル : #{movie[:title]}\n#{line}"
  puts "感想 :\n#{movie[:review]}\n#{line}"

  # 配列オブジェクトに追加
  a_movies << movie

  # a_moviesをメソッドの呼び出し元に返す
  return a_movies
end

def read_reviews(a_movies)
  # リストの表示
  number = 0
  a_movies.each do |movie|
    puts "[#{number + 1}]:#{movie[:title]}のレビュー"
    number += 1
  end

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

  # レビューの取得
  movie = a_movies[input]

  # レビューの描画
  line   = "---------------------------"
  puts "ジャンル : #{movie[:genre]}\n#{line}"
  puts "タイトル : #{movie[:title]}\n#{line}"
  puts "感想 :\n#{movie[:review]}\n#{line}"
end

movies = []             # 配列オブジェクトmoviesの生成

while true do
  # メニューの表示
  puts "レビュー数:#{movies.length}"
  puts "[0]レビューを書く"
  puts "[1]レビューを読む"
  puts "[2]終了する"
  input = gets.to_i

  if input == 0
    movies = movie_review(movies)  # movie_reviewメソッドの呼び出し
  elsif input == 1
    read_reviews(movies) # read_reviewsメソッドの呼び出し
  elsif input == 2
    exit
  else
    puts "入力された値は無効な値です"
  end
end

こんな感じのものを持ってきて、「どういう構造かがわからないし、実行順序もよくわからないから教えて欲しい」と頼まれました

基本

まず、プログラムは上から順に実行されていきます
前回(#4)で、「"def~end"はメソッドの定義なので無視する」といった旨を記述しましたが、正確には違います
表示がされないだけで「定義」の実行はされています
表示という面では"while true do"の記述の後の"puts"メソッドで初めてterminal上に表示がされます

"while true do ~ end"

while文は繰り返し実行したいときに使います
使い方としては下記の様になります

while "条件式" do
  "実行内容"
end

条件式が正しい(trueの値を返す)場合、繰り返し実行します
今回の場合、条件式には"true"が入っていますので、特別な記載がない限り、エンドレスループを行います
下から5行目の"exit"の記述により、この項目が選択された場合にこのアプリを終了します
この記述がないと、今回の場合アプリを終了させることができません(実際は"control + c"で強制終了ができます)

"if ~ elsif ~ else ~ end"

いわゆるif文です
今回の場合、"input = gets.to_i"にて入力した数字を元に判別します
"if input == 0"
ここでは"input"の中身が"0"と同じであればその下のプログラムを実行するということになります
判別には "=" ではなく "==" を使うことに注意してください
もし0でなかった場合はその下の"elsif input == 1"に移ります
ここでは"input"の中身が"1"と同じであればその下のプログラムを実行するということになります
ここでもまた1でなかった場合にはその下の"elsif input == 2"に移ります
もう解説は不要ですね
そして、0,1,2のどれにも当てはまらなかった(例えば"3"を入力した)場合には"else"以下が実行されます
最後はどこまでがif文に当てはまるのかを明示してあげないといけないので"end"を記述します

第2章 変数がよくかわからない

前述までで、inputに数字を入力し、その結果でどのプログラムを実行するかまでは理解できた様ですが、また新たな問題が…
「"movies"とか"a_movies"とか変数に何が入ってるかよくわかんないんですよねー」
そうですか、じゃあ解説しましょう

moviesはすでに定義している配列のこと

while文の前に"movies = []"があるかと思います
ここで"movies"を定義しています
"[]"は空の配列オブジェクトを作りますよってことです
配列オブジェクトは、後述するハッシュオブジェクトを管理するためのもので、収納順の番号によって中身を管理します
わかりやすくいうと「DVD買ってくるけど、収納場所がないから、収納ケース買ってきたよ」と、こういうことです
これからこの"movies"という収納ケース(配列オブジェクト)に、"movieのレビュー"というDVD(ハッシュオブジェクト)を収納していくわけです

a_moviesは仮引数で、movies(収納ケース)の代わりにメソッド内で使うもの

inputに"0"を入力したとしましょう
そうすると"movies = movie_review(movies)"が実行されます
変数"movies"に値(movie_review(movies))を代入する式です
この様な場合、右辺から実行されます
なので、まず引数を"movies"として、メソッド"movie_review"を呼び出します

第3章 メソッドが何してるかわからない

メソッド"movie_review"は一番上に定義されています
ここでの仮引数は"a_movies"です
なぜ"movies"があるのに代わりに"a_movies"を使うのかということに関しては、スコープという概念が絡んできますが、長くなるので、メソッド内は基本的に他からの干渉を受け付けないという認識でOKです
なので、"movies"という収納ケースを直接このメソッド内で使うことはできません

"movie = {}" はハッシュオブジェクト

次に上から4行目にあるものはハッシュオブジェクトと呼ばれるものです
"{}"ハッシュオブジェクトは「キー」と呼ばれるもので中身を管理します
今回の場合のキーは"movie[:genre]"の":genre"がそれに当たります
なので、一つの"movie"に対して、3つのキー":genre","title","review"を使ってデータを格納していきます
getsメソットで各項目を入力後、"a_movies << movie"この部分で、DVDを仮の収納ケースに格納しています

返り値は最終行が反映される

"return a_movies"によってこのメソッド内での最終的な返り値を決定しますが、これくらいの簡易アプリであれば不要です
理由としては基本的に最終行が返り値になるため、この記述がなかったとしたら、このメソッド内の返り値は最終行の"a_movies << movie"ということになり同義だからです

ようやく"movies"に代入するものが決まる

メソッド"movie_review"の返り値が決まりました
"movies = movie_review(movies)"この記述を今の状態に書き換えると、"movies = a_movies"となり、仮の収納ケースの中身を、元々定義した収納ケースに代入することで処理は完了します

まとめ

長くなったので、"read_reviews"の解説は次にまわします

  • プログラムは上から順に実行される
  • while文は条件式がtrueである限りループする
  • 配列オブジェクトは格納した順番で、ハッシュオブジェクトはキーによって中身を管理する(呼び出しは次回解説)