Skip to content

Instantly share code, notes, and snippets.

@simplay
Created May 20, 2013 14:57
Show Gist options
  • Save simplay/5612758 to your computer and use it in GitHub Desktop.
Save simplay/5612758 to your computer and use it in GitHub Desktop.
Refactoring in Ruby using dynamic methods and dynamic dispatch (1) using dynamic proxy that is also a blank slate (2) source: book - metaprogramming-ruby
# given class Computer: refactor me
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
def mouse
info = @data_source.get_mouse_info(@id)
price = @data_source.get_mouse_price(@id)
result = "Mouse: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
def cpu
info = @data_source.get_cpu_info(@id)
price = @data_source.get_cpu_price(@id)
result = "Cpu: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
def keyboard
info = @data_source.get_keyboard_info(@id)
price = @data_source.get_keyboard_price(@id)
result = "Keyboard: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
# ...
end
# refactoring: variant (1)
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
data_source.methods.grep(/^get_(.*)_info$/) { Computer.define_component $1 }
end
def self.define_component(name)
define_method(name) do
info = @data_source.send "get_#{name}_info", @id
price = @data_source.send "get_#{name}_price", @id
result = "#{name.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
end
end
# refactoring: variant (2)
class Computer
instance_methods.each do |m|
undef_method m unless m.to_s =~ /^__|method_missing|respond_to?/
end
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
def method_missing(name, *args)
super if !respond_to?(name)
info = @data_source.send("get_#{name}_info", args[0])
price = @data_source.send("get_#{name}_price", args[0])
result = "#{name.to_s.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
def respond_to?(method)
@data_source.respond_to?("get_#{method}_info") || super
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment