#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)