メインコンテンツまでスキップ

独習ruby

読んだまとめ

デバッグメソッド

puts

p pメソッドはputsに似ているが値をより型情報のわかる形で出力する。 たとえば、文字列であれば "Hoge" のようにクウォート付きで出力する。配列ならブラケット付きで出力。

rubyコマンド

ruby -w オプションを渡すとコードに問題があるい場合に警告を表示してくれる


データ型

動的型付け。 ただしデータ型をまったく意識しなくても良いわけではない。 値を演算/比較する場面ではデータ型によって挙動が変化する。

ヒアドキュメント

シンボル型(Symbol)

シンボルは文字列に比べてメモリ消費が少なく、比較(検索)のためのパフォーマンスも高い型

シンボル(Symbol)はシンボル(モノの名前)を表すための型。

head = :title
puts head # 結果 title

:名前 の形式で表す。文字列に似ているが以下の点で異なる

  • 値を変更で機内
  • 同じであるかを判定する場合、文字列よりも高速
  • 同じ値であれば同じメモリで管理されるのでメモリの利用効率が高い
  • 文字列よりも少しだけスッキリ表現できる。

nil型(ニル)

nil型はある変数が値を持たないこと表す。 より正確にはNilClassという型があり、nilはその値を格納した擬似変数

irb(main):003:0> puts 10
10
=> nil

=> 以降はputsが返す値を表す。 putsメソッドは指定された値を出力するだけで(voidみたいなものか)何らかの値を返すわけではない(=nilを返す)わけ

擬似変数

true/false、nilの他にも擬似変数が用意されている 擬似変数は変数とはいうが再代入ができない

self 現在のレシーバー

FILE 実行中の .rb ファイル

LINE 実行中の行(番号)

ENCODING 現在のコードの文字エンコーディング

配列

配列の値は互いに異なっていても構わない。 が、一般的には1つの配列内では型を統一するのが普通

配列ショートカット

p %w!山田 佐藤! # ["山田", "佐藤"]

p %i!isbn title price! # [:isbn, :title, :price]

式展開を有効 w → W i → I

連想配列(キーは文字列型)

ハッシュは名前をキーにアクセスできる配列。 言語によっては連想配列、マップなどとよばれる。 ※キーが重複した場合、後半に宣言したキーで上書きされる。

構文

data = {
'name' => '鈴木',
'address' => '営業',
}

puts data['name']

ハッシュ(連想配列)

ハッシュキーはシンボルにするのが必須

構文

data = {
:name => '鈴木',
:address => '営業',
}

puts data[:name]

シンプルな構文 キーがシンボルの場合、さらにシンプルに キー:値 で表すことも可能

data = {
name => '鈴木',
address => '営業',
}

puts data[:name]

さらにシンプルな構文

data = {
name: '鈴木'
address: '営業',
}

参照/値渡し

Integer/Floatの一部の値/true/false/nil/シンボル

これらの型は処理効率上の理由から(参照値ではなく)実際の値そのものが変数に格納される(このような実装を即値と呼ぶ) ただし、これらの型ではこれまた処理効率上の理由から同じ値は同じオブジェクトとして管理される(同じ値であれば同じ参照値が返される)

定数

定数は変更できない変数と捉えるのは違う。 再代入できない変数(つまり変数であっても値を変更できてしまう場合がある) →そもそもRubyでは再代入しても警告しか発生しない

  • イミュータブル(プリミティブ)
VALUE = 10
VALUE = 15 # エラー(警告)
  • ミュータブル
VALUE = [10, 20, 30]
VALUE = [1, 2, 3] # エラー(警告)
VALUE[0] = 100 # 動作してしまう

多重代入

  1. 同時代入 複数の変数/定数に対してまとめて値を代入するための仕組み
a, b = 12, 2
puts a # 12
puts b # 2
  1. 配列分解 配列を分解もできる(左辺の変数と右辺の要素数は一致していなくても良い) →余った変数はnil(空)となる。
