LoginSignup
1

More than 3 years have passed since last update.

ruby 動的メソッド 練習

Last updated at Posted at 2018-04-29

ruby 動的メソッド 練習

環境

ruby 2.4.1

概要

メタプログラミングの技術をリファクタリングに当てたらソースコードが
どうなるのかを検証しました。

メタプログラミング勉強して2日目のガチ初心者なので変なことやってたら
許してください。

動的メソッドにするソースコード

リファクタリングするソースコードは下記の物となります。
色々と被っていて嫌な感じです。

class TestClass
  def num1(num)
    tmp = get_num1(num)
    num + tmp
  end

  def get_num1(num) 10 * num; end

  def num2(num)
    tmp = get_num2(num)
    num + tmp
  end

  def get_num2(num) 20 * num; end

  def num3(num)
   tmp = get_num3(num)
   num + tmp
  end

  def get_num3(num) 30 * num; end
end

obj = TestClass.new
puts obj.num1(5)   --->  55
puts obj.num2(5)   --->  105
puts obj.num3(5)   --->  155

※ --->の場所は出力結果です。コードじゃないので注意。

1回目

sendを使ってメソッドを動的に呼び出すようにして被ってる部分をまとめました。
多少マシになった気がします。

class TestClass
  def num1(num); summarize_method(:num1, 5) end
  def get_num1(num) 10 * num; end

  def num2(num); summarize_method(:num2, 5) end
  def get_num2(num) 20 *num; end

  def num3(num); summarize_method(:num3, 5) end
  def get_num3(num) 30 * num; end


  def summarize_method(name, num)
    tmp = send "get_#{name}", num
    num + tmp
  end
end

obj = TestClass.new
puts obj.num1(5)
puts obj.num2(5)
puts obj.num3(5)

2回目

メソッドを動的に定義するようにしました。
結構コンパクトになってきました。

class TestClass

  def get_num1(num) 10 * num; end
  def get_num2(num) 20 * num; end
  def get_num3(num) 30 * num; end

  def self.summarize_method(name)
    define_method(name) do |num|
      tmp = send "get_#{name}", num
      num + tmp
    end
  end

  summarize_method :num1
  summarize_method :num2
  summarize_method :num3
end

obj = TestClass.new
puts obj.num1(5)
puts obj.num2(5)
puts obj.num3(5)

3回目

initializeを使ってメソッドを動的に定義している場所を一行にまとめてみました。

class TestClass

  def initialize
    val_names = [:num1, :num2, :num3]
    val_names.map{|t| TestClass.summarize_method t}
  end

  def get_num1(num) 10 * num; end
  def get_num2(num) 20 * num; end
  def get_num3(num) 30 * num; end

  def self.summarize_method(name)
    define_method(name) do |num|
      tmp = send "get_#{name}", num
      num + tmp
    end
  end

end

obj = TestClass.new
puts obj.num1(5)
puts obj.num2(5)
puts obj.num3(5)

4回目

evalを使ってget_num系をループで動的に定義するようにしました。
これでnum4とかnum5が出てきても、val_namesいじるだけでOKです。

class TestClass

  def initialize
    val_names = [:num1, :num2, :num3]
    val_names.map{|t| TestClass.summarize_method t}
  end

  val_names = [:get_num1, :get_num2, :get_num3]
  val_names.each_with_index do |val_name, i|
    weight = (i + 1) * 10
    eval <<-END_OF_DEF
      def #{val_name}(num)
        #{weight} * num
      end
    END_OF_DEF
  end

  def self.summarize_method(name)
    define_method(name) do |num|
      tmp = send "get_#{name}", num
      num + tmp
    end
  end

end

obj = TestClass.new
puts obj.num1(5)
puts obj.num2(5)
puts obj.num3(5)

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
1