私は普段主にC#やjavascriptを使ったりしているのですが、巷で話題のRubyにもそろそろ手を出そうと基礎を勉強し始めました。勉強の過程でRubyって今まで触れてきた言語と思ったより違うなぁと感じました。こういう違いを俯瞰できたら勉強しやすいと思ったのでこの記事を書いた次第です。
これをおさえておけば、ある程度ソースが読めるかも、という見慣れない構文や決まりなどをまとめています。あれもこれもと書いていると長くなってしまいました...。概要をまとめただけで、詳細は他のページや記事に任せるようにしています。
「これは他の言語にも共通じゃないか」と思われることもあるかもしれませんが、ご容赦ください。
※バージョンはRuby2.0を想定
#変数
変数の種類は、変数名の前にpublicとかprivateをつけるのではなく、変数名に特徴を持たせることで識別する。
##ローカル変数
スコープが変数がかかれたブロックに限定される変数。
変数名は 小文字のアルファベットまたは_
で始める。
ローカル変数x
に100を代入する場合はx = 100
と書けばおk。
##グローバル変数
スコープがプログラム全体の変数。
変数名の前に$
をつける。
グローバル変数$x
に100を代入する場合は$x = 100
と書く。
##クラス変数
クラス変数はクラス定義の中で定義され、クラスの特異メソッドやインスタンスメソッドから参照・代入できる。
クラス、サブクラスのみから参照可能。
クラス変数の値はクラスのすべてのインスタンスで共有する。
変数名の前に@@
をつける。
##インスタンス変数
インスタンス内に保持する変数。
変数名の前に@
をつける。
インスタンス変数@x
に100を代入する場合は@x = 100
と書く。
##定数
代入は原則1度。2回目以降は警告が出る。
先頭がアルファベット大文字。
慣例としてコードを見た感じ定数名全体が大文字であることが多いように思う。
定数CONSTに4を代入する場合CONST = 4
と書く。
#オブジェクト
##ハッシュ
他の言語にもある、ハッシュテーブルや連想配列のこと。
キーとオブジェクトをセットで格納する。
キーとオブジェクトは任意の種類のオブジェクトである。
キーにはしばしばシンボル(後述)が使用される。
#この例では"Taro"がキー、"Tarochan"が値
hash = {:name => "Taro", :nickname => "Tarochan"}
##シンボル
ソース上では文字列のように見え、内部では整数として扱われる。文字列の格好をした整数とも言える。直接文字列を処理するよりも早く処理ができるので、文字列自体が必要でない場合に利用される。具体的には以下の通り。
###用途
- ハッシュのキー
- アクセサの引数で渡すインスタンス名
- メソッド引数で渡すメソッド名
- C言語におけるのenumの代用
###メリット
- 新しく文字列を生成しない分やや効率がよく、比較も高速。
- 文字の意味がはっきりするのでコードが読みやすくなる
- immutable なので内容を書き換えられる心配がない
symbol = :hoge
##正規表現
Rubyが得意とする文字列処理を実現する1つの機能。
文字列からパターンを切り出したりすることができる。
以下は文字列からパターンに一致する位置を返す文。
#/パターン/ =~ マッチングする文字列
/Taro/ =~ "Yamada Taro deus" #=>7
#デフォルトでは大文字と小文字は区別される。
#nilは他言語のnullと同じような意味
/taro/ =~ "Yamada Taro desu" #=>nil
#パターンの後ろにiを追加すると大文字小文字の区別がなくなる。
/taro/i =~ "Yamada Taro desu" #=>7
#メソッド
##デフォルトの引数
デフォルト値が設定できる。
def numFunc(a, b="test")
puts a + " and " + b
end
numFunc("check") #=> check and test
numFunc("check", "check") #=> check and check
##引数の数を定めないメソッド
引数の数を自由に変えることが可能なメソッドを作ることができる。
形式は*変数名
def hoge(*args)
args
end
puts hoge(1, 2, 3)
#=> 1
# 2
# 3
##ブロック付きメソッド
このへんについては詳しい記事がありました。
[Ruby] ブロックとProcをちゃんと理解する
###yield
ブロック付きメソッドというメソッドからブロックを呼び出すときに使用する。
#メソッドの定義
def testFunc
yield(1,3)
end
#呼び出されるブロック
testFunc do |a,b|
puts a + b
end
# => 4
###Proc
ブロックをオブジェクト化したもの。
メソッドで受け渡しすることができるようになる。
#proc定義
test = Proc.new{ puts "a" }
#実行
test.call
# => a
##メソッドの定義とか
###alias
メソッドに別名をつけることができる。
別名が付けられたメソッドは、その時点でのメソッドの定義を引き継ぐ。元のメソッドの定義が変更されても、再定義前の定義と同じ動作をする。利用シーンとしてはあるメソッドの動作を変更するとき、変更前のメソッドの動作を仕様したいときが挙げられる。
書き方は
alias 別名 元の名前
またはシンボルを利用して書けば
alias :別名 :元の名前
と書ける。
#メソッドの定義
def test
"test"
end
# エイリアス(別名)を設定
# 元の定義を別の場所に保持する。
alias :_orig_test :test
#testの再定義
def test
#元のメソッドの定義を仕様
"#{_orig_test} dayo"
end
puts test
# => "test dayo"
###undef
メソッドの定義を取り消すキーワード。
具体的にはメソッド名とメソッドの定義との関係を切離す。
undef メソッド名
で使える。
#クラス
##初期化メソッド:initialize
new
メソッドによりインスタンスが生成された時に実行するメソッド。
class Test
#初期化
def initialize(initvalue = "初期値")
#インスタンス変数を初期化
@init = initvalue
end
def whtinit
puts @init
end
end
a = Test.new
a.whtinit # => 初期値
b = Test.new("test")
b.whtinit # => test
##アクセスメソッド
Rubyではインスタンスの外部からインスタンス変数を直接参照・代入することができないので、メソッドを介して参照・代入する。
class TestClass
#@fooを呼び出すためのメソッド
def foo
@foo
end
#@fooに代入するためのメソッド
def foo=(value)
@foo = value
end
end
記述を簡略化する方法がある。
上記のように参照・代入の両方を許容する場合以下のようにも書ける。
class TestClass
#@fooをfooで参照・代入
attr_accessor :foo
end
参照のみ許可したい場合はattr_reader
、
代入のみ許可したい場合はattr_writer
に変更する。
##変数self
インスタンスメソッドで、メソッドのレシーバ自身を参照する変数。
##クラスの定数
クラス内に定数を定義することもできる。
外部から参照するには、クラス名::定数名
で呼び出す。
class TestClass
Const = "testtest"
end
puts TestClass::Const
##クラスメソッド
クラスオブジェクトをレシーバとするメソッドである。
形式は特異クラス形式という class << クラス名 ~ end
または特異メソッド形式という def クラス名.メソッド名 ~ end
###特異クラス
先ほど挙げたclass << クラス名 ~ end
は特異クラスという。
特異クラスを利用してインスタンスメソッドを記述することが可能。
以下の解説ページが詳しい。
Ruby 初級者のための class << self の話 (または特異クラスとメタクラス)
##継承
既存のクラスの性質を引き継いだクラスを新しく作るのが継承。
他のオブジェクト指向言語と考え方は似ている。
ただしRubyにおいて継承できるクラスは1つまでである。
#クラスSuperClassを継承してNewClassクラスを定義
class NewClass < SuperClass
#クラス定義の内容
#...
end
#条件文
##unless
「〜でなければ」という条件文。
if(!条件)
と同じ。
unless a > b
puts "!(a > b)"
end
#モジュール
##モジュールとは
Ruby特有の機能の1つで、クラスとよく似た概念である。
クラスと比較して以下のような性質がある。
- インスタンスを生成出来ない。
-
モジュールクラスを継承できない。
モジュールは単純継承のモデルを保ったまま、複数のクラスの機能を共有するための機能。
モジュールの作り方は下記のようになる。
モジュール名は大文字で始める。
module TestModule
#モジュールの定義
#...
end
モジュールに関する詳しい説明がこちら
Rubyのオブジェクト指向におけるクラスとモジュール、継承、Mixin、アクセス制御の使い方 (4/5)
どうしてモジュールという概念を作ったかという背景が書いてある記事が以下。
まつもと直伝 プログラミングのオキテ 第3回(3)多重継承の光と影
モジュールには下記の大きく分けて2種類の役割がある。
###名前空間を提供
名前空間とは、定数・メソッド・クラスなどを管理する単位である。
モジュールの提供する名前空間でオブジェクトの名前の定義をわけることで、衝突を防ぐことができる。
###Mix-inで機能を提供
モジュールをクラスやモジュールに取り入れることをMix-inという。
定義にinclude
を使ってモジュールを取り込めばメソッドや定数を他のクラスやモジュールでも使用することができる。
##モジュールのメソッドの使用
メソッドを定義するのみでは使用できず、メソッドをモジュール関数として外部に公開する必要がある。シンボルを使って以下のように記述する。
module TestModule
def test
puts self
end
module_function :test
end
TestModule.test #=> TestModule
##モジュールによる特異メソッドの実装
モジュールを特異クラスにインクルードすることでオブジェクトにモジュールの機能を追加できる。
具体的にはオブジェクトからextend
メソッドを用いる。
module TestModule
def hello(n)
n.times do
print "hello"
end
end
end
str = "test"
str.extend(TestModule) #=>オブジェクトにMix-in
str.hello(5)
#=> hellohellohellohellohello
#繰り返し
##times
一定回数繰り返しの構文。
カウンタ変数の値を使わない場合はこれでおk。
5.times do
print "a"
end
# => aaaaa
##for
よくあるfor文と同じ。
配列の要素に対して、繰り返しを行なうこともできる。
#一般的なfor文
for i in 1..3
print i
end
# => 123
#配列に対して使用
for str in ["R", "u", "b", "y"]
print str
end
# => Ruby
##while
条件を満たしていれば繰り返す。
i = 0
while i < 5
print "a"
i += 1
end
# => aaaaa
##until
unless
の繰り返し版みたいな感じ。while
の逆版。
条件を満たさなければ繰り返す。
i = 5
until i == 0
print "a"
i += 1
end
# => aaaaa
##each
コレクションのようなオブジェクトの集合体に対して繰り返し処理が可能。
C#におけるforeachのような処理ができる。
lang = ["Ruby", "Python", "Perl"]
lang.each do |name|
print name + " "
end
# => Ruby Python Perl
##loop
いわゆる無限ループ。
loop do
print "a"
end
# => aaaaaa...
##繰り返し制御
###break
break
実行時、繰り返しのブロックを抜ける。
多重ループでは内側のループを一つ抜ける。
(他の言語だとすべて抜けたりする。)
###next
他の言語のcontinue
に相当。
next
実行時、次の回のループの始めに飛ぶ。
つまり次のアイテムに対してループを始める。
###redo
redo
実行時、その回のループの始めに飛ぶ。
つまり同じアイテムに対して、もう一度ループを始める。
#演算子
##真偽値の扱いについて
論理演算子について説明する前に、Rubyにおける真偽値の扱いをおさえておく。Rubyにおいて偽と扱われるのはfalse
またはnil
のみであり、それ以外はすべて真として扱われる。特に他の言語では偽と評価されうる0
、""
、[]
のいずれもRubyでは真と評価されることには注意が必要である。
##論理演算子によるエラー回避
配列の要素が存在しない状態でその要素を参照しようとするとエラーが起こる。
それを避けるために条件分岐を使用して参照を行なう。
element = nil
if ary
element = ary[0]
end
これを論理演算子で表現すると短く書ける。
論理式の評価がtrue
かfalse
が確定した時点で処理が終了することを活かしている。
element = ary && ary[0]
これはary
がfalse
またはnil
でないときのみ、右辺の値がary[0]
と更新されることを利用した例である。
以下のようにif
の後置により省略することも可能
element = nil
element = ary[0] if ary
さらに、三項演算子を用いても同様の働きをする処理が書ける。
element = ary ? ary[0] : nil
##デフォルト値の代入
||
の代入演算子を用いることで、ある変数の値がfalse
またはnil
のときのみ値を代入することができる。
var ||= 100
#以下に相当(詳細は下記URL参照)
var || var = 100
書き換えた代入文については以下の記事が詳しいです。
『a ||= b』は『a = a || b』ではなく『a || a = b』とほぼ同じ意味、と覚えましょう - わからん
##範囲演算子
Rubyには値の範囲を示すRange
オブジェクトが存在する。
他のオブジェクトの生成法と同じようにRange.new(from, to)
と書けるが、from..to
と省略して書くことも可能である。
これを実現するメソッドとしてsucc
メソッドというものがある。これは変数の数字あるいは文字の次の値を返す。
str = "c" #=>"c"
str = str.succ #=> "d"
var = 50 #=> 50
var = var.succ #=> 51
##演算子の定義
Rubyの演算子はインスタンスメソッドとして実装されているため、ユーザによる定義が可能である。
###二項演算子
+
、-
、*
をはじめとしたその他二項演算子をユーザは定義可能
###単項演算子
+
、-
、~
、!
の4つが定義可能である。
+@
、-@
、~@
、!@
というインスタンスメソッドとして定義することで使用することができる。
以下は+
の二項演算子と-
の単項演算子を、二次元座標を保持するPointクラスに定義した例である。
class Point
attr_accessor :x, :y
def initialize(x, y)
@x, @y = x, y
end
def show
"(#{x}, #{y})"
end
#x,yそれぞれの和を計算する二項演算子を定義
def +(other)
self.class.new(x + other.x, y + other.y)
end
#x,yの値に-1を乗じたものを返す単項演算子を定義
def -@
self.class.new(-x, -y)
end
end
p0 = Point.new(3.0, 4.0)
p1 = Point.new(1.0, 2.0)
puts (p0 + p1).show #=> (4.0, 6.0)
puts (-p0).show #=> (-3.0, -4.0)
#お決まり的なこと
##文末に;
が不要
ここまでしれっと書いてきましたが、割とびっくりしたところ。
##ライブラリのロード
ライブラリや、別に作った他の***.rb
を読み込んで使用するためにはCでおなじみのinclude
のようなことを記述する必要がある。Rubyではrequire
キーワードを使用する。
require "./hoge"
##変数への多重代入
Rubyでは1式で複数の変数に代入が可能。
#多重代入
hoge, foo, bar = 3, 4, 5
#これと同じ
hoge = 3
foo = 4
bar = 5
##ブールを返すメソッドの名前
true
やfalse
を返すメソッド名の末尾には?
をつけるしきたりがある。
わかりやすくするためで、無くても実行は可能。
定義するときこれに従うと親切。
例:String
型のString#empty?
メソッド
##単項インクリメント、デクリメントはない
Rubyの言語の仕様の都合で定義できていないらしいです。
よくわかっていないですが以下にまつもとゆきひろ氏本人のコメントがあります。
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/5323
##ブロックの書き方
###do-endでくくる
doは省略されることもある。
doが省略出来るのはブロックでない制御構造while
、until
、for
のdo
である。ブロックのdo~end
におけるdo
は省略出来ない。
(1..5).each do |i|
print i
end
# => 12345
###{}
でくくる
おそらく多くの言語で使われる形。
1行で記すときに構造が認識しやすい。
(1..5).each {|i| print i}
##並べ替えにおけるsortとsort_byの違い
ブロックの評価方法によって速度が違う。
以下のとおり。
instance method Enumerable#sort_by
sort + ブロックではなくsort_by + ブロックを使おう
##もっと色々な書き方とか
覚えておくとよさそうな書き方をまとめた記事。
読んでいて楽しい。
Railsを触る際知っていると便利なRubyの基礎 [ブロックとかシンボルとか]
#最後に
##良いコードを読むのが一番
Trending Ruby repositories on GitHub today
ここにはその日に更新された中で最もスターがついた(多くの人がイイねした)Rubyのリポジトリが表示される。
今回いくつか構文や記法を紹介したが、実用的でないものがあるかもしれない。
やはりまず覚えるべきは良く使われる表現だと思うので、コードを読んでわからないところは調べるというアプローチが一番上達する気がする。
#参考
オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.0.0/doc/index.html