0
1

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

Last updated at Posted at 2023-12-30

内容

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

前提

Ruby3.1系

学習教材

目次

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

Objectクラス関連

  • Objectクラスにメソッドを定義すると特異クラスでもそのメソッドを利用することができる
    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

  • レシーバの特異クラスを返す。また、特異クラスが存在しなければ新しく作成する

    • レシーバが IntegerFloatSymbolの場合にTypeErrorが発生する
    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を参照するとレシーバのオブジェクトを返す
    class Hoge
      def self._singleton
        class << Hoge
          self
        end
      end
    end
    
    p Hoge._singleton # => #<Class:Hoge>
    

method

  • オブジェクトに対してメソッド名を引数としてmethodを呼び出すと、当該メソッドをオブジェクト化したMethodオブジェクトを作って返す
    • メソッド名はStringまたはSymbolで指定
    • 定義されていないメソッド名を引数として与えるとNameErrorが発生する
    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が指定される
    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が指定される
    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から変わることはない
      class C
      public
        def initialize
        end
      end
      
      p C.new.private_methods.include? :initialize # => true
      

instance_eval

  • オブジェクトの特異クラスにインスタンスメソッドを定義することができる
    • instance_evalにブロックを渡した場合のネスト状態
      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に文字列を渡した場合のネスト状態
      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にブロックを渡した場合のネスト状態
      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に文字列を渡した場合のネスト状態
      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が発生する
    • インスタンス変数が定義されていなければ新たに定義される
    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を返す
    • インスタンス変数名は文字列かシンボルで指定
    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

  • 継続チェーンを辿った末にメソッドが見つからなかった場合に呼び出される
    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が発生する
      • 非破壊的な操作はできる
    • オブジェクトの代入はできる
    # 破壊的な操作をした場合
    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
    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

  • インスタンスメソッドを動的に定義できる
    • 第一引数にメソッド名、第二引数に処理を記述する(ブロックで渡すことも可能)
    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メソッドは、凍結状態・汚染状態・特異メソッドはコピーしない
    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__を使用することで安全性を確保できます。

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

class

  • レシーバのクラスを返す
    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_sendprotected_sendというメソッドは存在しない(引っ掛け問題で出題されました)
    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クラス
    • 同名のモジュールを別々に定義したとしてもテーブルを参照して値を取得することができる

      • 同名の定数やメソッドを定義している場合、後で定義したモジュール側の内容に上書きされる
      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"
      
    • モジュールをスーパークラスとして定義することはできない

      • ※クラスを継承する場合、スーパークラスはクラスである必要がある
      module Hoge;end
      
      class C < Hoge;end # superclass must be an instance of Class (given an instance of Module) (TypeError)
      

ancestors

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

    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にミックスインしているモジュールの配列を返す
    module Mixin
    end
    
    module Outer
      include Mixin
    end
       
    Mixin.included_modules   # => []
    Outer.included_modules   # => [Mixin]
    

include

  • 引数で指定したモジュールの定数、メソッド、モジュール変数(モジュールで定義されたクラス変数)を引き継ぐ(ミックスイン)ことができる
    • メソッド探索順はselfの後に追加される

      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
      
    • 複数モジュールを指定した場合、左側から右側の順でメソッド探索される

      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つずつ定義した場合、下から順に探索される

      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の定数、メソッド、モジュール変数を上書きする

    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
    
    • 複数モジュールを指定した場合、左側から右側の順でメソッド探索される

      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つずつ定義した場合、下から順に探索される

      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の特異メソッドとして追加する
    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」と言い替えることもできる
      # obj.extend Foo, Bar とほぼ同じ
      class << obj
        include Foo, Bar
      end
      

