ログイン
編集不可のページディスカッション情報添付ファイル
benevolent0505/ProgrammingSeminar2016/basic-grammar

MMA

Rubyの基本的な文法

この回ではRubyの基本的な文法をやっていきます。言語はRubyを使いますが、ここでやる内容のほとんどは他のプログラミング言語でも共通することです。ですので、他の言語をやってみたことがある人は、その言語と比較しながらやってみるといいでしょう。

前回のプログラムの解説

前回の文字を表示するプログラムについて解説します

puts "Hello, world!"

オブジェクト

まずは後ろの"Hello, world!"の部分に注目します。この部分をStringオブジェクトまたは文字列オブジェクト、あるいは単に文字列と呼んだりします。Rubyでオブジェクトとはデータや、それについての処理を表現する基本的な単位のことを言います。Rubyでは文字列や数値などの様々なデータがオブジェクトになります。ここでの"Hello, world!"は「Hello, world!」という文字列を表わすオブジェクトということになります。オブジェクトについては後々詳しく触れていくので、今すぐに理解する必要はありません。今は呼び方だけ慣れておきましょう。

メソッド

次にputsの部分に注目します。putsというのは「画面に文字の列を表示する(画面に文字列を出力する)」という メソッド です。メソッドという言葉も後々詳しく解説しますが、ここでは「プログラムで処理をする単位」というように覚えておけばいいでしょう。

今までputs 表示したい文字列のように書いてきましたが、実はこれは本来の書き方を省略した形になります。省略せずに書くと

puts("Hello, world!") # Hello, world!

のようにメソッド名の後ろに()を付けます。この()の省略は打ち込む文字数が減って便利ですが、やりすぎると読みにくいプログラムになってしまうので気をつけましょう。

さて、puts()の中にある文字列や数値を出力します。これはputsというメソッドに表示させたいオブジェクトを与えるという形になります。この後ろに与えるオブジェクトのことを (メソッドの)引数 といいます。ここでは"Hello, world!"putsメソッド引数になります。

またメソッドによっては引数が無いものもあります。

文字列

文字列についてもう少し解説をしておきます。文字列オブジェクトはダブルクォーテーションマーク""かシングルクォーテーションマーク''で囲んで作成することができます。

なので次の2つputsは同じものを出力します。

puts "Hello, world!" # Hello, world!
puts 'Hello, world!' # Hello, world!

さて、"Hello, "benevolent0505"!"という文字列を表示したくなったとします。ではやってみましょう。どのようになるでしょうか。

