Ruby 個人的メモ
=begin
と =end
を使ったコメントの書き方
Ruby では =begin
と =end
を使ってコメントを書くことができる。ただし RuboCop では非推奨とされている。
# bad =begin Multiple lines of comments... =end # good # Multiple lines # of comments...
この書き方だと、=begin
と =end
の前に空白を入れることができない。
また、このような形式は埋め込みドキュメントというらしい。
整数と小数の計算
-
Integer
同士の計算では結果はInteger
になる -
Float
同士の計算では結果はFloat
になる -
Integer
とFloat
の計算では結果はFloat
になる
というのは周知の事実かと思う。このあたりがRubyのリファレンスにどのように書かれているか気になったので調べてみたところ、
-
Float
に対する計算の結果はFloat
-
Integer
に対する計算の結果はNumeric
となっていた。
self * other -> Float
self * other -> Numeric
ファイルを読み込んで各行を出力するスクリプト
File.open('sample.txt') do |file|
file.each_line do |line|
p line
end
end
FloatをRationalに変換する
0.1r
# => (1/10)
0.1.rationalize
# => (1/10)
0.1.to_r
# => (3602879701896397/36028797018963968) 分母は2^55
0.9999999999999999r
# => (9999999999999999/10000000000000000)
0.9999999999999999.rationalize
# => (6004799503160661/6004799503160662)
0.9999999999999999.to_r
# => (9007199254740991/9007199254740992) 分母は2^53
3つ全てが同じRationalを返すわけではない。
Float#to_rはコンピュータが内部的にもっている2進数を有理数に変換するっぽい。Rubyでfalsyなもの
基本はnil
とfalse
のみがfalsy
[-1, 0, 1, '', ' ', [], {}, true, false, nil].each { |val| p val unless val }
# false
# nil
empty?
を使うと空文字列や空配列などをfalsy判定できる
['', ' ', [], {}].each { |val| p val if val.empty? }
# ""
# []
# {}
empty?
メソッドを使えるのは他にもありそう
blank?
を使うとfalse
、nil
、empty
なオブジェクト、空白のみで構成される文字列をfalsy判定できる
require 'active_support'
require 'active_support/core_ext'
[-1, 0, 1, '', ' ', [], {}, true, false, nil].each { |val| p val if val.blank? }
# ""
# " "
# []
# {}
# false
# nil
%記法でリテラルを作る
バックスラッシュ記法と式展開が有効なものとそうでないものがある。開き括弧と閉じ括弧の部分には空白、改行を含む任意の非英数字を使うことができる。ただし括弧を使うときは対応する開き括弧と閉じ括弧で囲む必要がある。
var = 'a b'
# 文字列
%(#{var}\sc) # => "a b c"
%q(#{var}\sc) # => "\#{var}\\sc"
%Q(#{var}\sc) # => "a b c"
# コマンド出力
%x(echo #{var}\sc) # => "a b c\n"
# 正規表現
%r{#{var}\sc} # => /a b\sc/
# 文字列の配列
%w[#{var} c\s \ d] # => ["\#{var}", "c\\s", " d"]
%W[#{var} c\s \ d] # => ["a b", "c ", " d"]
# シンボル
%s(#{var}\sc) # => :"\#{var}\\sc"
# シンボルの配列
%i[#{var} c\s \ d e] # => [:"\#{var}", :"c\\s", :" d", :e]
%I[#{var} c\s \ d e] # => [:"a b", :"c ", :" d", :e]
ヒアドキュメント (行指向文字列リテラル)
def print_text
text = <<TEXT
abc
def
TEXT
p text
end
print_text
# => " abc\n def\n"
# 終端行のインデントが無視される
def print_text
text = <<-TEXT
abc
def
TEXT
p text
end
print_text
# => " abc\n def\n"
# 最もインデントが少ない行を基準にして、全ての行の先頭から空白を取り除く
def print_text
text = <<~TEXT
abc
def
TEXT
p text
end
print_text
# => "abc\n def\n"
TEXT
の部分(識別子)は自由に付けられる。<<識別子
は1つの式(値を返すもの)であり、以下のような書き方ができる。
<<TEXT.upcase
hoge
TEXT
# => "HOGE\n"
'foo'.concat(<<TEXT1, <<TEXT2)
bar
TEXT1
baz
TEXT2
# => "foobar\nbaz\n"
ヒアドキュメント内では式展開、バックスラッシュ記法が有効である。識別子を"
、'
、`
で囲むと対応する文字列リテラルと同じ扱いになる。
case文における比較
上から順番に、when の直後の式を評価した結果をレシーバ、 case の直後の式を評価した値を引数として === 演算子を呼び出し、最初に真を返した when 節の本体を実行します。
self === other
は、「self
の表す集合がother
を含んでいるか」というイメージ。
Module#===
は次のようなときに使える。
String === 'str'
# => true
左辺のString
はClassクラスのインスタンスで、===
はClassクラスが継承しているModuleクラスのインスタンスメソッドである。
インスタンス変数
インスタンス内で共有される変数。
class User
def initialize(name)
@name = name
end
def greet
"Hello, my name is #{@name}"
end
end
user = User.new('Alice')
user.greet
# => "Hello, my name is Alice"
存在しないインスタンス変数を参照してもエラーにならず、nil
として扱われる。
class User
def initialize(name)
# @name = name
end
def greet
"Hello, my name is #{@name}"
end
end
user = User.new('Alice')
user.greet
# => "Hello, my name is "
インスタンス変数をクラスの外部からは参照することはできない。
class User
def initialize(name)
@name = name
end
end
user = User.new('Alice')
user.name
# => undefined method `name' for an instance of User (NoMethodError)
参照するには読み取りメソッドが必要になる。
class User
def initialize(name)
@name = name
end
def name
@name
end
end
user = User.new('Alice')
user.name
# => "Alice"
attr_reader
を使うと読み取りメソッドの定義を省略できる。
class User
attr_reader :name
def initialize(name)
@name = name
end
end
user = User.new('Alice')
user.name
# => "Alice"
また、インスタンス変数を外部から変更することはできない。
class User
def initialize(name)
@name = name
end
end
user = User.new('Alice')
user.name = 'Bob'
# => undefined method `name=' for an instance of User (NoMethodError)
変更するには書き込みメソッドが必要になる。
class User
def initialize(name)
@name = name
end
def name=(value)
@name = value
end
end
user = User.new('Alice')
user.name = 'Bob'
# => "Bob"
attr_writer
を使うと書き込みメソッドの定義を省略できる。
class User
attr_writer :name
def initialize(name)
@name = name
end
end
user = User.new('Alice')
user.name = 'Bob'
# => "Bob"
attr_accessor
を使うと読み取りメソッドと書き込みメソッドの両方が定義される。
class User
attr_accessor :name
def initialize(name)
@name = name
end
end
user = User.new('Alice')
user.name = 'Bob'
user.name
# => "Bob"
クラスメソッドの定義の仕方
Rubyにおけるクラスメソッドとはクラスの特異メソッドである。
そもそも特異メソッドとはある特定のオブジェクトに固有のメソッドであり、次のように定義することができる。
class Person; end
alice = Person.new
def alice.hello
'hello'
end
alice.hello
# => "hello"
bob = Person.new
bob.hello
# => undefined method `hello' for an instance of Person (NoMethodError)
特異メソッドを定義すると、そのメソッドを定義したオブジェクトのみが属する、特異クラスと呼ばれるクラスが内部的に作成され、そのクラスにメソッドが追加される。次のように特異クラスを作成することで、特異メソッドを定義することもできる。
class << alice
def hello
'hello'
end
end
alice.hello
# => "hello"
最初に述べた通り、Rubyにおけるクラスメソッドとは、クラスというオブジェクトに対して定義された特異メソッドである。したがってクラスメソッドは次のように定義できる。
class Person; end
# 特異メソッド方式
def Person.create_people(num)
Array.new(num) { Person.new }
end
Person.create_people(3)
# => [#<Person:0x0000ffff9889ec00>, #<Person:0x0000ffff9889ebd8>, #<Person:0x0000ffff9889ebb0>]
# 特異クラス方式
class << Person
def create_people(num)
Array.new(num) { Person.new }
end
end
Person.create_people(3)
# => [#<Person:0x0000ffff7328a3e8>, #<Person:0x0000ffff7328a348>, #<Person:0x0000ffff7328a2d0>]
クラスの定義の中でself
がそのクラス自身を表すことを用いると、上のコードは次のようにも書ける。
# 特異メソッド方式
class Person
def self.create_people(num)
Array.new(num) { Person.new }
end
end
# 特異クラス方式
class Person
class << self
def create_people(num)
Array.new(num) { Person.new }
end
end
end
特異クラス方式の書き方はクラスメソッドを複数定義するときに便利である。
Object#send を使うとプライベートメソッドを呼び出せる
class Klass
private
def greet
puts 'Hello'
end
end
Klass.new.greet
# private method `greet' called for an instance of Klass (NoMethodError)
Klass.new.send(:greet)
# Hello