Chiroru's Diary

日々の学びをちょこちょこメモしていきます

【ゼロからわかるRuby超入門3】Ruby ハッシュ・メソッド・クラス・モジュールなど

【目次】

6-1オブジェクトを組みで扱う

ハッシュ(Hash)

クラス名はHash「キー」「値」 をセットとして、複数のデータを扱う。
キーと値にはどんな種類のオブジェクトも入れられるが、キーのオブジェクトにより書き方が異なる。

{キー: 値}
# キーが「シンボル」の時のみ

{:キー => 値}
# キーが何でも  

{"文字列のキー" => 値}
# 文字列キーの場合  

{:キー => 値}のまとまりが、ハッシュオブジェクト。

シンボルって何だっけ

ここでシンボルの確認。Ruby 2.7.0 リファレンスマニュアル

Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの名前を整数で管理しています。 これは名前を直接文字列として処理するよりも速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。

シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。

名前を管理するという役割上、シンボルと文字列は一対一に対応します。また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。

文字列に見える数値、のような感じだろうか。

ハッシュ値の取得

ハッシュの値を取得したい場合は、「キー」から。

ハッシュ(※変数)[キー]
# キーがシンボルだったら[:キー]  

6-2ハッシュに要素の追加・削除

追加

  • 「キー + 値」の組みを書くことで追加
  • 同じキーは複数持てないため、同じキーを追加すると上書きされる
  • 存在しないキーを取得しようとした時に返ってくる値を「default = メソッド」で設定できる。(設定なしだとnilが返ってくる)

ハッシュを統合して新しいハッシュを作るmerge

A = {a: 300}
B = {b: 600}
menu = A.merge(B)

削除

ハッシュ.delete(キー) で削除

6-3ハッシュの要素を繰り返し表示

ハッシュで繰り返し処理を行う時、キーと値の2つの変数をブロック内で使うことができる。 また、どちらか1つだけでもできる。

ハッシュ.each do |キーの変数, 値の変数|  
  処理
end
# 2つを使う時  

ハッシュ.each_key do |keyの変数|
  処理
end
# keyだけ繰り返し行う時

7-2メソッドへオブジェクトを渡す

引数を使うことで、呼び出しの時にメソッドへオブジェクトを渡すことができる。

def メソッド名(引数1, 引数2)
  処理
end
# 引数を持ったメソッドの定義  

メソッド名(引数)
# 引数を渡して、メソッドを呼び出す  

メソッドを途中で終わらせたい時の「return」

  • 「return オブジェクト」が実行されると、そのオブジェクトが戻り値となる

7-3メソッドの引数について

  • メソッドに記入した引数のデフォルト値を指定することが可能。これにより、呼び出しの際引数の省略ができるようになる
  • ただし、キーワード引数の場合のデフォルト値の設定は書き方が異なる
  • そもそもキーワード引数とは、メソッドを呼び出す際に引数を名前付きで指定できる。(→これにより、呼び出しの際に順序を変えられる)
def メソッド (引数 = "デフォルト値")
  処理
end
# 通常の引数×デフォルト値

def メソッド (キーワード引数1:, キーワード引数2:)
  処理
end
# キーワード引数
# 呼び出しは「メソッド(キーワード引数2:, キーワード引数1:)」のように指定できる  

def メソッド (キーワード引数:"デフォルト値")
  処理
end
# キーワード引数×デフォルト値

7-4ローカル変数とスコープ

  • ローカル変数は、特定のメソッド呼び出しや宣言されているクラス内、ファイルの実行の中だけで使用できる変数
  • 変数にはスコープ(見える範囲・寿命)がある
  • メソッド内で出てくるローカル変数は、メソッドの中がスコープ

他参考:Rubyにおける変数と定数の使い方

8-1 クラスについて

クラスはオブジェクトの種族を表すもので、オブジェクトは全てクラスに属す。またこのクラスに属すオブジェクトは「インスタンス」であるともいう。

「オブジェクト」と「インスタンス

これらはほとんど同じような意味だが、あえて「インスタンス」と呼ぶ際は、

  • クラスから作ったオブジェクト
  • そのクラスに属する

を強調したい時。

クラスの見分け方

あるオブジェクトのクラスを知りたい時は、以下で表示する。

オブジェクト.class

新しくオブジェクトを作る方法

あるクラスの新しいオブジェクト(インスタンス)を作りたい時。

クラス.new

例)

p Array.new(3, "aaa") #=>["aaa", "aaa", "aaa"]

8-2クラスを作る

クラスを定義する

自分でクラスを作ること=「定義」する。定義は以下のように行う。

class クラス名
end

8-3オブジェクトが呼び出せるメソッドを定義する

定義したクラスは、初め最低限の機能しかない。そのためメソッドを追加してクラスを育てていく。

