Rubyまとめ
Rubyまとめ
基礎知識
- 以下のように、戻り値の一部を捨てることができる。
def test_method
[10, 20]
end
a, _b = test_method
-
/
: エスケープ処理(後の記号の意味をなくしてただの文字列とする) -
1_000_000_000
と書けば_
は無視される -
&&の優先順位は||より高い
丸め誤差
以下は左項が0.3000~04と丸め誤差があるため、等しくならない。
0.1 * 3 == 0.3 #=>false
そのため、以下のように有理数に変換する必要がある。
0.1r * 3r == 0.3 #=>true
また、メソッドはrationalize
である。
文字列
%! 文字列!
でエスケープが必要なく!
で文字列を作れる
複数行に渡る時は以下のようにヒアドキュメントを使用する。
str = <<識別子(TEXTなど大文字)
文字列
文字列
識別子
<<-
を使うと最後の識別子をインデントさせることができる。
sprintf('%0.3f',1.2)#=>"1.200"
というふうにsprintfで表示できる。
数値
- 基数指示子
基数指示子 | 内容 |
---|---|
0b | 2進数 |
0o | 8進数 |
0x | 16進数 |
- ビット演算
記号 | 内容 |
---|---|
& | ビットごとのAND |
| | ビットごとのOR |
^ | ビットごとのXOR |
>> | 右ビットシフト |
<< | 左ビットシフト |
~ | ビットごとのNOT |
- 指数表現
2e-3 #=>0.002
1 && nil && 3 # => nil
のように左から評価していき、式全体の真偽値が確定した時点で評価を終了する(短絡評価、ショートサーキット)
演算子の優先順位!
>&&
>||
>not
>and, or
and, or
は制御フローを扱うのに向いている
if文
条件演算子を用いた条件 ? trueの時の実行処理 : falseの時の実行処理
メソッド
-
?
で終わるメソッドは慣習として真偽値を返すメソッド -
!
で終わるメソッドは危険を意味する(破壊的メソッドなど) - エンドレスメソッド(1行でメソッドを書ける)
def メソッド名(引数) = 処理
- エイリアスメソッド: 同じメソッドに複数の名前が付いている
pp
pp 表示したい内容
:配列の内容を見やすく整形して出力する
Minitest
Minitestを使ったテストコードの基本系
require'minitest/autorun'
require_relative 'ファイル名'
class SampleTest < Minitest::Test
def test_sample
assert_equal A, B
end
end
検証メソッド
# aがbと等しければパスする
assert_equal b,a
# aが真であればパスする
assert a
# aが偽であればパスする
refute a
配列
a,b = [1, 2] # =>a = 1, b = 2
: 多重代入が可能
a[1, 3]
: 2つ目の要素から3つ分の要素を取り出す
配列のメソッド
-
<<
: 配列の最後に要素を追加 -
delete_at(要素番号)
: 要素番号に該当する要素の削除 -
delete(要素)
: 要素に等しい要素の削除 -
delete_if
: 以下のようにブロックの戻り値が真の要素を削除
a.delete_if do |n|
n.odd?
end
-
values_at(0, 2, 4): 0,2,4の要素を取得する
-
push
と<<
の違いはpushは引数に複数の値を入れることができる -
delete: 指定した値に一致する要素を削除
-
concat: 破壊的に配列を連結する(非推奨)
-
|、-、&はそれぞれ和集合、差集合、積集合を求めることができる
-
*
を前につけて残り全要素を配列として受け取る(途中に使ってもいいa, *b, c
)
a, *b = 1, 2, 3
p b #=> [2, 3]
-
*
だけで残りの配列を無視する
a, * = 1, 2, 3
-
*
(splat演算子)を配列の前につけることで配列が展開される
a = [1]
b = [2, 3]
a.push(*b) #=>[1, 2, 3]
[1, *b] #=>[1, 2, 3]
- 引数の前に
*
をつけることで可変長引数(rest引数)にできる
defgreet(*names)
"#{names.join('と')}、こんにちは!"
end
greet('田中さん') #=> "田中さん、こんにちは!"
greet('田中さん','鈴木さん') #=> "田中さんと鈴木さん、こんにちは!"
- %記法
%w(a b c) #=>["a", "b", "c"]
スペースあり
%w(a\ b c) #=>["a b", "c"]
式展開
a = "A"
%W(#{a} b\n c) #=>["A" "b\n", "c"]
文字列を配列に変換
-
cahrs
: 一文字ずつ配列に入れる
Ruby.chars #=> ["R", "u", "b", "y"]
-
split
: 区切り文字で配列に入れる
'R,u,b,y'.split #=> ["R", "u", "b", "y"]
デフォルト値
以下のようにデフォルト値を決めることができる。
Array.new(10){ |n| n%3 + 1 } #=> [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
※第二引数で決めてしまうと、同じものを参照しているので事故が起こりやすい。
ブロックでデフォルト値を決めるように
ブロック
- map/collect: 各要素に対してブロックを評価した結果を新しい配列にして返す。
空の配列を用意して、ほかの配列をループ処理した結果を空の配列に詰め込んでいくような処理の大半は、mapメソッドに置き換えることができる - select/find_all: 各要素に対してブロックを評価し、その戻り値が真の要素を集めた配列を返す
even_numbers = numbers.select { |n| n.even? }
- reject: ブロックの戻り値が真になった要素を除外した配列を返す
- find/detect: ブロックの戻り値が真になった最初の要素を返す
- sum: 要素の合計を出す
- sum(初期値)で初期値をオフセットしてタスことができる
- 先頭の文字列を与えて、文字列を連結することができる
以下のようにブロックにも使える
[r, g, b].sum('#') do |n|
n.to_s(16).rjust(2, '0')
end
以下の場合、&とシンボルで書くことができる
- ブロックパラメータが1個だけである
- ブロックの中で呼び出すメソッドには引数がない
- ブロックの中では、ブロックパラメータに対してメソッドを1回呼び出す以外の処理がない
['a', 'b', 'c'].map { |s| s.upcase }
# ↓
['a', 'b', 'c'].map(&:upcase)
-
map.with_index{ |obj, i| "#{i}: #{obj}" }
のように、each以外でindexを取れる(引数があると、その数からindexが始まる) -
以下のように、複数の要素をブロックに渡すことができる
[[1, 2],[3, 4]].each do | a, b |
a + b
end #=> [3, 7]
[[1, 2],[3, 4]].each do | (a, b), i |
a + b + i
end #=> [3, 8]
-
_1
,_2
など、ブロックパラメータの番号をそのままパラメータとして使える(使うかどうかは要検討)
[[1, 2], [10, 20], [100, 200]].each{ _1+_2 } #=> [3, 30, 300]
-
open
メソッドにもブロックは使える
Range
-
..
以内 -
...
以上、未満
()で囲まないと優先順位が低いので注意
以下のように配列の要素を範囲指定できる
a = [1, 2, 3, 4, 5]
a[1..3] #=> [2, 3, 4]
- include?: 基本的に離散値を扱い(Rangeが数値の時は別)、それぞれの要素に対して==で範囲内か判定している(だから、処理が遅い?)。
- cover?: 連続値を扱い、始点と終端に対して<=>で範囲内か判定する
増減を決める
-
n.upto(m)
: nからmまで数値を1つずつ増やす
a=[]
10.upto(12) {|n| a<<n}
a #=> [10, 11, 12]
-
n.downto(m)
: nからmまで数値を1つずつ減らす -
step(間隔): 値を増やす間隔を指定できる
(1..10).step(2) { |n| numbers << n }
-
開始値.step(上限値, 一度に増減する大きさ)
: 開始値から上限値まで増減する大きさを決められる
繰り返し処理
-
while
は1行で書くと
a = []
a <<1 while a.size < 5
- 必ず、1回は実行する時
begin
処理
end while false
-
unitl: 条件が偽である間処理を繰り返す
-
for文: 基本的にはeachを使う
for 変数 in 配列やハッシュ
処理
end
- loop: 無限ループ
繰り返し処理の制御
- 入れ子のループ構造の一番外側まで脱出したい
catch タグ do
処理
throw タグ 戻り値
end
- redo`: 現在の繰り返し処理の先頭に戻る
無限ループを生まないように、上限回数を決めておくこと
シンボル
シンボル特徴:
・表面上は文字列っぽいので、プログラマにとって理解しやすい。
・内部的には整数なので、コンピュータは高速に値を比較できる。
・同じシンボルは同じオブジェクトであるため、メモリの使用効率が良い。
・イミュータブルなので、勝手に値を変えられる心配がない。
ハッシュ
-
delete
: 指定したキーに対応する要素を削除 -
メソッドのキーワード引数
def メソッド名(キーワード引数1: デフォルト値1, キーワード引数2: デフォルト値2)
end
-
**をハッシュの前につけるとハッシュの要素を展開できる
merge
メソッドも同様 -
**引数で任意のキーワードを受け付ける
def メソッド名(key1: value1, key2: value2, **others)
end
- メソッドへの引数の前に**をつけることで、ハッシュを明示的にキーワード引数に変換する
メソッド名(**hash)
- ハッシュにデフォルト値を設定する
Hash.new { |hash,key| hash[key] = デフォルト値 }
正規表現
文字クラス: 文字の集合を表す
量指定子: 文字量を指定
文字列 =~ /正規表現/
$~ # MachDataオブジェクトを取得
$& # マッチした部分全体を取得
$1 # 1番目のキャプチャを取得
$+ # 最後のキャプチャ文字を取得
-
{n,m}
: 直前の文字が n 個以上、m 個以下 -
[a-z]
: aからzのいずれか -
[AB]
: AまたはBが1文字 -
?
: 直前の文字が1個、または無し -
.
: 任意の1文字 -
+
: 直前の文字が1個以上(「貪欲」で最長マッチを返す) -
*
: 直前の文字が0個以上(「貪欲」で最長マッチを返す) - *? や +? にすると、最短マッチを返す
-
( )
: マッチする部分をキャプチャ(捕捉)and グループ化 - キャプチャした部分は置換するときに $1 や \1 で参照できる
-
?:
をつけるとキャプチャなし -
\w
: 英単語を構成する文字(半角英数字とアンダースコア) -
[^AB]
: AでもなくBでもない任意の1文字 -
^
: 行頭を表す -
$
: 行末を表す -
\t
: タブ文字を表す -
\n
: 改行文字を表す -
\s
: 空白文字(スペース、タブ文字、改行文字等)を表す -
ABC|DEF
: 「文字列ABCまたは文字列DEF」のOR条件を表す -
^
:^文字
で行頭の意味になったり、[^ ]
で否定の文字クラスの意味になったりする -
\b
: 単語の境界を表す -
(?=abc)
: 「abcという文字列の直前の位置」を表す(先読み) -
(?<=abc)
: 「abcという文字列の直後の位置」を表す(後読み) -
(?!abc)
: 「abcという文字列以外の直前の位置」を表す(否定の先読み) -
(?<!abc)
: 「abcという文字列以外の直後の位置」を表す(否定の後読み) - キャプチャした文字列は正規表現内でも
\1
や\2
といった連番で参照できる(後方参照) -
?
や*
、+
といった量指定子は( )
の後ろに付けることもできる -
|
を使ったOR条件では、各条件内でもメタ文字が使える - メタ文字はバックスラッシュ
\
でエスケープする -
{n,}
や{,n}
はそれぞれ「直前の文字がn個以上」「n個以下」の意味になる -
\W
、\S
、\D
、\B
はそれぞれ\w
、\s
、\d
、\b
の逆の意味になる
=~
: マッチすれば真、しなければ偽
!~
: 上記と逆
キャプチャに名前をつける
-
(?<名前>)
: キャプチャに名前をつける
m = /(?<name>)/.match(text)
#以下は全て同じ
m[:name]
m['name']
m[0]
- キャプチャの名前をローカル変数に割り当てる
/(?<name>)/ =~ text
puts name
ただし、正規表現と対象の文字列を逆にすることはできない
また、正規表現を代入した時にも使えない
便利なStringクラスメソッド
-
scan
: 引数で渡した正規表現にマッチする部分を配列に入れて返す
()
があるとキャプチャを二次元配列として、グループ化する -
[]
,slice
,slice!
: 正規表現を渡すと、文字列から正規表現にマッチした部分を抜き出す
text = 'sample123-4567'
text[/\d{3}-\d{4}/] #=> "123-4567"
text[/(\d{3})-(\d{4})/, 2] #=> "4567"
text[/(?<left_num>\d{3})-(?<right_num>\d{4})/, 'right_num'] #=> "4567"
-
split
: マッチした文字列を区切り文字にして文字列を分解し、配列として返す -
gsub
,gsub!
: 第1引数の正規表現にマッチした文字列を第2引数の文字列で置換
置換対応をハッシュで指定可能
text = '1,2-3'
hash = { ',' => ':', '-' => '/' }
text.gsub(/,|-/, hash) #=> "1:2/3"
文字列番号で参照(''
で囲むことに注意)
text.gsub(/(\d),(\d)-(\d)/, '\1-\2-\3') #=> "1-2-3"
名前付きキャプチャ
text.gsub(/(?<first>\d),(?<second>\d)-(?<third>\d)/, '\k<first>-\k<third>') #=> "1-3"
text.gsub(/(?<first>\d),(?<second>\d)-(?<third>\d)/) do
"#{$~[:first]}-#{$~[:third]}"
end
# => "1-3"
クラス
属性(アトリビュート): オブジェクトから取得できる値
継承
継承の関係は「スーパークラスはクラスである」またはその逆が言えるかどうかで考える。
class Product
attr_reader :name, :price
def initialize(name, price)
@name = name
@price = price
end
end
class DVD <Product
attr_reader running_time
def initialize(name, price, running_time)
super(name, price) # superでもいい
@running_time = runnning_time
end
end
クラスメソッドをprivateにするには
class << self
end
定数を外部から参照するにはクラス名::定数名
とする。
モジュール
クラスを超えて、同じメソッドを使用する
include メソッド名
: クラスでモジュールのメソッドを呼び出す。
ミックスイン: にモジュールをクラスにincludeして機能を追加すること
クラス内でしか使わないのであれば、privateにする
特異メソッド: 特定のオブジェクトにだけ紐付くメソッドのこと
extend
: モジュールのメソッドを特異メソッド(クラスメソッド)とする
名前空間
モジュール構文の中にクラス定義を書くと「そのモジュールに属するクラス」という意味になるため、同名のクラスがあっても外側のモジュール名さえ異なっていれば名前の衝突は発生しなくなる
モジュール名::クラス名
でモジュールに属するクラスを呼び出す
::クラス名
: (左側には何もなし)トップレベルの同一名のクラスを呼び出す
関数や定数を提供
module_function
: ミックスインおよび特異メソッド(モジュール関数)として使用可能にする
状態を保持する
インスタンス変数を作成し値を保持する
yieldとProc
yield
yield
: メソッド内で渡されたブロックを実行する
引数の前に&
をつけることで、ブロックを引数とする(一番最後にすること)。ブロックを実行する場合はcall
メソッドを使用する。
def メソッド(&引数)
引数.call
end
Prco
Procオブジェクト: ブロックなどの処理をオブジェクトとして扱う
パターンマッチ
case 式
in パターン
else
end
asパターン
case {key1: value1, key2: value2}
in {key1: String => var1, key2: 18.. => var2}
in {key1: String, key2: 18.. } => var
end
alternativeパターン
|
で繋ぎどれか一つにマッチしたらマッチしたとみなす
自作クラスをマッチさせる
- arrayパターン
def deconstruct
[@x, @y]
end
- hashパターン
def deconstruct_key
[@x, @y]
end
デバッグ技法
tap
: メソッドチェーンを調べる
logger.debug
: ログにデバッグ情報を出力する
その他
-W:deprecated
オプションをつけて実行すると警告が出力される
Rake
以下をrake タスク名
で実行できる。
task :タスク名 do
end
書き方
- nilガード
X ||= A
X ||= begin
代入処理
end
Xがnilまたはfalseなら、AをXに代入
- 必ず真偽値を返す方法
!!true #=> true
!!1 #=> true
!!false #=> false
!!nil #=> false
Discussion