LoginSignup
2
0

More than 1 year has passed since last update.

Rubyの動的メソッド呼び出しと動的メソッド定義と ~send, define_method~

Last updated at Posted at 2022-12-15

はじめに

最近「メタプログラミングRuby」という本を読んで、動的メソッド呼び出しと動的メソッド定義について学習しました。
そこで、実際に2つ使って簡単なコードを書き本記事を作成しました。

前提

動的ではないメソッド定義とメソッド呼び出しは以下のようなものです。

class Hoge
  attr_accessor :name

  def print_name
    puts "name: #{@name}"
  end
end

hoge = Hoge.new
hoge.name = "Alice"

hoge.print_name
#=> name: Alice

特徴はそれぞれ次の通りです。

  • 固定の名前でメソッドを定義する
  • 固定の名前でメソッド呼び出しをする

動的メソット呼び出し

hoge.print_name
hoge.print_type
hoge.print_age

上のようにprint_○○という命名のメソッドを連続して呼び出す場合について考えます。

そこで、変化する部分を配列で持ちsendメソッドと式展開を利用し動的に記述することが、動的メソット呼び出しです。

columns = ['name', 'type', 'age']
columns.each do |column|
  hoge.send("print_#{column}")
end

動的メソッド定義

逆に類似の処理を行うメソッドは以下のようにdefine_methodを利用することで動的に記述できます。これが動的メソッド定義です。

class Hoge
  attr_accessor :name, :type, :age

  def self.print_item(name)
    define_method(name) do
      column = name.split('_').last
      puts "#{column}: #{self.send(column)}"
    end
  end

  ['name', 'type', 'age'].each do |column| # 動的メソッド呼び出しでメソッド定義
    print_item "print_#{column}"
  end
end

hoge = Hoge.new
{name: 'Alice', type: 'AB', age: 20}.each do |key, value| # 動的メソッド呼び出しで変数を定義する
  hoge.send("#{key}=", value)
end


hoge.print_name
#=> name: Alice

hoge.print_type
#=> type: AB

hoge.print_age
#=> age: 20

感想

コードを書く前はどちらもDryにコードを書く役に立ちそうだと感じていました。
しかし、実際にコードを書いてみると、動的メソッド定義の方は、そもそも類似処理をするメソッドを定義すること自体がDryではない気がしました。(下のように単一メソッドで書いた方が良いかも?)
公開済みGemなどメソッド名は変更できない状況で、リファクタリングをする際などは利用できそうです。

class Hoge
  attr_accessor :name, :type, :age
  def print_column(column)
    puts "#{column}: #{self.send(column)}"
  end
end

# (略)

hoge.print_column('name')
#=> name: Alice

動的メソッド呼び出しの方は、動的メソッド定義以降のコードでも多様できたので、とても役に立ちそうです。

参考文献

2
0
0

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
2
0