Ruby refineメソッド

2021年5月1日土曜日

Ruby

t f B! P L

概要

Rubyのrefineメソッドについて。usingメソッドとセットで使用する。
メソッドの再定義を行える。再定義した内容をグローバルに影響させたくない場合とかで使用する。

基本

こんな感じ。using以降から有効になる。usingはファイルの末尾か、クラス定義内ならクラス定義の末尾まで有効

class C
  def c_method
    p 'Cのメソッドだよ'
  end
end

module M
  refine C do
    def c_method
      p 'refineで定義し直したよ'
    end
  end
end

c = C.new
c.c_method
=> 'Cのメソッドだよ'

using M

c.c_method
=> 'refineで定義し直したよ'

self

refine内のブロックは無名モジュール。クラスのコンテキストではないので定数なんかは参照できない

class C
  CCONST = 'Cの定数だよ'
end

module M
  refine C do
    p self
    # => #<refinement:[email protected]>
    CCONST # Cのスコープじゃないのでエラー
    # => NameError
  end
end

メソッド探索

prependより優先される。以下の順序
refine < prependしたモジュール < クラス < includeしたモジュール < 親クラス

module P
  def c_method
    p 'prependのメソッドだよ'
  end
end

class C
  prepend P
  def c_method
    p 'Cのメソッドだよ'
  end
end

module M
  refine C do
    def c_method
      p 'refineで定義し直したよ'
    end
  end
end

c = C.new
c.c_method
=> 'prependのメソッドだよ'

using M

c.c_method
=> 'refineで定義し直したよ'

クラスメソッド

クラスメソッドのときはsingleton_classを使う。selfは使わない

class C
  def self.c_method
    p 'Cのクラスメソッドだよ'
  end
end

module M
  refine C.singleton_class do
    def c_method
      p 'refineで定義し直したクラスメソッドだよ'
    end
  end
end

using M

C.c_method
=> 'refineで定義し直したクラスメソッドだよ'

メソッド再定義

usingの後にメソッド再定義してもusingが有効

class C
  def c_method
    p 'Cのメソッドだよ'
  end
end

module M
  refine C do
    def c_method
      p 'refineで定義し直したメソッドだよ'
    end
  end
end

using M

class C
  def c_method
    p '再定義したCのメソッドだよ'
  end
end

c = C.new
c.c_method
=> 'refineで定義し直したメソッドだよ'

複数のusing

複数usingの場合は最後のusingのみ有効

class C
  def c_method
    p 'Cのメソッドだよ'
  end
end

module M1
  refine C do
    def c_method
      p 'M1 refineで定義し直したメソッドだよ'
    end
  end
end

module M2
  refine C do
    def c_method
      p 'M2 refineで定義し直したメソッドだよ'
    end
  end
end

using M1
using M2

c = C.new
c.c_method
=> 'M2 refineで定義し直したメソッドだよ'

メソッド定義内でusing

メソッド定義内でusingは呼び出せない。エラーになる

class C
  def c_method
    p 'Cのメソッドだよ'
  end
end

module M
  refine C do
    def c_method
      p 'refineで定義し直したメソッドだよ'
    end
  end
end

def call_using
  using M
end

call_using
=> RuntimeError

super

refineで定義したメソッド内でsuperを呼び出すと定義元のメソッドが呼ばれる

class C
  def c_method
    p 'Cのメソッドだよ'
  end
end

module M
  refine C do
    def c_method
      p 'refineで定義し直したメソッドだよ'
      super
    end
  end
end

using M
c = C.new
c.c_method
=> 'refineで定義し直したメソッドだよ'
'Cのメソッドだよ'

自己紹介

Webエンジニアをやっています。日々思ったことや、読書レビュー、IT系の記事などを書き連ねています

広告

Ruby mapでnilが入ってしまう件

  概要 ブロック内の結果を配列にして返すrubyのmap。 便利だが以下のように特定の値の時にスキップしたいケースでは、nilが入ってしまう ( 1 .. 5 ). map do | v | next if v == 3 v end => [ 1 , 2...

QooQ