Created
June 2, 2019 10:01
-
-
Save kenta-polyglot/bc0657525f37cd50c9f9399a4f86b04a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
・ 変数は「名札」である。(「参照」みたいなもの) | |
num = 10 | |
print(num) | |
num = 12 | |
print(num) | |
別のオブジェクトを代入するということは、変数を別のオブジェクトの名札に変更したということになります。 | |
上記の場合は最初の「print」メソッドでは「10」が出力されますが、 | |
次の「print」メソッドでは変数に別のオブジェクトを代入していますので「12」が出力されます。 | |
val = 10 | |
print(val) | |
val = "こんにちは" | |
print(val) | |
またオブジェクトは元になっているクラスが決まっていますが、 | |
変数はオブジェクトに付けられた名札でしかないため変数自体には型のようなものは存在しません。 | |
その為、一度代入が行われた変数に対して、まったく違うクラスから作成されたオブジェクトを代入することも可能です。 | |
pref1 = "東京" | |
pref2 = pref1 | |
変数はあくまでオブジェクトに対する名札ですので、 | |
変数「pref2」を新たに「東京」と言う文字列オブジェクトの名札にした場合でも | |
「東京」と言う文字列オブジェクトは1つのままです。 | |
つまり1つのオブジェクトに2つの名札が付いている状態です。 | |
str1 = "Tokyo" | |
str2 = str1 | |
str1 << ",Japan" # <<演算子は別の文字列オブジェクトを作成しないことに注意 | |
print(str1) | |
print(str2) | |
上記の場合、どちらの「print」メソッドも「Tokyo,Japan」を出力します。 | |
str1 = "Tokyo" | |
str2 = str1 | |
str1 = "Osaka" | |
print(str1) | |
print(str2) | |
この場合、str1は"Osaka"という文字列オブジェクトを指すようになるので、 | |
print(str1) # Osaka | |
print(str2) # Tokyo | |
となる。 | |
・ 複数の変数に代入 | |
変数1, 変数2, 変数3, ... = 式1, 式2, 式3, ... | |
変数1, 変数2, 変数3, ... = [要素1, 要素2, 要素3, ...] | |
代入演算子「=」の左辺に代入される変数をカンマで区切って並べて記述します。 | |
そして右辺には左辺に記述した変数に代入するオブジェクトや式などをカンマで区切って並べて記述します。 | |
この場合、右辺に記述された式を評価した値が左辺に記述された変数に順に代入されていきます。 | |
変数1には式1が、変数2には式2が、といった感じです。 | |
city1, city2, city3 = "東京", "大阪" | |
なお左辺に記述した変数の数より右辺に記述したオブジェクトの数が少ない場合、 | |
代入されるオブジェクトが無い変数には「nil」が代入されます。 | |
・ 定数 | |
変数名の一文字目が英大文字だと定数になる。 | |
・ 条件分岐 | |
if 条件式 then | |
条件式が真の時に実行する処理1 | |
条件式が真の時に実行する処理2 | |
end | |
→ 条件式の後に改行がある場合はthenは省略可能。 | |
基本的にその場合はthenは省略することがルールになっている。 | |
if 条件式 then | |
条件式が真の時に実行する処理1 | |
条件式が真の時に実行する処理2 | |
else | |
条件式が偽の時に実行する処理1 | |
条件式が偽の時に実行する処理2 | |
end | |
if 条件式1 then | |
条件式1が真の時に実行する処理 | |
elsif 条件式2 then | |
条件式1が偽で条件式2が真の時に実行する処理 | |
elsif 条件式3 then | |
条件式1及び条件式2が偽で条件式3が真の時に実行する処理 | |
else | |
全ての条件式が偽の時に実行する処理 | |
end | |
unless 条件式 then | |
条件式が偽の時に実行する処理 | |
end | |
case 対象オブジェクト | |
when 値1 then | |
値1と一致する場合に行う処理 | |
when 値2 then | |
値2と一致する場合に行う処理 | |
when 値3 then | |
値3と一致する場合に行う処理 | |
else | |
どの値にも一致しない場合に行う処理 | |
end | |
※ case文では「then」は省略可能です | |
真の時に実行する式 if 条件式 | |
「式修飾子」という。 | |
「if」修飾子は実行する処理を先に記述しているだけです。 | |
ただ、先に記述することで何を実行しようとしているのかが分かり易くなる場合があります。 | |
また簡潔に記述することもできます。 | |
例) | |
print("num = ", num) if debug | |
偽の時に実行する式 unless 条件式 | |
・ 繰り返し | |
while 条件式 do | |
実行する処理1 | |
実行する処理2 | |
end | |
※「do」は省略可能です。 | |
until 条件式 do | |
実行する処理1 | |
実行する処理2 | |
end | |
※「do」は省略可能です。 | |
until文は指定した条件式が偽(false)の間、繰り返し処理を行います。 | |
→ 実際には「○○という条件に達するまで」という用途で使わないとわかりにくいと思われる。 | |
for 変数 in オブジェクト do | |
実行する処理1 | |
実行する処理2 | |
end | |
※「do」は省略可能です。 | |
「for」文では繰り返しが1回行われるたびにオブジェクトに対して「each」メソッドが実行し取得した要素などを変数に代入します。 | |
よって「for」文で指定できるオブジェクトは「each」メソッドを持ったオブジェクトでなければなりません。 | |
例えば配列やハッシュ、範囲オブジェクトなどが該当します。 | |
例) | |
for num in 1..3 do | |
print("num = ", num, "¥n") | |
end | |
オブジェクト.each{|変数| | |
実行する処理1 | |
実行する処理2 | |
} | |
オブジェクト.each do |変数| | |
実行する処理1 | |
実行する処理2 | |
end | |
オブジェクトに含まれる要素を「succ」メソッドで順に取得して変数に格納し、 | |
「{」から「}」までの処理(又は「do」から「end」までの処理)を実行します。 | |
例) | |
range = 5..10 | |
range.each{|num| | |
print("num = ", num) | |
} | |
上記の場合では、範囲オブジェクトに対して「each」メソッドが実行されています。 | |
範囲オブジェクトから順に「5」「6」「7」「8」「9」「10」が取り出されて | |
変数「num」に格納された後で「{」から「}までの処理が実行されます。 | |
下記のような記述も可能 | |
(5..10).each{|num| | |
print("num = ", num) | |
} | |
※ ここで解説した「each」メソッドやこの後で解説する「times」メソッドなどのように | |
繰り返しを行うブロック{}付きのメソッドをイテレータと呼んでいます。 | |
オブジェクト.times{|変数| | |
実行する処理1 | |
実行する処理2 | |
} | |
「times」メソッドは、変数に「0」から「対象のオブジェクトが持つ数値 - 1」を順に代入しながら | |
「{」から「}」までの処理(又は「do」から「end」までの処理)を実行します。1回繰り返す毎に1ずつ数値は増加します。 | |
例) | |
10.times{ | |
print("Hello¥n") | |
} | |
オブジェクト.upto(max){|変数| | |
実行する処理1 | |
実行する処理2 | |
} | |
「upto」メソッドは、変数に「対象のオブジェクトが持つ数値」から「max」を順に代入しながら | |
「{」から「}」までの処理(又は「do」から「end」までの処理)を実行します。1回繰り返す毎に1ずつ数値は増加します。 | |
(「|変数|」の部分は省略可能です)。 | |
例) | |
3.upto(7){|num| | |
print("num = ", num, "¥n") | |
} | |
オブジェクト.downto(min){|変数| | |
実行する処理1 | |
実行する処理2 | |
} | |
「downto」メソッドは、変数に「対象のオブジェクトが持つ数値」から「min」を順に代入しながら | |
「{」から「}」までの処理(又は「do」から「end」までの処理)を実行します。1回繰り返す毎に1ずつ数値は減少します。 | |
(「|変数|」の部分は省略可能です)。 | |
例) | |
7.downto(3){|num| | |
print("num = ", num, "¥n") | |
} | |
オブジェクト.step(limit, step){|変数| | |
実行する処理1 | |
実行する処理2 | |
} | |
「step」メソッドは、変数に「オブジェクトの値」から「limit」を超える前まで順に代入しながら | |
「{」から「}」までの処理(又は「do」から「end」までの処理)を実行します。 | |
1回繰り返す毎に「step」に指定した数値だけ増加します。(「|変数|」の部分は省略可能です)。 | |
例) | |
2.4.step(5.3, 0.8){|num| | |
print("num = ", num, "¥n") | |
} | |
上記の場合、「2.4」「3.2」「4.0」「4.8」の値を変数「num」に格納しながら「{」から「}」までの処理を実行します。 | |
「limit」を超える前まで実行されることに注意して下さい。 | |
loop{ | |
実行する処理1 | |
実行する処理2 | |
} | |
「loop」メソッドはKernelクラスで用意されているメソッドです。無限ループを行います。 | |
例) | |
num = 1 | |
loop{ | |
print("num = ", num, "¥n") | |
num += 1 | |
if num > 10 then | |
break | |
end | |
} | |
break | |
「break」を使用することで、繰り返し処理の本来の終了条件とは別に繰り返しを終了させることが可能です。 | |
なお繰り返しが入れ子になっている場合は「break」が実行された一番内側の繰り返しを抜けます。 | |
next | |
繰り返し処理の中で「next」が実行されるとブロック内の「next」以降の処理が行われずに次の繰り返しへ進みます。 | |
(continueである) | |
なお繰り返しが入れ子になっている場合は「next」が実行された一番内側の繰り返しに関して次の繰り返しへ進みます。 | |
例) | |
count = 0 | |
("aa".."az").each{|str| | |
count += 1 | |
if count % 3 != 0 then | |
next | |
end | |
print(str + "¥n"); | |
} | |
redo | |
例えば下記の式で「each」メソッドのよって「ac」が取り出されて繰り返しが行われた場合、 | |
変数「count」の値は「3」となっているため「redo」によって繰り返しが改めて行われます。 | |
繰り返しが改めて行われるというのは取り出される要素が同じで改めて繰り返しが最初から実行されるということです。 | |
この場合「each」メソッドによって先ほどと同じ「ac」が取り出されて改めて繰り返しが行われますが、 | |
変数「count」の値は元に戻っていませんので今度は「4」となります。よって繰り返しは最後まで実行されます。 | |
→ 重要な点として「aa」に処理が戻るということではない、「ac」に対する処理がもう一回行われるということである。 | |
うまくやらないと無限ループになるので結構怖いが。 | |
例) | |
count = 0 | |
print("[start]¥n") | |
("aa".."ae").each{|str| | |
count += 1 | |
if count % 3 == 0 then | |
redo | |
end | |
print(count, ":" + str + "¥n"); | |
} | |
出力 | |
[start] | |
1:aa | |
2:ab | |
4:ac | |
5:ad | |
7:ae | |
真の時に実行する式 while 条件式 | |
偽の時に実行する式 until 条件式 | |
例) | |
num = 2 | |
num *= 2 while num < 1000 | |
・ 範囲オブジェクト | |
range1 = 5..10 | |
range2 = "d".."g" | |
first...last | |
..演算子と異なり、...演算子の場合、最後の要素は含まれない。 | |
range1 = Range.new(5, 10) # ..演算子と同様 | |
range2 = Range.new(5, 10, true) # ...演算子と同様(最後の要素は含まれない) | |
・ 配列 | |
array = [2005, 2006, 2007, 2008] | |
array = ["山田", "太郎", 1992, 12, 31, "男性"] | |
array = [2005, 2006, 2007, 2008] | |
print(array[0]) | |
year = array[1] | |
atメソッド | |
例) | |
array = [2005, 2006, 2007, 2008] | |
print(array[0]) | |
print(array.at(0)) | |
Arrayクラス | |
array = Array[2005, 2006, 2007, 2008] | |
array1 = Array.new(3) | |
array2 = Array.new | |
要素数だけを指定した場合、各要素には初期値としてのオブジェクトが代入されていませんので「nil」が代入されます。 | |
よって次のように配列オブジェクトを作成した場合と同じです。 | |
array1 = [nil, nil, nil] | |
array1 = ["Red", "Red", "Red"] | |
array2 = Array.new(3, "Red") | |
最初の例では、各要素には「Red」と言う文字列オブジェクトが各要素に代入されます。 | |
これらのオブジェクトは値は「Red」で同じですがオブジェクトとしては全て別のオブジェクトです。 | |
それに対して2つ目の例では「Red」と言う文字列オブジェクトが1つだけ作成され全ての要素に代入されます。 | |
各要素は同じオブジェクトを参照していることになります。 | |
よって文字列オブジェクトを何らかの方法で変更すると全ての要素が参照しているオブジェクトに影響が出ます。 | |
array = Array.new(3){"Red"} | |
この場合、要素数が3つの配列オブジェクトが作成されますが、各要素に対してブロック内の処理が呼び出されて実行されます。 | |
今回は単に文字列オブジェクトの「Red」を記述しています。 | |
この場合は各要素に「Red」が格納されますが、要素毎に毎回オブジェクトが作成されて代入されているため | |
各要素には値は同じですが別々の文字列オブジェクトが代入されます。 | |
array = ["Red", "Red"} | |
newarray = Array.new(array) | |
上記の場合、配列オブジェクト「array」の0番目の要素と1番目の要素に代入されているオブジェクトは別々のものでが、 | |
複製された配列オブジェクト「newarray」の0番目の要素に代入されているオブジェクトは、 | |
元の配列オブジェクト「array」の0番目の要素に代入されているオブジェクトは同一です。 | |
array = Array["赤", "あお", "緑"] | |
array[1] = "青" | |
インデックスが「1」の要素に対して、新しいオブジェクトの「青」を代入しています。 | |
array = Array["赤", "青", "緑"] | |
print(array.length) # 要素数 | |
print(array.nitems) # nilの要素を除外した要素数 | |
配列に対する繰り返し | |
array = Array["赤", "青", "緑"] | |
for var in array do | |
print("Color = " + var + "¥n") | |
end | |
array = Array["赤", "青", "緑"] | |
array.each{|var| | |
print("Color = " + var + "¥n") | |
} | |
多次元配列 | |
personals = [["佐藤", 20], ["山田", 28], ["加藤", 17]] | |
name1 = personals[0][0] | |
old1 = personals[0][1] | |
name2 = personals[1][0] | |
old2 = personals[1][1] | |
name3 = personals[2][0] | |
old3 = personals[2][1] | |
・ ハッシュ | |
hash = {"Yamada" => 34, "Katou" => 28, "Endou" => 18} | |
print(hash["Katou"]) # 存在しないキーの場合はnilが返される | |
print(hash.fetch("Katou")) # 存在しないキーの場合は「IndexError」エラーが発生する。 | |
# 空のハッシュを作成 | |
hash = Hash.new() | |
# 空のハッシュを作成 | |
hash = Hash.new {|hash, key| hash[key] = "none"} | |
上記はブロック内の変数名が実際の変数名と重複してるので例として不適切。(変数名を「h」とかにしてくれればいいのだが) | |
eachとかのブロックと同じ。 | |
# Hashクラスのクラスメソッドの[]を使用した方式(まあ分かりにくいので{}にすべきだろう) | |
hash = Hash["Yamada" => "Tokyo", "Katou" => "Nagano", "Endou" => "Aomori"] | |
copyhash = Hash[hash] | |
存在しないキーを指定した場合にデフォルトで返される値の変更 | |
例) | |
hash = Hash.new("none") | |
print(hash["Yamada"]) | |
例) | |
hash = Hash.new{|hash, key| | |
hash[key] = key | |
} | |
print(hash["Yamada"]) | |
print(hash["Takahashi"]) | |
この場合、存在しないキーを指定して値を取得した時、値としてキーのオブジェクト返されます。 | |
例) | |
hash = Hash.new{|hash, key| | |
key | |
} | |
print(hash["Yamada"]) | |
print(hash["Takahashi"]) | |
この場合も存在しないキーを指定して値を取得した時、値としてキーのオブジェクトが返されますが新しい要素としては格納されません。 | |
その為再度同じ存在しないキーを指定した場合は改めてブロック内が実行されます。 | |
例) | |
hash = Hash.new() | |
hash.default = "none" | |
print(hash["Yamada"]) | |
要素の追加と値の変更 | |
例) | |
hash = {"Lemon" => 100, "Orange" => 150} | |
hash["Lemon"] = 120 | |
hash["Banana"] = 90 | |
例) | |
hash = {"Lemon" => 100, "Orange" => 150} | |
hash.store("Lemon", 120) | |
hash.store("Banana", 190) | |
ハッシュのサイズの取得 | |
hash = {"Lemon" => 100, "Orange" => 150} | |
print(hash.length) | |
print(hash.size) | |
lengthでもsizeでもどちらでも良いらしい | |
→ rubyのコーディング規約では、エイリアスであるlengthではなく、sizeを使いましょうということになっている。 | |
ハッシュに対する繰り返し | |
hash = {"Lemon" => 100, "Orange" => 150} | |
hash.each{|key, value| | |
print(key + "=>", value) | |
} | |
hash = {"Lemon" => 100, "Orange" => 150} | |
hash.each_key{|key| | |
print("key = " + key) | |
} | |
→ each_keyではなくkeysか何かで代替できたはず。(each_keyは文字数が多いので嫌われているっぽい) | |
hash = {"Lemon" => 100, "Orange" => 150} | |
hash.each_value{|value| | |
print("value = ", value) | |
} | |
ハッシュに含まれるキーや値を配列として取得 | |
hash = {"Lemon" => 100, "Orange" => 150} | |
array = hash.keys | |
hash = {"Lemon" => 100, "Orange" => 150} | |
array = hash.values | |
hash = {"Lemon" => 100, "Orange" => 150} | |
array = hash.to_a | |
to_aだと、[[key1, values1], [key2, value2], ...]のようにして返される。 | |
括弧の省略 | |
http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2fliteral.html | |
メソッドの引数の末尾に要素が1つ以上のハッシュを渡す場合は、{ }を省略することができる。 | |
railsだと | |
render json: @user | |
のような箇所。これは全て省略しないで書くと | |
render({:json => @user}) | |
である。後置シンボル記法なら | |
render({json: @user}) | |
となる。 | |
・ メソッド | |
トップレベル | |
オブジェクト指向のプログラミングではクラスを定義し、そのクラスからオブジェクトを作成するということから開始します。 | |
ところが今までのサンプルでは次のように実行するプログラムを単に記述していました。 | |
print("Hello¥n") | |
このように特定のクラス定義の中に記述されたのではなく、クラス定義の外側の部分はトップレベルと呼ばれています。 | |
トップレベルにはクラスの定義などを記述できますし、プログラムが実行されるとトップレベルに記述されたプログラムが順に実行されて行きます。 | |
例えばJava言語であれば、あるクラス定義の中に記述されたmainメソッドが実行されますが、 | |
Rubyにおけるトップレベルは厳密には何かのクラスのメソッドではありません。 | |
オブジェクト指向でありながらもメソッド以外で実行する処理を記述してあるのは変な気もしますが、 | |
あまり細かい事にはこだわっていないようです。 | |
selfとmain | |
Rubyでは「self」と呼ばれる式が用意されています。 | |
「self」はメソッド内で実行されると、そのメソッドを実行しているオブジェクトを参照することが出来ます。 | |
ではトップレベルで「self」を実行するとどうなるのでしょうか。トップレベルは厳密にはメソッドではないのですが、 | |
「self」を実行すると「main」と言うオブジェクトを返してくれます。 | |
print(self.to_s) | |
では「main」と言うオブジェクトの元になっているクラスは何かを確認してみます。 | |
オブジェクトに対して「class」メソッドを実行するとそのオブジェクトをのクラスを返します。 | |
print(self.to_s) | |
print(self.class.to_s) | |
実行してみると「main」オブジェクトの元になっているクラスは「Object」クラスと表示されます。 | |
これらのことから、Rubyではプログラムが実行されると「Object」クラスのオブジェクトである「main」を作成し、 | |
その「main」オブジェクトの中のとあるメソッド内に記述されたプログラムを実行しているようにも見えます。 | |
ただそう見えるだけで、実際にはトップレベルはトップレベルであり、 | |
トップレベルであっても「self」が何も返さないのはおかしいので「main」と言うオブジェクトを返すようにしているだけのようです。 | |
トップレベルに定義されたメソッド | |
メソッドはクラスの中に記述するものですが、トップレベルの中にもメソッドを定義することが出来ます。 | |
トップレベルに定義されたメソッドは「Kernel」モジュールの中に追加されることになっています。 | |
(どういう仕組みなのかは良く分かっていません)。 | |
「Kernel」モジュールは全てのクラスの元になっている「Object」クラスに読み込まれています。 | |
その為、トップレベルに定義されたモジュールは、「Kernel」モジュールの中で既に定義されている | |
「print」メソッドなどと同じようにどのクラス内からでも呼び出すことができます。 | |
またメソッドを呼び出す際に、呼び出し元のオブジェクト(レシーバーと呼ばれています)を省略できるので、 | |
あたかも関数のように使用することが可能です。 | |
よって特定のクラス内ではなくトップレベルの位置にメソッドを定義すれば、 | |
関数のように使用できるメソッドを定義することが可能となります。 | |
→ ちなみにRuby 1.9以降、最上位の基底クラスはBasicObjectクラス。 | |
メソッドの定義と呼び出し | |
def メソッド名(引数1, 引数2, ...) | |
実行する処理 | |
実行する処理 | |
end | |
例) | |
def printHello | |
print("Hello¥n") | |
end | |
printHello | |
注) | |
メソッドは実際に呼び出されるよりも前に定義されていなければなりません。例えば次のようなプログラムはエラーとなります。 | |
printHello | |
def printHello | |
print("Hello¥n") | |
end | |
例) | |
def printHello(msg, name) | |
print(msg + "," + name + "¥n") | |
end | |
printHello("Hello", "Yamada") | |
例) | |
def addString(str) | |
str << ",Japan" # この場合、呼び出し元の変数も変更される(http://gam0022.net/blog/2013/02/09/ruby-variable/) | |
end | |
address = "Tokyo" | |
print(address + "¥n") | |
addString(address) | |
print(address + "¥n") | |
※ 重要!! | |
rubyのメソッド引数は「値渡し」であるが、rubyの変数は「ラベル」なので、 | |
「<<演算子」を使ったりすると、呼び出し元の変数の値も変更される。 | |
そういう意味では「参照を値渡ししている」と考えてよい。 | |
http://gam0022.net/blog/2013/02/09/ruby-variable/ | |
http://qiita.com/metheglin/items/ca452bc0a3866d2de7bf | |
要するに | |
str = "Tokyo" | |
では、strというラベルが新しい「Tokyo」という文字列オブジェクトを指すようになるだけだが、 | |
str << "Tokyo" | |
では、strの指し示す文字列オブジェクト自体が変更される。ここは要注意。 | |
重要なのは、代入演算子の動作が、「変数の向き先(参照先)を変更する」である点。 | |
変数の指しているオブジェクトの値を変更しているわけではない。ここの理解が重要。 | |
例)デフォルト引数 | |
def printHello(msg="No msg", name="No name") | |
print(msg + "," + name + "¥n") | |
end | |
printHello("Hello", "Yamada") | |
printHello("Hello") | |
printHello() | |
def printHello(msg, name="No name") | |
print(msg + "," + name + "¥n") | |
end | |
printHello("Hello", "Yamada") | |
printHello("Hello") | |
引数を配列として受け取る | |
例) | |
def printHello(msg, *names) | |
print(msg + "," + name + "¥n") | |
end | |
printHello("Hello") | |
printHello("Hello", "Yamada") | |
printHello("Hello", "Yamada", "Endou") | |
printHello("Hello", "Yamada", "Endou", "Katou", "Takahashi") | |
戻り値 | |
def tashizan(num1, num2) | |
return num1 + num2 | |
end | |
sum = tashizan(10, 25) | |
print("合計 = ", sum) | |
なお「return」は省略可能です。省略された場合はメソッド内の最後の式を評価した値が戻り値となります。 | |
戻り値(多重代入) | |
def keisan(num1, num2) | |
return num1 + num2, num1 - num2 | |
end | |
plus, minus = keisan(10, 25) | |
・ クラス | |
アクセスメソッド | |
定義式 機能 | |
attr_reader :変数名 参照が可能 | |
attr_writer :変数名 更新が可能 | |
attr_accessor :変数名 参照と更新が可能 | |
class Car | |
def initialize(carname="未定義") | |
@name = carname | |
end | |
attr_accessor :name | |
end | |
car = Car.new() | |
car.name = "civic" | |
print(car.name) | |
上記のように対象となるインスタンス変数名に対して「attr_reader」「attr_writer」「attr_accessor」のいずれかを使って | |
上記のように記述することでインスタンス変数の参照や更新用のメソッドを個別に定義する代わりとなります。 | |
「オブジェクト名.変数名」で参照したり更新したりが直接行えます。 | |
(クラス外からインスタンス変数が直接操作できるようになったわけではなく、 | |
参照や更新が行えるメソッドが自動的に作成されたと考えて下さい)。 | |
定数 | |
class Reji | |
SHOUHIZEI = 0.05 | |
def initialize(init=0) | |
@sum = init | |
end | |
def kounyuu(kingaku) | |
@sum += kingaku | |
end | |
def goukei() | |
return @sum * (1 + SHOUHIZEI) | |
end | |
end | |
reji = Reji.new(0) | |
reji.kounyuu(100) | |
reji.kounyuu(80) | |
print(reji.goukei()) | |
クラス外から定数を参照したい場合は | |
print(Reji::SHOUHIZEI) | |
のようにする。 | |
クラス変数 | |
class Car | |
@@count = 0 | |
def initialize(carname="未定義") | |
@name = carname | |
@@count += 1 | |
end | |
def getCount() | |
return @@count; | |
end | |
end | |
car1 = Car.new("crown") | |
car2 = Car.new("civic") | |
print("現在生成されたオブジェクト数:", car1.getCount()) | |
継承 | |
class Car | |
def accele | |
print("アクセルを踏みました") | |
end | |
def brake | |
print("ブレーキを踏みました") | |
end | |
end | |
class Soarer < Car | |
def openRoof | |
print("ルーフを開けました") | |
end | |
end | |
オーバーライド | |
class Car | |
def accele | |
print("アクセルを踏みました") | |
end | |
def brake | |
print("ブレーキを踏みました") | |
end | |
end | |
class Soarer < Car | |
def openRoof | |
print("ルーフを開けました") | |
end | |
def accele | |
print("アクセルを踏み加速しました") | |
end | |
end | |
class Crown < Car | |
def reclining | |
print("シートをリクライニングしました") | |
end | |
end | |
オーバーライドの際には特にキーワードは不要なようである。 | |
スーパークラスのメソッドを呼び出す | |
class Car | |
def accele | |
print("アクセルを踏みました¥n") | |
end | |
end | |
class Soarer < Car | |
def accele | |
super | |
print("加速しました¥n") | |
end | |
end | |
# 引数のある場合 | |
class Car | |
def accele(acceletime) | |
print(acceletime, "秒間アクセルを踏みました") | |
end | |
end | |
class Soarer < Car | |
def accele(acceletime) | |
super(acceletime) | |
print("加速しました") | |
end | |
end | |
# 引数が自動的に渡されるケース | |
class Car | |
def accele(acceletime) | |
print(acceletime, "秒間アクセルを踏みました") | |
end | |
end | |
class Soarer < Car | |
def accele(acceletime) | |
super | |
print("加速しました") | |
end | |
end | |
「super」は特殊なメソッドと考えて下さい。 | |
メソッドの中で「super」メソッドを実行すると、 | |
スーパークラスの中でその呼び出されたメソッドと同じメソッド名を持つメソッドを探して実行します。 | |
アクセス制御 | |
class Car | |
def accele(acceletime=1) | |
print("アクセルを踏みました¥n") | |
print("スピードは", calcSpeed(acceletime), "Kmです¥n") | |
end | |
public :accele | |
def brake | |
print("ブレーキを踏みました¥n") | |
end | |
public :brake | |
def calcSpeed(acceletime) | |
return acceletime * 10 | |
end | |
private :calcSpeed | |
end | |
car = Car.new | |
car.accele(10) | |
特に指定しない場合はpublicになる。 | |
initializeメソッドは常にprivate。 | |
# まとめて指定する方式 | |
class Car | |
public | |
def accele(acceletime=1) | |
print("アクセルを踏みました¥n") | |
print("スピードは", calcSpeed(acceletime), "Kmです¥n") | |
end | |
def brake | |
print("ブレーキを踏みました¥n") | |
end | |
private | |
def calcSpeed(acceletime) | |
return acceletime * 10 | |
end | |
end | |
car = Car.new | |
car.accele(10) | |
・ モジュール | |
モジュールの定義 | |
module HeikinModule | |
def heikin(x, y) | |
kekka = (x + y) / 2 | |
print(kekka) | |
end | |
end | |
モジュールはクラスと同じくメソッドを定義する事が出来ます。 | |
クラス変数に相当するものはモジュールにはありませんが定数は定義する事が出来ます。 | |
モジュールの利用方法としては「モジュール名.メソッド名」の形式で関数のように実行するか、 | |
または他のクラスの中にインクルードして利用することが出来ます。 | |
モジュールを関数のように使う | |
module SuuchiModule | |
def minValue(x, y) | |
if x < y | |
return x | |
else | |
return y | |
end | |
end | |
def maxValue(x, y) | |
if x > y | |
return x | |
else | |
return y | |
end | |
end | |
module_function :minValue | |
module_function :maxValue | |
end | |
print(SuuchiModule.minValue(10, 8), "¥n") | |
print(SuuchiModule.maxValue(10, 8), "¥n") | |
# includeして呼び出す場合は下記のように行える | |
include SuuchiModule | |
print(minValue(10, 8), "¥n") | |
print(maxValue(10, 8), "¥n") | |
→ 別ファイルから使う場合はrequireとincludeが必要。 | |
クラスにモジュールをincludeする。 | |
module SuuchiModule | |
def minValue(x, y) | |
if x < y | |
return x | |
else | |
return y | |
end | |
end | |
end | |
class Test | |
include SuuchiModule | |
def dispValue(x, y) | |
min = minValue(x, y) | |
print("2つの値", x, "と", y, "の中で小さい値は", min, "です¥n") | |
end | |
end | |
test = Test.new | |
test.dispValue(10, 8) | |
・ %記法 | |
http://d.hatena.ne.jp/shunsuk/20081220/1229779001 | |
%{I LOVE #{name}} | |
文字列リテラル。式展開が有効。%記法だとシングルクォートやダブルクォートをエスケープする必要がありません。 | |
・ %w記法 | |
%w(foo bar) is a shortcut for ["foo", "bar"]. | |
→ %w[foo bar]でもよい。 | |
Meaning it's a notation to write an array of strings seperated by spaces instead of commas and without quotes around them. | |
You can find a list of ways of writing literals in zenspider's quickref. | |
・ メソッド引数のアスタリスク | |
http://tm.root-n.com/programming:ruby:etc:parameter_asterisk | |
def hoge(a, b, c, d) | |
p a | |
p b | |
p c | |
p d | |
end | |
arr = [111, 222, 333] | |
hoge(1, *arr) | |
「呼び出す側の引数にアスタリスクを付けると与えられた配列は展開されます」 | |
とのことなので、上記はhoge(1, 111, 222, 333)となる。 | |
よって、recipeの | |
role :web, *%w[ | |
192.168.1.121 | |
192.168.1.122 | |
] | |
は、 | |
role(:web, "192.168.1.121", "192.168.1.122") | |
である。 | |
・ シンボル | |
http://d.hatena.ne.jp/keyesberry/20080802/p1 | |
シンボルは文字列と一対一で対応する記号である | |
文字列'Charlie'に対応するシンボルは:Charlieとなる | |
→ Ruby 1.9から、ハッシュキーのシンボルのコロンは前置でも後置でもオッケーになった。(後置だと「=>」を省略できる) | |
http://d.hatena.ne.jp/sevenpg/20100822/1282477146 | |
http://ruby-newbie.hatenablog.com/entry/2012/12/30/201905 | |
→ ハッシュの表記方法ですがRoRでよく使われるのは、 | |
capital = { :france =>"Paris", :japan => "Tokyo", :uk => "London" } | |
ではなくて。下の書き方です。 | |
capital = { france: "Paris", japan: "Tokyo" , uk: "London" } | |
キーにシンボルを使う場合はコロンをハッシュキーの最後につけると矢印を省略して書けますというRuby1.9の表記方法です。 | |
文字列のところで書いたように | |
my_name = 'Charlie' | |
his_name = 'Charlie' | |
とした場合 | |
2つの異なるオブジェクトがRuby空間に生成される | |
my_name.object_id # => 8848520 | |
his_name.object_id # => 8827340 | |
これらのシンボルは以下により得られる | |
my_name.intern # => :Charlie | |
his_name.intern # => :Charlie | |
当然に異なるオブジェクトのシンボルは | |
異なるオブジェクトであることが期待される | |
しかしそうはならない | |
my_name.intern.object_id # => 314378 | |
his_name.intern.object_id # => 314378 | |
つまり同一記号のシンボルは同じオブジェクトである | |
これはつまり一つのRuby空間には | |
無数の"Charlie"が存在しうるけれども | |
これに対応する:Charlieというシンボルオブジェクトは | |
ただ一つしか存在しないということを意味している | |
そうこれはまるで整数だ | |
整数と同様にシンボルには名札を付ける必要はない | |
シンボル記号に対するオブジェクトは一意であり | |
ユーザは名札がなくても希望するオブジェクトにアクセスできる | |
つまりシンボル記号自体がそのオブジェクトの名札の役割を担う | |
ここまで来ればシンボルの正体ははっきりする | |
文字列のような顔をして | |
数字のようにそれ自体が名札として機能する | |
そうシンボルとは… | |
文字列の皮を被った整数だったんだ! | |
→ 「名札のついた整数」と考えれば分かりやすい。 | |
シンボルの出番 | |
Rubyには複数の関連するオブジェクトを | |
ユーザがまとめて管理できるようにするオブジェクトがある | |
配列とハッシュである | |
our_name = [ 'Charlie', 'Fox', 'Henry' ] | |
これでRuby空間に3つの文字列オブジェクトを管理する | |
1つの配列オブジェクトが生成され | |
それにour_nameの名札が付けられる | |
配列で管理されるオブジェクトへのアクセスは | |
その位置を表す数字で行なえる | |
our_name[1] # => "Fox" | |
でも数字には個性がないので | |
1と”Fox"との間にはその位置以上の関連性はない | |
できればもっと関連性を持たせて意味付けをしたい | |
そのような場合シンボルが使える | |
our_name = { :my_name => 'Charlie', :his_name => 'Fox', :my_nephew => 'Henry' } | |
これでRuby空間に3つの文字列オブジェクトを管理する | |
1つのハッシュオブジェクトが生成され | |
それにour_nameの名札がつけられる | |
ハッシュで管理されるオブジェクトへのアクセスは | |
そのキー値を使って行う | |
our_name[:his_name] # => "Fox" | |
なおRuby空間では:his_nameは"his_name"に対応しているが | |
それらは別のオブジェクトなので | |
our_name["his_name"] # => nil | |
となる | |
→ これが困るのでシンボルが使われると考えてよい。つまりハッシュのキーには基本的にシンボルを使う。 | |
Rails空間では事情が異なるようだ | |
シンボルの特性をまとめてみよう | |
・文字列と一対一に対応した記号である(文字列オブジェクトとシンボルオブジェクトは多対一の関係になる) | |
・同一記号のシンボルはRuby空間に唯一つ存在する(整数と同様、文字列と相違) | |
・シンボル記号自体が意味付けを表象できる(文字列と同様、整数と相違)→つまり見た目が文字列なので整数よりも分かりやすいということ。 | |
これらの特性を考えれば | |
そのオブジェクトの変更が予定されない場合 | |
無駄なオブジェクトが生成されないシンボルは | |
速度の点で文字列オブジェクトよりも有利であり | |
またその記号の可読性を高めたい場合 | |
整数オブジェクトよりも有利である | |
・ print/puts/p/inspect | |
printメソッドは、改行を行いません。 | |
putsメソッドは、文字列の最後で強制改行を行います。 | |
pメソッドは、引数が文字列の場合は、出力の際に「"」で文字列を囲んで返します。 | |
出力された値が、文字列なのか数値なのかを見分けられます。 | |
pメソッドは、プログラムの動作を確認したいときに、出力された値の型や構造を確認したい場合に使います。 | |
inspectメソッドは、変数のリテラル表現を返します。 | |
a = ["0", "1"] | |
puts a.inspect # p a と同様 | |
・ requireとincludeの違い | |
http://faultier.blog.jp/archives/1220074.html | |
Rubyファイルを読み込むのはrequire | |
includeは「モジュールを使うよって宣言」ではなくて「モジュールが持ってる性質を、クラスに組み込むメソッド」 | |
includeをclass/module文の中で使うと、モジュールの特徴をそのクラスに追加する | |
モジュールの中でdef self.hogeとして定義されてたやつはそのクラスのクラスメソッドになる | |
モジュールの中でdef fugaとして定義されてたやつはそのクラスのインスタンスメソッドになる | |
includeをclass/module文の外で使うと、モジュールの特徴をObjectクラスに追加する | |
モジュールの中でdef self.hogeとして定義されてたやつは全てのクラスのクラスメソッドになる | |
モジュールの中でdef fugaとして定義されてたやつは全てのクラスのインスタンスメソッドになる | |
・ alias | |
http://doc.ruby-lang.org/ja/1.9.3/doc/spec=2fdef.html#alias | |
# メソッド foo を定義 | |
def foo | |
"foo" | |
end | |
# 別名を設定(メソッド定義の待避) | |
alias :_orig_foo :foo | |
# foo を再定義(元の定義を利用) | |
def foo | |
_orig_foo * 2 | |
end | |
p foo # => "foofoo" | |
・ define_method | |
http://www.func09.com/wordpress/archives/373 | |
class DynamicMethod | |
# my_method_1, my_method_2というメソッドを定義する | |
[1,2].each do |num| | |
define_method("my_method_#{num}") do |message| # 引数message | |
puts "My method #{num}:#{message} " | |
end | |
end | |
end | |
dm = DynamicMethod.new | |
p dm.methods.select{|i| i=~/my_method/} # => ["my_method_1", "my_method_2"] | |
dm.my_method_1 "hello" # => My method 1:hello | |
dm.my_method_2 "good-bye" # => My method 2:good-by | |
・ module | |
http://blog.livedoor.jp/sparklegate/archives/50254891.html# | |
module Com | |
module Example | |
module Web | |
module Util | |
class MyClass; | |
def initialize; p 'Hello World.'; end | |
end | |
end | |
end | |
end | |
end | |
ディレクトリ階層もJavaスタイルでmoduleと対応させて下さい。 | |
% mkdir ./com; mkdir ./com/example; mkdir ./com/example/web; mkdir ./com/example/web/util | |
使うとき | |
require 'com/example/web/util/MyClass' | |
module Com | |
module Example | |
class Sample | |
include Com::Example::Web::Util | |
def execute | |
my_class = MyClass.new | |
end | |
end | |
end | |
end | |
おそらく、capistranoの「load」は、requireとincludeを一緒にやってくれていると思われる。 | |
で、「namespace」は、おそらくmoduleだろう。 | |
「task」は、多分define_method。 | |
・ ローカル変数、インスタンス変数、クラス変数、グローバル変数、定数 | |
1. 小文字aからz か、_ で始まるのは、ローカル変数。 | |
<例>num1 | |
最初に宣言されたブロック内だけで有効のようです。ブロックとは { } で囲まれた間のことかな?beginからendもブロックというのかな? | |
2.@から始まるのは、インスタンス変数。 | |
<例>@num1 | |
3.@@から始まるのは、クラス変数。 | |
<例>@@num1 | |
4.$から始まるのは、グローバル変数。 | |
<例>$num1 | |
どこでも使えるグローバル変数です。これを多用すると結構危険ですよね。 | |
5.大文字AからZで始まるのは、定数。 | |
<例>Num1 | |
でも、初期化した後にも代入できるらしいです。ただし初期化の後の代入は、Warningが出るようです。 | |
・ DSL(Domain Specific Language) | |
http://gihyo.jp/admin/feature/01/dsl/0002?page=2 | |
Rubyでは,DSLの作成にeval,class_eval,そしてinstance_evalという便利な機能を使う事ができます。 | |
evalは,文字列をRubyのステートメントとして評価します。evalはRubyカーネルのメソッドであり, | |
オブジェクト内部や単純なスクリプトの中でも使うことができます。 | |
これにより,非常に柔軟なプログラムを作ることができるのです。 | |
http://www.atmarkit.co.jp/news/201009/13/spell.html | |
・ block, Proc, lambda, method | |
http://qiita.com/kidachi_/items/15cfee9ec66804c3afd2 | |
ブロックとは | |
do~end(もしくは{~})で囲われた、引数となるためのカタマリ。 | |
yieldは「ブロックを呼び出すもの」、Procは「ブロックをオブジェクト化したもの」 | |
ブロックの性質は | |
それ単体では存在できず、メソッドの引数にしかなれない(「do~endのカタマリ」がその辺に単体で転がっているのは見た事ないはず。) | |
引数として渡されたブロックは、yieldによって実行される | |
def foo | |
yield(1,2) | |
end | |
foo {|a,b| | |
p [a, b] | |
} # => [1, 2] (要するに p [1, 2] を実行した) | |
def give_me_block | |
yield | |
end | |
give_me_block do | |
p "Hello, block!" | |
end | |
↓この定義は、下記のように書くことも出来る。 | |
def give_me_block( &block ) | |
block.call | |
end | |
give_me_block do | |
p "Hello, block!" | |
end | |
→ &blockの「&」について。 | |
&を付けることで、実際に引数にブロックが渡ってきた際、 | |
Procオブジェクトに変換している。 | |
→ Procオブジェクトとは | |
ブロックをオブジェクト化したものがProc | |
ブロックがそれ単体では存在できないことを思い出す (→オブジェクト化してしまえばok) | |
ブロックをオブジェクトに変換することで、引き渡されたメソッド(give_me_block)内で扱えるようにする | |
→ ブロック引数は、仮引数の中で一番最後に定義されていなければならない | |
以下みたいなのはNG | |
def give_me_block( &block1, param1 ) | |
def give_me_block( &block1, &block2 ) | |
つまるところ引数として渡せるブロックは一つだけ。 | |
以上を踏まえるとこんな考え方も出来る。 | |
「どうせブロック引数は一つしか取れないんだから | |
呼び出し箇所をblock.callなんて明示せずに、yieldで統一しちゃえば良いじゃん」 | |
def give_me_block( &block ) | |
yield # block.callをやめてyieldに変更 | |
end | |
give_me_block do | |
p "Hello, block!" | |
end | |
さらに | |
「ブロックは全部yieldが示すんだから、仮引数(&block)もいらなくね?」 | |
def give_me_block # (&block)を除去 | |
yield | |
end | |
give_me_block do | |
p "Hello, block!" | |
end | |
これが色々省略されまくったyield文の正体です。 | |
一見give_me_blockは何も引数をとらないメソッドのように見えるのに、 | |
その内部にyieldを持っている以上「ブロックを引数として受けとるメソッドである」 | |
ということを認識しないといけない。 | |
Rubyコードを読み解く際によく注意しておかなければならない点の一つのみたいです。 | |
■Rubyのblock、Proc、lambdaを理解する | |
http://d.hatena.ne.jp/shunsuk/20090101/1230816826 | |
lambdaはProc.newもしくはproc と同じ。 | |
l = lambda {p "hoge"} | |
l.call | |
=> "hoge" | |
lambda は -> で書ける | |
l = -> {p "hoge"} | |
l.call | |
引数を1つ渡す場合 | |
l = -> (x){p x} | |
l.call("hoge") | |
=> "hoge" | |
引数を2つ渡す場合 | |
l = -> (x,y){p x,y} | |
l.call("hoge", "fuga") | |
■RubyでのDSLの作り方 | |
http://d.hatena.ne.jp/rubikitch/20080217/rubydsl | |
■メソッドの引数にブロックを渡す | |
http://www.yukun.info/blog/2008/01/ruby-block.html | |
・ 「!」キーワード | |
破壊的メソッド(オブジェクトの状態が変わるメソッド)には!を付加するのがrubyの流儀らしい。 | |
→ a.sort | |
と | |
a.sort! | |
だと、前者はa配列の内容は変化しないが、後者はa配列の内容そのものがソートされる。 | |
・ クラス内でのselfと@の違い | |
@hoge は、インスタンス変数 @hoge を参照します。 | |
self.hoge は、インスタンスメソッド hoge を呼び出します。 | |
self.hoge = は、インスタンスメソッド hoge= を呼び出します。 | |
・ 特異クラス | |
http://magazine.rubyist.net/?0046-SingletonClassForBeginners | |
Ruby でのクラスメソッドの定義の仕方には大きくわけて二つのやり方があります。一つは特異メソッド方式、もう一つが特異クラス方式です。 | |
def self.method_name の特異メソッド形式 | |
特異メソッド方式では、def self.class_method のようにメソッド名の前にクラスメソッドを定義する対象のクラス名をつけて定義します。 | |
リファレンスマニュアルにあるように直接クラス名を書いてもいいのですが、 | |
定義するクラス自身の中に書く場合はこのように self. と書くことが多いでしょう。 | |
class << self の特異クラス形式 | |
特異クラス方式では、class << self と書いた行から end までの間に def class_method のように | |
クラス名を書かずにインスタンスメソッドと同じようなメソッド定義を書いていきます。 | |
この間に書いたものはクラスメソッドとして定義されます。 | |
どちらも正しいクラスメソッドの定義の仕方ですが、 | |
特異メソッド方式では複数のクラスメソッドをまとめて定義したい場合に都度の self. を書くのが面倒なため、 | |
そのようなときは特異クラス方式がとられることが多いようです。 | |
・ rubyでselfを省略出来ない場合 | |
http://qiita.com/akira-hamada/items/4132d2fda7e420073ab7 | |
(rubyコーディング規約にも書いてある) | |
セッターメソッドを呼ぶ時はselfを省略出来ません。以下set_default_nameメソッドの様な例ですね。 | |
class User | |
attr_accessor :name | |
def set_default_name | |
name = 'unknown' # nameというローカル変数が作られるだけ | |
# self.name = 'unknown' # こう書くべき | |
end | |
end | |
user = User.new | |
user.set_default_name | |
user.name # => nil | |
こういうケースがあるので、基本的に値をセットする場合は「@name」のようにした方が好ましいとも言える。 | |
ただ、その場合setterメソッドを呼び出さないので、setterメソッド内でなにか特別な処理を行っている場合は問題となる。 | |
・ module_functionの用途 | |
http://qa.atmarkit.co.jp/q/37 | |
http://ref.xaio.jp/ruby/classes/module/module_function | |
module_functionを使うと | |
クラスメソッド | |
プライベートメソッドなインスタンスメソッド(includeしたクラス内で使う) | |
の2つの形で使えるようになります。 | |
代表的なのは Mathモジュールの数学関数ですね。 | |
モジュールMathに対して呼ぶ | |
includeしてレシーバなしで使う | |
という2通りのやり方で使用することが出来ます。 | |
・ Module::includedメソッド | |
http://ref.xaio.jp/ruby/classes/module/included | |
includedメソッドは、includeメソッドによってモジュールが他のモジュールやクラスにインクルードされたあとに呼び出されます。 | |
引数にはモジュールをインクルードするクラスやモジュールが入ります。 | |
module Feature | |
def self.included(klass) | |
puts "#{klass} has included #{self}!" | |
end | |
end | |
class Container | |
include Feature | |
end | |
#Container has included Feature! | |
Rubyではモジュールをインクルードしても、モジュールメソッド(モジュールの特異メソッド)はクラスには継承されませんが、 | |
次のようにincludedの中でextendメソッドを呼び出すことでモジュールメソッドをクラスメソッドとして使えるようにできます。 | |
→ 下記のようにクラスメソッドとインスタンスメソッドを同時に追加する際は | |
Moduleの中にModuleを定義する方式が頻出パターンのようである。 | |
http://www.techscore.com/blog/2013/03/01/rails-includeされた時にクラスメソッドとインスタンスメ/ | |
module Feature | |
def method_i | |
"Instance Method" | |
end | |
module ClassMethods | |
def method_c | |
"Class Method" | |
end | |
end | |
extend ClassMethods | |
def self.included(klass) | |
klass.extend ClassMethods | |
end | |
end | |
class Container | |
include Feature | |
end | |
puts Container.new.method_i | |
puts Container.method_c | |
#Instance Method | |
#Class Method | |
・ begin/rescue/ensure | |
http://www.minituku.net/courses/566428009/lessons/760432481/texts/302758961?locale=ja | |
begin | |
<例外を発生させる可能性のある処理> | |
rescue => <変数> | |
<例外が起こった場合の処理> | |
ensure | |
<例外の有無に関わらず実行される処理> | |
end | |
実際の例 | |
begin | |
x = 10 | |
y = "a" | |
p x + y | |
rescue => ex | |
puts(ex.message) | |
ensure | |
puts("足し算をしました") | |
end | |
メソッドの処理をbegin 〜 rescue 〜 endを使った例外処理ですべて囲む時は、beginとendを省略して書くことができます。 | |
def foo | |
<メソッドの本体> | |
rescue => ex | |
<例外処理> | |
ensure | |
<後処理> | |
end | |
実際に実行した例が以下になります。 | |
def foo(x, y) | |
result = x + y | |
return result | |
rescue => ex | |
return x, y | |
ensure | |
if result | |
puts "xとyを足した結果は、#{result}でした" | |
else | |
puts "xとyは足せませんでした" | |
end | |
end | |
foo(10, 20) | |
foo(10, "a") | |
・ block_given?(ブロックが渡されたかどうかの判定) | |
http://qiita.com/kidach1/items/15cfee9ec66804c3afd2#2-6 | |
https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md#auto-release-resources | |
例えば「File.open」というクラスメソッドは、ブロックが渡された場合と渡されなかった場合で動作が異なる。 | |
f = File.open('testfile') | |
# 自分でcloseする必要がある | |
f.close | |
File.open('testfile') do |f| | |
# 何か処理を行う | |
end | |
# 自分でcloseする必要がない | |
この場合に使用されているのが、block_given?である。下記の用に使う | |
def wonder_seven_box | |
if block_given? | |
yield(7) | |
else | |
p "Don't mind. Feel free to call me." # ブロックが与えられなければこちら | |
end | |
end | |
下記のように、ブロックを渡しても渡さなくてもどちらでも呼び出すことが出来る。 | |
wonder_seven_box do |x| | |
p 3 + x | |
end | |
=> 10 | |
wonder_seven_box do |x| | |
p "happy_block! " * x | |
end | |
=> "happy_block! happy_block! happy_block! happy_block! happy_block! happy_block! happy_block! " | |
wonder_seven_box | |
=> "Don't mind. Feel free to call me." | |
・ &.オペレーター(Safe Navigation Operator) | |
[What does &. (ampersand dot) mean in Ruby? - Stack Overflow](http://stackoverflow.com/questions/36812647/what-does-ampersand-dot-mean-in-ruby/36812667) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment