ソニックの部屋

主にプログラミングに関する記事を投稿します

プロを目指す人のためのRuby入門を読む(一部他教材を参照)

気になった用語や感想をまとめる(使用頻度が高くないもの等細かい所はきる)

導入(下記参考文献2より)

  • putsはpと省略可(微妙に挙動が違う)
  • オブジェクトを操作するのがメソッド「オブジェクト.メソッド」
  • オブジェクトは何らかのクラスに所属する
  • オブジェクト(インスタンス)はクラスから作られる「オブジェクト=クラス.new」
  • 1列は一次元配列、2列以上は多次元配列
  • インスタンス変数はオブジェクトのメソッドからのみ参照できる
  • ただしアクセサを使うとオブジェクトの外から参照できる(ex. attr_accessor :xxx)

第1章_本書を読み進める前に

  • ローカルで環境構築した

第2章_Rubyの基礎を理解する

良かったところ

  • Rubyは変数の型を指定しなくて良いので楽と感じた

学んだこと

  • メソッドの呼び出しは引数のカッコなしでも可だが基本的に省略しない「オブジェクト.引数」
  • 文字列はダブルクオートでないと式展開#{xxx}が使えないため基本的にはダブルクオートを使う
  • 数値の_は無視されるのでコンマ代わりに使うと便利「1_000_000」
  • 整数同士の割り算は整数になる点注意「1 / 2 #=> 0」
  • false又は nilであれば偽
  • if文で条件に合致しない場合はnilが返る
  • 最後に評価された式がメソッドの戻り値になるためreturnは不要
  • 式全体が真又は偽であることを決定するまで左から順に式を評価し式全体の真偽が確定したタイミングで式の評価を終了し最後に評価した式の値を返す「1 && 2 && 3 #=> 3」
  • and, orは優先順位がないので基本的には&&, ||を使う
  • unless, caseはifでも表現可なので基本的にはifを使う
  • ?で終わるメソッドは慣習として真偽値を返す
  • 破壊的メソッドとはオブジェクトの状態を変更してしまうメソッド
  • 破壊的メソッドは慣習として!で終わるメソッドとして表現されることが多い
  • ガベージコレクションとは使用されなくなったオブジェクトを回収し自動的にメモリを解放すること
  • エイリアスメソッドとは同じ実装で名前だけ異なるメソッドのこと
  • gemとは外部ライブラリのこと
  • 自作ライブラリを読み込む場合はrequireでなくrequire_relativeを必ず使う「require_relative "ファイルの相対パス"」
  • ヒアドキュメントとは複数行にわたる長い文字列を作成する際の便利な記法のこと
a = <<TEXT
これはヒアドキュメントです。
複数行にわたる長い文字列を作成するのに便利です。
TEXT
p a
#=> これはヒアドキュメントです。
複数行にわたる長い文字列を作成するのに便利です。

第3章_テストを自動化する

学んだこと

  • テストのクラス名は慣習としてTestで終わる又は始まる名前を付ける
  • テストファイル名はクラス名と合わせる
  • テストはtestで始まるメソッド名に基づき実行されるためテストクラスのメソッド名はtestで始めることが必須
# 基本形
require "minitest/autorun"

class SampleTest < Minitest::Test
  def test_sample
    assert_equal "RUBY", "ruby".upcase # 基本はassert_equal "期待値", "テスト対象"
  end
end

第4章_配列や繰り返し処理を理解する

学んだこと

  • 配列 << 要素で配列の最後に要素を追加「a << 1」
  • pushメソッドの方が複数の要素を一度に追加できるので便利「配列.push(2, 3)」
  • ブロックはメソッドの引数として渡せる処理のかたまり
  • 繰り返しはeachを使う
# 配列の要素を順番に取り出すのはeachが行い、その要素をどうするかはブロック(do~endまで)に記述する
# nはブロックパラメータ
# do endを省略して簡潔に{}とする場合もある
numbers = [1, 2, 3, 4]
sum = 0
numbers.each do |n|
  sum += n