included

  • includeしたモジュールのインスタンスメソッドをクラスのインスタンスメソッドだけではなく、クラスメソッドとして使用することができる
    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した際の挙動が変わる
    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

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

    module A
      p Module.nesting # => [A]
    
      class B
        p Module.nesting # => [A::B, A]
      end
    end
    
    • xxx_evalでの渡し方の違いによる挙動の変化について
      • ブロックで渡した場合、クラス・モジュールのスコープに入らない
      • テキストコードを与えた場合、class・moduleキーワード等でオープンしたとき相当の処理がされるため、スコープに入る
      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メソッドであると同時に特異メソッドでもあるようなメソッドを指す
    • 引数が与えられた場合、引数で指定されたメソッドをモジュール関数にする
      • 引数なしの場合、今後このモジュール定義文内で新しく定義されるメソッドをすべてモジュール関数にする
      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して使用する場合
      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)
      
    • モジュール関数に別名を付ける場合、先に別名を定義してからモジュール関数にする必要がある
      # モジュール関数の別名は定義できないため、エラーになる
      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呼び出し一覧
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クラス

    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先のクラスメソッドは参照できない

    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に定義された定数の値を返す
    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が発生する
    class Fred
      @@foo = 99
    end
    
    def Fred.foo
      class_variable_get(:@@foo)
    end
    
    p Fred.foo # => 99
    

private

  • privateメソッドの呼び出し時に明示的にレシーバを指定することはできない。ただし、selfをレシーバとして指定することはできる

    • private以降で定義されたメソッドはそのクラス、またはサブクラス内でのみ使用することができる
    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メソッドは親クラスから呼び出すことができない
    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を指定する
    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でメソッド名を別名に変更した場合の挙動
      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が発生する
    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

  • 既存のメソッドに対して別名を付ける
    • グローバル変数やクラスメソッドに対して使用することはできない
    module Kernel
      alias_method :hoge, :puts
    
      hoge 'hoge' # => hoge
    end
    
    • aliasalias_method同様、既存のメソッドに対して別名を付ける
      • メソッド名に文字列は使えない
      alias new_method old_method           # 識別子
      alias :new_method :old_method         # シンボル
      alias $new_global_val $old_global_val # グローバル変数も可能
      

refinement

  • 既存のクラスやモジュールを拡張・修正することができる
    • usingrefinementの引数で指定したモジュールで定義された拡張を有効にする
      • メソッド内で呼び出した場合、RuntimeErrorが発生する
      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で作成したモジュールを指す
      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を使う
        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したモジュールで定義された定数は対象外になる
      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

  • 定義されていない定数を参照したときにこのメソッドを呼び出される
    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) 次に、継承チェーンを辿る探索を行う

      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
      
    • クラスと特異クラスに継承関係はない

      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'
      
    • ミックスイン先の定数は参照できる

      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クラスの手前まで)辿る探索を行う
      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!"
      

  • 余談
    • 代入を行うと警告が発生するが、値は変更される
      class Hoge
        HOGE = 'hoge'
      end
      
      Hoge::HOGE              # => "hoge"
      Hoge::HOGE = 'hogehoge' # warning: previous definition of HOGE was here
                              # => "hogehoge"
      Hoge::HOGE              # => "hogehoge"
      

クラス変数

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

    class C
      @@val = 10
    end
    
    module B
      @@val = 30
    end
    
    module M
      include B
      @@val = 20
    
      class << C
        p @@val # => 20
      end
    end
    
    • 子モジュールと親モジュールにて同名のクラス変数を書き換えるとエラーが発生する

      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
      
      • 尚、クラスとモジュールではなく、親クラスとその親クラスで同じクラス変数を書き換えている場合はエラーが発生しない
        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
        
        • 余談:トップレベルでクラス変数を読み書きするとエラーが発生する
        @@val = 10 # `<main>': class variable access from toplevel (RuntimeError)
        @@val      # `<main>': class variable access from toplevel (RuntimeError)
        

クラスインスタンス変数

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

    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.speakSpeakerクラスのコンテキストで評価されるため、特異クラスのインスタンス変数ではなく、Speakerクラスのインスタンス変数を参照する
      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_readerattr_accessorなどのアクセサを使用しても参照できない
        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)
        

インスタンス変数

  • 自身のクラスに定義されたインスタンス変数を最優先で参照する

    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"
    
  • 次クラスにはなく、継承関係のクラスにある場合、親クラスのインスタンス変数を参照する

    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"
    
  • ミックスインで追加された場合、親クラスのインスタンス変数を参照する

    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"
    

余談

  • インスタンスメソッド内のインスタンス変数は値を保持しない
    class Foo
      def foo
        @foo ||= 0
        @foo += 1
      end
    end
    
    Foo.new.foo # => 1
    Foo.new.foo # => 1
    Foo.new.foo # => 1
    