irb(main):010:0> puts "Hello, "benevolent0505"!"
SyntaxError: (irb):10: syntax error, unexpected tIDENTIFIER, expecting end-of-input
puts "Hello, "benevolent0505"!"
                            ^
    from /Users/Mikio/.rbenv/versions/2.2.3/bin/irb:11:in `<main>'
irb(main):011:0>

なにやら見慣れぬ表示が出てきました。 SyntaxError とは正しくRubyのプログラムを入力しなかったときに出るエラーメッセージです。
ここでは、"Hello, "で一区切りされているのに、benevolent0505というRubyにとってよくわからないものが現れたのでエラーが出たのです。

では""の中で"を使うためにはどうすればいいのでしょうか。"の前にバックスラッシュ\の記号を付けてやってみましょう。(環境によっては¥記号で表示されます)

puts "Hello, \"benevolent0505\"!" # Hello, "benevolent0505"!

今度は思った通りに表示されました。このようにRubyにとって特別な記号を表示するには記号の前に\の記号を付けると表示されます。他にもRubyにとって特別な役割を持つ特殊文字が存在します。詳しくは下のリファレンスマニュアルを見てみるといいでしょう。

さて、さっきのputs "Hello, \"benevolent0505\"!""の囲みを'に変えてみるとどうなるでしょう。

puts 'Hello, \"benevolent0505\"!' # Hello, \"benevolent0505\"!

今度は\"がそのまま表示されてしまいました。このように''で囲んだ文字列は中身の特殊文字を解釈しません。

参考: Ruby 2.3.0 リファレンスマニュアル > リテラル > バックスラッシュ記法

p, printメソッド

文字を表示するメソッドについてもう2つ紹介しておきます。
一つはprintメソッドです。putsメソッドでは文字列を表示した後で改行を行っていましたが、printメソッドでは文字列の最後に改行を行わないません。実際に試してみましょう。

print "Hello, world!"
Hello, world!=> nil

printメソッドは表示の最後で改行を行いたくないときに使うと便利です。

もう一つはpメソッドはirb上で使うと便利なメソッドです。試しに下のプログラムをirb上で動かしてみましょう。

puts "100" # 100
puts 100 # 100
p "100" # "100"
p 100 # 100

putsやprintメソッドでは"100"100も表示されるときには同じ100と表示されてしまいます。これでは 数値 の100か 数字 の100かわかりません。pメソッドはオブジェクトによって表示の仕方を変えてくれるので、このように数値や数字の違いを意識したいときなどに使うと便利です。

変数

今までのプログラムでは文字を表示するときや計算をするときには、"Hello, world!"1などの値をそのまま扱ってきました。このままでもプログラムを組むことはできますが、何度も同じ文字列を表示させたり、沢山の値を使って計算させるときには不便です。

こうした不便を解決してくれるもので 変数 というものがあります。変数とはそれぞれの値に名前を付けるようなイメージです。

変数の作り方は下の様に変数名 = 値というように書きます。これを「変数名に値を代入する」と言います。

変数名 = 値
mma_id = "benevolent0505"
student_number = "1410000"

puts mma_id
puts student_number

予約語

変数名にはどんな文字列を使ってもいいですが、変数に使えない文字列というものがあります。これを 予約語 といって、これらは既にRubyのプログラミング言語を作る上で使用されている文字列なので、それを上書きするようなことは出来ません。

BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined? for      or       then     yield
and      do       if       redo     true     __LINE__
begin    else     in       rescue   undef    __FILE__
break    elsif    module   retry    unless   __ENCODING__
case     end      next     return   until

試しに予約語に値を代入してみようとすると

irb(main):001:0> __LINE__ = "Hello"
SyntaxError: (irb):1: Can't assign to __LINE__
__LINE__ = "Hello"
          ^
    from /Users/Mikio/.rbenv/versions/2.2.3/bin/irb:11:in `<main>'
irb(main):002:0>

このようにエラーが出ます。

参考: Ruby 2.3.0 リファレンスマニュアル > 字句構造 > 予約語

とは簡単に言ってしまえば「評価をして値を返すもの」のことです。評価するとはその式がどんな値になるのかを言います。
次に書いたものはRubyでは全部式になります。

irb(main):010:0> message = "Hello, world!" # 変数への代入も式
=> "Hello, world!" ← これ
irb(main):011:0> message # 変数自体も式
=> "Hello, world!"
irb(main):012:0> "Hello, world!" # 具体的な値も式
=> "Hello, world!" ← これ
irb(main):013:0> 1 # ↑と同じ
=> 1 ← これ
irb(main):014:0> 1 + 1 # 計算式も式
=> 2 ← これ
irb(main):015:0>

また返される値のことを 返り値 (戻り値) と言います。今までirbでプログラムを実行していたときに=>の後にnilなどの表示が出てきていたと思います。これが返り値です。

参考: Ruby 2.3.0 リファレンスマニュアル > プログラム・文・式

式展開

puts 変数名という形で書くと、その変数の値が表示されることをやりました。さて、プログラムを書いていると、文字列と変数の値を組み合せて表示したいときがあります。文字列と変数の値を組み合せて表示する方法は後で説明する+の演算子式を使うやり方と、ここで説明する 式展開 があります。

mma_id = "benevolent0505"
student_number = "1410000"

puts "Hello, #{mma_id}" # "Hello, benevolent0505"
puts "Your student number is #{student_number}" # Your student number is 1410000

puts 'Hello, #{mma_id}' # Hello, #{mma_id}

ダブルクォートで""で囲まれた文字列の中では#{}の中の式を評価することができます。これを使うことで文字列と変数の値を組み合わせることができます。式展開を使うことができるのはダブルクォートで囲まれた文字列だけなので、シングルクォート''で囲まれた文字列では評価されません。

式展開は文字列中で式を評価するので、文字列の中でRubyのプログラムを実行させることができます。

