rubyのdefine_methodとdefine_singleton_method

2022.07.21

define_method

インスタンスメソッドを定義します。

Ruby 3.1 リファレンスマニュアル

動的にメソッドを作れる。

特徴

Gomiテーブルでゴミの種類を判別するメソッドがあるとする。判別にはkindカラムを使っている。

静的にメソッドを定義している状態。これだとプラごみとか缶・ビンのゴミを追加するたびにメソッドも増やす必要が出てくる。

class Gomi
  attr_accessor :kind

  def recycle?
    kind == "Recycle"
  end
  
  def burn?
    kind == "Burn"
  end

  def raw?
    kind == "Raw"
  end
end

g = Gomi.new
g.kind = "Burn"
g.raw? #=> false
g.burn? #=> true

define_methodを使って動的にメソッドを定義したコード。今後ゴミの種類が増えたとしてもメソッドは1つで足りる。

class Gomi
  attr_accessor :kind
  KIND = ["Recycle", "Burn", "Raw"]

  KIND.each do |k|
    define_method(:"#{k.downcase}?") { kind == k }    
  end
end

g = Gomi.new
g.kind = "Burn"
g.raw? #=> false
g.burn? #=> true

define_singleton_methodとは

self に特異メソッドを定義します

Ruby 3.1マニュアルリファレンス

特異メソッドを定義できる。

特徴

ゴミの種類ごとに最新のレコードを取得する処理があるとする。

class Gomi
  attr_accessor :kind
  KIND = ["Recycle", "Burn", "Raw"]

  def self.latest_recycle?
    where(kind: recycle).last
  end
  
  def self.latest_burn?
    where(kind: burn).last
  end

  def self.latest_raw?
    where(kind: raw).last
  end
end

define_singleton_methodを使って特異メソッドを設定する。

class Gomi
  attr_accessor :kind
  KIND = ["Recycle", "Burn", "Raw"]

  KIND.each do |k|
    define_singleton_method(:"latest_#{k.downcase}") { where(kind: k).last }  
  end
end

まとめ

define_methodはインスタンスメソッドを動的に作れる。同じ処理をしているメソッドがあれば使えるかもしれない。

define_singleton_methodは特異メソッドを動的に作れる。こちらも同じ処理を繰り返して使っている場合は使えるかもしれない。