こんにちは、のりにぃです!
この記事では、Rubyの各クラスごとのメソッドや特徴を紹介しています。
Ruby Silberで頻出のメソッドもまとめていますので、ぜひ活用ください。
Hashクラス
Hashオブジェクトの生成
空のHashオブジェクトを生成するにはHash({}), {}, Hash.newのいずれかを用います。
Hash({})
=> {}
Hash#to_h
Hash#to_hは2次元配列からハッシュを生成します。
[[key, value]].to_hの場合{key => value}になる認識です。
[[1, "data 1"], [2, "data 2"]].to_h
=> {1=>"data 1", 2=>"data 2"}
Hash#to_a
Hash#to_aはキーと値の2要素の配列を並べた配列を作成し、返します。
h = {a: 100, b: 200, c: 300}
p h.to_a
# 出力結果
[[:a, 100], [:b, 200], [:c, 300]]
Hash#key
Hash#keyメソッドは引数を1つ取ります。返却値は引数に合った値を持つキーです。 もし引数の値を持つキーがなければ、nilを返します。
hash = {name: "taro", birth_day: "2022/01/1"}
hash.key("taro") # => :name
hash.key("hanako") # => nil
キーの上書き
ハッシュはキーが同じものがあれば、右側で定義されたもので上書きされます。
次の例ですと、キーaの値は200で上書きされます。
hash = {a: 100, a: 200}
p hash
# 出力結果
=> {:a=>200}
values_atとvaluesの違い
Hash#valuesメソッドは、引数を取らずHashのvalueを集めた配列を返します。
対してHash#values_atメソッドは、可変長引数を取ります。返却値は引数に指定したキーの値を集めた配列です。
以下は両者とも同じ結果が返ります。
hash = {name: "taro", birth_day: "2022/01/1"}
hash.values # => ["taro", "2022/01/1"]
hash.values_at(:name, :birth_day) # => ["taro", "2022/01/1"]
Hashクラス破壊的メソッド一覧
Hashクラスには以下の破壊的メソッドが存在しています。
破壊的メソッドとは、これらのメソッドを要素に対して使用すると、要素自身の構造を変えてしまうものです。
| メソッド | 説明 |
|---|---|
| []= | キーに対応する値を置き換えます。 |
| delete | キーを削除します。 |
| reject! | キーと値を引数としてブロックで評価した結果が真である要素を削除します。 |
| delete_if | reject!の別名です。 |
| replace | ハッシュの内容を引数の内容で置き換えます。 |
| shift | ハッシュからキーが追加された順番で要素を取り除きます。取り除いた要素は [key, value]形式の配列で返します。 |
| merge! | selfと引数のハッシュの内容をマージします。 |
| update | merge!の別名です。 |
| clear | ハッシュの中身を空にします。 |
例えばclearメソッドで考えてみましょう。
以下のコードを実行すると、空のhash {}が返ります。これこそが破壊的メソッドの効果です。
h = {a: 1, b: 2}
h.clear
p h
=> {}
eachメソッド
Hash#eachのブロックパラメータはArrayで渡されます。
以下のコードで考えてみましょう。
h = {a: 100, b: 200}
h.each {|p|
p p
}
# 出力結果
[:a, 100]
[:b, 200]
このように、hashをeachで繰り返し処理を行う場合は、配列として渡されることがポイントです。
Arrayクラス
Array#slice
sliceメソッドは指定された自身の要素を返します。array[0]と同じ意味を持ちます。
p [0, 1, 2].slice(1) #=> 1 a = [1,2,3,4] p a.slice(2,1) #=> 3 0番目から始まり2番目から1個目の要素を取得
sortメソッド
sortメソッドは配列の要素を並び替えたい時に使用します。
要素の並び替えは<=>演算子によって行われます。
(要素1 <=> 要素2)の結果が-1なら要素1が順番として先に並び、0ならそのまま、1なら要素2が先に並びます。
また<=>演算子で比較できない要素があると例外ArgumentErrorが発生します。
比較できない例としては数字 <=> 文字列といったパターンです。
Stringクラス
eql?, equal?, ==の使い分け
処理自体はシンプルですが、「あれ、eql?が同値だっけ?同一性だっけ?」となりがちですのでまとめておきます。
eql?と==は同値性
同値性とは、比較対象が同一文字列の場合にtrueを返します。
eql?と==が当てはまり、String#==(other)はotherが文字列の場合は、String#eql?と同じ結果を返します。
a = "abc" b = 'abc' print a.eql? b print a == b # 出力結果 true true
equal?は同一性
equal?は、内部的にObject#equal? が呼び出されており、レシーバと引数のオブジェクトIDを比較し同一性を検証します。
そのためStiringクラスではありません。
Rubyでは全てがオブジェクトとして扱われるため以下の例のように同じリテラルでもオブジェクトIDは異なります。
# 実行環境によってidは異なります
String.new.object_id # => 70135176141780
String.new.object_id # => 70135176158660
そのため以下のようにeql?ではtrueでもequal?ではfalseになります。オブジェクトIDが異なるためです。
str1 = "a" str2 = "a" # 同じ文字列を代入してもオブジェクトIDは異なる str1.object_id = 320 str2.object_id = 340 str1.eql?(str2) # => true str1.equal?(str2) # => false
String#%
String#%はフォーマットされた文字列を返します。
"%d"や%sが指示子と言われ、引数の値で置き換わります。(詳しい説明はRubyリファレンスを参照してください。)
例えば、以下のコードを実行すると"%d"が10進数表現で1に置き換わります。
"Hello%d" % 1 => "Hello1"
chop、chomp、strip、strip!のそれぞれの特徴
Stringクラスには改行や文字列を取り除くメソッドが複数あるため説明を以下にまとめます。
| メソッド名 | 説明 |
|---|---|
| chop | 末尾の文字を取り除きます。ただし、文字列の末尾が"\r\n"であれば、2文字とも取り除きます。 |
| chomp | 末尾から改行コードを取り除きます。 |
| strip | 文字列の先頭と末尾の空白文字(\t\r\n\f\v)を取り除きます。 |
| strip! | 文字列の先頭と末尾の空白文字(\t\r\n\f\v)を破壊的に取り除きます。 |
ただし破壊的メソッドではないので、selfは影響を受けません。
str = "Ruby \r\n" str.chop p str # 出力結果 "Ruby \r\n"
String#delete
deleteメソッドは引数に指定した文字を削除します。
ただし非破壊的メソッドであることに注意しましょう。
なお、ArrayクラスとHashクラスのdelete、Stringクラスのdelete!は破壊的メソッドになります。
s = "1234567890"
#非破壊的
s.delete("^1-5") # => "12345"
p s # => "1234567890"
# 破壊的
s.delete!("1-5")
p s # => "67890"
String#sub
subメソッドは第一引数の検索対象のパターンと、第二引数の置換後の文字列を使って1回だけレシーバーの文字列を置換します。
p "Hi, I love Ruby.".sub(/[A-Z]/, "*") # "*i, I love Ruby."と表示される
あくまで全ての文字列ではなく、pattern にマッチした最初の部分をreplaceしている点がポイントです。
String#gsub
gsubメソッドはマッチしたすべての部分を置換します。subメソッドは最初の1回だけに対して、gsubは全てであることに注意しましょう。
a = "abc-abc" a.gsub(/abc/, "*") => "*-*"
ちなみに、subはsubstitutionで置換という意味を持ち、gsubはglobal substitutionで全てを置換の意味になります。
正確な英語の名称を覚えると忘れにくくなりますね。
String#split
String#splitはselfの文字列を分割するメソッドです。
分割の際は、正規表現と文字列型で表現することができます。
str = "1;2;3;4"
str.split(";")
=> ["1", "2", "3", "4"]
str.split(/;/)
=> ["1", "2", "3", "4"]
Dirクラス、Fileクラス、IOクラス
Dirクラス
Dirクラスはディレクトリの移動や作成、ディレクトリ内のファイル一覧の取得などディレクトリを扱うクラスです。
| メソッド | 意味 |
|---|---|
| pwd / getwd | ディレクトリの取得 |
| chdir | ディレクトリの移動 |
| mkdir | ディレクトリの新規作成 |
| rmdir / unlink / delete | ディレクトリの削除 |
Fileクラス
Fileクラスはファイルの読み取りや書き込み、新規作成、削除などファイルを扱うクラスです。
ファイルを開くにはFile.openメソッドもしくはFile.newメソッドを利用します。
内容を取得には、readメソッド、ファイルを閉じる場合にはcloseメソッドです。
File.open('README.md').read
=> "# READMEの内容が出力される\n"
File.open('README.md').close
=> nil
ファイルのモード
File.openメソッドの第2引数にファイルを開くモードを指定できます。
| 文字列 | 意味 |
|---|---|
| “r” | 読み込みモード |
| “w” | 書き込みモード。既存ファイルの場合はファイルの中身を空にする。 |
| “a” | 追記モード。常にファイルの末尾に追加される。 |
| “r+” | 読み書きモード。ファイルの読み書きの位置が先頭になる。 |
| “w+” | 読み書きモード。”r+”と同じだが既存ファイルの場合はファイルを空にする。 |
| “a+” | 読み書きモード。ファイルの読み込み位置は先頭に、書き込み位置は常に末尾になる。 |
IOクラス
IOクラスはDileクラスのスーパークラスで、ファイルのプロセスなどとの入出力を扱うクラスです。
Fileクラスの動作確認をしたい方はこちらの記事が参考になりました。
例外
Rubyにおいて頻繁に利用される例外,raiseは例外を発生させます。
第1引数に発生させる例外クラスを指定でき、第2引数にはメッセージを指定できます。第1引数には例外クラスのインスタンスを指定することもできます。
引数は省略可能で例外クラスの指定を省略した場合はRuntimeErrorが発生します。
rescue節は、例外クラスを指定しない場合StandardErrorとそのサブクラスが補足対象となり、補足する例外を指定することで指定した例外とそのサブクラスのみを補足します。
実際にコードを見てみましょう。
begin raise # 引数を指定していないのでRuntimeErrorが発生します。 rescue StandardError => e puts e.class # => RuntimeError puts e.message # => 空文字 end
Integerクラス
odd?とeven?
Inetger#odd?は奇数であればtrue、そうでなければfalseを返します。
Inetger#even?は偶数であればtrue、そうでなければfalseを返します。
3.odd? => true 3.even? => false
数値
数値リテラル
基数指示子を指定することで、何進数で解釈させるかを指定できます。一覧は以下の通りです。
| 進数 | 基数指示子 | 使用可能文字列 | 例 |
|---|---|---|---|
| 2進数(binary) | 0b | 0と1 | 0b10 => 2 |
| 8進数(octal) | 0oまたは0 | 0〜7 | 0o10 => 8 |
| 10進数(decimal) | 0d | 0〜9 | 0d10 => 10 |
| 16進数(hexadecimal) | 0x | 0〜F | 0x10 => 16 |
使用可能な文字列以外を利用すると例外が発生するので注意が必要です。
0xG9 # Gは16進数に含まれてないため例外発生 080 # 8は8進数に含まれていないため例外発生
また文字列に対してto_i、oct、hexを使用して表現することもできます。
ただし、変換可能なものを文字列から探して変換を試みます。もしなければ0を返します。
puts "10G".hex # 16 と表示 puts "10G".oct # 8 と表示 puts "10G".to_i # 10 と表示 puts "XXX".hex # 0 と表示
「なんで”10G”.hexが16になるの?どうゆう計算しているの?」と思う方もいると思います。
結論、16進数のそれぞれのケタに対応した重み(16の何乗という数)に16進数の数を掛けて足していきます。
“10G”.hexの場合、変換可能なものが「10」になります。
そこで、10の位の1に対して16の1乗をかけます。
その後、1の位の0に16の0乗をかけます。(0乗は1になることに注意しましょう)
それぞれの値「16と0」を足して16になるという仕組みです。
1 × 16¹ + 0 × 16⁰ = 16 + 0 = 16
例えば「320」を16進数に変換する場合は、以下の通りです。
3 × 16² + 2 × 16¹ + 0 × 16⁰ = 768 + 32 + 0 = 800
それぞれの進数の変換方法については、こちらのブログが参考にしやすいのでご覧ください