puts "1 + 1 = #{1 + 1}" # 2

参考: Ruby 2.3.0 リファレンスマニュアル > リテラル > 式展開

演算子式

今まで変数の作成や計算などで使っていた=, +, -, *, /, %などの記号のことを 演算子 と呼びます。

puts 1 + 1  # 2
puts 5 - 3  # 2
puts 5 * 5  # 25
puts 10 / 3 # 3
puts 10 % 3 # 1

上で紹介しているものは算術演算子と呼ばれるもので、Rubyには他にも論理演算子や範囲演算子などがあります。演算子については次回改めて説明をします。

Rubyでは+の演算子を使って、文字列を連結することができます。

puts "Hello, " + "world!" # Hello, world!

また、*の演算子を使って文字列をその数だけ表示することもできます。

puts "Hello!" * 3 # Hello!Hello!Hello!

演算子には優先順位があります。算術演算子において、()が先で*, /がその次などの計算の優先順位は普通の数学と同じになります。

(1 + 10) * 10 / 2
> 55

自己代入

例えば変数countを使っていてcount1を足した値を代入したいとします。そのときは例えばcount = count + 1というように書くことができます。しかしcountを2回書かないといけないため若干面倒です。そこでRubyではcount += 1のように書くこともできます。これを自己代入といいます。

count = count + 1
count += 1

算術演算子での自己代入の例を下に示しておきます。

自己代入 意味
a += 2 a = a + 2
a -= 2 a = a - 2
a *= 2 a = a * 2
a /= 2 a = a / 2

参考: Ruby 2.3.0 リファレンスマニュアル > 演算子式

数値オブジェクトとStringオブジェクト

今まで数値と文字列を扱ってきましたが、あまり詳しくは触れてきませんでした。ここでは数値オブジェクトとStringオブジェクトについて見ていきます。

数値オブジェクト

Rubyでは整数同士の計算では、その返り値も整数になります。また浮動小数点数(小数)同士の計算では、その返り値も浮動小数点数になります。では整数と浮動小数点数の計算ではどうなるでしょうか。戻り値は浮動小数点数になります。

1 + 1 # 2
2.5 + 1.0 # 3.5

1.5 + 1 # 2.5
0.0 + 1 # 1.0

数値のあとに.to_f.to_iを付けることで整数を浮動小数点数にした値を返したり、逆に浮動小数点数を整数にした値を返します。

10.to_f # 10.0
10.1.to_i # 10
10.9.to_i # 10

他にもRubyには有理数や複素数を表すオブジェクトがあります。

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Numericクラス

Stringオブジェクト

今まで文字列は単発で表示させてきましたが、それぞれを連結することができます。文字列同士を連結するには+の記号を使います。

message = "Hello"
mma_id = "benevolent0505"

puts message + ' ' +  mma_id # Hello benevolent0505

ここではHellobenevolent0505が連結されたものが表示されています。このようにして文字列を連結することができます。

さて、数字の'1'と数字の'2'を足すとどうなるでしょうか。'1' + '2'の戻り値は'12'になります。これは文字列の'1'と文字列の'2'を連結したために'12'という結果になったのです。

'1' + '2' # 12

文字列の数字を数値にして扱いたいときは、文字列の後に.to_i.to_fを付けると文字列の数字を整数や浮動小数点数にした値を返します。

'1'.to_i # 1
'1'.to_f # 1.0

またプログラムを書いているときに文字列の長さが知りたいときがあります。そのときは文字列の後ろに.sizeを付けることで、その文字列の長さの数値を返します。

"ruby-lang".size # 9

str = "ruby-lang"
str.size # 9

参考:Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Stringクラス

ここで紹介したto_ito_f,sizeはみなそれぞれのオブジェクトの持つ メソッド です。オブジェクトはデータや、それについての処理を表現するものだと書きました。このそれぞれのデータについての処理がメソッドなのです。

制御構造

今までのプログラムは上にかかれたものから1行ずつ順番に実行していくものでした。しかし、実際に作りたいプログラムはこれでは中々表現することができません。プログラムでは条件に応じて特定の処理を行いたかったり、同じ処理を何度も繰り返したかったりします。これを 制御構造 と言います。制御構造には次の4つがあります。

  • 条件分岐
  • 繰り返し
  • 例外処理

