How to refactor the following 2 function (4 lines each)

Hello

I’m trying to DRY my code and I think It could be done even better. The following 2 functions are “before_save” callbacks that practically do the same thing, but on a different set of attributes.

Since the code is highly similar, I was wondering if someone could help me to refactor the code?

def normalize_budget
result = normalize_generic(self.budget)
self.budget_min = result[:min]
self.budget_max = result[:max]
self.budget = result[:display]
end

def normalize_size
result = normalize_generic(self.size)
self.size_min = result[:min]
self.size_max = result[:max]
self.size = result[:display]
end

Kind regards,
Axinte

def normalize(property)
    result = normalize_generic(self.send(property))
    self.send("#{property}_min=", result[:min])
    self.send("#{property}_max=", result[:max])
    self.send("#{property}=", result[:display])
  end

object.normalize(:size)
object.normalize(:budget)

Hi,

try this:

  def normalize
    update_result("budget")
    update_result("size")
  end

  def update_result(field_name)
    result = normalize_generic(self.send(field_name))
    eval("self.#{field_name}_min = result[:min]")
    eval("self.#{field_name}_max = result[:max]")
    eval("self.#{field_name} = result[:display]")
  end

Thank you both for your feedback. Based on your suggestions, I’ve finally decided to implement it in the following way:

%w[size budget].each do |property|
define_method(“normalize_#{property}_range”) do |*args|
result = normalize_generic_range(self.send(property))
self.send("#{property}_min=", result[:min])
self.send("#{property}_max=", result[:max])
self.send("#{property}=", result[:display])
end
end

this code defines normalize_size_range and normalize_budget_range and updates both sets of attributes accordingly.

kind regards,
Axinte

Here's a better solution:

  %w[size budget].each do |property|
    class_eval %Q!
        def normalize_#{property}_range
            result = normalize_generic_range( self.#{property} )
            self.#{property}_min = result[:min]
            self.#{property}_max = result[:max]
            self.#{property} = result[:display]
        end
    !
  end

Mauricio,

Thank you again for your help. Is there any difference between your solution and mine?

Kind regards,

Axinte

Yes, you're defining and method and using send at every call, my
solution will generate a method with direct calls instead of sending
them.