Ruby 技術者認定試験 Gold対策集

## 内容
Ruby技術者認定試験のGold資格取得のための振り返り記事になります。

## 前提
Ruby3.1系

## 学習教材
- REx
    - https://rex.libertyfish.co.jp/exam_histories
- ruby-association
    - https://github.com/ruby-association/prep-test/blob/version3/gold_ja.md
- CTC
    - https://www.school.ctc-g.co.jp/ruby/training_ruby_gold_01_10.html
- まとめ記事

https://qiita.com/jonakp/items/c7b7ecfe3eb9ee8c950e

# 目次
[objectクラス関連](#objectクラス関連)
[module関連](#module関連)
[self関連](#self関連)
[探索順](#探索順)
[enumeratorクラス関連](#enumeratorクラス関連)
[procオブジェクト](#procオブジェクト)
[例外処理関連](#例外処理関連)
[気になるメソッド](#気になるメソッド)
[演算子関連](#演算子関連)
[日付関連](#日付関連)
[正規表現関連](#正規表現関連)
[制御構造関連](#制御構造関連)
[パーセント記法](#パーセント記法)
[rubyオプション一覧](#rubyオプション一覧)
[その他](#その他)

# Objectクラス関連
- `Object`クラスにメソッドを定義すると特異クラスでもそのメソッドを利用することができる
    ```ruby
    class Object
      CONST = "1"
      def const_succ
        CONST.succ!
      end
    end
    
    class Child1
      const_succ   # "2"になる
      class << self
        const_succ # 特異クラス内のメソッドも実行されるため、"3"になる
      end
    end
    
    class Child2
      const_succ  # "4"になる
      def initialize
        const_succ
      end
    end
    
    Child1.new # "4"のまま
    Child2.new # "5"になる
    
    p Object::CONST # => "5"
    ```

## singleton_class
- レシーバの特異クラスを返す。また、特異クラスが存在しなければ新しく作成する
    - レシーバが `Integer`、`Float`、`Symbol`の場合に`TypeError`が発生する
    ```ruby
    Object.new.singleton_class  # => #<Class:#<Object:0xb7ce1e24>>
    String.singleton_class      # => #<Class:String>
    nil.singleton_class         # => NilClass
    true.singleton_class        # => TrueClass
    false.singleton_class       # => FalseClass
    1.singleton_class           # `singleton_class': can't define singleton (TypeError)
    ```

    - 特異クラスで`self`を参照するとレシーバのオブジェクトを返す
    ```Ruby
    class Hoge
      def self._singleton
        class << Hoge
          self
        end
      end
    end
    
    p Hoge._singleton # => #<Class:Hoge>
    ```

## method
- オブジェクトに対してメソッド名を引数として`method`を呼び出すと、当該メソッドをオブジェクト化したMethodオブジェクトを作って返す
    - メソッド名は`String`または`Symbol`で指定
    - 定義されていないメソッド名を引数として与えると`NameError`が発生する
    ```ruby
    arr = [1, 2, 3]
    arr_pop = arr.method(:pop)
    
    arr_pop.call # => 3
    arr          # => [1, 2]
    arr_pop.call # => 2
    arr_pop.call # => 1
    arr          # => []
    ```

## methods
- そのオブジェクトに対して呼び出せる`public`および`protected`メソッド名の一覧を配列で返す
    - `private`メソッドは含まれない
    - 引数が`false`の場合、`Object#singleton_methods（false)`と挙動は同じになり、特異メソッド名の一覧を返す
        - 引数を指定しない場合、デフォルトで`true`が指定される
    ```ruby
    class Parent
      private;   def private_parent()   end
      protected; def protected_parent() end
      public;    def public_parent()    end
    end
    
    class Foo < Parent
      private;   def private_foo()   end
      protected; def protected_foo() end
      public;    def public_foo()    end
    end
    
    obj = Foo.new
    
    class << obj
      private;   def private_singleton()   end
      protected; def protected_singleton() end
      public;    def public_singleton()    end
    end

    p obj.methods(false) => [:public_singleton, :protected_singleton]

    # Objectクラスのインスタンスメソッドは除外する
    p obj.methods(true) - Object.instance_methods(true)
    # => [:public_singleton, :protected_singleton, :protected_foo, :public_foo, :protected_parent, :public_parent]
    ```

## instance_methods
- そのクラス/モジュールで定義されている`public`および`protected`メソッド名の一覧を配列で返す
    - 引数に`false`を指定するとそのモジュールで定義されているメソッドのみ返す
        - 引数を指定しない場合、デフォルトで`true`が指定される
    ```ruby
    class Foo
      private;   def private_foo()   end
      protected; def protected_foo() end
      public;    def public_foo()    end
    end
    
    # あるクラスのインスタンスメソッドの一覧を得る
    p Foo.instance_methods(false)           # => [:protected_foo, :public_foo]
    p Foo.public_instance_methods(false)    # => [:public_foo]
    p Foo.private_instance_methods(false)   # => [:private_foo]
    p Foo.protected_instance_methods(false) # => [:protected_foo]
    
    class Bar < Foo
      private;   def private_foo2()   end
      protected; def protected_foo2() end
      public;    def public_foo2()    end
    end

    # Object のインスタンスメソッドは一覧から排除している前提（ - Object.instance_methods(false)）
    p Bar.instance_methods(false) # => [:protected_foo2, :public_foo2]
    p Bar.instance_methods(true)  # => [:protected_foo2, :public_foo2, :protected_foo, :public_foo]
    ```

## initialize
- ユーザ定義クラスのオブジェクト初期化メソッド
    - `public`などでアクセス修飾子をつけたとしても、`private`から変わることはない
        ```ruby
        class C
        public
          def initialize
          end
        end
        
        p C.new.private_methods.include? :initialize # => true
        ```

## instance_eval
- オブジェクトの特異クラスにインスタンスメソッドを定義することができる
    - `instance_eval`にブロックを渡した場合のネスト状態
        ```ruby
        class C
          CONST = "Hello, world"
          class << self
            CONST = "Hello, world!"
          end
        end
        
        module M
          C.instance_eval do
            CONST = "Hello, world!!" # instance_eval内でCONST定数を定義しないとNameErrorとなる
            def awesome_method
              CONST
            end
          end
        end

        p C.awesome_method # => "Hello, world!!"
        ```
    - `instance_eval`に文字列を渡した場合のネスト状態
         ```ruby
        class C
          CONST = "Hello, world"
          class << self
            # instance_eval内に定数が定義されていなければ、この定数が呼ばれる
            CONST = "Hello, world!" 
          end
        end
        
        module M
          C.instance_eval(<<-CODE)
            CONST = "Hello, world!!"
            def awesome_method
              CONST
            end
          CODE
        end

        p C.awesome_method # => "Hello, world!!"
        ```

## class_eval

- ブロックをあたかもクラス定義やモジュール定義の中にあるかのように実行することができる
    - エイリアスメソッド：`module_eval`
    - `class_eval`にブロックを渡した場合のネスト状態
        ```ruby
        class C
          CONST = "Hello, world"
        end
        
        module M
          CONST = "Hello, world!!" # モジュールMにCONST定数の定義がない場合、NameErrorとなる
          C.class_eval do
            def awesome_method
              CONST
            end
          end
        end
        
        p C.new.awesome_method # => "Hello, world!!"
        ```
    - `class_eval`に文字列を渡した場合のネスト状態
        ```ruby
        class C
          # クラスCにCONST定数の定義がない場合、モジュールMのCONST定数が参照される
          CONST = "Hello, world" 
        end
        
        module M
          CONST = "Hello, world!!"
          C.class_eval(<<-CODE)
            def awesome_method
              CONST
            end
          CODE
        end
        
        p C.new.awesome_method # => "Hello, world"
        ```

## instance_variable_set
- オブジェクトのインスタンス変数「`var`」に値「`value`」を設定する
    - 第1引数に`var`、第2引数に`value`を設定
        - 引数が正しく設定されていないと`ArgumentError`が発生する
    - インスタンス変数が定義されていなければ新たに定義される
    ```ruby
    obj = Object.new
    p obj.instance_variable_set("@foo", 1)  # => 1
    p obj.instance_variable_set(:@foo, 2)   # => 2
    p obj.instance_variable_set(:@hoge)
    # => instance_variable_set': wrong number of arguments (given 1, expected 2) (ArgumentError)
    ```

## instance_variable_get
- オブジェクトのインスタンス変数の値を取得して返す
    - インスタンス変数が定義されていなければ`nil`を返す
    - インスタンス変数名は文字列かシンボルで指定
    ```ruby
    obj = Object.new
    p obj.instance_variable_set("@foo", 2)  # => 2
    p obj.instance_variable_get(:@foo)      # => 2
    p obj.instance_variable_get("@bar")     # => nil
    ```

## method_missing
- 継続チェーンを辿った末にメソッドが見つからなかった場合に呼び出される
    ```ruby
    module M
      def method_missing(id, *args)
        puts "M#method_missing"
      end
    end
    
    class A
      include M
      def method_missing(id, *args)
        puts "A#method_missing"
      end
    end
    
    class B < A
      # このmethod_missingメソッドをコメントアウトするとAクラスのmethod_missingが呼ばれる
      def method_missing(id, *args)
        puts "B#method_missing"
      end
    end
    
    obj = B.new
    obj.dummy_method # => B#method_missing
    ```

## freeze
- オブジェクトを凍結する
    - 破壊的な操作をすると`FrozenError`が発生する
        - 非破壊的な操作はできる
    - オブジェクトの代入はできる
    ```ruby
    # 破壊的な操作をした場合
    a = ['001', '002', '003'].freeze
    a.map!{|id| id << 'hoge'} # => `map!': can't modify frozen Array: ["001", "002", "003"] (FrozenError)
    a.push('add') # => `push': can't modify frozen Array: ["001hoge", "002hoge", "003hoge"] (FrozenError)

    # 配列内の要素をfreezeしていないため、変更可能
    b = ['001', '002', '003'].freeze
    b.map{|id| id << 'hoge'} # => ["001hoge", "002hoge", "003hoge"]

    # 非破壊的な操作はできる
    c = ['001', '002', '003'].freeze
    c.map{|id| id << 'hoge'} # => ["001hoge", "002hoge", "003hoge"]
    ```

## respond_to?
- レシーバが引数で指定した`public`メソッドを持っていれば、真を返す
    - 第二引数に`true`を設定すると、`private`メソッドと`protected`メソッドを確認の対象に含めることができる（デフォルトは`false`）
    ```ruby
    class Hoge
      def hoge ;end

      private

      def hogehoge ;end
    end

    hoge = Hoge.new
    hoge.respond_to?(:hoge)           # => true
    hoge.respond_to?(:hogehoge)       # => false
    hoge.respond_to?(:hogehoge, true) # => true
    ```

## define_method
- インスタンスメソッドを動的に定義できる
    - 第一引数に**メソッド名**、第二引数に**処理**を記述する（ブロックで渡すことも可能）
    ```ruby
    define_method(:add) do |x, y|
      x + y
    end
    
    p add(1, 2) # => 3

    # 第二引数に既存のメソッドを設定した場合
    class Foo
      def foo() p "foo" end
      define_method(:bar, instance_method(:foo))
    end

    Foo.new.bar # => "foo"
    ```

## clone
- オブジェクトをコピーする
    - 凍結状態・汚染状態・特異メソッドなどの情報も含めた完全な複製を作成
        - 同様にオブジェクトをコピーする`dup`メソッドは、凍結状態・汚染状態・特異メソッドはコピーしない
    ```ruby
    obj = Object.new

    def obj.hello
      puts "Hi!"
    end
    
    copy = obj.clone
    copy.hello # => Hi!

    dup = obj.dup
    dup.hello # undefined method `hello' for #<Object:0x000000010855dd78> (NoMethodError)
    ```

## __send__
- オブジェクトのメソッドを`args`を引数にして呼び出し、メソッド結果を返す
    - 第一引数にメソッド名をシンボルで指定
    - 第二引数に呼び出すメソッドに渡す引数
- `send`メソッドが再定義された場合に備えて別名`__send__`が用意されており、ライブラリではこちらを使っている ※1(そのため、`__send__`は再定義すべきではない)
    >Rubyの標準ライブラリや多くの`gem`では、`send`メソッドが特定の用途で再定義されていることがあります。`send`はオブジェクトに対してメソッドを動的に呼び出すメソッドであり、一般的には安全な使い方が期待されますが、一部のコードで`send`が上書きされている場合、予期しない結果が生じる可能性があります。そこで、`Ruby`は標準で`__send__`という別名を提供しています。`__send__`は常に`send`と同じ動作をしますが、再定義されていない限りはそのままの動作をするため、安全にメソッドを呼び出すことができます。一般的なコードでは、通常は`send`を使用しますが、特殊なケースやライブラリで`send`が再定義されている可能性がある場合、代わりに`__send__`を使用することで安全性を確保できます。
    ```ruby
    p -365.send(:abs)           # => 365
    p "ruby".send(:sub,/./,"R") # => "Ruby"

    p -365.__send__(:abs)           # => 365
    p "ruby".__send__(:sub,/./,"R") # => "Ruby"
    ```

## class
- レシーバのクラスを返す
    ```ruby
    p "ruby".class # => String
    p 100.class    # => Integer
    p ARGV.class   # => Array
    p self.class   # => Object
    p Class.class  # => Class
    p Kernel.class # => Module
    
    class Hoge
      def hoge
        p self.class # => Hoge
      end

      def self.hoge
        p self.class # => Class
      end
    end
    
    module Hoge
      def self.hoge
        p self.class # => Module
      end
    end
    ```

## public_send
- `public`メソッドのみを対象にメソッドの実行結果を返す
    - 第一引数には**メソッド名**、第二引数には**引数**を指定する
    - `protected`メソッドや`private`メソッドに対して実行した場合に`NoMethodError`が発生する
    - ※ `private_send`や`protected_send`というメソッドは存在しない（引っ掛け問題で出題されました）
    ```ruby
    class Foo
      def foo(val)
        p val
      end
    
      private

      def bar(val)
        p val
      end
    
      def baz
        p 'baz'
      end
    end

    Foo.new.public_send(:foo, 'foo') # => "foo"
    Foo.new.public_send(:bar, 'bar')
    # => `public_send': private method `bar' called for #<Foo:0x0000000106f5dc30> (NoMethodError)

    # ただし、抜け道はある（参照先のメソッド名はシンボルでは動作しないため、文字列で渡す必要あり）
    Foo.new.public_send(:instance_eval, 'baz') # => "baz"

    # privateメソッドを参照する場合はsendメソッドを使用する
    Foo.new.send(:bar, 'bar') # => "bar"
    ```

# Module関連
- `module`のスーパークラスは`Object`クラス
    - 同名のモジュールを別々に定義したとしてもテーブルを参照して値を取得することができる
        - 同名の定数やメソッドを定義している場合、後で定義したモジュール側の内容に上書きされる
        ```ruby
        module Hoge
          HOGE = 'hoge'
          def hoge
            'hoge'
          end

          def hoge2
            'hoge2'
          end
        end
    
        module Hoge
          HOGE = 'hogehoge'
          def hoge
            'hogehoge'
          end
        end
    
        class C
          include Hoge
        end
    
        C.new.hoge   # => "hogehoge"
        C.new.hoge2  # => "hoge2"
        C::HOGE      # => "hogehoge"
        ```

    - モジュールをスーパークラスとして定義することはできない
        - ※クラスを継承する場合、スーパークラスは**クラス**である必要がある
        ```ruby
        module Hoge;end
        
        class C < Hoge;end # superclass must be an instance of Class (given an instance of Module) (TypeError)
        ```

## ancestors
- クラス、モジュールのスーパークラスとミックスインしているモジュールを優先順位順に配列に格納して返す

  ```ruby
  module Foo
  end
  
  class Bar
    include Foo
  end
  
  class Baz < Bar
    p ancestors        # => [Baz, Bar, Foo, Object, PP::ObjectMixin, Kernel, BasicObject]
    p included_modules # => [Foo, PP::ObjectMixin, Kernel]
    p superclass       # => Bar
  end
  ```

## included_modules
- `self`にミックスインしているモジュールの配列を返す
  ```ruby
  module Mixin
  end

  module Outer
    include Mixin
  end
     
  Mixin.included_modules   # => []
  Outer.included_modules   # => [Mixin]
  ```

## include
- 引数で指定したモジュールの定数、メソッド、モジュール変数（モジュールで定義されたクラス変数）を引き継ぐ（ミックスイン）ことができる
    - メソッド探索順は`self`の後に追加される
        ```ruby
        module M
          def foo
            super
            puts "M#foo"
          end
        end
    
        class C2
          def foo
            puts "C2#foo"
          end
        end
        
        class C < C2
          def foo
            super
            puts "C#foo"
          end
          include M
        end

        C.ancestors # => [C, M, C2, Object, PP::ObjectMixin, Kernel, BasicObject]
    
        C.new.foo # => # C2#foo
                       # M#foo
                       # C#foo
        ```
        
    - 複数モジュールを指定した場合、左側から右側の順でメソッド探索される
        ```ruby
        module M end;
        module L end;
        module N end;

        class Hoge
          include M, L, N
        end

        Hoge.ancestors # => [Hoge, M, L, N, Object, PP::ObjectMixin, Kernel, BasicObject]
        ```

    - 1つずつ定義した場合、下から順に探索される
        ```ruby
        module M end;
        module L end;
        module N end;

        class Hoge
          include M
          include L
          include N
        end

        Hoge.ancestors # => [Hoge, N, L, M, Object, PP::ObjectMixin, Kernel, BasicObject]
        ```
## prepend
- 引数で指定したモジュールを`self`の継承チェーンの先頭に「追加する」ことで、`self`の定数、メソッド、モジュール変数を上書きする
    ```ruby
    module M
      def foo
        super
        puts "M#foo"
      end
    end
    
    class C2
      def foo
        puts "C2#foo"
      end
    end
    
    class C < C2
      def foo
        super
        puts "C#foo"
      end
      prepend M
    end
    
    C.ancestors # => [M, C, C2, Object, PP::ObjectMixin, Kernel, BasicObject]
    
    C.new.foo # => C2#foo
                 # C#foo
                 # M#foo
    ```

    - 複数モジュールを指定した場合、左側から右側の順でメソッド探索される
        ```ruby
        module M end;
        module L end;
        module N end;

        class Hoge
          prepend M, L, N
        end

        Hoge.ancestors # => [M, L, N, Hoge, Object, PP::ObjectMixin, Kernel, BasicObject]
        ```

    - 1つずつ定義した場合、下から順に探索される
        ```ruby
        module M end;
        module L end;
        module N end;

        class Hoge
          prepend M
          prepend L
          prepend N
        end

        Hoge.ancestors # => [N, L, M, Hoge, Object, PP::ObjectMixin, Kernel, BasicObject]
        ```

## extend
- 引数で指定したモジュールのインスタンスメソッドを`self`の特異メソッドとして追加する
    ```ruby
    module Foo
      def a
        'ok Foo'
      end
    end
    
    module Bar
      def b
        'ok Bar'
      end
    end
    
    obj = Object.new
    obj.extend Foo, Bar
    p obj.a # => "ok Foo"
    p obj.b # => "ok Bar"
    
    class Klass
      include Foo
      extend Bar
    end
    
    p Klass.new.a # => "ok Foo"
    p Klass.b     # => "ok Bar"
    ```
    - extend の機能は、「特異クラスに対す`include`」と言い替えることもできる
        ```ruby
        # obj.extend Foo, Bar とほぼ同じ
        class << obj
          include Foo, Bar
        end
        ```

## included
- `include`したモジュールのインスタンスメソッドをクラスのインスタンスメソッドだけではなく、クラスメソッドとして使用することができる
    ```ruby
    module Mod
      def self.included(base) # 引数　base　には includeしたクラス　Car　が格納される
        base.extend ClassMethods
      end
    
      module ClassMethods
        def run #クラスメソッドとして使いたい
          puts "GO!!"
        end
      end
    
      def stop  # インスタンスメソッドとして使いたい
        puts "STOP!!"
      end
    end

    class Car
      include Mod
    
      car = Car.new
      car.stop # => STOP!!
    
      Car.run # => GO!!
    end
    ```

## append_features
- `include`の実態で、オーバーライドすると`include`した際の挙動が変わる
    ```ruby
    module M
      def self.append_features(klass)
        super # 記述しないとモジュールMがincludeされない
        p klass.ancestors
      end
    end
    
    class C
      include M
    end
    
    p C.ancestors # => [C, M, Object, PP::ObjectMixin, Kernel, BasicObject]
    
    # superがない場合 => [C, Object, PP::ObjectMixin, Kernel, BasicObject]
    ```

## Module.nesting 
- このメソッドを呼び出した時点のクラス/モジュールのネストの状態を配列に入れて返す

    ```ruby
    module A
      p Module.nesting # => [A]
    
      class B
        p Module.nesting # => [A::B, A]
      end
    end
    ```
    - `xxx_eval`での渡し方の違いによる挙動の変化について
        - ブロックで渡した場合、クラス・モジュールのスコープに入らない
        - テキストコードを与えた場合、class・moduleキーワード等でオープンしたとき相当の処理がされるため、スコープに入る
        ```ruby
        class C
          p Module.nesting     # =>  [C]
        end
        
        C.class_eval do
          p Module.nesting     # => []
        end
        
        C.class_eval(<<~CODE)
          p Module.nesting     # => [C]
        CODE
        
        C.instance_eval(<<~CODE)
          p Module.nesting     # => [#<Class:C>]
        CODE
        ```

## module_function
- メソッドをモジュール関数にする
    - モジュール関数とは、`private`メソッドであると同時に特異メソッドでもあるようなメソッドを指す
    - 引数が与えられた場合、引数で指定されたメソッドをモジュール関数にする
        - 引数なしの場合、今後このモジュール定義文内で新しく定義されるメソッドをすべてモジュール関数にする
        ```ruby
        module M
          def foo
            p "foo"
          end

          def bar
            p "bar"
          end

          module_function :foo
        end
        
        M.foo   # => "foo"
        M.bar   # <main>': undefined method `bar' for M:Module (NoMethodError)

        # 引数なしの場合
        module M
          def foo
            p "foo"
          end

          module_function

          def bar
            p "bar"
          end
        end

        M.foo # undefined method `foo' for M:Module (NoMethodError)
        M.bar # => "bar"
        ```
    - クラス内で`include`して使用する場合
        ```ruby
        module M
          def foo
            p "foo"
          end
          
          module_function :foo
        end

        class C
          include M

          def bar
            foo
          end
        end

        c = C.new
        c.bar # => "foo"
        
        # privateメソッドのため、オブジェクトからは呼ぶとエラーになる
        c.foo # private method `foo' called for #<C:0x0000000104766c68> (NoMethodError)
        ```
    - モジュール関数に別名を付ける場合、先に別名を定義してからモジュール関数にする必要がある
        ```ruby
        # モジュール関数の別名は定義できないため、エラーになる
        module M
          def foo
            p "foo"
          end
          module_function :foo
          alias bar foo
        end
        
        M.foo   # => "foo"
        M.bar   # => undefined method `bar' for Foo:Module (NoMethodError)

        # モジュール関数に別名を付ける場合
        module M
          def foo
            p "foo"
          end
        
          alias bar foo
          module_function :foo, :bar
        end
        
        M.foo   # => "foo"
        M.bar   # => "foo"
        ```

# self関連
現在のメソッドの実行主体（レシーバ）を指す
- `self`呼び出し一覧
```ruby
p self # => main # mainはトップレベル（Objectクラス）に存在するインスタンス

class Hoge
  p self # => Hoge

  # メソッド内のself
  def hoge
    p self
  end

  # クラスメソッド内のself
  def self.hoge
    p self
  end

  # 特異メソッド内のself
  class << Hoge
    def foo
      p self
    end

    def bar
      baz
    end

    private

    # プライベートメソッド内のself
    def baz
      p self
    end
  end
end

Hoge.new.hoge # => <Hoge:0x000000010090eb00>
Hoge.hoge     # => Hoge
Hoge.foo      # => Hoge
Hoge.bar      # => Hoge

# 名前空間
module Zoo
  class Cat
    def where_self
      self
    end
   end
end

Zoo::Cat.new.where_self # => #<Zoo::Cat:0x007f8c02bf4f10>
```

- クラスメソッド内の`self`のクラスは`Class`クラス
    ```ruby
    class Identity
      def self.this_object
        self
      end
    
      def this_object
        self
      end
    end
    
    p Identity.this_object.class     # => Class
    p Identity.new.this_object.class # => Identity

    p Identity.this_object           # => Identity
    p Identity.new.this_object.class # => #<Identity:0x00000001010198f0>
    ```

- `Mixin`先のクラスメソッドは参照できない
    ```ruby
    module Bar
      def self.bar
        p self
      end

      def bar
        p self
      end
    end

    class Baz
      include Bar
    end

    Baz.bar # `<main>': undefined method `bar' for Baz:Class (NoMethodError)
    # 通常メソッドは参照可能
    Baz.new.bar # => #<Baz:0x0000000104682978>
    ```

## const_get
- `self`に定義された定数の値を返す
    ```ruby
    module Bar
      BAR = 1
    end
    
    class Object
      include Bar
    end
    
    # include されたモジュールに定義された定数を見付ける
    p Object.const_get(:BAR)   # => 1
    
    class Baz
      include Bar
    end
    
    # Object以外でも同様
    p Baz.const_get(:BAR)      # => 1
    
    # 定義されていない定数
    p Baz.const_get(:NOT_DEFINED) # => raise NameError
    
    # 第二引数に false を指定するとスーパークラスや include したモジュールで定義された定数は対象外になる
    p Baz.const_get(:BAR, false) # const_get': uninitialized constant Baz::BAR (NameError)
    p Bar.const_get(:BAR, false) # => 1
    
    # 完全修飾名を指定すると include や自分自身へ定義されていない場合でも参照できる
    p Class.const_get("Bar::BAR") # => 1
    ```

## class_variable_get
- クラス/モジュールに定義されているクラス変数の値を返す
    - クラス変数は`String`または`Symbol`を指定する
    - クラス変数が定義されていない場合、`NameError`が発生する
    ```ruby
    class Fred
      @@foo = 99
    end
    
    def Fred.foo
      class_variable_get(:@@foo)
    end
    
    p Fred.foo # => 99
    ```

## private
- `private`メソッドの呼び出し時に明示的にレシーバを指定することはできない。ただし、`self`をレシーバとして指定することはできる
    - `private`以降で定義されたメソッドはそのクラス、またはサブクラス内でのみ使用することができる
    ```ruby
    class A
      def foo
        self.bar
      end
    
      private
    
      def bar
        "baz"
      end
    
      def self.bar
        "quux"
      end
    end
    
    puts A.new.foo # => "baz"
    puts A.bar     # => "quux"
    
    # 明示的にレシーバを指定しているため、エラーになる
    puts A.new.bar # NoMethodError: private method `bar' called for xxx
    ```

- 親クラスに定義されている`private`メソッドは継承先からも呼び出ことができる
    - 逆に子クラスに定義されているprivateメソッドは親クラスから呼び出すことができない
    ```ruby
    class Parent
      private
      
      def hoge
        'hoge'
      end
    end
    
    class Child < Parent
      def test
        hoge
      end
    end
    
    Child.new.test # => "hoge"
    ```

## undef_method
- 引数（`String`または`Symbol`）に指定したインスタンスメソッドを未定義にする
    - スーパークラスのメソッドには影響しないが、サブクラスでそのメソッドが「未定義」となっているため、スーパークラスに同名メソッドが存在しても参照できず、`NoMethodError`になる
        - `undef` ：上記と機能は同様なのだが、引数に**識別子**もしく`Symbol`を指定する
    ```ruby
    class M1
      def foo ;end
      def self.moo
        undef foo
      end
    end
    
    M1.instance_methods(false) # => [:foo]
    M1.moo
    M1.instance_methods(false) # => []
    
    class M2
      def foo ;end
      def self.moo
        undef_method :foo
      end
    end
    
    M2.instance_methods(false) # => [:foo]
    M2.moo
    M2.instance_methods(false) # => []

    class M
      def foo ;end
    end

    class M3 < M
      def foo; end
      def self.moo
        undef_method :foo
      end
    end
    
    M3.instance_methods(false) # => [:foo]
    M3.moo
    M3.instance_methods(false) # => []
    M.instance_methods(false)  # => [:foo]
    ```

    - `alias`でメソッド名を別名に変更した場合の挙動
        ```ruby
        class Foo
          def foo
           "foo"
          end
         end
        
         class Bar < Foo
          def foo
           super + "bar"
          end
          alias bar foo
          undef foo
         end
        
         puts Bar.new.bar # => foobar
        ```

## remove_method
- 引数に指定したインスタンスメソッドを削除する
    - スーパークラスの同名メソッドには影響しない
    - 指定したメソッドが定義されていない場合、`NameError`が発生する
    ```ruby
    class C
      def foo
        p 'C#foo'
      end
    end

    class C2 < C
      def foo
        p 'C2#foo'
      end

      def bar; end

      remove_method :foo, :bar
    end

    p C2.new.foo # => "C#foo"
    p C2.new.bar # => undefined method `bar' for #<C2:xxx> (NoMethodError)
    ```

## alias_method
- 既存のメソッドに対して別名を付ける
    - グローバル変数やクラスメソッドに対して使用することはできない
    ```ruby
    module Kernel
      alias_method :hoge, :puts

      hoge 'hoge' # => hoge
    end
    ```
    - `alias`：`alias_method`同様、既存のメソッドに対して別名を付ける
        - メソッド名に文字列は使えない
        ``` ruby
        alias new_method old_method           # 識別子
        alias :new_method :old_method         # シンボル
        alias $new_global_val $old_global_val # グローバル変数も可能
        ```

## refinement
- 既存のクラスやモジュールを拡張・修正することができる
    - `using`：`refinement`の引数で指定したモジュールで定義された拡張を有効にする
        - メソッド内で呼び出した場合、`RuntimeError`が発生する
        ```ruby
        class C
          def m1
            400
          end
        end
        
        module M
          refine C do
            def m1
              100
            end
          end
        end
        
        class C
          using M
          # puts C.new  => スコープ内で呼び出した場合、 100 を返す
        end

        # using で Refinementを有効化しているが、スコープ外のため、 クラスCの m1 メソッドを参照している
        puts C.new.m1 # 400
        ```
    - `refine`は無名モジュールを作成するため、ブロック内の`self`は無名モジュールになる
        - 無名モジュール：`Module.new`で作成したモジュールを指す
        ```ruby
        class C
          def self.m1
            200
          end
        end
        
        module R
          refine C do
            def self.m1
              self # => <Module:0x000000010311d3d0>
              100
            end
          end
        end
        
        using R

        puts C.m1 # => 200
        ```
        - `Refinement`でクラスメソッドを再定義したい場合は`singleton_class`を使う
            ```ruby
            class C
              def self.m1
                'C.m1'
              end
            end
            
            module M
              refine C.singleton_class do
                def m1
                  self # => C
                  'C.m1 in M'
                end
              end
            end
            
            using M
            
            puts C.m1 #　=> C.m1 in M と表示されます。
            ```

## const_defined?
- クラス/モジュールに引数に指定した名前の定数が定義されている場合、真を返す
    - 第引数は`String`または`Symbol`で指定する
    - 第2引数に`false`を指定するとスーパークラスや`include`したモジュールで定義された定数は対象外になる
        ```ruby
        mod = Module.new

        mod.module_eval do
          CONST_IN_BLOCK = 100
        end
        
        mod.module_eval(<<-EVAL)
          CONST_IN_HERE_DOC = 100
        EVAL
        
        puts mod.const_defined?(:CONST_IN_BLOCK)           # => true
        puts mod.const_defined?(:CONST_IN_BLOCK, false)    # => false
        puts Object.const_defined?(:CONST_IN_BLOCK)        # => true
        puts Object.const_defined?(:CONST_IN_BLOCK, false) # => true
        
        puts mod.const_defined?(:CONST_IN_HERE_DOC)           # => true
        puts mod.const_defined?(:CONST_IN_HERE_DOC, false)    # => true
        puts Object.const_defined?(:CONST_IN_HERE_DOC)        # => false
        puts Object.const_defined?(:CONST_IN_HERE_DOC, false) # => false
        ```

## const_missing
- 定義されていない定数を参照したときにこのメソッドを呼び出される
    ```ruby
    class Foo
      def Foo.const_missing(id)
        warn "undefined constant #{id.inspect}"
      end
    
      Bar = 'baz'
    end

    Foo::Bar # => "baz"
    Foo::Baz # => undefined constant :Baz
    ```

# 探索順

### 定数
- 定数名のみを記述した場合の探索経路は次のようになる
    - (1) クラス/モジュールのネストを辿る探索を行う
        - クラス/モジュールのネストの状態を返すメソッド「`Module.nesting`」の配列内容が、探索経路となる　
            - `[M1::C2::M2::Cb, M1::C2::M2, M1::C2, M1]`の場合
                - `M1::C2::M2::Cb` -> `M1::C2::M2` -> `M1::C2` -> `M1`の順に探索する
    - (2) 次に、継承チェーンを辿る探索を行う

        ```ruby
        module M1
          class C1
            CONST = "001"
          end
        
          class C2 < C1
            CONST = "010"
        
            module M2
              CONST = "011"
        
              class Cb
                p Module.nesting # => [M1::C2::M2::Cb, M1::C2::M2, M1::C2, M1]
                p CONST # => "011"（モジュールM2に定数の定義されてなければ、 010 が出力される）
              end
            end
          end
        end

        # クラス・モジュールのネストを辿ったが見つからず、次の継承チェーンを辿った場合
        module M1
          class C1
            CONST = "001"
          end
        
          class C2 < C1
            module M2       
              class Ca
                CONST = "100"
              end
              
              class Cb < Ca
                p Module.nesting # => [M1::C2::M2::Cb, M1::C2::M2, M1::C2, M1]
                p CONST          # => "100"　（継承先のクラスCaの定数を辿る）
              end
            end
          end
        end
        ```
            
    - クラスと特異クラスに継承関係はない
        ```ruby
        class C1
          FOO = 'C1'
        end

        class << C1
          def foo
            Module.nesting # [#<Class:C1>]
            FOO
          end
        end
        
        C1.foo # => `foo': uninitialized constant #<Class:C1>::FOO (NameError)
        
        class << C1
          FOO = '特異C1'
        end

        C1.foo # => '特異C1'
        ```

    - ミックスイン先の定数は参照できる
        ```ruby
        module M1
          FOO = 'M1'
        
          class ::C1
            Module.nesting # [C1, M1]
            FOO            # => "M1"
          end
        end

        class C2 < C1
          Module.nesting   # [C2]
          # FOO  => includeする前だと下記エラーが発生する　
          #         <class:C2>': uninitialized constant C2::FOO (NameError)
          include M1
          FOO              # => 'M1'
        end
        ```

- `::`演算子を用いて記述した場合の探索
    - 継承チェーンを(Objectクラスの手前まで)辿る探索を行う
        ```ruby
        CONST = 'TOP'

        module M3
          CONST = 'M3!' # この定数が定義されていない状態で呼び出すと NameErrorが発生する
        end
        
        module M1
          CONST = 'M1'
          module M2
            CONST = 'M2'
            module M3
              CONST = 'M3'
            end
          end
        end

        p ::M3::CONST # => "M3!"
        ```

https://tech.i3-systems.com/entry/2023/10/03/120057

- 余談
    - 代入を行うと警告が発生するが、値は変更される
        ```ruby
        class Hoge
          HOGE = 'hoge'
        end

        Hoge::HOGE              # => "hoge"
        Hoge::HOGE = 'hogehoge' # warning: previous definition of HOGE was here
                                # => "hogehoge"
        Hoge::HOGE              # => "hogehoge"
        ```

### クラス変数
- クラスに所属するあらゆるもので情報を共有するためにあり、特異クラス定義の中でクラス変数を定義してもレキシカルに決定される

    ```ruby
    class C
      @@val = 10
    end
    
    module B
      @@val = 30
    end
    
    module M
      include B
      @@val = 20
    
      class << C
        p @@val # => 20
      end
    end
    ```
    - 子モジュールと親モジュールにて同名のクラス変数を書き換えるとエラーが発生する
        ```ruby
        class C
          @@val = 10
        end
        
        module B
          @@val = 30
        end
        
        module M
          @@val = 20
          include B
        
          class << C
            p @@val # `singleton class': class variable @@val of M is overtaken by B (RuntimeError)
          end
        end
        ```

        - 尚、クラスとモジュールではなく、親クラスとその親クラスで同じクラス変数を書き換えている場合はエラーが発生しない
            ```ruby
            class C
              @@val = 10
            end
            
            class C2 < C
              @@val = 20
            end
            
            class C3 < C2           
              class << self
                def hoge
                  p @@val
                end
              end
            end

            C3.hoge # => 20
            ```
            - 余談：トップレベルでクラス変数を読み書きするとエラーが発生する
            ```ruby
            @@val = 10 # `<main>': class variable access from toplevel (RuntimeError)
            @@val      # `<main>': class variable access from toplevel (RuntimeError)
            ```

### クラスインスタンス変数
- 継承先のサブクラスからはクラスインスタンス変数を参照できないため、エラーにはならないが`nil`を返す

    ```ruby
    class Foo
      attr_reader :var
    
      @var = "1"
    
      def initialize
        @var = "2"
      end
    end
    
    class Baz < Foo
      def self.var
        @var
      end
    end
    
    def Foo.var
      @var
    end
    
    arr = [
      Foo.new.var, # "2"
      Foo.var,     # "1"
      Baz.new.var, # "2"
      Baz.var      # nil
    ]
    ```

    - 特異クラスにも同様のクラスインスタンス変数が存在する場合
        - 特異メソッド`Speaker.speak`は`Speaker`クラスのコンテキストで評価されるため、特異クラスのインスタンス変数ではなく、`Speaker`クラスのインスタンス変数を参照する
        ```ruby
        class Speaker
          @message = "Hello!"
        
          class << self
            @message = "Howdy!"
        
            def speak
              @message
            end
          end
        end
        
        p Speaker.speak # => "Hello!"

        # 特異クラスのクラスインスタンス変数にアクセスする場合（Speakerの特異クラス定義を再オープン）
        speaker_message = class << Speaker; @message; end
        p speaker_message # => Howdy!
        ```
        - 余談
            - インスタンスメソッド内から直接参照できない
            - クラスメソッド（特異メソッド）からアクセスできる
            - `attr_reader`や`attr_accessor`などのアクセサを使用しても参照できない
            ```ruby
            class Hoge
              @hoge = 1
              attr_accessor :hoge
            
              def initialize
                @hoge *= 2 if hoge
              end
            
              def instance_hoge
                @hoge
              end
            
              class << self
                def class_hoge
                  @hoge
                end
              end
            end
            
            hoge = Hoge.new
            hoge.instance_hoge # => nil
            Hoge.class_hoge    # => 1
            hoge.hoge # <main>': undefined local variable or method `hoge' for main:Object (NameError)
            ```

### インスタンス変数
- 自身のクラスに定義されたインスタンス変数を最優先で参照する
    ```ruby
    class Foo
      def initialize
        @hoge = 'hoge'
      end
    end
    
    class Bar < Foo
      def initialize
        @hoge = 'hogehoge'
      end
      
      def bar
        p @hoge
      end
    end

    bar = Bar.new
    bar.bar # => "hogehoge"
    bar.instance_variable_get(:@hoge) # => "hogehoge"
    ```

- 次クラスにはなく、継承関係のクラスにある場合、親クラスのインスタンス変数を参照する
    ```ruby
    class Foo
      def initialize
        @hoge = 'hoge'
      end

      def foo
        p @hoge
      end
    end

    class Bar < Foo
      def bar
        p @hoge
      end
    end

    bar = Bar.new
    bar.bar # => "hoge"
    bar.instance_variable_get(:@hoge) # => "hoge"
    ```

- ミックスインで追加された場合、親クラスのインスタンス変数を参照する
    ```ruby
    module Baz
      def baz
        @hoge = 'mixin hoge'
      end
    end

    class Foo
      def initialize
        @hoge = 'hoge'
      end

      def foo
        p @hoge
      end
    end

    class Bar < Foo
      include Baz
      def bar
        p @hoge
      end
    end

    bar = Bar.new
    bar.bar # => "mixin hoge"
    bar.instance_variable_get(:@hoge) # => "mixin hoge"
    ```

---
余談
- インスタンスメソッド内のインスタンス変数は値を保持しない
    ```ruby
    class Foo
      def foo
        @foo ||= 0
        @foo += 1
      end
    end

    Foo.new.foo # => 1
    Foo.new.foo # => 1
    Foo.new.foo # => 1
    ```

### インスタンスメソッド
- 継承順に参照される
    - `クラス名.ancestors` でクラス/モジュールの継承順を配列で確認することができる

    ```ruby
    class Foo
      def hoge
        p 'Foo#hoge'
      end
    
      def hogehoge
        p 'Foo#hogehoge'
      end
    end
    
    class Bar < Foo
      def hoge
        p 'Bar#hoge'
      end
    end

    # 探索順を確認
    Bar.ancestors # => [Bar, Foo, Object, PP::ObjectMixin, Kernel, BasicObject]

    bar = Bar.new
    bar.hoge # => "Bar#hoge"
    
    # Barクラスにメソッド「hogehoge」が存在しないため、探索順通りに辿り、Fooクラスのメソッドを参照する
    bar.hogehoge # => "Foo#hogehoge"

    # どのクラスが持っているメソッドなのか確認
    p bar.method(:hoge).owner     # => Bar
    p bar.method(:hogehoge).owner # => Foo
    ```

    - `include`で追加したメソッドの場合、親クラスのメソッドより優先される
        ```ruby
        module Foo
          def hoge
            p 'Foo#hoge'
          end

          def hogehoge
            p 'Foo#hogehoge'
          end
        end
        
        class Bar
          def hoge
            p 'Bar#hgoe'
          end

          def hogehoge
            p 'Bar#hogehoge'
          end
        end

        class Baz < Bar
          include Foo
          def hoge
            p 'Baz#hgoe'
          end
        end

        Baz.ancestors # => [Baz, Foo, Bar, Object, PP::ObjectMixin, Kernel, BasicObject]
    
        baz = Baz.new
        baz.hoge     # => "Baz#hgoe"
        baz.hogehoge # => "Foo#hogehoge"
        ```

    - `prepend`で追加したメソッドの場合、自身の持つメソッドより優先される
        ```ruby
        module Foo
          def hoge
            p 'Foo#hoge'
          end

          def hogehoge
            p 'Foo#hogehoge'
          end
        end
        
        class Bar
          def hoge
            p 'Bar#hgoe'
          end

          def hogehoge
            p 'Bar#hogehoge'
          end
        end

        class Baz < Bar
          prepend Foo
          def hoge
            p 'Baz#hgoe'
          end
        end

        Baz.ancestors # => [Foo, Baz, Bar, Object, PP::ObjectMixin, Kernel, BasicObject]
    
        baz = Baz.new
        baz.hoge     # => "Foo#hoge"
        baz.hogehoge # => "Foo#hogehoge"
        ```

    - 同名メソッドが特異メソッドに存在する場合、クラスが持つメソッドより優先される
        ```ruby
        module Mod
          def foo
            p 'Mod Foo'
          end
        end
        
        class Foo
          prepend Mod
        
          def foo
            p 'foo'
          end
        end
        
        foo = Foo.new
        
        def foo.foo
          p 'FOO FOO'
        end
        
        foo.foo # => "FOO FOO"

        # 特異メソッドはインスタンスに生えているので `クラス名.ancestors` では確認できない
        p Foo.ancestors # => [Mod, Foo, Object, PP::ObjectMixin, Kernel, BasicObject]

        # 自身のオブジェクトを含んだリストを確認する場合
        p foo.singleton_class.ancestors
        # => [#<Class:#<Foo:xxx>>, Mod, Foo, Object, PP::ObjectMixin, Kernel, BasicObject]
        ```
---
余談
- トップクラスに定義したインスタンスメソッドをサブクラスから参照できる
    ```ruby
    def hoge
      p 'hoge'
    end

    class Foo
      def foo
        hoge
      end
    end

    Foo.new.foo # => "hoge"
    ```
- トップクラスに定義したプライベートメソッドを直接参照できる
    ```ruby
    private
    def hoge
      'hoge'
    end

    p hoge # => "hoge"
    ```

- クラスメソッド内でインスタンスメソッドを呼び出すとエラーになる
    ```ruby
    class Hoge
      def self.foo
        bar
      end

      def bar
        p 'bar'
      end
    end

    Hoge.foo # foo': undefined local variable or method `bar' for Hoge:Class (NameError)
    ```

- クラス内に直でセットしたインスタンスメソッドは、クラス定義が読み込まれた時点で実行される
    - インスタンス作成時には実行されない
    ```ruby
    def hoge
      p 'hoge'
    end

    class Foo
      hoge # 当該箇所

      def foo
        p 'foo'
      end
    end

    Foo.new.foo # => "foo"
    ```

# Enumeratorクラス関連
`each`以外のメソッドにも`Enumerable`の機能を提供するためのラッパークラス

## enum_for, to_enum
- `Enumerator`オブジェクトを作成する
    ```ruby
    a = [1, 2, 3]
    p(a.to_enum)  # => #<Enumerator: [1, 2, 3]:each>
    p(a.enum_for) # => #<Enumerator: [1, 2, 3]:each>
    ```
    - 文字列を扱う場合、引数に`each_char`を設定する
        ```ruby
        enum = "hoge".enum_for(:each_char)

        p enum.next # => "h"
        p enum.next # => "o"
        p enum.next # => "g"
        p enum.next # => "e"
        ```

## each_char
- 文字列の各文字に対して繰り返し処理を行う
    - `enum_for(:each_char)`、または`to_enum(:each_char)`でも同様の結果が得られる

    ```ruby
    "hello世界".each_char {|c| print c, ' ' } # => h e l l o 世 界
    ```

## filter_map
- ブロックが返した値の内、真の値だけを配列として返す
    ```ruby
    ary = ["foo", "bar", nil, "baz"]

    p ary.filter_map { |i| i&.upcase } # => ["FOO", "BAR", "BAZ"]
    ```

## for文
- 指定したオブジェクトから繰り返しのたびに値を取り出し、値がなくなるまで繰り返しを行う
    - ※ 他の繰り返し処理との大きな違いとして、新しいスコープを作成しないため、ループ内で定義された変数は**ループ外のコンテキストでも参照されてしまう**ため、予期しない動作を引き起こす可能性がある点に注意！
    ```ruby
    for i in 1..3 do # do は省略可
      puts i
    end
    
    puts i # => 3 （ループ外でも参照できる）
    ```

## partition
- ブロックの条件を満たす配列と条件を満たさない配列に分割して、結合した2次元配列を返す
    - 条件を満たす配列が0番目に入る
    ```ruby
    a = (1..5).partition(&:odd?)
    p a # => [[1, 3, 5], [2, 4]]
    ```

## tally
- `self`に含まれた要素を数え上げた結果を`Hash`で返す
    - 返り値の`Hash`の`key`は`self`に含まれる要素で、`value`は対応する要素が出現する回数が格納される
        - **Ruby 3.1**から`tally`メソッドが引数としてハッシュを受け取れるようになった
        ```ruby
        fruits = ['apple', 'banana', 'grape', 'orange', 'apple']
        fruits.tally # => {"apple"=>2, "banana"=>1, "grape"=>1, "orange"=>1}

        ['apple', 'grepe', 'peach'].tally(fruits.tally)
        # => {"apple"=>3, "banana"=>1, "grape"=>1, "orange"=>1, "grepe"=>1, "peach"=>1}
        ```

## lazy
- `map`や`select`メソッドに遅延評価を提供する
    ```ruby
    # 先頭から3つの値を取り出す場合
    (1..10).each.lazy.first(3)      # => [1, 2, 3]
    (1..10).each.lazy.take(3).force # => [1, 2, 3]
    (1..10).each.lazy.take(3).to_a  # => [1, 2, 3]
    ```

## chunk
- 要素を前から順にブロックで評価し、その結果によって要素をチャンクに分けた要素を持つ`Enumerator`を返す
    - ブロックの評価値が同じ値が続くものを一つのチャンクとして扱い、ブロックの評価値が一つ前と異なる所でチャンクが区切られる
    - 返り値の`Enumerator`は各チャンクのブロック評価値と各チャンクの要素を持つ配列のペアを各要素とする
    - 構文：`enum.chunk {|elt| key }.each {|key, ary| do_something }`
    ```ruby
    [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk {|n|
      n.even?
    }.each {|even, ary|
      p [even, ary]
    }
    
    # => [false, [3, 1]]
    #    [true, [4]]
    #    [false, [1, 5, 9]]
    #    [true, [2, 6]]
    #    [false, [5, 3, 5]]
    ```

https://inokara.hateblo.jp/entry/2022/12/04/231855

# Procオブジェクト
- ブロックをオブジェクト化したProcクラスのインスタンス
    - `call`または`[]`で呼び出すことができる
        - 引数の数が曖昧のため、引数を省略可能
    ```ruby
    local = 0
    
    p1 = Proc.new { |arg1, arg2|
      arg1, arg2 = arg1.to_i, arg2.to_i
      local += [arg1, arg2].max
    }
    
    p p1.call("1", "2") # => 2
    p p1.call("7", "5") # => 9
    p p1.call("9")      # => 18
    ```
## lambda

- `Proc.new`に殆ど一緒
    - 引数の数が厳密のため、引数を省略できない
    
    ```ruby
    local = 0
    
    p1 = lambda { |arg1, arg2|
      arg1, arg2 = arg1.to_i, arg2.to_i
      local += [arg1, arg2].max
    }
    
    p p1.call("1", "2") # => 2
    p p1.call("7", "5") # => 9
    p p1.call("9") # => wrong number of arguments (given 1, expected 2) (ArgumentError)
    ```
    - `lambda`の省略記法（ラムダリテラル構文）を使用した場合
        - `->`と引数リストの括弧の間にスペースがあるとエラーになる（くっついている必要がある）
        ```ruby
        local = 0
    
        p1 = ->(arg1, arg2) {
          arg1, arg2 = arg1.to_i, arg2.to_i
          local += [arg1, arg2].max
        }
    
        p p1.call("1", "2") # => 2
        p p1.call("7", "5") # => 9
        p p1.call("9") # => wrong number of arguments (given 1, expected 2) (ArgumentError)
        ```

## yield
- メソッド内部でブロックの実行結果を呼び出すことができる
    ```ruby
    def multiply_by(n)
      n * yield
    end

    p multiply_by(4) { 2 + 3 } # => 20
    ```

## ブロックを引数で明示的に受け取る方法
- `&`が付いた引数(ブロック引数)に渡されたブロックを`Proc`オブジェクトに変換することができる
    ```ruby
    val = 100
    
    def hoge(val)
      yield(15 + val)
    end
    
    _proc = Proc.new{|arg| val + arg }
    
    p hoge(val, &_proc) # => 215
    ```

## to_proc
- `self`に対応するProcオブジェクトを返す
    - 第一引数をレシーバとして、`self`という名前のメソッドを残りの引数を渡して呼びだす
    - 生成される`Proc`オブジェクトは`lambda`
    - メソッドに`&`と共にシンボルを渡すと`to_proc`が呼ばれ、ブロックとして扱うことができる
    ```ruby
    # "ff".to_i(16)と同様
    :to_i.to_proc["ff", 16] # => 255

    :object_id.to_proc.lambda? # => true

    # &プレフィックスを使用して暗黙的に呼び出す場合
    (1..5).select(&:odd?) # => [1, 3, 5]

    # &プレフィックスを使用しない場合
    (1..5).select { |i|i.odd?.to_proc } # => [1, 3, 5]
    ```

# 例外処理関連

## rescue
- `rescue`節でほできる例外は、指定した例外クラスとそのサブクラス
    - `rescue`に例外クラスを指定しない場合は、`StandardError`が捕捉される
    ```ruby
     class Error1 < StandardError; end
     class Error2 < Error1; end
    
     begin
      raise Error2
     # rescue　に　Error1　を指定しているが、Error1　のサブクラスの　Error2　が
     # raise に指定されているため、Error2 が捕捉される
     rescue Error1 => ex
      puts ex.class # Error2
     end
    ```

- `rescue`節で`raise`が引数なしで呼び出された場合、捕捉された例外が再度`raise`される
    ```ruby
    CustomError = Class.new(StandardError)

    def boom
      raise CustomError 
    rescue
      raise # 引数なし
    end
    
    begin 
      boom
    rescue => e
      p e.class # => CustomError
    end
    ```
- 殆どの組み込み例外クラスは`StandardError`のサブクラスですが、通常捕捉されることを想定していないいくつかの例外クラスは`Exception`を直接継承している
    ```ruby
    ArgumentError < StandardError < Exception

    ScriptError < Exception
    ```

## raise
- `RuntimeError`を発生させる
    - `raise`に例外クラスを指定しない場合は、`RuntimeError`を捕捉する
        - `RuntimeError`は`StandardError`のサブクラス
    ```ruby
    class Hoge
      raise
    rescue => e
      e.class # => RuntimeError
    end
    ```

## ensure
- メソッド(または`begin/end`ブロック)の`ensure`節は、例外が発生してもしなくても、常に実行される
    - ただし、`ensure`節の値は返り値としては使用されず、`ensure`節が実行される直前の評価結果が返り値として使用される
    ```ruby
    def greeting
      puts "greeting called!"
      "hello"
    ensure
      puts "Ensure called!"
      "hi"
    end
    
    puts greeting

    # 実行結果
    # greeting called!
    # Ensure called!
    # hello
    ```

# 気になるメソッド

## block_given?
- メソッドにブロックが与えられていれば真を返す
    - `{ }`は`do end`よりも結合度が高い為、実行結果が異なる
    ```ruby
    def m1(*)
      str = yield if block_given?
      p "m1 #{str}"
    end
    
    def m2(*)
      str = yield if block_given?
      p "m2 #{str}"
    end

    # ブロックの場合
    m1 (m2 {
          "hello"
        }
    )
    # 実行結果
    # "m2 hello"
    # "m1 "

    # do endで置き換えた場合
    m1 m2 do  # m1(m2) do と解釈される
      "hello"
    end
    # 実行結果
    # "m2 "
    # "m1 hello"
    ```

## instance
- そのクラスの唯一のインスタンスを返す
    - `Singleton`を`include`しないと使用することができない
        - `Singleton`を`include`したクラスで定義されるので、正確には`Singleton`モジュールのメソッドではない
    - ミックスインしたクラスのインスタンスは常に同一のものを返す
        ```ruby
        require 'singleton'

        class Hoge
          include Singleton
        
          def hoge
            @hoge ||= 0
            @hoge += 1
          end
        end
        
        p Hoge.instance.hoge # => 1
        p Hoge.instance.hoge # => 2
        p Hoge.instance.hoge # => 3
        ```

## catch
- `catch`ブロックでは、`throw`が実行されるまでコードが実行される
    - `catch`に対応するシンボルが`throw`に渡されると、Rubyはブロックの実行を終了し、ブロックの次の処理から実行を継続する
    ```ruby
    def x
      puts "x"
    end
    
    def y
      puts "y"
      throw :done # catchに対応するシンボル
    end
    
    def z
      puts "z"
    end
    
    
    catch :done do
      x
      y
      z
    end
    
    puts "done!"
    
    # [実行結果]
    # x
    # y
    # done!
    ```

    - `catch`ブロック内で`return`を使用すると`LocalJumpError`になる
    ```ruby
    result = catch do |tag|
      for i in 1..2
        for j in 1..2
          for k in 1..2
            return k
            # => `block (4 levels) in <top (required)>': unexpected return (LocalJumpError)
          end
        end
      end
    end
    ```

## succ
- `self`の次の文字列を返す
    ```ruby
    p "aa".succ        # => "ab"
    p "88".succ.succ   # => "90"

    # 繰り上がり
    p "99".succ   # => "100"
    p "a9".succ   # => "b0"
    p "Az".succ   # => "Ba"
    p "zz".succ   # => "aaa"
    p "-9".succ   # => "-10"
    p "9".succ    # => "10"
    p "09".succ   # => "10"
    
    # アルファベット・数字とそれ以外の混在
    p "1.9.9".succ # => # "2.0.0"
    
    # アルファベット・数字以外のみ
    p ".".succ     # => "/"
    p "\0".succ    # => "\001"
    p "\377".succ  # => "\001\000"
    ```

## `__method__`
- 現在のメソッド名を返す
    - メソッド外で呼ぶと`nil`を返す
    ```ruby
    def foo
      p __method__
    end
    alias :bar :foo
    foo          # => :foo
    bar          # => :foo (メソッド名が変更された場合でも元のメソッド名を返す)
    p __method__ # => nil
    ```

## ord
- 文字列の最初の文字の文字コードを整数で返す
    - `self`が空文字の場合は`ArgumentError`を返す
    ```ruby
    p "h".ord    # => 104
    p "hoge".ord # => 104
    p "".ord     # ord': empty string (ArgumentError)
    ```

## def_delegator
- メソッドの委譲先を設定する
    - 第一引数に**移譲先のオブジェクト**、第二引数に**移譲先のメソッド**、第三引数に**移譲元のメソッド**を設定する
        - 委譲元と委譲先のメソッド名が同じ場合、第三引数を省略することが可能
    - `extend Forwardable`で拡張することで使用できるようになる
    ```ruby
    require 'forwardable'
    
    class List
      extend Forwardable
    
      def initialize
        @contents = []
      end
    
      def_delegator :@contents, :push, :mypush
      def_delegator :@contents, :[]
    end
    
    list = List.new
    list.mypush("a")
    list.mypush("b")
    list.mypush("c")
    p list[1] # => "b"
    ```

## match
- 指定した文字列に対して文字列によるマッチングを行い、マッチした場合には結果を`MatchData`オブジェクトで返す
    - マッチしなかった場合、`nil`を返す
    - 第二引数には、マッチの位置を指定することができる（デフォルトは0）
        ```ruby
        s = 'aage bbge ccge'
        
        s.match('bbge')    # => #<MatchData "bbge"> 
        s.match('cc')      # => #<MatchData "cc"> 
        s.match('hoge')    # => nil
        s.match('..ge', 1) # => #<MatchData "bbge">
        s.match('ge', 13)  # => nil
        ```
https://waterlow2013.hatenablog.com/entry/2014/05/10/125000

## match?
- 指定した文字列に対して文字列によるマッチングを行い、マッチした場合には`true`を返す
    - マッチしない場合には`false`を返す
    - 第二引数には、マッチの位置を指定することができる（デフォルトは0）
        ```ruby
        "Ruby".match?('Ru')    # => true
        "Ruby".match?('Ru', 1) # => false
        "Ruby".match?('ho')    # => false
        ```

## super
- 現在のメソッドがオーバーライドしているメソッドを呼び出す
    - 括弧と引数が省略された場合には現在のメソッドの引数をそのまま引き渡す
        - 引数を渡さずにオーバーライドしたメソッドを呼び出すには、`super()`と括弧を明示する
    ```ruby
    class Foo
      def foo(arg=nil)
        p arg
      end
    end
    
    class Bar < Foo
      def foo(arg)
        super(5)       # 5 を引数にして呼び出す
        super(arg)     # 5 を引数にして呼び出す
        super          # 5 を引数にして呼び出す super(arg) の略記法
        arg = 1
        super          # 1 を引数にして呼び出す super(arg) の略記法
        super()        # 引数なしで呼び出す
      end
    end
    Bar.new.foo 5

    # 実行結果
    # 5
    # 5
    # 5
    # 1
    # nil
    ```
    - プライベートメソッドも参照できる
        ```ruby
        class C
          private
          def c
            p 'c'
          end
        end
        
        class B < C
          def c
            super
          end
        end

        B.new.c # => "c"
        ```

        - オーバーライド先のメソッドが引数を受け取らない場合、`super()`と括弧を明示しないとエラーになる
        ```ruby
        # 括弧を明示しない場合
        class Parent
          def say
            puts "親です"
          end
        end
        
        class Child < Parent
          def say(message)
            super
          end
        end
        
        Child.new.say('Hi!')
        #　=> ArgumentError (wrong number of arguments (given 1, expected 0))
        
        # 括弧を明示した場合
        class Child < Parent
          def say(message)
            super() # superキーワードに丸括弧を明示する
          end
        end
        
        Child.new.say('Hi!') #　=> 親です
        ```

## dig
- ハッシュや配列などのデータ構造に対して、`key`や`index`を設定　することで要素を参照できる（ネストしたオブジェクトを再帰的に返す）
    - 存在しない要素にアクセスする場合でもエラーは発生せず、`nil`を返す
    ```ruby
    h = { foo: {bar: {baz: 1}}}

    h.dig(:foo, :bar, :baz)      # => 1
    h.dig(:foo, :zot, :xyz)      # => nil
    
    g = { foo: [10, 11, 12] }
    g.dig(:foo, 1)               # => 11
    ```

## exit
- 例外`SystemExit`を発生させることによってプログラムの実行を終了させる
    - `SystemExit`でエラーをキャッチした場合、`exit`によるプログラム終了処理自体が中断されるため、後続処理が実行される
    - ※ 下記コードは`irb`では再現不可（`rails consoleで再現可能`）
    ```ruby
    puts 'start'
    begin
      puts 'start1...'
      exit
    rescue SystemExit => err
      puts "end1 with #{err.inspect}"
    end
    
    begin
      puts 'start2...'
      exit
    ensure
      puts 'end2...'
    end
    puts 'end' #　実行されない
    
    # => start
    #    start1...
    #    end1 with #<SystemExit: exit>
    #    start2...
    #    end2...
    ```

## squeeze
- 引数に含まれる文字が複数並んでいたら1文字にまとめる
    - 引数を 1 つも指定しない場合は、すべての連続した文字を 1 文字にまとめる
    - 引数を複数指定した場合は、すべての引数にマッチする文字を 1 文字にまとめる
        ```ruby
        p "112233445566778899".squeeze          # => "123456789"
        p "112233445566778899".squeeze("2-8")   # => "11234567899"
        
        # 以下の2つは同じ意味
        p "112233445566778899".squeeze("2378")          # => "11234455667899"
        p "112233445566778899".squeeze("2-8", "^4-6")   # => "11234455667899"
        ```

## strip
- 文字列の先頭と末尾の空白文字を全て取り除いた文字列を生成して返す
    - 空白文字の定義は `"\t\r\n\f\v"` 。また、文字列右側からは `\0`も取り除くが、左側の`\0`は取り除かない
    ```ruby
    p "  abc  \r\n".strip   # => "abc"
    p "  abc  ".strip       # => "abc"
    p "  \0  abc  \0".strip # => "abc"
    p "abc".strip           # => "abc"

    # 非破壊的メソッドのため、元の文字列は変わらない
    str = "\tabc\n"
    p str.strip # => "abc"
    p str       # => "\tabc\n"

    # !を末尾に付けると破壊的メソッドになり、元の文字列が変わる
    str = "\tabc\n"
    p str.strip! # => "abc"
    p str        # => "abc"
    ```

# 演算子関連

## AND
- `&&`と同じ動作をするが優先順位が低い
    ```ruby
    is_empty = true AND false
    is_empty # => true (AND よりも = の優先度が高いので true が代入される)
    ```

## ::
- ダブルコロン(`::`)を用いて、探索の始点となるオブジェクトを指定して定数やメソッドを参照できる
    - 左辺を省略して`::`が先頭にするとトップレベルから定数の探索を行う
    ```ruby
    CONST = 'Top'
    
    class Foo
      CONST = 'Foo'
      def foo
        'foo'
      end
    end

    class Bar 
      CONST = 'bar'
    end

    class Baz < Bar
      CONST = 'baz'
    end

    Foo::CONST   # => "Foo"
    Foo.new::foo # => "foo"
    
    ::CONST       # => "Top"
    'str'::upcase # => "STR"
    ```

### `...`
- **転送引数**と言い、キーワード引数やブロックを含め、残りの引数を転送する
    - 引数は括弧で囲う必要がある（省略できない）
    ```ruby
    class Hoge
      def foo(*arg)
        p arg
      end

      def bar(...)
        foo(...)
      end
    end

    hoge = Hoge.new
    hoge.bar('foo', 'bar', 'baz') # => ["foo", "bar", "baz"]
    ```

## ..
- **半無限区間**と言い、開始インデックスと終了インデックスを指定して対象の範囲の要素を新しい配列として取得する
    - 構文：`Arrayオブジェクト[start..end]`
    ```ruby
    arr = %i[a b c d]

    arr[2..3]   # => [:c, :d]
    arr[2..-1]  # => [:c, :d]
    arr[2..-3]  # => []
    arr[2..]    # => [:c, :d]
    arr[..2]    # => [:a, :b, :c]
    ```

## splat演算子
- 全ての残りの右辺値を配列として一つの変数に代入する
    - 引数を指定しない場合、空配列を返す
    - デフォルト値を直接設定することはできない
    ```ruby
    a, *b = *[1, 2, 3]
    p a # => 1
    p b # => [2, 3]

    a, b = [1, [2, 3]]
    p a # => 1
    p b # => [2, 3]

    a, b = [1, *[2, 3]]
    p a # => 1
    p b # => 2

    def ary(*args)
      p args
    end

    ary # => []
    ```

https://waterlow2013.hatenablog.com/entry/2014/05/15/000013


- 配列展開の挙動の違い
    ```ruby
    # 引数が文字列の場合
    def fx(*args)
      p(args)
    end
    fx("apple", "banana", "carrot") # => ["apple", "banana", "carrot"]
    
    # 引数が配列の場合
    def fx(*args)
      p(args)
    end
    fx(["apple", "banana", "carrot"]) # => [["apple", "banana", "carrot"]]
    
    # 引数が配列且つpメソッド呼び出し時にsplat演算子を付与した場合
    def fx(*args)
      p(*args)
    end
    fx(["apple", "banana", "carrot"]) # => ["apple", "banana", "carrot"]
    
    # 引数が配列且つsplat演算子を付与した場合
    def fx(*args)
      p(args)
    end
    fx(*["apple", "banana", "carrot"]) # => ["apple", "banana", "carrot"]
    ```

- メソッド内でデフォルト値を明示的に設定する場合
    ```ruby
    def example_method(arg1, *args)
      default_value = "default" # デフォルト値をセット
      
      args = [default_value] if args.empty?      
      puts "args: #{args.inspect}"
    end
    
    example_method("first_arg")               # => args: ["default"]
    example_method("first_arg", "second_arg") # => args: ["second_arg"]
    ```

## <<
- 指定されたオブジェクトを自身の末尾に破壊的に追加する
    - `self`を返すので、連続して書くことができる
    - オーバーライド可能
    ```ruby
    ary = [1]
    ary << 2 << 3 << 4
    p ary   #　=> [1, 2, 3, 4]
    ```

## フリップフロップ
- 条件式の中で範囲式を使うことでフリップフロップ回路のように一時的に真偽を保持するような挙動をとる
    - 評価順
        1. 左辺が`true`になるまで`false`を返し、左辺が`true`になると、次から右辺を評価する
        1. 右辺が`true`になるまで`true`を返し、右辺が`true`になると、次から左辺を評価する
        1.  左辺が`true`になるまで`false`を返す
    ```ruby
    10.times{|d| print d < 2...d > 5 ? "O" : "X" }
    # OOOOOOOXXX=> 10
    ```

https://www.buildinsider.net/language/rubytips/0015

# 日付関連

- クラス同士の減算
    ```ruby
    require 'date'
    
    # Date同士の減算
    d = Date.today - Date.today - 1
    d.class # => Rational
    
    # DateTime同士の減算
    dt = DateTime.now - DateTime.now - 1
    dt.class # => Rational
    
    # Time同士の減算
    t = Time.now - Time.now - 1
    t.class # => Float
    ```

## date << | >>
- `<<`は現在の日付のn月前を表す`Date`オブジェクトを返す
- `>>`は現在の日付のn月後を表す`Date`オブジェクトを返す
    ```ruby
    require "date"
    
    date = Date.new(2000, 2, 24)
    
    puts(date << 12) # => 1999-02-24
    puts(date >> 12) # => 2001-02-24
    ```

## strptime
- `Date`, `DateTime`, `Time`クラスの特異メソッドで、与えられた雛形（書式文字列）で日時表現を解析し、その情報に基づいてオブジェクトを生成する
    - ※ `DateTime`クラスは非推奨なクラスとなり、`DateTime`クラスではなく`Time`クラスを使うよう、公式にアナウンスされているので割愛

### `Time`クラスの場合
- 第一引数に**時刻を表す文字列**を、第二引数に**書式文字列**を設定する
- 引数を設定しないと`ArgumentError`になる
- `Time`クラスを拡張するRubyのライブラリのため、`require 'time'`が必要
    ```ruby
    # 構文
    # Time.strptime(date, format, now=self.now)
    # Time.strptime(date, format, now=self.now) {|y| ... }

    require 'time'

    Time.strptime("00000024021993", "%S%M%H%d%m%Y")
    # => 1993-02-24 00:00:00 +0900

    # ブロックを渡すと年の部分を変更できる
    Time.strptime('91/5/18 4:13:00', '%Y/%m/%d %T'){|y| # y には year(91)が渡される
      if y > 100 then y
      elsif y >= 69 then y + 1900
      else y + 2000
      end
    } # => 1991-05-18 04:13:00 +0900
    ```

### `Date`クラスの場合
- 第一引数に**時刻を表す文字列**を、第二引数に**書式文字列**を、第三引数に**グレゴリオ暦をつかい始めた日をあらわすユリウス日**を設定
    - 第三引数を省略した場合、`「ITALY (1582年10月15日)」`が設定される（気になる方は下記参考記事まで）
    - `Date`クラスを拡張するRubyのライブラリのため、`require 'date'`が必要
        ```ruby
        require 'date'

        Date.strptime('2001-02-03T12:13:14Z')
        # => #<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>

        date = Date.strptime('2001-02-03T12:13:14Z').to_s # => "2001-02-03"
        Date.strptime(date, '%Y-%m-%d')
        # => #<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>
        ```

https://qiita.com/jooohn1234/items/737a94bf19438a4c615f

## strftime
- 与えられた雛形（書式文字列）で日時表現を解析し、その情報に基づいてオブジェクトを生成する
    - 引数には書式文字列を設定
        ```ruby
        p t = Time.now # => 2023-12-29 10:13:44.373922 +0900
        p t.strftime("Printed on %m/%d/%Y") # => "Printed on 12/29/2023"
        p t.strftime("%Y%m%d")              # => "20231229"
        p t.strftime("%F")                  # => "2023-12-29"
        p t.strftime("%Y%jT%H%MZ")          # => "2023363T1014Z" 
        ```

## Time.iso8601
- XML Schemaで定義されている`dateTime`として引数に指定した日付文字列をパースして`Time`オブジェクトに変換する
    - 引数が`ISO 8601`で定義されている形式に準拠していない、または`Time`クラスが指定された日時を表現できないときに`ArgumentError`が発生する
        ```ruby
        require 'time'

        iso8601_time = '2008-08-31T12:34:56+09:00'
        Time.iso8601(iso8601_time) # => 2008-08-31 12:34:56 +0900

        # => 2008-08-31の後の「A」が形式に準拠していないため、エラーとなる
        begin
          non_iso8601_time = '2008-08-31A12:34:56+09:00'
          Time.iso8601(non_iso8601_time)
        rescue ArgumentError => err
          puts err #=> invalid date: "2008-08-31A12:34:56+09:00"
        end
        ```


# 正規表現関連
- ある一定の規則で並んでいる文字列を検出するための技法

### 正規表現一覧
- `.`：任意の1文字（改行は含まない）
- `*`：0回以上の繰り返し
- `+`：1回以上の繰り返し
- `?`：0回か1回の繰り返し

    ```ruby
    'hello'.match(/.*/)     # => #<MatchData "hello">
    'hello'.match(/l+/)     # => #<MatchData "ll">
    'hello'.match(/he?llo/) # => #<MatchData "hello">
    ```
- `{n}`：ちょうどn回(nは数字)
- `{n,} `：n回以上(nは数字)
- `{,m}`：m回以下(mは数字)
- `{n,m} `： n回以上m回以下(n,mは数字)

    ```ruby
    'aabbcc'.match(/a{1}b{2}c{1}/)       # => #<MatchData "abbc">
    'aabbcc'.match(/a{,1}b{2,}c{,1}/)    # => #<MatchData "abbc">
    'aabbcc'.match(/a{1,2}b{1,2}c{0,2}/) # => #<MatchData "aabbcc">
    ```
- `-（ハイフン）`：範囲の表現
- `[..]（ブランケットで囲む）`：いずれかの1文字にマッチ
- `[^..]`：いずれかの文字にもマッチしない

    ```ruby
    'hello'.match(/h[a-e][l-n]lo/)   # => #<MatchData "hello">
    'hello'.match(/he[^a-g][^h-j]o/) # => #<MatchData "hello">
    'hello world'.match(/[^ ]*/)     # => #<MatchData "hello">
    ```

- `\w`：単語構成文字 `[a-zA-Z0-9_]`
- `\W`：非単語構成文字 `[^a-zA-Z0-9_]`
- `\s`：空白文字 `[ \t\r\n\f]`
- `\S`：非空白文字 `[^ \t\r\n\f]`
- `\d`：16進数字 `[0-9a-fA-F]`
- `\D`：非10進数字 `[^0-9]`
- `\h`：16進数字 `[0-9a-fA-F]`
- `\H`：非16進数字 `[^0-9a-fA-F]`

    ```ruby
    /\w+/.match("ABC_def")    # => #<MatchData "ABC_def">
    /\W+/.match("ABC def")    # => #<MatchData " ">
    /\s+/.match(" ")          # => #<MatchData " ">
    /\S+/.match(" ")          # => nil
    /\d+/.match('ABCabc123')  # => #<MatchData "123">
    /\D+/.match('ABCabc123')  # => #<MatchData "ABCabc">
    /\h+/.match('ABCabc123Z') # => #<MatchData "ABCabc123">
    /\H+/.match('ABCabc123Z') # => #<MatchData "Z">
    ```

    応用
    ```ruby
    p "Matz is my tEacher"[/[J-P]\w+[^ ]/] # => "Matz"
    ```

## $1..
- 特殊なローカル変数で`$`の後にn(整数)を付けるとn個目の括弧内の正規表現にマッチした文字列を参照できる
    - 該当する括弧がなければ`nil`が入る
- `$0`：Rubyスクリプトが実行された時のプログラムのファイル名を表す特別な変数
    ```ruby
    %r|(http://www(\.)(.*)/)| =~ "http://www.example.com/"
    
    p $0 # => irb (irbで実行した場合)
    p $1 # => "http://www.example.com/"
    p $2 # => "."
    p $3 # => "example.com"
    p $4 # => nil
    
    ```

## =~
- 正規表現もしくは`=~`メソッドを持つオブジェクト（`self`）とのマッチを行う
    - 構文：`self =~ other`
        - マッチしていればマッチした位置のインデックスを、そうでなければ`nil`を返す
        - `other`が正規表現でも文字列でもない場合は`other =~ self`を行う
        - `other`が文字列の場合、`TypeError`が発生する
    ```ruby
    p "string" =~ /str/   # => 0
    p "string" =~ /not/   # => nil
    p "abcfoo" =~ /foo/   # => 3
    p /str/ =~ "str"      # => 0
    p "string" =~ "str"   # =~': type mismatch: String given (TypeError)
    
    # 正規表現としての利用例
    regex = /\d+/  # 1つ以上の数字にマッチする正規表現
    regex =~ "123" # 0
    ```

# 制御構造関連
## case(when節)
- 一つの式に対する一致判定による分岐を行う
    - 上から順番に`when`の直後の式を評価した結果をレシーバとし、`case`の直後の式を評価した値を引数として`===` 演算子を呼び出し、最初に真を返した`when`節の本体を実行する
    - どの `when`節でも条件が成立しなかった場合は、`else`節を実行する
    ```ruby
    def hoge(arg)
      case arg
      when 'foo'
        p 'foo'
      when 'bar'
        p 'bar'
      else
        p 'baz'
      end
    end

    hoge('bar') => "bar"
    ```
## case(in節)
- パターンマッチしているか確認する
    ```ruby
    def hoge
      case { a: '1', b: '2', c: '3' }
      in { a: 1, b: 2, c: 3 }
        p 'foo'
      in { a: '1', b: '2', c: '3' }
        p 'bar'
      else
        p 'baz'
      end
    end

    hoge # => 'bar'

    # ハッシュ式の設定値によっては、エラーになる（in節の設定値でシンボルを使う文法ではない場合）
    def hoge
      case { a: '1', b: '2', c: '3' }
      # syntax error, unexpected symbol literal, expecting label or ** or **arg or string literal (SyntaxError)
      in { :a => 1, :b => 2, :c => 3 }
        p 'foo'
      in { :a => '1', :b => '2', :c => '3' }
        p 'bar'
      else
        p 'baz'
      end
    end

    hoge # undefined local variable or method `hoge' for main:Object (NameError)
    ```


# パーセント記法

## %/ /
- ダブルクォート文字列にする
    ```ruby
    fruits = %/apple banana orange/
    p fruits # => "apple banana orange"
    ```

## %r/ /
- 正規表現にする
    ```ruby
    fruits = %r/apple banana orange/
    p fruits # => /apple banana orange/
    ```

## %w/ /
- 要素を文字列の配列にする
    ```ruby
    fruits = %w/apple banana orange/
    p fruits # => ["apple", "banana", "orange"]
    ```

# Rubyオプション一覧
- 前提：`Mac`の`Terminal`でシェル(zsh)で実行
 
## -e
- 引数にファイル名を取らずに、引数に与えられた文字列をそのまま Ruby スクリプトとして解釈して実行する
    ```shell
    % ruby -e 'puts "hoge"' # => hoge
    ```

## -n
- 標準入力として与えられた文字列の各行に対してRubyスクリプトを実行する
    - 各行の文字列は`$_`変数に格納される
    ```shell
    % echo 'foo\nbar\nbaz' | ruby -ne 'puts "hoge" + $_'
    # => hogefoo
    # => hogebar
    # => hogebaz
    ```

## -p
- `-n`フラグとほぼ同じだが, 各ループの最後に`$_`の値を出力するようになる
    ```shell
    % echo 'foo\nbar\nbaz' | ruby -pe '$_ =  "hoge" + $_'
    # => hogefoo
    # => hogebar
    # => hogebaz
    ```

## -a
- `-n`や`-p`と一緒に用いた際に、各行の文字列が split されて $F 配列に格納される
    - `-n`か`-p`オプションが同時に指定されない限り, このオプションは意味を持たない
    ```shell
    % echo 'foo bar baz' | ruby -ane 'puts $F'
    # => foo
    # => bar
    # => baz

    % echo 'foo bar baz' | ruby -ane 'puts $F[1]'
    # => bar
    ```
## -l
- 行末の自動処理（読み込み時の改行除去、出力時に行末に自動で改行を付与）を行う
    - `$_`変数の末尾に改行が残っていることにより、意図しない結果が出力される場合の回避策として使用できる
    ```shell
    echo 'foo\nbar\nbaz' | ruby -lne 'puts $_ + "hoge"'
    # => foohoge
    # => barhoge
    # => bazhoge

    # -lオプションを使用しなかった場合
    echo 'foo\nbar\nbaz' | ruby -ne 'puts $_ + "hoge"'
    # => foo
    # => hoge
    # => bar
    # => hoge
    # => baz
    # => hoge
    ```

## -i
- `-p`や`-n`と併用することで、引数として指定されたファイルの内容を置換する
    - `-i.bak`のように拡張子を指定すると、バックアップファイルとして指定拡張子が付いたファイルを作成する
    ```shell
    % echo matz > /tmp/junk
    % cat /tmp/junk # => matz
    % ruby -i.bak -pe '$_.upcase!' /tmp/junk
    % cat /tmp/junk # => MATZ
    % cat /tmp/junk.bak # => matz
    ```

## -C
- スクリプト実行前に指定されたディレクトリに移動する
    ```shell
    # /tmp/junk の中身
    puts 'MATZ'
    
    % ruby -C /tmp junk # => MATZ
    ```

## -c
- スクリプトの内部形式へのコンパイルのみを行い, 実行しない
    - コンパイル終了後, 文法エラーが無ければ, **Syntax OK**と出力する
    ```shell
    % ruby -c /tmp/junk # Syntax OK
    ```

## -r
- スクリプト実行前に指定したライブラリを`require`する
    ```shell
    # SecureRandomを読み込む場合
    ruby -r 'SecureRandom' -e 'puts SecureRandom.hex'
    # => 1e0b847dd05a195ffa0f6d302e64d8c7
    ```

https://studioplustwo.hatenablog.jp/entry/2021/11/30/173353

https://peakp.hatenablog.com/entry/2015/05/06/213912

# その他
## require
- Rubyライブラリをロードする
    - 同じファイルは1度のみロードする
    - `.rb`や`.so`を自動補完する
    ```ruby
    # lib.rb
    module Lib
      $num += 1
    end

    # program.rb
    $num = 0
    1..10.times do |n|
      require './lib.rb'
    end
    puts $num # => 1
    ```


## load
- 設定ファイルの読み込みに用いる
    - ファイルを無条件ロードする
    - 補完はしない
    ```ruby
    # lib.rb
    module Lib
      $num += 1
    end

    # program.rb
    $num = 0
    1..10.times do |n|
      load './lib.rb'
    end
    puts $num # => 10
    ```

## Numbered parameter
- 暗黙的にブロックの引数を参照することができる構文 
    - `_1` ~ `_9` を使用することができる
    ```ruby
    h = {a: "gold", b: "silver"}
    puts h.map { puts "#{_1}, #{_2}"}
    
    # 実行結果 
    a, gold
    b, silver
    ```