ここでは上の条件分岐と繰り返しを取扱います。

条件分岐

プログラムを書いていると、特定の条件に応じて処理を分けたいことがあります。例えばテストの点数に応じて表示するメッセージを変えたかったり、学年によって履修出来る授業の表示を変えたかったりといったりです。

こうした条件に応じて処理を分岐させることを 条件分岐 と言います。

真偽値

真を表現するtrueと偽を表現するfalseがあります。

比較演算子式

比較演算子式は、オブジェクト同士を比較してその結果をtrue/falseで返します。比較演算子式には以下のようなものがあります。数学で使っているような記号が多いですが、==,!=,>=,<=などの記号は見なれていないと思うので気を付けましょう。

2 == 2 # true
1 == 2 # false
2 != 2 # false
1 != 2 # true
3 > 1  # true
3 > 3  # false
3 >= 3 # true
3 < 1  # false
3 < 3  # false
3 <= 3 # true

論理演算子式

論理演算子式は複数の条件を1つにまとめることができます。

true && true   # かつ true
true && false  # かつ false
true || true   # または true
true || false  # または true
false || false # または false
!true          # 否定 false
!false         # true

例えば、変数xが1以上かつ100以下の整数という条件は次のようになります。

x = 80

x >= 1 && x <= 100 # true

また&&,||,!はそれぞれand, or, notを使うことができます。

x >= 1 and x <= 100 # true

if式

Rubyで条件分岐を行うものとしてif式があります。if式は次のように書きます。

if 条件式
  条件式が成立している時に実行したいこと
end

これによりmath_point60点以上のときに合格ですと表示するプログラムを書くときには

math_point = 70

if math_point >= 60
  puts "合格です"
end

というふうに書くことができます。

条件が成立していない場合にも処理を行いたいときがあります。

if 条件式
  条件式が成立している時に実行したいこと
else
  条件式が成立していない時に実行したいこと
end

ある条件が成立していないときに、次の条件について調べたいときもあります。

if 条件式1
  条件式1が成立している時に実行したいこと
elsif 条件式2
  条件式1が成立しておらず、条件式2が成立している時に実行したいこと
elsif 条件式3
  条件式1,2が成立しておらず、条件式3が成立している時に実行したいこと
else
  条件式1,2,3が成立していない時に実行したいこと
end

これらのことを使ってmath_pointの値によって成績の表示を変えるプログラムを書いてみると次のようになります。

math_point = 70

if math_point >= 90
  puts "秀"
elsif math_point >= 80
  puts "優"
elsif math_point >= 70
  puts "良"
elsif math_point >= 60
  puts "可"
else
  puts "不可"
end

またRubyにおいてif なので値を返します。if式の返す値は実行された条件の最後の式を評価した値が返り値になります。

message = if max_point == 100
  "満点です"
end

puts message # "満点です"

条件式が成立しない場合はnilが返ってきます。nilとはオブジェクトが存在しないことを指す特別な値です。

message = if 0 == 1
  "not return"
end

message # => nil

if修飾子

Rubyではある1行を条件に応じて実行したいときは次のように書くこともできます。条件が成立しない場合は実行されません。

math_point = 60

puts "合格です" if math_point >= 60
puts "not execute" if math_point < 60

条件演算子式

条件演算子式はとても便利な演算子です。他の言語では三項演算子などと呼ばれていたりします。

a = 1
b = 2
max = 0

if a < b
  max = b
else
  max = a
end

puts max

これまでやったことでこのプログラムはa < bという条件式の真偽値によってmax = bmax = aが評価されるとわかるでしょう。しかし、行っていることを考えてみると結構単純で、慣れてくるとこれだけのことにわざわざこれだけのことを書くのが面倒になってきます。

このプログラムを一行で書けるようになるのが条件演算子式です。書き方は条件式 ? 成立しているときの式 : 成立していないときの式と書き、上のプログラムは次のようになります。

# こう書ける
max = a < b ? b : a
puts max

条件演算子式はとても便利でプログラムがすっきりしますが、複雑な条件分岐をやるのには適していません。使う場面には注意が必要です。