end
sum #=> 10
# 繰り返しの中でsum使用
def to_hex(r, g, b)
  [r, g, b].sum("#") do |n|  # "#"は初期値
    n.to_s(16).rjust(2, "0")  # to_s(16)は整数を16進数に変換
  end
end
  • mapメソッドで各要素に対してブロックを評価した結果を新しい配列で返す
# 繰り返しの中でmap使用
def to_ints(n)
  r = n[1..2]
  g = n[3..4]
  b = n[5..6]
  [r, g, b].map do |s|
    s.hex  # 16進数を10進数に変換
  end
end
  • 配列の連結は+を用いる「a=[1], b=[2,3], a + b #=> [1, 2, 3]」
  • pushを用いて配列の要素を展開して別の配列に追加する場合はを付ける「a=[1], b=[2,3], a.push(b) #=> [1, 2, 3]」
  • メソッドの可変長引数は呼び出される側で*引数とする
  • 文字列.split("区切り文字")で指定した区切り文字で文字列を配列に変換する「"r, j, p".split(",") #=> ["r", "j", "p"]」
  • 添字付きの繰り返しはwith_indexメソッドを使う
# eachの時はeach_with_index 、mapなどはmap.with_index
f = ["a", "b", "c"]
f.each_with_index(1) {|f, i|  # with_index(1)の1は初期値(デフォは0)
  p "#{i}: "{f}"
}
#=> 1: a
#=> 2: b
#=> 3: c
  • 繰り返し処理の入れ子中のbreakは内側の繰り返し処理を抜ける
  • 外側の繰り返し処理も抜ける場合はthrow, catchメソッドを使う
# タグは:doneなど
catch タグ do
  # 繰り返し処理
  throw タグ
end

難しかったこと

  • Rubyは結果が同じ色々な書き方がありわかりずらい(以下同様)

第5章_ハッシュやシンボルを理解する

学んだこと

  • ブロックパラメータが1つだとキーと値が配列に格納される
c = {"japan" => "yen", "us" => "dollar"}
c.each do |key_value|  # パラメータが2つだとkeyとvalueに分かれる
  key = key_value[0]
  value = key_value[1]
  p "#{key}: #{value}"
end
# japan: yen
# us: dollar
  • シンボルとは文字列のようなもので処理効率が良い「:xxx」
  • シンボルをハッシュのキーとして使用する場合は{キー: 値}となりコロンの位置が右になる
  • **でハッシュを展開させる
h = {us: "dolar", india: "rupee"}
p {japan: "yen", **h}
#=> {:japan=>"yen", :us=>"dolar", :india=>"rupee"}
  • ハッシュをキーワード引数としてメソッドに渡す場合は呼び出し側で**ハッシュとする
  • ハッシュから配列への変換はto_aメソッド、配列からハッシュへの変換はto_hメソッドを使う
  • メソッドの引数は種類ごとに並ぶ順番が決まっている

第6章_導入(下記参考文献3-1~4より)

正規表現につき学んだこと