メソッドが呼びだされるオブジェクトのことを、「レシーバ」と呼ぶ。
このレシーバで呼び出すことができるメソッドを確認したい場合は「methods」メソッドを使う。

レシーバ(※オブジェクト).methods.sort

しかしそもそもレシーバがどのオブジェクトかがわからないことがある。そんな時は、メソッドを呼び出したい場所で「self」を使うことで、対象のレシーバを調べることができる。

8-4オブジェクトにデータを持たせる

インスタンス変数(@)

メソッド内で使った変数を、別のメソッド内でも使いたい場合はインスタンス変数を利用する。インスタンス変数は、ローカル変数よりスコープが広く同じオブジェクトであれば、複数のメソッドで使うことが可能

オブジェクトごとに存在するインスタンス変数

またインスタンス変数は、オブジェクトごとに存在する。そのため、同じクラスに書かれているインスタンス変数でも、オブジェクトが異なれば、別物となる。

オブジェクトの外でインスタンス変数を取得したい

もしオブジェクトの外で、オブジェクト内で使ったインスタンス変数を取得したければ、クラスにそのインスタンス変数が戻り値となるメソッドを追記すれば良い。

ちなみに、「同じ名前のインスタンス変数を戻り値とするメソッドを定義」したい場合は、以下のものがある。

attr_reader :(@なしの)インスタンス変数名

また「同じ名前のインスタンス変数へ代入するメソッドを定義」する時は以下になる。

attr_writer :(@なしの)インスタンス変数名

上記の二つはよくセットで使用されるので、これをまとめて書くこともできる。

attr_accessor :(@なしの)インスタンス変数名

オブジェクトが持ってるインスタンス変数を知りたい

「instance_variables」メソッドを利用すれば、そのオブジェクトが持っているインスタンス変数の変数名一覧を取得できる。

8-5オブジェクトが作られるタイミングで処理をする

自動で呼び出されるinitializeメソッド

クラスが持つ特別なメソッドで、メソッドを定義すると、newなどでオブジェクトが作成される時に、自動でこのメソッドも呼び出される。

この使いどきとしては、

  • インスタンス変数初期値の設定。(メソッド内に初期値を記載、オブジェクト作成時に代入される)
  • 初期値を自由に設定したければメソッドに「引数」を受け取るようにし、オブジェクト作成時に引数を渡す

8-6クラスを使ってメソッド呼び出し

オブジェクトを作らずにクラスを使って呼び出せるメソッドを「クラスメソッド」という。(⇄インスタンスメソッド)

クラスメソッドは、例えばnewのようなクラスに対してメソッドを呼び出し、クラスのオブジェクトを作る

クラスメソッドの定義は「self .」をつける。

def self .メソッド名  
end
# クラスメソッド定義  

クラス名.メソッド名
# 呼び出す時

ちなみに「インスタンスメソッド」からクラスメソッドを呼ぶことも可能。
self.clas.クラスメソッド or クラス.クラスメソッド
(クラスメソッドからインスタンスメソッド呼び出しは不可)

8-8メソッドの呼び出しを制限する

メソッドの呼び出しを制限したい時は、クラスに「private」を書く。(⇄public)

※クラスメソッドの定義と制限について

しかしクラスメソッド(self.メソッド)を制限したい場合は、privateの代わりに 「private_class_method」 を書く。

また同じクラスメソッドの定義でも、self.メソッドの形式ではなく「class << self」を書いてからメソッドを定義する形式もあり、その場合でメソッドを制限する時はprivateを利用できるので注意。

9-1複数のクラスでメソッドを共同利用する

モジュールについて

  • メソッドを共同利用するためのもの
  • (クラスでは作れる)インスタンスを作れない
  • クラスでは「include」メソッドでモジュールを指定することで(モジュールのメソッドをインスタンスメソッドとして)使えるようになる
  • 「extend」メソッドでモジュールを指定すると、extend先のクラスメソッドとして使えるようになる

モジュールの定義

module モジュール名
end

クラスにincludeメソッド

class クラス名
  include モジュール名
end

9-2 モジュールで定義したメソッド・定数をそのまま使う

モジュールにクラスメソッドや定数を定義して、それを呼び出して使うことができる。
定数の呼び出しは以下の形式。(※クラスの場合は「モジュール名.クラスメソッド」)

モジュール名::定数

名前空間

また同じクラス名を複数の場所で使いたい時など、モジュールごとに名前をつけ分けて、クラスを使い分けることができる。
この方法を「名前空間を作る」という。

module CafeA
  class Late
    def self.info
      "美味しいラテ"  
    end
  end
end
module CafeB
  class Late
    def self.info
      "甘いラテ"  
    end
  end
end

puts CafeA::Late.info
puts CafeB::Late.info
# ↑クラスを使い分けてる