ここでは紹介しませんでしたが、他にもunlesscaseの条件分岐の式があります。詳しくはリファレンスマニュアルを見てみるといいでしょう。

参考: Ruby 2.3.0 リファレンスマニュアル > 制御構造 > 条件分岐

繰り返し

Rubyで繰り返しの処理を行う方法はいくつかあります。ここではwhile, foreachメソッドを使った繰り返しを説明します。

配列

繰り返しについてやる前に、 配列 というものについて触れておきます。配列とはいくつかのデータを順に並べたものです。配列もオブジェクトで、配列オブジェクトやArrayオブジェクトと呼ばれたりします。

配列の中のデータのことを普通は (配列の)要素 と呼んだりします。配列の作り方は[]で囲んだものの中に要素をカンマ,で区切りで書いていきます。

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
colors = ["red", "blue", "green", "orange", "pink", "light blue", "purple"]

# 別々の種類のオブジェクトを一つの配列に格納することも出来る
mix = ["one", 2, "three", 4, 5]

配列の要素を取得するためには配列名[要素の位置]で要素の値を返すことができます。

puts numbers[0] # 1
puts numbers[3] # 4

puts colors[0] # "red"
puts colors[8] # nil

puts mix[-1] # 5

また配列名[要素の位置]に値を代入することができます。

arr = [] # 中身が空の配列ができる
arr[0] = 'M' # "M"
arr[1] = 'M' # "M"
arr[2] = 'A' # "A"

p arr #  ["M", "M", "A"]

arr[4] = "outside" # 範囲外の位置にアクセスすると

p arr # ["M", "M", "A", nil, "outside"] その位置に値が格納されて、間はnilで埋める

配列の大きさが知りたいときにはsizeメソッドを使います。

puts numbers.size # 10
puts colors.size # 7

文字列オブジェクトと配列

文字列の一文字一文字を格納した配列がほしいときがあります。そのような場合にはcharsメソッドを使います。charsメソッドは文字列の各文字列を格納した配列を返します。

p "Hello, world!".chars # ["H", "e", "l", "l", "o", ",", " ", "w", "o", "r", "l", "d", "!"]

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Stringクラス > chars

putsメソッドと配列について

putsメソッドは引数が配列の場合、その要素と改行を順に出力します。配列を配列の形のまま表示したかったら、pメソッドか文字列に式展開で埋め込むのがいいでしょう。

> puts numbers
1
2
3
4
5
6
7
8
9
10
=> nil

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Kernelモジュール > puts

範囲オブジェクト

Rubyには範囲を表すオブジェクトがあります。これを 範囲オブジェクト といい次のように表します。

puts 1..10  # 1 から 10 を表すオブジェクト
puts 1...10 # 1 から 9 を表すオブジェクト

ここでの.....範囲演算子式 といい、..の演算子式の左側に置かれたものから右側に置かれたもの以下の範囲オブジェクトを返します。...の演算子式は左側に置かれたものから右側に置かれたものまでの範囲オブジェクトを返します。

また当然数値を直接書かずに変数に入れたものでも大丈夫です。

a = 5
b = 20
puts a..b

範囲オブジェクトから配列を返すto_aというメソッドがあります。これは範囲オブジェクトの示す範囲の値を含んだ配列を返して、例えば(1..10)[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]という配列を返します。

p (1..10).to_a # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Rangeクラス

while式

ここからは繰り返し処理を行う式やメソッドについて紹介していきます。

while式は条件式が成立している間に、処理を行うものです。while式は次のように書きます。

while 条件式 do
  繰り返したい処理
end

doは省略して書くことができます。

while 条件式
  繰り返したい処理
end

例えばwhileを使って配列の中身を全て表示するプログラムはこのように書けます。

i = 0
while i < numbers.size
  puts numbers[i]
  i += 1
end

実行結果

1
2
3
4
5
6
7
8
9
10
=> nil

参考: Ruby 2.3.0 リファレンスマニュアル > 制御構造 > while

for式

繰り返しを行う式としてfor式もあります。書き方は次の通りです。このdoも省略することができます。

for 変数 in 繰り返したい配列or範囲オブジェクト do
  繰り返したい処理
end

forは配列や範囲オブジェクトについての繰り返し処理を行う式です。変数には配列や範囲オブジェクトの値が順々に代入されていきます。