メタ文字 内容 使用例・備考
/正規表現/ Rubyでの正規表現は//の中に記述する よって文中に/を使う場合は\によりエスケープする
\d 1個の半角数字 [0-9]と同じ意味
{n,m} 直前の文字が n 個以上、m 個以下 \d{2,5}
{n} ちょうどn文字
[AB] AまたはBのいずれか1文字 内の文字数制限なし
[a-z] aからzまでのいずれか1文字 -が文中にある場合は範囲を表し-自体を表すのは文頭・文末のみ
? 区切りなし [  ・]?
区切り文字が1文字、 もしくは区切り無し
(ABC)?
文字列 ABC があり、または無し(2文字以上の場合は()でくくる)
. 任意の1文字
+ 直前の文字が 1文字以上 [a-z0-9_]+
(正規表現) 正規表現に ( ) を使うと、正規表現部分がキャプチャ(捕捉)され、連番が付けられる キャプチャする必要がない ( ) は (?: ) のように、?: をつける
? は ( ) の後ろに置くと、「カッコに囲まれた文字列が1個、またはゼロ」を表す
(エディタ上で)$1,$2 キャプチャによりマッチした文字列を xxx, xxx の文字列に置換
* 直前の文字が0文字以上 .*
\w 英単語を構成する文字 [a-z\d_]+とほぼ同じ意味
[^A] A以外の任意の1文字
*? *? や +? にすると最長ではなく、最短のマッチを結果として返す
^ 行頭 ^ +
行頭からスペースが1文字以上続く
の中の先頭で使われる時は否定、の中の文末で使われる時は^それ自身
$ 行末 ^ +$
行頭から行末までスペースが1文字以上続く
\t タブ ^[ \t]+$
\s 空白文字全般 改行文字(\n)も含まれる点注意
ABC|DEF 文字列ABC、または文字列DEF
\r\n Windows環境の改行コード
\b 単語の境界 \bear\b
earと検索
(?<=abc) その文字列の「直後の位置」(abc であれば c の直後)にマッチ
(?=abc) その文字列の「直前の位置」(abc であれば a の直前)にマッチ
(?<!abc) "abc" という文字列 以外 の「直後の位置」にマッチ
(?!abc) "abc" という文字列 以外 の「直前の位置」にマッチ
\1 ( ) でキャプチャされた1番目の文字列 <\a href="(.+?)">\1<\/a>
(.+?) と \1 は同じ文字列を指す

第6章_正規表現を理解する

良かったところ

  • 今まで意味不明な正規表現だったが理解できるようになった

学んだこと

  • 正規表現とはパターンを指定して文字列を効率良く検索、置換するためのミニ言語
  • 文字列と正規表現のマッチには=~を使う
  • マッチした結果は組み込み変数$に代入されるため$&(全体を取得), $1(1番目のキャプチャを取得)のように使用可
  • 正規表現はStringクラスのメソッド(scan, , split, gsub)がよく使われるため使い方留意
# gsubは第1引数の正規表現にマッチした文字列を第2引数の文字列で置き換える
# 基本形
text = "123,456-789"
text.gsub(",", ":") #=> 123:456-789
# 第2引数をブロックの戻り値に置き換え可

第7章_クラスの作成を理解する

学んだこと

  • クラス名は必ず大文字から始める
  • initializeメソッドはデフォルトでprivateメソッドなので外部から呼び出し不可(initialize以外のメソッドはデフォルトでpublic)
  • 値を読み出すメソッドをゲッターメソッド
  • 値を書き込むメソッドをセッターメソッド(下記(def name=(v)のような))
  • インスタンス変数は外部から参照・変更不可、参照・変更する場合は専用にメソッドを作る
  • 変更用のメソッドは=で終わる(使用しない、次のアクセサメソッドを使う)
def name=(v)
  @name = v
end

user = User.new("Alice")
user.name = "Bob"  #=>"Bob"
  • 参照・変更用のメソッドはattr_accessorメソッドが使われることが多い
class User
  attr_accessor :name
# いちいち専用のメソッド(def name=(v)のような)を用意する必要がない
  • 読み取り専用はattr_reader 、書き込み専用はattr_writerメソッドを使う
  • 一つ一つのインスタンスに含まれるデータ(インスタンス変数)は使わない時はクラスメソッドを使った方が便利
class クラス名
  def self.クラスメソッド  # selfがポイント
    # 処理
  end