インスタンスメソッド

  • 継承順に参照される

    • クラス名.ancestors でクラス/モジュールの継承順を配列で確認することができる
    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で追加したメソッドの場合、親クラスのメソッドより優先される

      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で追加したメソッドの場合、自身の持つメソッドより優先される

      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"
      
    • 同名メソッドが特異メソッドに存在する場合、クラスが持つメソッドより優先される

      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]
      

余談

  • トップクラスに定義したインスタンスメソッドをサブクラスから参照できる

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

    private
    def hoge
      'hoge'
    end
    
    p hoge # => "hoge"
    
  • クラスメソッド内でインスタンスメソッドを呼び出すとエラーになる

    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)
    
  • クラス内に直でセットしたインスタンスメソッドは、クラス定義が読み込まれた時点で実行される

    • インスタンス作成時には実行されない
    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オブジェクトを作成する
    a = [1, 2, 3]
    p(a.to_enum)  # => #<Enumerator: [1, 2, 3]:each>
    p(a.enum_for) # => #<Enumerator: [1, 2, 3]:each>
    
    • 文字列を扱う場合、引数にeach_charを設定する
      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)でも同様の結果が得られる
    "hello世界".each_char {|c| print c, ' ' } # => h e l l o 世 界
    

filter_map

  • ブロックが返した値の内、真の値だけを配列として返す
    ary = ["foo", "bar", nil, "baz"]
    
    p ary.filter_map { |i| i&.upcase } # => ["FOO", "BAR", "BAZ"]
    

for文

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

partition

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

tally

  • selfに含まれた要素を数え上げた結果をHashで返す
    • 返り値のHashkeyselfに含まれる要素で、valueは対応する要素が出現する回数が格納される
      • Ruby 3.1からtallyメソッドが引数としてハッシュを受け取れるようになった
      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

  • mapselectメソッドに遅延評価を提供する
    # 先頭から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 }
    [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]]
    

Procオブジェクト

  • ブロックをオブジェクト化したProcクラスのインスタンス
    • callまたは[]で呼び出すことができる
      • 引数の数が曖昧のため、引数を省略可能
    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に殆ど一緒

    • 引数の数が厳密のため、引数を省略できない
    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の省略記法(ラムダリテラル構文)を使用した場合
      • ->と引数リストの括弧の間にスペースがあるとエラーになる(くっついている必要がある)
      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

  • メソッド内部でブロックの実行結果を呼び出すことができる
    def multiply_by(n)
      n * yield
    end
    
    p multiply_by(4) { 2 + 3 } # => 20
    

ブロックを引数で明示的に受け取る方法

  • &が付いた引数(ブロック引数)に渡されたブロックをProcオブジェクトに変換することができる
    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が呼ばれ、ブロックとして扱うことができる
    # "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が捕捉される
     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される

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

    ArgumentError < StandardError < Exception
    
    ScriptError < Exception
    

raise

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

ensure

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

気になるメソッド

block_given?

  • メソッドにブロックが与えられていれば真を返す
    • { }do endよりも結合度が高い為、実行結果が異なる
    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

  • そのクラスの唯一のインスタンスを返す
    • Singletonincludeしないと使用することができない
      • Singletonincludeしたクラスで定義されるので、正確にはSingletonモジュールのメソッドではない
    • ミックスインしたクラスのインスタンスは常に同一のものを返す
      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はブロックの実行を終了し、ブロックの次の処理から実行を継続する
    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になる
    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の次の文字列を返す
    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を返す
    def foo
      p __method__
    end
    alias :bar :foo
    foo          # => :foo
    bar          # => :foo (メソッド名が変更された場合でも元のメソッド名を返す)
    p __method__ # => nil
    

ord

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

def_delegator

  • メソッドの委譲先を設定する
    • 第一引数に移譲先のオブジェクト、第二引数に移譲先のメソッド、第三引数に移譲元のメソッドを設定する
      • 委譲元と委譲先のメソッド名が同じ場合、第三引数を省略することが可能
    • extend Forwardableで拡張することで使用できるようになる
    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)
      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
      

match?

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