for i in 1..5 # iには1, 2, 3, 4, 5と繰り返しのたびに範囲オブジェクトの値が代入されていく
  puts i
end

実行結果

1
2
3
4
5
=> 1..5
for i in colors # iには"red", "blue", "green", ...とcolors配列の値が代入されていく
  puts i
end

実行結果

red
blue
green
orange
pink
light blue
purple
=> ["red", "blue", "green", "orange", "pink", "light blue", "purple"]

参考: Ruby 2.3.0 リファレンスマニュアル > 制御構造 > for

break

繰り返し中処理の途中で処理をから抜けたい(終わりたい)場合があります。そのような場合にはbreakを使います。

i = 0
while i < colors.size
  puts colors[i]
  if colors[i].size > 5
    break
  end
end

実行結果

red
blue
green
=> nil

参考 Ruby 2.3.0 リファレンスマニュアル > 制御構造 > break

eachメソッド

配列や範囲オブジェクトには、要素の一つずつにアクセスできるeachというメソッドがあります。書き方は次の通りです。

(配列or範囲オブジェクト).each do |変数|
  繰り返したい処理
end

# こうも書ける
(配列or範囲オブジェクト).each { |変数| 繰り返したい処理 }

eachは配列や範囲オブジェクトのメソッドなので、配列.eachと書きます。変数には配列や範囲オブジェクトの値が順々に代入されていきます。

numbers.each do |item|
  puts item # itemには1, 2, 3, 4, ...と繰り返しのたびに配列numbersの値が代入されていく
end

実行結果

1
2
3
4
5
6
7
8
9
10
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Arrayクラス > each

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Rangeクラス > each

for式とeachメソッドの違い

forとeachの違いについて述べておきます。forとeachは式とメソッドという違いがありますが、処理は ほぼ 同じことをします。例えば、次の2つのプログラムは

for i in 1..3
  puts i
end
(1..3).each do |i|
  puts i
end
1
2
3
=> 1..3

この実行結果はどちらも上のようになります。では次は繰り返し処理をした後に変数のiをforやeachの繰り返しの外で表示してみましょう。irbで動かす場合は先にeachメソッドの例から実行してみてください。

for i in 1..3
  puts i
end

puts i
1
2
3
=> 1..3
> puts i
3
=> nil
(1..3).each do |i|
  puts i
end

puts i
1
2
3
=> 1..3
> puts i
NameError: undefined local variable or method `i' for main:Object
    from (irb):2
    from /Users/Mikio/.rbenv/versions/2.2.3/bin/irb:11:in `<main>'

eachを実行した後に変数iを表示しようとしたらエラーが出てしまいました。このエラーは変数などが作られていない(宣言されていない)ときに、その変数を参照しようとして出るエラーです。一方forの後でiを表示した場合は3が出てきました。forとeachの違いはこの始めに宣言する変数が繰り返し処理の外でも使えるのか、中でも使えるのかが違います。この違いは後に詳しく説明します。

色々な繰り返しの方法について

Rubyには繰り返しの方法はここに紹介した以外にもあります。極端なことを言えば、whileだけがあれば繰り返し処理を行う分には十分です。しかし、whileは条件式だけでしか繰り返しの開始と終了を表現できないですが、forやeachは配列の要素に対して繰り返し処理を行うことができます。配列についての繰り返しはforやeachが向いていることが多いですが、ある条件が成立している間ずっと繰り返し処理をしてほしいときはwhileの方が向いていることが多いです。

このように、繰り返しの場面によって向き不向きが出てきます。どんな場合でも同じ式やメソッドを使うのではなく、場面を考えて使い分けることが大切になります。

injectメソッド

puts numbers.inject(0) { |result, item| result + item} # 55

# 次に書くプログラムと同じ意味

result = 0
numbers.each do |item|
  result += item
end

puts result # 55

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Enumerableモジュール > inject

参考: Ruby 2.3.0 リファレンスマニュアル > 制御構造 > 繰り返し

値を入力する

今まではプログラムの中で宣言された数値や文字列の値を使ってプログラムしていきました。しかし、実際のプログラムではプログラム外からの 入力 を受け取ってプログラムを実行していくものがほとんどです。ここでは2種類の値を入力する方法を説明します。