end
  • Minitestではsetupメソッドを定義するとテストメソッドの実行前に毎回setupメソッドが呼ばれるので共通のオブジェクトはsetupに定義する
  • Rubyの継承は基本的には単一継承(サブクラス < スーパークラス
  • privateの記述より下がプライベートとなるためprivateはクラス内の最後に書くことが多い
  • privateメソッドはサブクラスからも呼び出せる
  • クラスメソッドをprivateにしたい場合はclass << selfの中にprivateと記述する
class User
  class << self
    private

    def hello
      # 処理
  • 定数は必ず大文字から始め、全て大文字が慣習
  • 定数はクラスの外部から参照可能で参照する場合は「クラス名::定数名」
  • 定数はメソッド内で定義不可なので必ずクラス直下又はトップレベルで定義する
  • Rubyの定数は変更しようと思えばできてしまうのでそれを防ぐには工夫が必要
  • グローバル変数はクラス内外どこからでも参照可能で$xxxと記述する

第8章_モジュールを理解する

学んだこと

  • モジュールとは
# クラスと似ているが以下が違う
# ・モジュールからインスタンスの作成不可
# ・他のモジュールやクラスの継承不可

module Loggable
  def log("text")
    puts xxx
  end
end

class Product
  include Loggable # ここがポイント

  log "title is called."
end

# クラスでモジュールをincludeするとモジュールで定義したメソッドがインスタンスメソッドとして呼び出し可
# これをミックスインといい、共通機能をモジュールに持たせることで、多重継承に似た仕組みを実現する
  • モジュールの中にクラスを書くことで同名のクラスがあっても外側のモジュール名で区別できる
  • モジュールに属するクラスを参照する際は「モジュール名::クラス名」

第9章_例外処理を理解する

学んだこと

  • 基本形
begin
  # 例外が起きうる処理
  1 / 0
rescue 捕捉したい例外クラス => e # 慣習でe
  # 例外が発生した場合の処理
  puts e.full_message  # エラーメッセージなどを表示
  retry xxx  # retryでbeginからやり直すことが可能
  raise "#{変数}"  # raiseで意図的に例外を発生させる
end
  • 捕捉したい例外クラスはStandardErrorとなり特殊なエラーは捕捉されない点注意
  • 例外処理は例外が発生しても原則rescueしない、又はrailsの例外処理に任せる
  • 例外処理よりも条件分岐を使った方が可読性やパフォーマンスの面で有利
  • 入力を受け付けるgetsメソッドについて
input = gets.chomp
# chompメソッドで改行を除く
  • printメソッドは文字列を表示した後に改行しない
  • rescueの中でraiseを使うことでログに残しつつ終了させる
  • 独自例外の作成
class NoCountry < StandardError
end

raise NoCountry, "無効な国名です。#{country}"

第10章_yieldとProcを理解する

学んだこと

  • yieldはブロックとメソッドのやり取りの際に利用する
def greet
  # ブロックに引数を渡し戻り値を受け取る
  text = yield "こんにちは"
  puts text  # こんにちはこんにちは
end

greet do |text|
  # yieldで渡された”こんにちは”を2回繰り返す
  text * 2
end
  • ブロックをメソッドの引数として明示的に受け取る時は引数の前に&、ブロックを実行する時はcallメソッドを使う
def greet(&block)
  text = block.call("こんにちは")
  puts text  # こんにちはこんにちは
end

greet do |text|
  text * 2
end
  • Procクラスはブロック(処理のかたまり)をオブジェクト化する
def greet(&block)
  text = block.call("こんにちは")
  puts text  # こんにちはこんにちは
end

repeat_proc = Proc.new { |text|  # Procオブジェクトを作成
                                   text * 2 }
greet(&repeat_proc)  # greetに渡す

第11章_パターンマッチを理解する

学んだこと

  • 3.0verから導入されたため2.0ver代のものはエラーとなる点注意
  • パターンマッチは配列やハッシュの構造をパターン化して条件分岐させる
  • inで=を使わずにローカル変数の宣言と代入を行う
  • case文に似ている
records = [[2021], [2019, 5], [2017, 11, 25]]

records.map do |record|
  case record  # ここからendまでがパターンマッチ
  in [y]  # 1要素のみの配列にマッチ
    Date.new(y, 1, 1)
  in [y, m]  # 2要素のみの配列にマッチ
    Date.new(y, m, 1)
  in [y, m, d]  # 3要素のみの配列にマッチ
    Date.new(y, m, d)
  end
end
# 上記はarrayパターンとなり他にも色々なパターンあり
  • パターンマッチは変数スコープを作らない点注意

第12章_Rubyデバッグ技法を身につける

学んだこと

  • 基本的にはprintデバッグだが原因がつかめず時間がかかりそうな場合はデバッガを使う
require "debug"  # デバッグ用のライブラリ

def fizz_buzz(n)
  binding.break  # ブログラムが停止する箇所(ブレークポイント)
  ・・・
コマンド 説明
s 実行を1行進めて停止する。メソッドがあればメソッドの中に入って停止する(ステップイン)
n 実行を1行進めて停止する。メソッドがあればメソッドを実行してから次の行で停止する(ステップアプト)
f メソッドを最後まで実行し呼び出し元に戻ってきた所で停止する
c 再開する。ブレークポイントがなければ最後まで実行する
p pメソッドのように指定された値を表示する

第13章_Rubyに関するその他のトピック

学んだこと

  • Bundlerは1つのコマンドで大量のgemをどの環境でも同一のバージョンでインストール可
  • 素のRubyなのかRailsRubyなのかを意識して使う(Rails特有のRubyの使い方があるため)

その他(下記参考文献4より)

自己学習(課題)の中で気になった文法をまとめる

  • %w[A B C]
    • カンマでなく空白文字、クオートなしで配列を作る
  • 配列.sample
    • ランダムに要素を一つ取得する
  • rand(2..3)

    • 2, 3からの整数を返す
  • optparseの使い方について

    • OptionParser オブジェクト opt を生成する
    • オプションを取り扱うブロックを opt に登録する
    • opt.parse(ARGV) でコマンドラインを実際に parse する
# parse!実行後にはオプション(-m)が配列から削除
opt = OptionParser.new
opt.on('-m') { |v| p v }  #=> ["-m", "12"]
p ARGV  #=> true
opt.parse!(ARGV)
p ARGV  #=> ["12"]
  • (1..12).to_a
    • 1から12の配列を作る
  • 配列.include?(値)
    • 配列に値が含まれていればtrueを返す
  • Date
    • require 'date'を読み込み日付等を扱うDateクラスが使える
  • if文は戻り値を返す
  • 文字列.center(20)
    • 空白文字で中央寄せ
  • rjust
  • ""の使い方について
    • "\n"ではなく'\n'とするとエスケープ処理となってしまうため注意
    • 式展開#{}を使う際は""が必須
  • 末尾のprint "\n"について

    • ⚫︎
  • puts, print, p, ppについて |用語|説明| |---|---| |puts|・改行あり
    ・クオーテーションなし表示| |print|・改行なし
    ・クオーテーションなし表示| |p|・改行あり
    ・ダブルクオートで表示| |pp|整形して表示|

参考文献
1. プロを目指す人のためのRuby入門[改訂2版] 言語仕様からテスト駆動開発・デバッグ技法まで
伊藤 淳一/ Software Design plus/2022

2-1. キノコード / プログラミング学習チャンネル, 【たった1時間で学べる】Rubyのプログラミング初心者向けの超入門講座【文字書き起こし、ソースコードも完全無料!】 (2023/8/21取得,https://youtu.be/0DO5bsQB5So).

3-1. 伊藤 淳一 / 初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」 (2023/8/23取得,https://qiita.com/jnchito/items/893c887fbf19e17d3ff9).

3-2. 伊藤 淳一 / 初心者歓迎!手と目で覚える正規表現入門・その2「微妙な違いを許容しつつ置換しよう」 (2023/8/23取得,https://qiita.com/jnchito/items/64c3fdc53766ac6f2008).

3-3. 伊藤 淳一 / 初心者歓迎!手と目で覚える正規表現入門・その3「空白文字を自由自在に操ろう」 (2023/8/23取得,
https://qiita.com/jnchito/items/6f0c885c1c4929092578).

3-4. 伊藤 淳一 / 初心者歓迎!手と目で覚える正規表現入門・その4(最終回)「中級者テクニックをマスターしよう」」 (2023/8/23取得,https://qiita.com/jnchito/items/b0839f4f4651c29da408).

4-1. Ruby 3.2 リファレンスマニュアル(2023/8/27取得,
https://docs.ruby-lang.org/ja/latest/library/optparse.html).