Open11
Ruby Cherry Book vol.2🍒
基礎知識
全てがオブジェクト
Rubyはオブジェクト指向言語なので、文字列、配列、数値、nil、正規表現まで全てがオブジェクトである。
なので、nilやtrue, falseに対して、メソッドを呼び出すことができるようになっている。
irb(main):001> "1".to_s
=> "1"
irb(main):002> 1.to_s
=> "1"
irb(main):003> nil.to_s
=> ""
irb(main):004> true.to_s
=> "true"
irb(main):005> false.to_s
=> "false"
irb(main):006> /\d+/.to_s
=> "(?-mix:\\d+)"
メソッド呼び出し
メソッドはカッコありなし両方で記述することができる。
irb(main):034> 1.to_s()
=> "1"
irb(main):035> 1.to_s
=> "1"
irb(main):036> 10.to_s(16)
=> "a"
irb(main):037> 10.to_s 16
=> "a"
文の区切り
基本的に改行が文の区切りになる。
ただ、;
を使って区切りを指定することもできる。
1.to_s; nil.to_s, 10.to_s(16)
コメント
基本、#
の後に書いた文字がコメントになる。
=begin
, =end
を使ってもコメントを書くことができる。
# コメントだよ。(基本こっち使うかな)
=begin
begin, endで囲った部分がコメントになるよ。
(こっちはあまり使わないかな?)
=end
予約語
変数やメソッド、クラスに付ける名前は「識別子」と言われ、半角英数字(ASCII文字)、漢字、ひらがなを使うことができる。
ただ、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 and next return until
変数の宣言
# ローカル変数の定義にはスネークケースを使用する。
special_price = 200
# アンダースコアで始まる書き方も使えるらしい
_special_price = 200
# 数字から始まる書き方はできない
2_special_price = 200
<internal:kernel>:187:in `loop': (irb):40: trailing `_' in number (SyntaxError)
# 一応、漢字、ひらがなも使える
変数 = 200
へんすう = 200
# 多重代入
a, b, = 1, 2 # a=>1, b=>2
a, b = 1 # a=>1, b=>nil
a, b = 1, 2, 3 # a=>1, b=>2, 3は切捨
# 2個以上の変数に同じものを代入
a = b = 200 #a=>200, b=>200
文字列
シングルクオートとダブルクオート
# 改行文字を埋め込みたい場合
puts "こんにちは\nさようなら"
#=> こんにちは
さようなら
puts 'こんにちは\nさようなら'
#=> こんにちは\nさようなら
エスケープ(\)
puts "こんにちは\\nさようなら #=> こんにちは\nさようなら
puts 'He said, "Don\'t speak."' #=> He said, "Don't speak."
puts "He said, \"Don't speak. \"" #=> He said, "Don't speak."
文字列の比較
'ruby' == 'ruby' #=> true
'ruby' == 'Ruby' #=> false
'ruby' != 'perl' #=> true
'ruby' != 'ruby' #=> false
'a' < 'b' #=> true
'a' < 'A' #=> false
'a' > 'A' #=> true
'abc' < 'def' #=> true
'abc' < 'ab' #=> false
'abc' < 'abcd' #=> true
'あいうえお' < 'かきくけこ' #=> true
%記法
# !!の区切り文字はなんでもいい
# %q! !でシングルクオートで囲んだものと同じになる
puts %q!He said, "Don't speak."! #=> He said, "Don't speak."
# %Q! !(%! !)でダブルクオートで囲んだものと同じになる
something = "Hello"
puts %Q!He said, #{something}! #=> He said, Hello
ヒアドキュメント
# 通常のドキュメント
text = <<EOS
ここにヒアドキュメントを記述する。
`EOS`で記述している識別子はなんでもいいみたい。(大文字にするのが慣習)
EOS
p text #=> "ここにヒアドキュメントを記述する。\n`EOS`で記述している識別子はなんでもいいみたい。(大文字にするのが慣習)\n"
# 最後の識別子をインデントさせる
text = <<-EOS
最後の識別子をインデントさせる場合は、「-」を付ける。
EOS
p text #=> "最後の識別子をインデントさせる場合は、「-」を付ける。\n"
# 内部の文字列のインデントを無視させる
text = <<~EOS
空白を無視させる。
ちゃんと空白が反映されているか。
EOS
p text #=> "空白を無視させる。\nちゃんと空白が反映されているか。\n"
# 内部の空白を反映させる
text = <<~EOS
\ 各行の行頭に空白を2文字入れる。
\ このとき行頭はバックスラッシュで指定する。
EOS
p text #=> " 各行の行頭に空白を2文字入れる。\n このとき行頭はバックスラッシュで指定する。\n"
# "識別子"なら式展開、改行が有効
name = "Taro"
text = <<"EOS"
こんにちは, #{name}さん
ヒアドキュメント内の改行は\n有効になる。
EOS
puts text
#=>
こんにちは, Taroさん
ヒアドキュメント内の改行は
有効になる。
# '識別子'なら式展開、改行が無効になる。
name = "Taro"
text = <<'EOS'
こんにちは, #{name}さん
ヒアドキュメント内の改行は\n無効になる。
EOS
puts text
#=>
こんにちは, #{name}さん
ヒアドキュメント内の改行は\n無効になる。
#
数値
演算子の優先順位
# 上から高い
::
[]
+(単項)
**
-(単項)
* / %
+, -
<<, >>
&
|, ^
>, >=, <, <=
<=>, ==, ===, !=, =~, !~
&&
||
.., ...
?:(条件演算子)
= (+=, -=)
not
and, or
真偽値と条件分岐
論理演算子
&&と||について
# &&(かつ)は、すべて真であればtrueに、1つでもfalseならfalseを返す。
a = true
b = true
c = false
a && b #=> ttue
b && c #=> false
# ||(または)は、いずれかが真であればtrue、全て偽であればfalseを返す。
a = true
b = false
c = false
a || b #=> true
b || c #=> false
# &&は||よりも優先度が高い。
a = true
b = true
c = false
d = false
a && b || c && d #=> true 下記と同じ意味になる。
(a && b) || (c && d) #=> true
# !で真偽値を反転できる
a = true
!a #=> false
# !()でも反転できる
a = true
b = true
!(a && b) #=> false
# &&が全て真の場合は、最後に評価されたものを返す(偽は見つけた時点で返す)
a = 1
b = 2
c = 3
d = false
a && b && c #=> 3
a && b && d && c #=> false
# ||は真を見つけた時点で返す。(全て儀の場合は、最後に評価されたものを返す)
a = false
b = 1
c = nil
a || b || c #=> 1
a || c #=> nil
配列
オブジェクトの作成
# .newで作成する方法
Array.new(1, "apple") #=> ["apple"]
Array.new(3, "apple") #=> ["apple", "apple", "apple"]
# []でも作成できる
["apple"] #=> ["apple"]
["apple", "apple", "apple"] #=> ["apple", "apple", "apple"]
# デフォルト値を指定する際の注意点(ブロックを使うと良い)
fruits = Array.new(3, "apple")
a = fruits[0]
a.upcase!
fruits #=> ["APPLE", "APPLE", "APPLE"] (全てが同じオブジェクトになるらしい)
fruits = Array.new(3) { "apple" }
a = fruits[0]
a.upcase!
fruits #=> "APPLE", "apple", "apple"](異なるオブジェクトが作成されている)
%記法
# %wの場合(エスケープを利用できる)
%w(apple grape orange) #=> ["apple", "grape", "orange"]
%w(big\ apple small\ grape orange) #=> ["big apple", "small grape", "orange"]
# %Wの場合(式展開、改行文字を含めることができる)
a = "apple"
g = "grape"
o = "orange"
%W(#{a}, #{g}, #{o}) #=> ["apple,", "grape,", "orange"]
要素の変更・追加・削除
# インデックスを指定して要素を変更
a = [1, 2, 3]
a[1] = 20
a #=> [1, 20, 3]
# 存在するインデックスよりも大きいインデックスを指定した場合(間にはnilが入る)
a = [1, 2, 3]
a[5] = 6
a #=> [1, 2, 3, nil, nil, 6]
# <<で末尾に要素を追加できる
a = [1, 2, 3]
a << 4
a #=> [1, 2, 3, 4]
# 特定に位置の要素を削除(delete_at)
a = [1, 2, 3]
a.delete_at(2)
a #=> [1, 2]
配列を使った多重代入
a, b = [1, 2]
a #=> 1
b #=> 2
a, b = [1]
a #=> 1
b #=> nil
a, b = [1, 2, 3]
a #=> 1
b #=> 2
# 2は切り捨て
a, b, c = 1, [2, 3], 4
a #=> 1
b #=> [2, 3]
c #=> 4
a, *b, c, d = 1, 2, 3, 4, 5
a #=> 1
b #=> [2, 3]
c #=> 4
d #=> 5
配列の配列を使った多重代入
demension, i = [[10, 20], 0]
demension #=> [10, 20]
i #=> 0
(length, width), i = [[10, 20], 0]
length #=> 10
witdh #=> 20
i #=> 0
インデックス
a = [1, 2, 3]
a[0] #=> 1
a[1] #=> 2
a[-1] #=> 3
a[-2] #=> 2
和集合・差集合・積集合
# 和集合
a = [1, 2, 3]
b = [3, 4, 5]
a | b #=> [1, 2, 3, 4, 5]
# 差集合
a = [1, 2, 3]
b = [3, 4, 5]
a - b #=> [1, 2]
# 積集合
a = [1, 2, 3]
b = [3, 4, 5]
a & b #=> [3]
範囲
オブジェクトの作成
1..5
1...5
'a'..'e'
'a'...'e'
範囲を使った配列の作成
# to_aメソッドを使う
(1..5).to_a #=> [1, 2, 3, 4, 5]
(1...5).to_a #=> [1, 2, 3, 4]
('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
('a'...'e').to_a #=> ["a", "b", "c", "d"]
# splat演算子(*)を使う
[*1..5] #=> [1, 2, 3, 4, 5]
[*1...5] #=> [1, 2, 3, 4]
[*'a'..'e'] #=> ["a", "b", "c", "d", "e"]
[*'a'...'e'] #=> ["a", "b", "c", "d"]
始端や終端のない範囲オブジェクト
numbers = [1, 2, 3, 4, 5]
numbers[2..] #=> [3, 4, 5]
numbers[2..nil] #=> [3, 4, 5](nilでもいい)
numbers[..3] #=> [1, 2, 3, 4]
numbers[nil..3] #=> [1, 2, 3, 4](nilでもいい)
メソッド
可変長引数
# 引数を配列をして受け取れる
def greet(*names)
"#{names.join('と')}、こんにちは!"
end
greet('田中さん', '加藤さん') #=> "田中さんと加藤さん、こんにちは!"
ミュータブルとイミュータブル
いい記事があったので、これで。。。
繰り返し処理の制御
break(一番内側の処理を脱出)
breakについては、繰り返し処理からの脱出になる。
fruits = ["apple", "grape", "orange"]
numbers = [1, 2, 3]
fruits.each do |fruit|
numbers.shuffle.each do |n|
puts "#{fruit}, #{n}"
break if n == 3
end
end
#=>
apple, 2
apple, 3
grape, 1
grape, 3
orange, 2
orange, 3
throwとcatch(外側のループまで脱出)
fruits = ["apple", "grape", "orange"]
numbers = [1, 2, 3]
catch :done do
fruits.each do |fruit|
numbers.shuffle.each do |n|
puts "#{fruit}, #{n}"
if n == 3
throw :done
end
end
end
end
#=>
apple, 1
apple, 2
apple, 3
return(メソッドの脱出)
returnの場合は、繰り返し処理及びメソッドからの脱出になるので、注意する。
# breakの場合
def calc_with_break
numbers =[1, 2, 3, 4, 5, 6]
target = nil
numbers.shuffle.each do |n|
target = n
break if n.even?
end
target * 10
end
calc_with_break #=> 20
# returnの場合(nが2の時に処理を脱出して、さらにメソッドも脱出するから。。。)
def calc_with_break
numbers =[1, 2, 3, 4, 5, 6]
target = nil
numbers.shuffle.each do |n|
target = n
return if n.even?
end
target * 10
end
calc_with_break #=> nil
# ただただ繰り返しの箇所でreturnを呼ぶとエラーになる(あくまでメソッドの脱出用)
(1..3).each do |n|
puts n
return
end
# =>
1
(irb):271:in `block in <top (required)>': unexpected return (LocalJumpError)
next(繰り返し処理の次の処理に進む(一番内側の処理のみ))
numbers = [1, 2, 3, 4, 5]
numbers.each do |n|
next if n.even?
puts n
end
# =>
1
3
5
ハッシュ
オブジェクトの作成
{}
Hash.new([])
{ "japan" => "yen", "us" => "dollar", "india" => "rupee" }
{ japan: "yen", us: "dollar", india: "ruppe" }
要素の追加・変更・取得
# 追加
currencies = { "japan" => "yen", "us" => "dollar", "india" => "ruppe" }
currencies["italy"] = "euro"
currencies
#=> {"japan"=>"yen", "us"=>"dollar", "india"=>"ruppe", "italy"=>"euro"}
# 変更
currencies = { "japan" => "yen", "us" => "dollar", "india" => "ruppe" }
currencies["japan"] = "円"
currencies
#=> { "japan" => "円", "us" => "dollar", "india" => "ruppe" }
# 取得
currencies = { "japan" => "yen", "us" => "dollar", "india" => "ruppe" }
currencies["india"]
# => "ruppe"
繰り返し処理
# ブロックパラメータを2つで受け取る場合
currencies = { "japan" => "yen", "us" => "dollar", "india" => "ruppe" }
currencies.each do |key, value|
puts "#{key}, #{value}"
end
#=>
japan, yen
us, dollar
india, ruppe
# ブロックパラメータを1つで受け取る場合
currencies = { "japan" => "yen", "us" => "dollar", "india" => "ruppe" }
currencies.each do |key_value|
puts "#{key_value[0]}, #{key_value[1]}"
end
#=>
japan, yen
us, dollar
india, ruppe
ハッシュの展開
# ダブルスプラット演算子「**」を使って、ハッシュを展開できる
h = { us: "dollar", india: "rupee" }
{ japan: "yen", **h }
#=> {:japan=>"yen", :us=>"dollar", :india=>"rupee"}
擬似キーワード引数(変数 = {})
# 変数 = {}でハッシュの形で引数を受け取れる(何でも受け取れるので注意)
def buy_burger(menu, options = {})
drink = options[:drink]
potato = options[:potato]
puts "menu: #{menu}, drink: #{drink}, potato: #{potato}"
end
buy_burger("cheese", drink: true, potato: true)
#=> menu: cheese, drink: true, potato: true
任意のキーワードを受け取る引数(**変数)
def buy_burger(menu, **others)
puts others
end
buy_burger("cheese", drink: true, potato: true, chicken: false)
#=> {:drink=>true, :potato=>true, :chicken=>false}(ハッシュの形で値を受け取れる)
ハッシュから配列、配列からハッシュへ
# ハッシュから配列へ
currencies = { japan: "yen", us: "dollar", india: "rupee" }
currencies.to_a
#=>[[:japan, "yen"], [:us, "dollar"], [:india, "rupee"]]
# 配列からハッシュへ
currencies = [[:japan, "yen"], [:us, "dollar"], [:india, "rupee"]]
currencies.to_h
#=> { japan: "yen", us: "dollar", india: "rupee" }
シンボル
メリット
- 文字列っぽいので理解しやすい
- 内部的には整数なので、高速に値を比較できる
- 同じシンボルは同じオブジェクトなので、メモリの使用効率が良い
- イミュータブル(破壊的変更が不可)なので、勝手に値を変えられる心配がない。