data = [1, 2, 3]
a, b, c = data
  1. 配列分解(であまった値をすべて代入)(アスタリスク)は末尾でなくても構わない。また値が入らなかった場合はからの配列が生成される。
data = [1, 2, 3, 4, 5]
a, *b, c = data

制御構文

Rubyの制御構文はすべて式(つまり値を返す。返す値がなければnil)


条件式が真の場合に命令を実行する

if(文)

  • 後置if命令 else節がないのであれば、後置ifを使う

note 後置ifで変わるニュアンス 前置構文では「条件が正しければしなさい」条件が主体 後置構文では「しなさい。条件が正しければ」処理そのものが主体

if(式)

式としても利用可能(つまり値を返し変数に代入できる) if式では最後に評価された値を返す。


条件式が偽の場合に実行するunless

unless

否定は人間の頭にとって把握しにくいもの。 ※unlessのelseは否定の否定はかえって理解しづらいのでやめる。

unless 条件式
# 条件式が偽の時に実行する処理
else
# 条件式が真の時に実行する処理
end
  • 後置unless

case ... when

switchのこと


例外処理

例外処理とは、あらかじめ発生するかもしれないエラーを想定しておき実行を継続できるよう処理する。または安全に終了させるための処理のこと

begin
# 例外が発生するかもしれないコード
rescue 例外の種類 => 例外変数
# 例外発生時の処理
end

第5章 最初らへん重要なことが書いてある

インスタンス構文

クラスによってはnewメソッドの代わりにインスタンス生成のための専用メソッドが用意しているものもある。

t = Time.now # 現在時刻を表すTimeインスタンスが生成される

構文

a = クラス名.new()

組み込みは読み込み不要だが、標準添付ライブラリ(Rubyと一緒にインストールされる)はRuby本体とは別のためあらかじめ読み込む必要がある。

&.(ぼっち演算子) Safe Navigation Operator

実際のコーディングでオブジェクトがnilではない時だけ、そのメンバーにアクセスしたいまたnilの場合はそのままnilを返す という状況はよくある。

このような処理をRubyでは &. で簡単にd系r。

str = nil
p str&.upcase # 結果 nil strがnilでもエラーにならない。

キーワード引数

引数はカンマ区切りで値を列挙するのが基本だが、メソッドによっては 名前: 値 の形式で渡せる場合もある。

日付/時刻

組み込みのTimeクラスを利用すれば十分。 DateTimeは非推奨になっている。

ブロックは複数の処理を束ねたもの


6章

セット(集合)

セットは、配列と同じく複数の値を束ねるための型。 配列とは以下の違い

  • 順番はない(よって何番目の要素を取り出すといったことはできない)
  • 重複した値は許されない(これが一番重要)Rubyの場合は無視される(エラーはなし)
  • 順番を持たないため、実行結果の並び順はその都度変わる。
  • ブラケット [] 構文によるアクセスはできない。
require 'set'

# もっとも基本
sets = Set['山田', '佐藤']

# 配列などEnumerableな型からセットを作成したいのであれば、Set::newメソッドを利用する
sets = Set.new(['山田', '佐藤']) # 2

# 末尾にブロックを渡して、元の配列を加工してからSetが作成できる。
sets = Set.new([15, 32, 33]) {}

2が結構重要 配列などをSetにかまして重複を取り除くっていうのはいわゆるテクニック。

ハッシュ(再)

ハッシュは一意のキーと値のペアで管理されるデータ構造 ハッシュは内部的にハッシュ表(ハッシュテーブル)と呼ばれる配列を持つ。 応訴を保存する際に、キーからハッシュ値を求めることでハッシュ表のどこに値(オブジェクト)を保存するかを決定する。


8章

ブロックとは

メソッド呼び出しの際に引数と一緒に渡すことのできる処理のかたまり 引数の他に、do~endまたはで囲まれたブロック構文。

