Open5
プロを目指す人のためのRuby入門メモ
2章
ダブルクウォートとシングルクウォートの挙動の違い
ダブルクウォート | シングルクウォート |
---|---|
改行文字(\n)が改行として認識される | 改行文字(\n)がただの\nという文字列として認識される |
式展開が使える | 式典会が使えない |
演算子
- Rubyには前置/後置演算子がない
-+=
や-=
は使える
丸め誤差対策
-
Rational(有理数)
クラスを使う
(通常) 0.1 * 0.3 #=> 0.30000000000000004
(Rational使用) 0.1r * 0.3r #=> (3/10)
- 変数に値が入っている場合は、
rationalize
メソッドを呼ぶ
a = 0.1
b = 3.0
a.rationalize * b.rationalize #=> (3/10)
4章
配列に初期値を設定する場合の注意点
配列に初期値を設定する場合、第2引数に初期値を指定する方法と、ブロックで初期値を渡す方法で挙動が異なりうる(文字列などミュータブルな場合)
- 第2引数に初期値を指定する方法
a = Array.new(3, 'hoge')
a[0].upcase!
# 同じ文字列オブジェクトを参照するため、配列の要素すべて変更されてしまう
a #=> ["HOGE", "HOGE", "HOGE"]
- ブロックで初期値を渡す方法
a = Array.new(3) { 'hoge' }
a[0].upcase!
# 1番目の要素のみ変更される
puts a #=> ["HOGE", "hoge", "hoge"]
do...endと{}の結合度の違い
基本的には do...end
と {}
は書き換え可能だが、do...end
より {}
のほうが結合度が強い
- 以下の場合には、構文エラーになる
a = [1, 2, 3]
a.delete 5 { 'Not Found' } # 5 { 'Not Found' }と解釈され、5にブロックが渡せずエラー
- 解決版
a = [1, 2, 3]
a.delete(5) { 'Not Found' } # ()で囲む
5章
メソッドの引数にキーワード引数を使う
メソッドの引数が何を表しているかわかりづらいとき、キーワード引数
を使うと、何を表しているかわかりやすくなる
# わかりづらい例
def buy_coffee(menu, syrup, milk)
# コーヒーを購入
if syrup
# シロップをつける
end
if milk
# ミルクをつける
end
end
buy_coffee('black', true, false)
# わかりやすい例
def buy_coffee(menu, syrup: true, milk: true) # デフォルト値を指定しない場合は (menu, syrup:, milk:)
# コーヒーを購入
if syrup
# シロップをつける
end
if milk
# ミルクをつける
end
end
buy_coffee('black', syrup: true, milk: false)
# デフォルト値と同じ値を渡す場合省略可能
buy_coffee('black')
7章
privateメソッドはレシーバを指定できない
# 例1
class Person
private
def greet
"Hi!"
end
end
person = Person.new
person.greet
#=> レシーバ `person` を指定できないので `NoMethodError`
# 例2
class Person
def greet
"Hi, my name is #{self.name}!"
end
private
def name
'Bob'
end
end
person = Person.new
person.greet
#=> `greet` メソッド内で `self` というレシーバを指定して `name` メソッドを呼び出そうとしているため `NoMethodError`
privateメソッドはサブクラスでも呼び出せる
class Car
private
def name
'A great car'
end
end
class Taxi < Car
def to_s
"name: #{name}"
end
end
taxi = Taxi.new
taxi.to_s
#=> `to_s` メソッドの内部でスーパークラスのprivateメソッド `name` を呼び出しているがエラーにならない
※オーバーライドも可能
private
キーワードの下に書いてもprivateにならない
クラスメソッドは -
private
キーワードの下にクラスメソッドを書く場合、privateにならない
class Car
private
def self.name
'A great car'
end
end
Car.name #=> "A great car"
- クラスメソッドをprivateにしたいのであれば、
class << self
を使用する orprivate_class_method
を使う
# `class << self` を使用する場合
class Car
class << self
private
def name
'A great car'
end
end
end
Car.name #=> NoMethodError
# `private_class_method` を使用する場合
class Car
def self.name
'A great car'
end
private_class_method :name
end
Car.name #=> NoMethodError
protected
メソッド
protected
メソッドは、レシーバ付きで そのクラスとサブクラスから呼び出せる
※レシーバ付きで というところがprivateメソッドとのちがい
class Car
attr_reader :model
def initialize(model, speed)
@model = model
@speed = speed
end
def faster_than?(other_car)
other_car.speed < @speed
end
protected
def speed
@speed
end
end
ferrari = Car.new('Ferrari', 200)
lamborghini = Car.new('Lamborghini', 220)
# 同じクラスのインスタンスメソッド内であればspeedメソッドが呼び出せる
ferrari.faster_than?(lamborgini) #=> false
# クラス外部からspeedメソッドを呼び出すとエラー
ferrari.speed #=> NoMethodError
定数は再代入できてしまう
class User
DEFAULT_NAME = 'Taro'
# 再代入して定数の値を変更する
DEFAULT_NAME = 'Jiro'
end
# 再代入後の値が返る
puts User::DEFAULT_NAME # => "Jiro"
# クラス外部からでも再代入できる
User::DEFAULT_NAME = 'Saburo'
- 再代入を防ぎたい場合は
freeze
する必要がある
# クラスをfreeze
User.freeze
# クラス内でfreezeを呼ぶ
class User
DEFAULT_NAME = 'Taro'
freeze
end
User::DEFAULT_NAME = 'Shiro' # => RuntimeError
※ただし、定数を上書きする人はまずいないと見て、上記のようにクラスをfeeezeしたり、メソッド内でfreezeを呼ぶことはあまりない
- ミュータブルなオブジェクトで定数の値の変更を防ぐ方法
class User
NAME = 'Alice'.freeze
SOME_NAMES = ['Alice', 'Bob', 'Carol'].map(&:freeze).freeze
end
※真偽値や数値、シンボルなどはイミュータブルな値なので、このような対応は不要
比較メソッドのちがい
equal?
object_id
が等しい場合にtrueを返す
==
オブジェクトの内容が等しい場合にtrueを返す
eql?
ハッシュのキーとして2つのオブジェクトが等しい場合にtrueを返す
ダックタイピング
- オブジェクトのクラスがなんであろうと、そのメソッドが呼び出せればOKとするプログラミングスタイルのこと
- 「もしもそれがアヒルのように歩き、鳴くのであれば、それはアヒルである」という言葉に由来
def show_title(object)
puts "The title is <<#{object.title}>>"
end
class Movie
def title
'A great movie'
end
end
class Book
def title
'A great book'
end
end
# MovieとBookは無関係なクラスだが、show_titleメソッドはクラスを気にせず使える
movie = Movie.new
show_title(movie) #=> A great movie
book = Book.new
show_title(book) #=> A great book
Rubyにオーバーロードはない
- 1つのメソッドで、可変長引数をとったり、内部でデータ型を変換することで様々なデータ型を受け取ったりすることができるため、オーバーロードの概念がない
8章
- トップレベルのモジュールやクラスを指定したいときは、クラス名やモジュール名の前に
::
をつけると名前の衝突を回避できる
class Work
def initialize(company, working_hours)
@company = company
@working_hours = working_hours
end
end
module Art
class Work
def initialize(title)
@title = title
@work_for_company = ::Work.new('Company name', 8) # トップレベルのWorkクラスを参照できる
end
end
end