コマンドライン引数 ARGV

ターミナルからruby プログラム名.rbというプログラムを起動するときに、このプログラムに引数を渡すことができます。この引数のことを コマンドライン引数 と呼びます。

コマンドライン引数の渡し方は

> ruby プログラム名.rb 引数1 引数2 ...

という形で、ファイル名の後にスペースをあけて指定します。

Rubyのプログラムからコマンドライン引数を取得する方法はARGV配列を使います。ARGVにはコマンドライン引数の値が渡された順に配列になって格納されています。ですので次のようなコマンドライン引数を渡したときは

ruby display.rb 1 2 3 4 5 6 7 8 9 10

このようになります。

p ARGV # ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
value1 = ARGV[0] # "1"
value2 = ARGV[1] # "2"
value3 = ARGV[2] # "3"

またコマンドライン引数で取得できる値は 文字列オブジェクト なので、数値を取得したいと思った場合はto_ito_fメソッドを使って取得する必要があります。

getsメソッド

getsメソッドは一行読み込んで、読み込みに成功した時にはその文字列を返します。

> message = gets
hello, world # ←打ち込んだ文字列
=> "hello, world\n"

ここでgetsメソッドの返り値を見てみましょう。打ち込んだ文字列以外の文字\nが見えます。これは 改行文字 と呼ばれるものです。改行文字始めの方で述べた特殊文字の一つで、文字通り改行を表す文字です。

irb(main):043:0> puts "Hello\nworld"
Hello
world
=> nil
irb(main):044:0>

では何故改行文字が追加されてしまうのでしょうか。getsメソッドは一行読み込んでその文字列を返します。ここで一行の終わりを示すためにEnterキー(Return)を入力しました。このEnterキー(Return)によって改行文字が入力されたのです。

この改行文字を取り除くにはchompというメソッドを使います。chompは文字列の改行文字を取り除きます。

> message = gets.chomp
hello, world
=> "hello, world"

これにより、標準入力から文字列を取得できます。

参考: Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > IOクラス > gets

エラーについて

ここではよく見るエラーとその原因として考えられること、またその取り除き方を紹介します。まず次のプログラムを見てください。

error.rb

1 arr = [-43, 61, 24, -49, -25, 59, -13, 8, 48, 58]
3
4 arr.each do |item|
5   puts itme # ここにスペルミスがある
6 end
7

このプログラムは4行目で変数のスペルミスがあるので、正常に動かずエラーが出ます。

実行結果

error.rb:5:in `block in <main>': undefined local variable or method `itme' for main:Object (NameError)
    from error.rb:4:in `each'
    from error.rb:4:in `<main>'

このエラーを見てみましょう。エラーの始めにerror.rb:5と書いてあります。ここはエラーが起こった行を指しています。現実にはここで表示される行がエラーの直接の原因でないこともあるのですが、原因を探る手掛かりにはなります。

