######## 2016.8.28修正中 ########
結構ひどい間違い多い。徐々に修正していきます
環境
- OS X Yosemite 10.10.1
- ruby 2.2.1p85
はじめに
ruby についてざーっとまとめてみました。サンプルのコードは動かしながら書いているので動作的には大丈夫だと思いますが、1週間で纏めきるという時限付きでの投稿なので日本語がぐだぐだで説明になっていない場所もあるかもです。クリティカルにダメな表現・内容がございましたら、コメントにてご一報いただけると幸いです。
ってことで、ひと通りの文法をざっくりと理解するために irb というツールも利用するよ。irb はざっくり言っちゃえばターミナル等から ruby を 入力/実行 するツールだよ
irb の使い方
ターミナルで以下のように入力
$ irb
irb(main):001:0>
irb(main):001:0> 的な状態になったら、入力を待機している状態だよ
puts と p
puts メソッドは改行付きで出力するよ。System.out.println 的な役割。
p メソッドは、デバッグ用の出力メソッドだよ。より詳細な情報を出力してくれるんだ。console.log みたいなもんだね!
Hello World
以下のように、puts "Hello World" と入力するよ
irb(main):001:0> puts "Hello World"
Hello World
=> nil
ファイルの実行
ファイルは ruby ファイル名 で実行できるよ。仮に hello.rb というファイルを作って以下のように書くよ。(*このポストではファイル実行の結果をわかりやすくするために、ファイル内に標準出力するための puts だの p が呼ばれた結果に => を使うことにするよ)
puts "Hello World"
ターミナルでは以下のようにして実行するよ
$ ruby hello.rb
=> Hello World
コメント
一行コメントは # で、ブロックコメントは =begin と =end を使うよ
# 一行コメント
=begin
ぺろぺろ
ぺろりん
ぺーろぺろ
=end
変数
Ruby には 変数宣言 をするための構文がないよ。また、変数名(の一文字目)によって変数の種類が決まるよ
先頭文字 | 種類 | デフォルト値 |
---|---|---|
小文字または _ | ローカル変数 | 参照する前に代入が必要 |
@ | インスタンス変数 | nil |
@@ | クラス変数 | 参照する前に代入が必要 |
$ | グローバル変数 | nil |
大文字 | 定数 | 参照する前に代入が必要 |
各種変数のスコープについて
変数 | 説明 |
---|---|
ローカル変数 | スコープを「ブロック」、「メソッド」、「クラス・モジュール定義」各定義の終わりまでとした、一番スコープの狭い変数 |
インスタンス変数 | 特定のオブジェクトに属する変数。同じオブジェクトのメソッド間で共有。そのオブジェクトの状態を表すなどに利用 |
クラス変数 | 基本的にはクラスに属する変数。子孫クラス、それらのクラスのすべてのインスタンス間で共有される。Java や C# でいう static変数 |
定数 | 状態が変更されない変数。Java で言うと final を使った変数。C# で言うと const を使った変数。 |
数値
Rubyの組み込みの数値型は「整数(Integer)」オブジェクトと「浮動小数点数(Float)」オブジェクトに分類される。なので 10 はInteger(のサブクラスであるFixnumクラス)のオブジェクトで 10.5 は Float のオブジェクトだよ
i = 10
puts i.class
f = 0.1
puts f.class
=> Fixnum
=> Float
数値演算
演算 | 例 | 説明 |
---|---|---|
加算 | 5 + 3 | 足し算。結果は 8 |
減算 | 5 - 3 | 引き算。結果は 2 |
乗算 | 5 * 3 | 掛け算。結果は 15 |
整数除算 | 5 / 3 | 整数での割り算。結果は 1 |
実数除算 | 5.0 / 3 | 実数での割り算。結果は 1.6666666666666667 |
べき乗 | 5 ** 3 | 5 の 3乗。結果は 125 |
剰余 | 5 % 3 | 5 ÷ 3 の 余り。結果は 2 |
インクリメント、デクリメント
Ruby には C言語系に見られる インクリメント演算子(++) や デクリメント演算子 (--) がない。ってことで「自己代入演算子」やメソッドを利用する
# 自己代入演算子の例
i = 0
i += 1
# next メソッドを利用した例
i.next
*ちなみに nextメソッド は i自体 を書き換えないよ。
i = 0
p i.next
puts i
=> 1
=> 0
代表的な自己代入演算子
演算子 | 例 | 意味 |
---|---|---|
+= | i += 1 | i = i + 1 |
-= | i -= 1 | i = i - 1 |
*= | i *= 2 | i = i * 2 |
/= | i /= 2 | i = i / 2 |
%= | i %= 2 | i = i % 2 |
**= | i **= 2 | i = i ** 2 |
比較演算子
演算子 | 意味 | 例 | 結果 |
---|---|---|---|
== | 同値 | 1 == 1 | true |
!= | 非同値 | 1 != 1 | false |
< | 小なり | 1 < 2 | true |
> | 大なり | 1 > 2 | false |
<= | 小なりイコール | 1 <= 2 | true |
>= | 大なりイコール | 2 >= 1 | true |
文字列
文字列リテラルは、二重引用符「"」または一重引用符「'」で表現したい文字列の内容を囲う。
dq = "Hello World"
puts dq
=> Hello World
sq = 'Hello World'
puts sq
=> Hello World
バックスラッシュを使った代表的なエスケープ文字
記法 | 表現される文字 |
---|---|
\t | タブ |
\n | 改行 |
\s | 空白 |
" | 二重引用符 |
' | 一重引用符 |
\|バックスラッシュ |
エスケープ文字を文字列内で使うには
エスケープ文字を文字列内で表現するためには、「"」二重引用符を利用します。
hoge = "Hello \n World"
puts hoge
=>Hello
=> World
文字列内で変数を展開するには
文字列内で変数を展開するには、「"」二重引用符を利用します。また、変数は #{変数名} で展開します。
hoge = "Hello"
puts "#{hoge} World"
=> Hello World
#{} のカッコでくくられた部分は Ruby の式として解釈される。
i = 5
puts "5x5=#{i * 5}"
=> 5x5=25
puts "#{Time.now}"
=>2015-01-01 00:0:00 +0900
バッククォート文字列
文字列をバッククォートでくくると、くくられた中身をシェルとして実行し、コマンドが出力した内容を文字列にして返す
puts `pwd`
=> /Users/chrowa3
ヒアドキュメント
puts <<EOS
Hello
World
Ruby
EOS
=> Hello
=> World
=> Ruby
正規表現
正規表現リテラルは / と / で囲う。例えばこんな感じ
/\d{3}-\d{4}/
これを簡単にマッチさせるなら =~ 演算子を使う
puts /\d{3}-\d{4}/ =~ "郵便番号:192-0041"
=> 5
返ってきた数値は先頭文字列を 0 としたオフセット値を返すよ。上記例だと 6文字目 からマッチしているので、5が返る。
ちなみにキャプチャはこんな感じで
if /(\d{3}-\d{4})/ =~ "郵便番号:192-0041"
puts $1
end
=> 192-0041
マッチしなかったらnil
が返ってくるよ
文字列の「部分」へのアクセス
添字を使う
s = "sos"
puts s[1]
=> o
Rubyの文字列は mutable(変更可能) なので部分的な更新も可能
s = "SOS"
s[1] = "N"
puts s
=> SNS
文字列を部分的に取得する時、インデックスに2つ目の数値を与えるとその数値分の文字をとる
str = "hoge"
p str[0,1]
=> "h"
p str[0,2]
=> "ho"
文字列結合
加算演算子 + を使う
puts "Hello" + "World"
=> HelloWorld
反復
乗算演算子で繰り返すことが可能
puts "NO!" * 3
=> NO!NO!NO!
分解
splitメソッドを使って文字列を配列に分解。引数に正規表現を渡すとそのパターンにマッチする文字列を区切り文字とし分割する。
p "a,b,c,d".split(/,/)
=> ["a","b","c","d"]
比較
文字列は比較演算子で比較できる。文字列大小関係は辞書式となるよ。
"abc" == "abc"
=> true
"a" < "b"
=> true
"a" > "b"
=> false
各種メソッド(抜粋)
# 長さを取得
"abc".length
=> 3
# クラスを取得
"abc".class
=> String
# 空かどうか
"".empty?
=> true
# 整数型へ変換
"5".to_i
=> 5
"5".to_i.class
=> Fixnum
# インデックスを取得
"abcdefg".index("c")
=> 2
# 正規表現で置換 (2015.04.10 @scivola 氏に頂いたありがたいコメントを参考に修正)
"box".gsub(/[a-z]{2}(x)/) do
"Fi#{$1}"
end
=> Fix
# 左右の空白を取り除く
" ab c ".strip
=> "ab c"
などなど。他にもいっぱい
文字列をペロる
"ペロペロペロリン".each_char do |c|
p c
end
=> "ペ"
=> "ロ"
=> "ペ"
=> "ロ"
=> "ペ"
=> "ロ"
=> "リ"
=> "ン"
シンボル
シンボルを理解するためには、まず文字列同士を比較する次のようなコードを見ていったほうが理解が早いかも
str1 = "a"
str2 = "a"
p str1 == str2
p str1.equal? str2
=> true # 同値
=> false # 同じオブジェクトではない
equal? は「同じオブジェクトかどうか」を調べるメソッドだよ。このコードからわかるのは、文字列は「同じ値でも同じオブジェクトとは限らない」ということ。
ただし、次のコードでは同一になる。(当たり前かw
str1 = "a"
str2 = str1
p str1 == str2
p str1.equal? str2
=> true # 同値
=> true # 同じオブジェクト
「同じオブジェクトとは限らない」ということは、オブジェクト自体の identity が違うということ。仮に object_id を見てみるとこんな感じになる。
str1 = "a"
str2 = "a"
p str1.object_id
p str2.object_id
=> 70231276141340
=> 70231276141320
僕の環境では str1 の object_id は「70231276141340」、str2 の object_id は「70231276141320」となったよ。要するにまったく別物なんだってこと。
では、シンボルではどうだろうか。シンボルは : コロンを使ってつくる。次のコードで諸々を一気に確認してみよう。
sym1 = :a
sym2 = :a
p sym1 == sym2
p sym1.equal? sym2
p sym1.object_id
p sym2.object_id
=> true
=> true
=> 702428
=> 702428
同値判定、同オブジェクトかの判定、object_id の一致を見て同じものだということがわかるよ。
ってことでシンボルは「値が同値であれば必ず同一のオブジェクト」だということがわかるよ。
まとめると
- Rubyの内部実装では、識別子を整数で管理しており、文字列として処理(捜索)するよりも速度面で有利になる。シンボルはその内部実装のような仕組みをコード上で表現したもの。だから文字列同士の比較などよりも数値の比較になるのでよっぽど速い。見た目は文字列な整数値、的なイメージ
- 唯一性を維持するため、シンボルは文字列と違い変更不可能(immutable)であり、同値ならば必ず同一のオブジェクトとなる。
- これらの性質からハッシュ(連想配列)のキーなどに利用される
配列
配列のつくりかた
[]ブラケットを使う
arr = ['a','b','c']
=> ["a","b","c"]
要素の型は自由
arr = [5,'abc',{'key'=>'value'}]
=> [5, "abc", {"key" => "value"}]
当然多次元も
wey = [1,2,3]
hey = [wey,wey,wey]
p hey
=> [[1,2,3],[1,2,3],[1,2,3]]
添字参照
配列の要素は 0 から始まる番号でインデックスされています。[]ブラケットとインデックスで各要素にアクセスできます。
arr = ['a','b','c']
p arr[2]
=> "c"
インデックスを 負の数 で指定すると、配列要素の最後からの参照となる
arr = ['a','b','c']
p arr[-1]
=> "c"
インデックスは変数でもよいよ
arr = ['a','b','c']
i = 2
p arr[i]
=> "c"
インデックスに続いて、整数値を指定すると「そのインデックスからの整数値分を要素とした新しい配列を生成」するよ
arr = ['a','b','c']
p arr[1,2]
=> ["b","c"]
同じようなことを「範囲演算子」を使って実現できるよ。範囲演算子は「..」と「...」があり、たとえば 0..10 は「0から10」までを示すよ。0...10 は「0から9」までを示すよ。「含む、含まない」の違いだね。
arr = ['a','b','c']
p arr[1..2]
=> ["b","c"]
配列は参照を保持
添字での参照で返ってくる値は配列が保持している「オブジェクトへの参照」だよ。
しかし、[]ブラケットに 範囲演算子 などを指定して新たに別の配列を用意する場合はあくまでも「あらたな配列を生成」しているので、生成した配列を操作しても元となる配列には影響はありません。
arr = ['a','b','c']
newArr = arr[1..2]
newArr[0] = "hey!"
p arr
p newArr
=> ["a","b","c"]
=> ["hey!","c"]
代入
代入演算子 =(イコール)を使って代入。各要素へは[](ブラケット)へインデックスを指定するよ
arr['a','b','c']
arr[1] = 'd'
p arr
=> ["a","d","c"]
比較
配列同士を比較した場合、同一インデックスの参照先が同一の値を持っていれば true になるよ
foo = [2,3,4]
bar = [2,3,4]
p foo == bar
=> true
値の内容が一緒でも、インデックスが違えば false になるよ
foo = [2,3,4]
bar = [4,3,2]
p foo == bar
=> false
各種メソッド(抜粋)
# 前提となるサンプルの配列
arr = [5,4,3,2,2,1]
# 配列の要素数
p arr.length
p arr.size
=> 4
# 要素の参照先に指定した値を含むか
p arr.include? 3
=> true
# 配列のソート
p arr.sort
=> [2,3,3,4]
# 要素の参照先に重複した値があればそれを削除した状態の新しい配列を返す
p arr.uniq
=> [4,3,2]
# 先頭の要素を取り出す
a = arr.shift
p a
p arr
=> 4
=> [3,2,2]
# 末尾の要素を取り出す
a = arr.pop
p a
p arr
=> 2
=> [3,2]
# 末尾に要素を追加
arr.push("hoge")
p arr
=> [3,2,"hoge"]
配列をペロる
eachメソッドを使う
arr = ['a','b','c']
arr.each do |c|
p c
end
=> "a"
=> "b"
=> "c"
do ~ end はブロックを表すよ。|と| はパラメータを渡す部分だと思ってよいよ。この each メソッドでは、arr を一つ一つ舐めていき、その一つ一つ が c に代入されていくっていうイメージ。
ハッシュ(連想配列)
ハッシュのつくりかた
{} カーリーブラケットを使う
user = { "name" => "chrowa3" , "age" => 16 }
=> {"name"=>"chrowa3", "age"=>16}
ruby 1.9 からは : コロンを使ってつくれるよ!これは嬉しい。key: value
のkey:
はハッシュ
user = { name: "chrowa3" , age: 16 }
=> {:name=>"chrowa3", :age=>16}
参照
ハッシュは配列のように、範囲指定などができない分単純な参照しかないよ。[]ブラケットにキーとなるオブジェクトを指定するだけだよ。
user = { "name" => "chrowa3" , "age" => 16 }
p user["name"]
=> "chrowa3"
user = { name: "chrowa3" , age: 16 }
p user[:name]
=> "chrowa3"
コロンを使った記法は、ruby 1.9 からの導入ですが、シンボルとなりうる Key と コロンとの間にスペースがあると Syntax error になるようです。
h = {a: 5}
p h
=> {:a=>5}
e = { a : 5 }
p e
=> syntax error, unexpected tSYMBEG, expecting keyword_do or '{' or '('
代入、更新
user = { name: "chrowa3" , age: 16 }
user[:name] = "PeroPero"
p user
=> {:name=>"PeroPero", :age=>16}
追加
user = { name: "chrowa3" , age: 16 }
user[:blood] = :b
p user
=> {:name=>"chrowa3", :age=>16, :blood=>:b}
比較
個人的にはこの機能結構強力だなーって思ったりします
h1 = {a:1,b:5}
h2 = {a:1,b:5}
h3 = {b:5,a:1}
h4 = {"a"=>1,"b"=>5}
p h1 == h2
p h1 == h3
p h1 == h4
=> true
=> true # 順序は関係ないってさ
=> false # シンボルと文字列は別物
キーが違ったり要素数が違えば false になるよ
各種メソッド
user = {
name: "chrowa3",
age: 15,
blood: :b,
job: "programmer",
web: "http://webya.in"
}
p user.size
=> 5 #要素数
p user.keys
=> [:name, :age, :blood, :job, :web] # keyのみで構成された配列
p user.values
=>=> ["chrowa3", 15, :b, "programmer", "http://webya.in"] # value のみで構成された配列
p user.key?(:job)
=> true # 指定の key を含んでいるか
user.delete("age")
p user
=> {:name=>"chrowa3", :blood=>:b, :job=>"programmer", :web=>"http://webya.in"} # key age を削除
user.clear
p user
=> {} ハッシュの中身を削除
ハッシュをペロる
引数は2つの値を渡される。一つ目は Key。2つ目は Value
user.each do |key,value|
p key.to_s + ":" + value.to_s
end
=> "name:chrowa3"
=> "age:15"
=> "blood:b"
=> "job:programmer"
=> "web:http://webya.in"
制御式
とりあえず使いそうなやつだけ書く。
if
# 構文
if 条件 then
処理
else
処理
end
Ruby での 真偽値
ruby での 偽 は false と nil のみ。0 や "" も true となる
イテレーターと脱出式
イテレーターには
- loop
- times
- upto
などがある。
# loop
loop do
p "hoge"
end
p "hoge" を繰り返すよ。脱出式を使わない限り無限ループ。
# times
3.times do
p "hoge"
end
=> "hoge"
=> "hoge"
=> "hoge"
times は内部にカウンタを引き渡してくれるよ
# times
3.times do |i|
p "hoge" + i.to_s
end
=> "hoge0"
=> "hoge1"
=> "hoge2"
upto は オブジェクトを引数で指定した数値までカウントアップするよ。
# upto
3.upto(5) do |i|
p i
end
=> 3
=> 4
=> 5
break
現在の繰り返し構造(while、for、loopなど)のもっとも内側から一つ外に脱出できるよ
i = 0
loop do
i += 1
p i
if i == 5 then
break
end
end
p "complete!"
=> 1
=> 2
=> 3
=> 4
=> 5
=> "complete!"
他にも next や redo などの脱出式はあるけど割愛
例外処理
ruby での 例外処理は java に置き換えると、try が「begin」、throw が「raise」、catch が「rescue」、finaly が「ensure」となるよ。この全てを使った最小の例は以下のとおり
begin
p "in begin"
raise
rescue
p "in rescue"
ensure
p "in ensure"
end
p "end"
=> "in begin"
=> "catch"
=> "finaly"
=> "end
もういっこ例
begin
p "in begin"
raise Exception, "raise Exception,"
rescue Exception => e
p "in rescue"
p e.message
ensure
p "in ensure"
end
p "end"
=> "in begin"
=> "in rescue"
=> "raise Exception"
=> "in ensure"
=> "end"
メソッド
定義
メソッドを定義するには def 式をつかうよ。
# 諸々省略した構文
def メソッド名
処理
end
簡単なメソッドをつくって見よう
def m
p "m was called to by chrowa3"
end
引数を指定してみるよ
def m name
p "m was called to by " + name
end
引数は ,カンマ区切りで複数渡せるよ。
次に戻り値を指定してみようか。戻り値は return で指定するよ。
def m name
return "m was called to by " + name
end
だたし、rubyでは最終的な式の結果を返すのでreturn
は書かない習慣がある
def m name
"m was called to by " + name
end
デフォルト値の指定はこんな感じ。
def m age,name = "nanashi"
p "m was called to by " + name
p name + " is " + age + "years old."
end
呼び出し
メソッド名と必要な引数を指定して呼び出すよ。
def m age,name = "nanashi"
p "m was called to by " + name + "."
p name + " is " + age + "years old."
end
m(5)
=> "m was called to by nanashi."
=> "nanashi is 5years old."
呼び出し時の()かっこは省略可能だよ
def m age,name = "nanashi"
p "m was called to by " + name + "."
p name + " is " + age + "years old."
end
m 5
=> "m was called to by nanashi."
=> "nanashi is 5years old."
メソッドチェーンもjsばりに使えるよ
i = 12345
p i.to_s.length
=> 5
クラス
サンプルコードにモヤっとしないでね!( なんで Car クラスなんかにしちまったんだ... )
定義
class クラス名
任意の式
end
インスタンスメソッド
クラスに def式 で定義する。
class Car
def run
p "Run"
end
end
クラスメソッド
さっきの run をクラスメソッド(いわゆる static なメソッド)にするには def 式に クラス名をつける
class Car
def Car.run
p "Run"
end
end
クラス名で指定するよりも self を使ったほうがちょっとエレガントよね
class Car
def self.run
p "Run"
end
end
コンストラクタ
initialize という名前のメソッドを定義することにより、そのクラスをインスタンス化(new)したタイミングで呼び出され、オブジェクトの固有の状態を保持できるよ。
class Car
def initialize carName
@carName = carName
end
def self.run
p "Run"
end
def getCarName
@carName
end
end
この例では initialize が呼ばれた時に carName を初期化
インスタンス変数
インスタンス変数は @マークを使うよ。この例では @carName がそれにあたるよ。
また、インスタンス変数は直接アクセスが出来ないので、メソッド経由などの方法でアクセスする必要があるよ。
class Car
def initialize carName
@carName = carName
end
def self.run
p "Run"
end
def carName
@carName
end
def carName=(name)
@carName = name
end
end
アクセサ
上記ののように単純なインスタンス変数へのアクセスならば、attr_accessor
にインスタンス変数の名前をシンボルで渡してあげれば自動的に定義されるよ
class Car
attr_accessor :carName
def initialize(carName)
@carName = carName
end
def self.run
p "Run"
end
end
外部から代入する必要がない場合は、attr_reader
のみを使い、逆に代入だけ必要な場合はattr_writer
を使いましょう
クラス変数
@@で定義するよ。これもメソッド経由などでのアクセスが必要だよ。オブジェクト間で共有されるよ。
class Car
attr_accessor :carName
def initialize(carName)
@carName = carName
end
def self.run
p "Run"
end
end
myCar = Car.new('Benz')
アクセサを複数定義する場合にはカンマ区切りで列挙すればおk
new
クラスを実体化するには newメソッドを使うよ。
class Car
...処理
end
myCar = Car.new
new で指定したメソッドは initialize メソッドに引き渡されるよ。次の例ではこのクラスのインスタン変数 @carName に "Benz" を引き渡しているよ。
class Car
attr_reader :carName
def initialize carName
@carName = carName
end
def self.run
p "Run"
end
end
myCar = Car.new "Benz"
各呼び出し
class Car
attr_accessor :carName
def initialize carName
@carName = carName
end
def self.run
p "Run"
end
end
myCar = Car.new "Benz"
# インスタンス変数へのアクセス
p myCar.getName
=> "Benz"
# クラスメソッドを呼び出し
Car.run
=> "Run"
継承
ruby は 単一継承をサポートしています。クラス定義時、クラス名に < に続けて継承したいクラス名を指定することにより継承することになるよ。
class Vehicle
...処理
end
class Car < Vehicle
...処理
end
スーパークラスの呼び出し
super式は、親クラスの同名のメソッドを呼び出すよ。initialize メソッド内で呼べば親クラスの initilize メソッドを呼び出すよ。
class Vehicle
attr_reader :otherName
def initialize otherName
@otherName = otherName
end
end
class Car < Vehicle
attr_reader :carName
def initialize carName, otherName
super otherName
@carName = carName
end
def self.run
p "Run"
end
end
myCar = Car.new "Benz", "myBenz"
p myCar.carName
Car.run
p myCar.otherName
アクセス制限
===========2016.8.28 編集中===========
アクセス制限 | 説明 |
---|---|
public | どこからでも呼び出せる |
protected | そのクラス内とそのクラスを継承したクラスのインスタンスメソッドからの呼び出しのみ |
private | selfに対してしか呼び出せない |
オーバーライド
クラスを継承した場合に、親クラスで定義されたメソッドと同じ名前で新しいメソッドを定義し直すことができるよ。これをオーバーライドっていうよ。
たとえば親クラスである、Vehicle に horn メソッドを追加したとしよう。
class Vehicle
attr_reader :otherName
def initialize otherName
@otherName = otherName
end
def horn
p "ぺっぺー"
end
end
Vehicle を new して horn を呼べば「ぺっぺー」と表示される
v = Vehicle.new "R32"
v.horn
=> "ぺっぺー"
一方 Car クラスで horn を再定義してみるよ(注意:private なインスタンスメソッドよりも後に定義すると怒られるみたい。調査しておきます)
def horn
"ぷっぷー"
end
.
. 省略
.
myCar.horn
=> "ぷっぷー"
ってことで、ざっペロ完了です。定数や、特異メソッド、特異クラス、ブロック、proc、yield など重要なトピックが抜けてますがそれはまた今度どこかで。