super

  • 現在のメソッドがオーバーライドしているメソッドを呼び出す
    • 括弧と引数が省略された場合には現在のメソッドの引数をそのまま引き渡す
      • 引数を渡さずにオーバーライドしたメソッドを呼び出すには、super()と括弧を明示する
    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
    
    • プライベートメソッドも参照できる

      class C
        private
        def c
          p 'c'
        end
      end
      
      class B < C
        def c
          super
        end
      end
      
      B.new.c # => "c"
      
      • オーバーライド先のメソッドが引数を受け取らない場合、super()と括弧を明示しないとエラーになる
      # 括弧を明示しない場合
      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

  • ハッシュや配列などのデータ構造に対して、keyindexを設定 することで要素を参照できる(ネストしたオブジェクトを再帰的に返す)
    • 存在しない要素にアクセスする場合でもエラーは発生せず、nilを返す
    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で再現可能
    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 文字にまとめる
      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は取り除かない
    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

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

::

  • ダブルコロン(::)を用いて、探索の始点となるオブジェクトを指定して定数やメソッドを参照できる
    • 左辺を省略して::が先頭にするとトップレベルから定数の探索を行う
    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"
    

...

  • 転送引数と言い、キーワード引数やブロックを含め、残りの引数を転送する
    • 引数は括弧で囲う必要がある(省略できない)
    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]
    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演算子

  • 全ての残りの右辺値を配列として一つの変数に代入する
    • 引数を指定しない場合、空配列を返す
    • デフォルト値を直接設定することはできない
    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 # => []
    

  • 配列展開の挙動の違い

    # 引数が文字列の場合
    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"]
    
  • メソッド内でデフォルト値を明示的に設定する場合

    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を返すので、連続して書くことができる
    • オーバーライド可能
    ary = [1]
    ary << 2 << 3 << 4
    p ary   # => [1, 2, 3, 4]
    

フリップフロップ

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

日付関連

  • クラス同士の減算
    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オブジェクトを返す
    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'が必要
    # 構文
    # 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'が必要
      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)>
      

strftime

  • 与えられた雛形(書式文字列)で日時表現を解析し、その情報に基づいてオブジェクトを生成する
    • 引数には書式文字列を設定
      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が発生する
      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回の繰り返し

    '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は数字)

    '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文字にマッチ

  • [^..]:いずれかの文字にもマッチしない

    '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]

    /\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">
    

    応用

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

$1..

  • 特殊なローカル変数で$の後にn(整数)を付けるとn個目の括弧内の正規表現にマッチした文字列を参照できる
    • 該当する括弧がなければnilが入る
  • $0: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が発生する
    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節を実行する
    def hoge(arg)
      case arg
      when 'foo'
        p 'foo'
      when 'bar'
        p 'bar'
      else
        p 'baz'
      end
    end
    
    hoge('bar') => "bar"
    

case(in節)

  • パターンマッチしているか確認する
    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)
    

パーセント記法

%/ /

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

%r/ /

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

%w/ /

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

Rubyオプション一覧

  • 前提:MacTerminalでシェル(zsh)で実行

-e

  • 引数にファイル名を取らずに、引数に与えられた文字列をそのまま Ruby スクリプトとして解釈して実行する
    % ruby -e 'puts "hoge"' # => hoge
    

-n

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

-p

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

-a

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

-l

  • 行末の自動処理(読み込み時の改行除去、出力時に行末に自動で改行を付与)を行う
    • $_変数の末尾に改行が残っていることにより、意図しない結果が出力される場合の回避策として使用できる
    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のように拡張子を指定すると、バックアップファイルとして指定拡張子が付いたファイルを作成する
    % 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

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

-c

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

-r

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

その他

require

  • Rubyライブラリをロードする
    • 同じファイルは1度のみロードする
    • .rb.soを自動補完する
    # lib.rb
    module Lib
      $num += 1
    end
    
    # program.rb
    $num = 0
    1..10.times do |n|
      require './lib.rb'
    end
    puts $num # => 1
    

load

  • 設定ファイルの読み込みに用いる
    • ファイルを無条件ロードする
    • 補完はしない
    # 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 を使用することができる
    h = {a: "gold", b: "silver"}
    puts h.map { puts "#{_1}, #{_2}"}
    
    # 実行結果 
    a, gold
    b, silver
    
0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1