次にundefined local variable or method `itme' for main:Object (NameError)という部分を見てみましょう。この部分を読むと、どういうエラーが発生しているのかがわかります。undefined local variable or method ``itme' for main:Objectと書いてあるので「itmeという(ローカル)変数かメソッドが定義されていません」という意味です(このくらいの英語は読もう)。後に続く(NameError)はエラーの名前を表示しています。

このようにプログラム上の誤りを バグ といい、それを取り除くことを デバッグ といいます。デバッグを行うときに大切なことは、原因をきちんと追求すること です。よくエラーが出たときにいきなり書いたプログラムを消したり書き直す人がいますが、それはよくありません。プログラムを間違えたときは必ずエラーが出るので、それを見て何がエラーの原因だったのか、 どうやったら二度とこの間違いを起こさないのかを考えて、再発防止の対策を打つまでがデバッグです。

以下ではよく見るエラーを紹介していきます。

syntax error

文字通り文法上のエラー。よくあるミスとしては

  • ifなどの対応するend{}の対応を書き忘れ
  • (), {}, []"", ''がちゃんと閉じられていない
  • 演算子式は正しく使われているか

などがあるので、このエラーに遭遇したときはこのような内容を確認してみるといいでしょう。

NameError / NoMethodError

変数やメソッド名が宣言されてなかった時のエラー。よくあるミスは

  • 変数名やメソッド名のスペルミス
  • 変数が宣言されていない
  • 変数の代入が正しく行われていない

などがあります。

ArgumentError

メソッドの引数に誤りがあったときのエラー。メソッドの引数の数を確認してみましょう。

演習問題

各実行例を参考にして、プログラムを作ってみてください。

基本

  • 3つの数を入力させて、それを足し算した結果を表示するプログラム
> ruby input_three_num.rb 1 2 3
a = 1, b = 3, c = 3
a + b + c = 6
>
  • 文字列と整数を入力させて、文字列を指定された整数回繰りかえして表示するプログラム
> ruby repeat_str.rb Hello,world! 3
Hello,world!
Hello,world!
Hello,world!
>
  • 西暦の値が与えられた時、閏年かどうかを判定するプログラム。閏年の条件は次の3つになります。
    1. 西暦年が4で割り切れる年は閏年
    2. 西暦年が100で割り切れる年は平年(閏年ではない)
    3. 西暦年が400で割り切れる年は閏年

参考: 閏年 wikipedia

> ruby leap_year.rb 2020
2020 is leap year.
> ruby leap_year.rb 2019
2019 is common year.
  • 渡された数値の配列の最大値を取得するプログラム(渡す配列の中身はなんでもいいですが、要素は一つ以上にしてください)
> ruby max.rb
Array is [16, 71, 15, 99, 73, 66, 24, 3, 72, 83]
Max number is 99.
  • 数値の配列の平均を求めるプログラム
> ruby average.rb
Array is [41, 95, 56, 15, 98, 6, 85, 61, 1, 78]
Average is 53.6
  • 2つの数値を変数に格納し、その変数の中身を入れ変えるプログラム
> ruby swap.rb 12 41
before swap
a = 12 b = 41
after swap
a = 41 b = 12
  • 数値の配列が与えられた時、それを逆順に出力するプログラム
> ruby arr_reverse.rb
Array: [97, 32, 3, 74, 6, 77, 71, 33, 72, 79]
size: 10
Reversed: [79, 72, 33, 71, 77, 6, 74, 3, 32, 97]
  • 文字列を引数にとって、それをひっくり返したものを戻り値とするメソッド
> ruby str_reverse.rb "No lemon, No melon"
input str is No lemon, No melon
reversed str is nolem oN ,nomel oN
  • BMIを計算して太りすぎか痩せ過ぎかを判定するプログラム。BMIの計算方法はBMI = 体重(kg) / 身長(m)^2です。

また太りすぎか痩せ過ぎかの判定は次の基準で行うことにします。

低体重(痩せ型) 18.5未満
普通体重 18.5以上、25未満
肥満(1度) 25以上、30未満
肥満(2度) 30以上、35未満
肥満(3度) 35以上、40未満
肥満(4度) 40以上
> ruby bmi.rb 56 1.6
あなたのBMIは21.87
普通体重です
  • 数値を与えられたら1からその数値までの数値を表示するプログラムを作ってください。ただし、3の倍数になったらFizz、5の倍数になったらBuzz、3と5の倍数になったらFizzBuzzと表示させてください。
> ruby fizzbuzz.rb 15
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
  • 数当てゲーム
    自分が思い浮べた数値を推測するプログラム。例えば70を思い浮べたときは
> ruby guess_number.rb
guess number 1 ~ 100
Do you choose 50?
Type bigger, smaller or yes...: bigger
Do you choose 75?
Type bigger, smaller or yes...: smaller
Do you choose 62?
Type bigger, smaller or yes...: bigger
Do you choose 68?
Type bigger, smaller or yes...: bigger
Do you choose 71?
Type bigger, smaller or yes...: smaller
Do you choose 69?
Type bigger, smaller or yes...: bigger
Do you choose 70?
Type bigger, smaller or yes...: yes
Fufu!

というように実行される。

発展(?)

  • 素数を見つける(エラトステネスの篩)
  • 最大公約数(ユークリッドの互除法)
  • ズンドコキヨシ
  • ハノイの塔

benevolent0505/ProgrammingSeminar2016/basic-grammar (最終更新日時 2016-07-02 11:31:52 更新者 benevolent0505)