代表的なブロックの使い方

代表的な使い方が以下の3つです。

  • 繰り返し
  • 処理の隠蔽
  • 処理の一部の差し替え

ブロック付きメソッド

メソッドによってはブロックを受け取れるものもある。 ユーザ定義メソッドでもブロック付きは実装可能(def..end配下でyield命令を呼び出すだけ)

考え方 children と似ている。 枠組みとなる機能をだけを実装しておき、詳細な機能はメソッドの利用者が決める汎用性の高いメソッドを設計できる。

# ブロック付きメソッドの定義
def my
start_t = Time.now.to_f
# ブロック呼び出し
yield
end_t = Time.now.to_f
end

my do
sleep(4)
end

ブロックを渡さなかった場合 yield呼び出しを伴うメソッドでブロックが渡されなかった場合 no block given(yield)(LocalJumpError) のようなエラーが発生する。

ブロックを省略可能にする

ブロックの引数

yield 命令に渡した値がそのままブロックの引数(パラメーター)になる。

def walk(list)
for item in list
yield item
end
end

data = [1, 3, 5]
walk(data) do |item|
puts item
end


10章

例外処理

すべての例外クラスはExceptionを基底クラスとしている。 ※アプリ固有のビジネスロジックに起因する問題に対しては、適切な例外クラスを用意しておくのが望ましい(もちろん標準例外で事足りるのであればそちらを優先すべき)

  • rescue節が呼び出される方式 発生した例外がrescue節に記述されたものと一致した場合、または発生した例外の基底クラスである場合

  • rescue節実行順序 複数のrescue節がある場合には、記述が先にあるものが優先される。 最初は下位の例外クラスで捉え、より範囲を広げていくイメージで作成していく。

バックトレース情報に関して 例外が発生するまでに経てきたメソッドの一覧(スタックトレースともいう) エントリーポイント(トップレベル)から呼び出し順に記録される(エラー文は下からentrypointとなる) ※一般的にはバックトレースの末尾を確認することで例外の直接原因を特定できる。

  • ensure節 finalと同一。

  • raise 例外を発生させる

raise [exp], [message]

アプリロジックの例外を作成

class MyAppError < StandardError

end

# アプリ独自例外の個別クラス
class MyInputError < MyAppError
attr_reader :code

def initialize(code)
super("Invalid Input: #{code}")
@code = code
end
end

構造体(Struct)

参考URL

Struct(構造体クラス)は簡易的なクラスのようなもの 以下に使用できる

  • まとまったデータを扱いたいがクラスを作るまでもない場合
  • クラス内で特定のデータのまとまりを表現する場合

※Structクラス自体を継承したサブクラスを定義することは非推奨

remote 0v

メリット

# 戻り値の代入先が構造体の名前になるので大文字。
Person = Struct.new(:name, :age)

フィールド フィールドには(. 演算子)でのアクセスのほかブラケット構文でハッシュのようにアクセスすることも可能。

構造体にメソッドを追加する

ブロック配下でメソッド定義を列挙するだけ

# 戻り値の代入先が構造体の名前になるので大文字。
Person = Struct.new(:name, :age) do
def show
puts "私の名前は#{name} #{age}歳です。"
end
end

モジュール

※クラスもモジュールも定数の一種 モジュールとは再利用可能なコード(メソッド/定数)を束ねるための仕組み。 クラスと意味的には似ているが、以下のような制約がある。

  • インスタンスを生成できない

断片的なクラスみたいな感じ、以下の用途がある

  • アプリ共通の機能を束ね、特定のクラスにインクルードする(ミックスイン)
  • 名前空間を定義する

名前空間

多くのクラスを利用 & 作成していると思わぬところで名前衝突が起きる。 Rubyには名前空間を表すための専用構文はない。 たとえば MyApp::Config::Person クラスであれば /my_app/config/person.rb のように