9-3別ファイルを読み込む

例えばモジュールとクラスが別ファイル同士であった場合、「require_relative」メソッドを利用して読み込むことで利用できる。

require_relative "ファイル名"

また「require」メソッドを使って読み込むこともできるが、別ファイルの読み込みが目的の時は、「require_relative」メソッドのがおすすめとのこと。

10-1 ライブラリ使い方と管理方法

Rubyには大きく分けて3つのライブラリがある。

  • 組み込みライブラリ:Integer・Array・Hashなど
  • 標準添付ライブラリ:JSONなど(requireメソッド実行で準備)
  • Gem:機能をひとまとめにしたパッケージ

この中のGemについて。複数のGemを管理するのに「bundler」が用いられる。

bundler

bundler自体もgemであり、これを使うことで複数のgemの依存関係を保ちながら管理することができる。コマンドは「bundle」。

bundlerを使うステップは以下。
1. bundlerインストール
2. Gemfileに対象のインストールしたいGemを記載
3. bundle installの実行
4. bundle exec コマンド を実行

$ gem install bundler
$ bundle -v
# bundleインストール確認  

$ bundle init
# Gemfile作成  

# gem記載  

$ bundle install
# gemのインストール

$ bundle exec コマンド
# bundlerでインストールしたgemの実行

3番目のステップ「bundle install」を済ますと、「Gemfile.lock」が作成される。
これはGemfileとセットなので、バックアップの際などは両方保管すること。

  • 「Gemfile」:インストールするgemを記述する
  • 「Gemfile.lock」:インストールされたgemのバージョンと、依存関係が記述されている
    (※自動で作成されるので、編集はしない)

bundle updateでGemバージョンアップ

gemに新しいバージョンが出たら、アップデートするために「bundle update」を実行する。ちなみにこの時、古いバージョンは残されたままになっている。

アップデートすると、通常新しいバージョンのgemが使用されるが、Gemfileに書かれたバージョンを使いたいときは 「bundle exec」コマンドを利用する。 (⇄bundle execなしでは、システム共通のコマンドが実行される)

10-3Webへアクセス!

webページへアクセスするには

「HTTP」「HTTPS」を使う。そのためにRubyの「net/http」ライブラリを使用する。

require "net/http" ←標準ライブラリnet/http読み込み  
require "uri" ←標準ライブラリuri読み込み
uri = URI.parse("https://example.com") ←URIを扱うオブジェクト作成
puts Net::HTTP.get(uri) ←uriオブジェクト渡してHTTP GETメソッドでリクエスト送る

上記は、「Net::HTTPクラス」と「URIモジュール」を使って HTTPリクエス を投げている。

11-1 例外処理

処理がうまくいかなかった場合の処理を書くことができる。

  • 「rescue」節は例外時のみ実行される
  • 「ensure」節を使えば、例外の有無に関わらず実行される処理を書ける
  • もし処理がメソッド内・ブロック内(2.5以降)で行われる場合は、「rescue」 のみ書けばOK(beginとend省略可)  
begin 
  例外が起きる可能性のある処理
rescue (※例外クラス名)  => e
  例外時の処理
ensure
  発生有無関係なし処理
end

# ※例外クラス名は省略可
# rescue~endを「rescue節」という
# 「=> e」をつけると、変数eに例外オブジェクトが代入され取得できる

また例外について調べるため、例外を発生させる 「raise」メソッド もある。

raise (※例外クラス), "例外メッセージ"

# ※例外クラスも指定可能

11-3文字列の調査・置き換え-正規表現 -

文字列含むか判定

文字列の中から特定の文字列を探したい時は「match?」メソッドを使う。

"文字列".match?(/特定の文字列/)
# 「/」で囲まれた「特定の文字列」部分は正規表現オブジェクトであり「パターン」と呼ぶ

"文字列".match?(/特定の文字列\z/)
# 「\z」文字列末尾に、特定の文字列がマッチするかのパターン

"文字列".match?(/\A特定の文字列/)
# 「\A」文字列の先頭に、特定の文字列がマッチするかのパターン

その他

  • 「[文字群]」:書いた文字群のいずれかにマッチ
  • 「.」:「.」の部分が任意の一文字にマッチ
  • 「*」:これより前の文字が0回以上繰り返す時にマッチ

置換

「gsub」メソッドを使う。

"文字列".gsub(置換前, 置換後)

11-4 ブロックについて

ブロックは処理のかたまりをメソッド(eachやmap)に渡すもの。
ブロックを渡されたかについては「block_given?」メソッドで判別できる。渡されたブロックを実行するには「yield」を使う。

渡されたブロックを引数で受け取る

この場合、ブロックを受け取る引数は「&引数」とする。
変数に代入されたブロック(Procオブジェクトとして扱う)を実行するには「call」メソッドを使用する。