文法
ローカル変数
変数はクラス内部の変数でもメソッドとは違うスコープになる
v1 = 1 #Objectクラスの変数 $v2 = 2 class Qux1 p v1 #エラー p $v2 #2 v2 = 2 #Qux1クラスの変数 def method1; v1; end #エラー:Objectの変数への接近が出来ない def method2; v2; end #1エラー:Qux1の変数への接近は出来ない end
- グローバル変数はどこからでも呼べる
インスタンス変数
インスタンス内部での変数、継承されず、自分のインスタンス内部でのみ存在する
@v1 = 1 class Qux1 @v2 = 2 def method1; @v1; end def method2; @v2; end end Qux1.new.method1 # nil Qux1.new.method2 # nil
アクセッサ
attr_reader : getterメソッドを生成する
attr_writer : setterメソッドを生成する
attr_accessor : getterとsetterメソッドを生成する
attr : getterメソッドを生成する v1.9以降非推奨
def v3 #getterメソッド return @v3 end def v3=(value) #setterメソッド @v3 = value end
アクセッサ
class Qux1 attr_accessor :v3 end
クラス変数
インスタンス変数とは違い継承されサブクラスでも参照出来る
クラス変数はクラス定義時にコードが実行されるため、初期化メソッドの中に初期化しなくても初期化される
class Qux @@v2 = 1 def v2; @@v2; end def v2=(value); @@v2 = value; end end class QuxExt < Qux end Qux.new.v2 #1 QuxExt.new.v2 #1 QuxExt.new.v2 = 2 #2 このタイミングで全ての値が変わる Qux.new.v2 #2 QuxExt.new.v2 #2
定数
大文字で始まる変数、2回目の設定は警告を発するが、値は更新される
※メソッドは複数回実行が前提であるため、定数の定義は出来ない
ネストした定数
class M A = 1 class B A = 2 end def method1 p A # 1 p B::A # 2 p self::A #エラー p M::B::A #2 end end M.new.method1 1 2 2
- MのAとMのBのAは違い定数
- B::A =2 とも同じ
constants
M.constants #["B", "A"] M::B.constants #["A"]
定数の参照
定数はモジュールや継承チェーンを辿り、定数を探して値を返す
module M A = 1 class B ; A = 2; end end class C include M p A p B::A end
- モジュールのAを探して表示
const_missingメソッド
module M def self.const_missing(id) 1 end end
- 定数が見つからない場合、1を返す
「+=」演算子
a = a + 2 # a + 2 a += 2 # a + 2
「**」演算子
a**= 2 # a^2
オブジェクトのクラス名
全てのオブジェクトはクラスである
数字でもクラスであり、全てクラスのインスタンスになる
1.class -> Fixnum 1.class.superclass -> Integer 1.class.superclass.superclass -> Numeric
全ての演算子はそのクラスに定義されたメソッドになる
加算の場合は1クラスの+メソッドを実行しているに過ぎない
1.+(2) # 3 1 + 2 # 3
- 「1」クラスの「+」メソッドは引数の値と合算した結果を返す
演算子は再定義可能であるが、例外として出来ないものもある
::,=,?:,..,...,&&,and,||,!,not
「&&」 演算子
- 左の式の結果がTrueの場合のみ右の結果を確認する
- 左と右が両方Trueの場合、右の値を返す
- 左がTrueで右がFalseの場合、右の値を返す
- 左がFalseの場合、右はチェックしないため、左の値を返す
メソッド定義
- defで定義する。
- 引数には「()」を付けても付けなくても結構
- 最後の式がreturn扱いになる
- 明確にreturnを記述しても同じ
デフォルト値の指定
def foo(a, b=100) end
- 引数bは未設定の場合、100になる
Boolの値は基本Falseとnil以外はTrueとみなされる
1 #true 2 #true False #false nil #false a #true
条件分岐
if i = 1 then elsif i=2 end
- 1行目のthenは省略可能
擬似変数
変数の様に使用するが、変数として新しい値が生成されるわけではなく唯一インスタンスを設定する
true trueclassのインスタンス false falseclassのインスタンス nil nilclassのインスタンス self 現在のオブジェクト __FILE__ 現在実行中のファイル名 __LINE__ 現在実行しているプログラムの行数 __ENCODING__ 現在のソースのエンコーディング(Ruby1.9)
展開式
「""」の内部には#{}で展開式が記述出来る
「''」の内部は全て文字列として表現される。展開式不可
a = "abc" p "#{a}" #"abc" p '#{a}' #"#{a}"
値変換メソッド
変換不可文字は無視される
"12.aa".to_i # 12 "23.2.1".to_f # 23.2 "a33".to_i # 0
- to_s 文字列へ変換
- to_i Integerへ変換
- to_f Floatへ変換
エスケープ文字「\」
\x xを文字として表示 \n 改行 \r キャリッジリターン \f 改ページ \a ベル \e エスケープ \s 空白 \nnn 8進数表記 "\101" => 8進数 結果"A" \xnn 16進数表記 "\x41" => 16進数 結果"A" \C-x \M^x \M-\C-x
「p」「puts」「print」の違い
実際の印刷状態を観るためにはpでは無くputsやprintを使うこと
pはデバッグ用として関連情報を表示する
p "a\nb" # "a\nb" print "a\nb" # "a" 改行後 "b" puts "a\nb" # "a" 改行後 "b" 改行
ヒアドキュメント
複数行を自然体で入力する場合使用する
前後に同じ文字列を指定する下記は「ABC」
前後に同じ文字列
a = <<ABC this is a book ABC
-文字列
前に「-」をつけると、閉じる部分の前に空白を設定できる
a=<<-ABC this is a book ABC
「''」で囲む
リテラルの''で包まれているのと同じ効果
a = <<'ABC' this is a book ABC
- 3種類の表現方法が存在する
- 全て結果は" this is\n a book\n"となる
「%」パーセント記法
a = %*test* # "test" a = %*test"* # "\"test\""
「*」の代わりに(),[],{}が指定出来る
a= 1 a = %q!#{ a+1}! # "#{a+1} a = %Q!#{a + 1}! # "2"
「%」記法
%s シンボル %W 要素がダブルクォート文字列となる配列、要素の区切りは空白文字 %w 様相がシングルクォート文字列となる配列、要素の区切りは空白文字 %x コマンド出力 %r 正規表現 + 文字列を連結する *n 文字列をn回繰り返す <, >, ==, <=> 文字列を文字コードとして数字比較結果を返す length 文字列の長さ size バイト長さ
sprintf フォーマット指定
sprintf("result %#b", 16) # "result 0b10000" sprintf("result %#o", 16) # "result 020" sprintf("result %#x", 16) # "result 0x10" sprintf("result %#X", 16) # "result 0X10" sprintf("result %02d", 1) # "result 01" sprintf("result %03d", 1) # "result 001" sprintf("result %05.2f", 1.111) # "result 01.11"
シンボルリテラル
文字列の先頭に「:」を付加する
a = :"foo1" => :foo1
- クォートは省略可能
a = %s!foo1! => :foo1
結果はシンボルクラスのインスタンスとなる
String.to_sym シンボルへ変換
※String文字列は常に新しいオブジェクトを生成する
インスタンスはobject_idで区分が出来る
但し、シンボルは新しいオブジェクトを生成しない
シンボルはメモリ節約やスピード向上に役たつがgcの対象外で有るため、使うときは慎重に擦る必要がある
破壊的メソッド
「!」が付いているメソッドの中では引数の元値も変えるものがある
例chopとchop!
v1 = "foo1" v1.chop => "foo" v1 => "foo1" v1.chop! => "foo" v1 => "foo"
配列
v1 = $w(hoge foo bar) => v1 = ["hoge", "foo", "bar"] v1.join() => "hogefoobar" v1.join("_") => "hoge_foo_bar" a = Array.new(5) => [nil, nil, nil, nil, nil] a.length => 5 Array.new(2){|index| index + 10} => [10, 11]
初期値指定
a = Array.new(2, "a") => ["a", "a"]
※a[0]とa[1]は同じオブジェクト
なので、a[0].replace("b") => ["b", "b"]になってしまう
同じオブジェクトにならないようにするため
a = Array.new(2){"a"} => ["a", "a"] a[0]とa[1]は別のオブジェクトとなる a[0].replace("b") => ["b", "a"]
サイズを超える配列を求めるとnilを返す
v1 = {"a", "b"] v1.length => 2 v1[2] => nil v1[4] = "c" => ["a", "b", nil, nil, "c"] v1.length = 5
式による代入
a = [0, 1, 2,, 3] a[1,2] = "a", "b" <- []は省略可能 #a配列の1番目から2個までを指定し置換している a => [0, "a", "b", 3] a[1,2] = "c" #a配列の1番目から2個目までを"c"にする a => [0, "c", 3] a[1,1] = 4,5,6 #a配列の1番目の値に4,5,6挿入する a => [0, 4,5,6,3] #間に挿入される
多重代入
a, b, c = 1,2 #=> a =1, b = 2, c =nil a, b = 1,2,3 #=> a = 1, b= 2 3番目は無視される a, *b = 1,2,3,4,5 # 「*」が付いてる変数は残りを全て配列で取得する #=> a = 1, b = [2,3,4,5]
配列の演算
a = [1,1,2,2] b = [2,2,3,4] a & b # [2] a | b # [1,2,3]
- 「&」 両方に存在するものを返す
- 「|」 共通に存在するものを返す
a + b # [1,1,2,2,2,2,3,4] a - b # [1,1]
演算子
[1,2] * 3 # [12,12,12] [1,2,3] * "-" # "1-2-3" [1,2,3].join("-") # "1-2-3"
for文
for <識別子> in <式> do end list = [1,2,3] for item in list do p item end
forは内部スコープが適用されない
for i in [1,2,3] aa = 1 end aa # 1
eachメソッド
[2,3,4].each do bar = 1 end p bar #=> 例外が発生
- eachメソッドはスコープを発生させる
Hash
両側を「”」で囲む
a = { "foo1" = 1, "foo2" = 2, "foo3" =3} a["foo2"] #=> 2
キーは文字列を使う場合、シンボルを使う方が高速で効率
a = Hash.[:foo1. 1. :foo2, 2, :foo3, 3]
最後の引数をHashで設定する
def foo(a,b,c) p c end foo(1,2, {:foo1=>1, :foo2=>2}) foo(1,2, :foo1=>1, :foo2=>2)
- 最後の引数の場合のみ可能
- {}は省力が可能
範囲
1 .. 10 #=> 1から10まで 1 ... 10 #=> 1から9まで
include? と === で含まれているかを確認出来る
(1..5).include?(3) #=> true (1..5) == 3 #=> false (1..5) === 3 #=> true for i in "a".."z" end a="abcdef" a[1] #=> 98 a[1..1] #=> "b" a[1..2] #=> "bc" a[1...2] #=> "b"
case式
case <式> when <条件式1> [then] when <条件式2> [then] else end case 7 when 1...5 then; p 1 #= (1...5) === 7 を評価 when 5..10 then; p 2 #= (5..10) === 7 を評価 end
while式
条件がTrueの間繰り返される
while <条件式> do end
無条件で1回は実行された後Trueの場合、繰り返される
begin i += 1 end while(1..4) === i
begin..endを省略可能
i += 1 while(0..4) === i
until式
条件がTrueになるまで繰り返される
until <条件式> do end
「=~」マッチしている場所を返す
/Ruby/ =~ "I love Ruby" #=> 7
マッチした文字列は「$&」で取得
戦後の文字列は「$`,$'」を使用する
/bb/ =~ "aabbcc" $` #=> "aa" $& #=> "bb" $' #=> "cc"
^<式> 式で始まる
<式>$ 式で終わる
reg = /^(aa|bb)c$/ reg === "aac" #=> true reg === "bbc" #=> true reg === "abc" #=> false
[<式>] 式の何れが来る
reg = /a[bcd]e[fg]h/ reg === "abegh" #=> true reg === "aefh" #=> false
正規表現記号
. 改行をのぞく任意の1文字。ただし、後述するmオプションが指定された場合は改行もマッチ \d 数字 \D 数字以外の文字 \w 英数字とアンダースコア \W 英数字とアンダースコア以外の文字 \s 空白文字(\t, \n, \r, \f) \S 空白以外の文字 \A 先頭の文字。改行の有無に影響されない \z 末尾の文字。改行の有無に影響されない \Z 末尾の文字。改行で終わっていればその改行の直前にマッチ
例
/a\db/ === "a2b" #=> true
繰り返し文字の判定
* 直前の文字の0回以上の繰り返し + 直前の文字の1回以上の繰り返し {m} 直前の文字のm回繰り返し {m,} 直前の文字の最低m回繰り返し {m,n} 直前の文字の最低m回、最高n回の繰り返し /a*b/ === "aab" /a+b/ === "aaab" /a{2}b/ === "aab" /a{2,}b/ === "aaaab" /a{2,3}b/ == "aaab"
()によりグループ化が可能
/a(bc)*d/ === "abcbcd"
$n 正規表現でマッチした値とグループ値を返す
%r|(http://www(\.)(.*)/| =~ "http://www.xyz.org/" p $1 #=> "http://www.xyz.org/" p $2 #=> "." wwwの次の任意文字(\.) p $3 #=> "xyz.org" (.*) 任意文字の繰り返し p $4 #=> nil 対応なし
- $0はスクリプト名を返す
正規表現のオプション
i 大文字と小文字を区別しない o 一度だけ式展開を行う x パターン中の空白と改行を無視する、また#以降をコメントとして無視する m 正規表現記号「.」が改行にもマッチする(複数行モード) /ruby/ === "RUBY" #=> false /ruby/i === "RUBY" #=> true /a.*b/ === "a\nb" #=> false /a.*b/m === "a\nb" #=> true
コマンド出力
「`」で囲まれた文字列はコマンド命令と認識される
puts `date`
終了ステータス参照は「$?」を利用する
1.8.7-p376 :062 > puts `date` Tue Aug 5 22:06:10 JST 2014 => nil 1.8.7-p376 :063 > $? => #<Process::Status: pid=22231,exited(0)>
コマンド出力は""の内部と同様に式展開、バックスラッシュ記法。パーセント記法が適用される
a = "date" puts `#{a}` puts %x|date|
ブロック
do - end や{} の中はブロックとなり、スコープが発生する
関数の内部のyieldはブロックが代入される
def func y y + yield end x = 2 func(1) { x+= 2} #= 5 p x #= 4
yieldに引数が有る場合は|で囲んだ内部にコンマ区切りで設定する
def func(a ,b) a + yield(2, b) end p func(1,2) { |x, y| x+y} #= 5
- yieldの引数2,bが |x, y|に代入されている
block_given?
ブロックが指定されたかを関数内部で判断する
def func return 1 if block_given? 2 end func() #= 2 func(){} #= 1
Proc
ブロックをオブジェクト化する
callメソッドで実行する
p = Proc.new{|x| p x} p.call(1) #= 1
Procをブロックとして渡す
def func x x + yield end p = Proc.new {2} func(1, %p) #= 3
- 引数に渡す場合は「&」を付けて渡す
def func x, &proc x + proc.call end func(1) do 2 end
lambda
lmd = lambda{|x| p x} lmd.call(1) #= 1
procとlambdaの違い
procは処理後、呼び元に戻らず処理を終了する
lambdaは処理後、呼び元に戻り、次に処理を行う
procの例
def func proc = Proc.new {return1 } proc.call p 2 #<= ここは処理されずに終わる end
lambdaの例
def func lmb = lambda{ return 1} lmb.call p 2 #<= ここも実行される end
procでは引数が足りない場合nilを返すが、lambdaではエラーとなる
p1 = Proc.new {|x,y| y} p1.call(1) #= nil l1 = lambda{ |x,y| y} l1.call(1) #<= エラーとなる
each
値の繰り返し
[1,2,3].each do |value| p value end
each_with_index
インデックスが必要な場合
[1,2,3].each_with_index do |value, index| p value + index end
Hashのeach
{:a => 1, :b => 2}.each do |key, value| p "#{key}:#{value}" end
Hashのキーのみの繰り返し
{:a => 1, :b => 2}.each_key do |key| p key end
範囲のeach
("a".."z").each do |value| p value end
upto
順に値を増やしていく
2.upto(4) do |i| p i end
- 2から4まで+1していく