2013-01-04 138 views
2

嗨,我有一个代码,我想重构如何重构ruby代码?

def gear_type 
    @gear_type ||= self.class.gear_types.find{|gears| gears["id"]==source["gear_type_id"]}["text"] if source["gear_type_id"] 
end 

def brand 
    @brand ||= self.class.brands.find{|node| node["id"]==source["brand_id"].to_s}["text"] if source['brand_id'] 
end 

什么是最好的办法吗?使用eval还是定义方法?我已经尝试过这一点,但也有一些错误,我不能发现尚未:

%w(gear_type brand).each do |meth| 
    define_method(meth){ 
    instance_variable_get("@#{meth}") rescue 
     instance_variable_set("@#{meth}", self.class.send(meth.pluralize).find{|node| node["id"]==source["#{meth}_id"]}["text"]) if source["#{meth}_id"] 
    } 
end 
+2

代码审查/重构现在在http://codereview.stackexchange.com –

回答

4

我只是写一个共同的查找方法,你可以参数:

def gear_type 
    @gear_type ||= generic_finder :gear_types, "gear_type_id" 
end 

def brand 
    @brand ||= generic_finder :brands, "brand_id" 
end 

def generic_finder(collection, primary_key) 
    self.class.send(collection).each do |object| 
    return object["text"] if object["id"] == source[primary_key] 
    end if source[primary_key] 
    nil 
end 
+0

+1不错!每当我们认为我们需要元编程时,我们应该首先考虑如果我们可以通过传递符号的通用方法来实现它。即使在Rails上的find_by_ *方法也改变为这种方法。 –

+0

谢谢。它非常干净! – Danil

1

instance_variable_get("@#{meth}")如果实例变量没有设置不会引发错误,则返回nil。所以你必须做几乎相同的你在做什么:

%w(gear_type brand).each do |meth| 
    define_method(meth){ 
    instance_variable_get("@#{meth}") || instance_variable_set("@#{meth}", self.class.send(meth.pluralize).find{|node| node["id"]==source["#{meth}_id"]}["text"]) if source["#{meth}_id"] 
    } 
end 

你也应该重构该行。它有很多东西在上面

%w(gear_type brand).each do |meth| 
    def source(meth) 
    @source ||= source["#{meth}_id"] 
    end 

    def class_meths(meth) 
    self.class.send(meth.pluralize) 
    end 

    def look_for(meth) 
    class_meths(meth).find{|node| node["id"] == source(meth)}["text"] 
    end 

    define_method(meth) do 
    value = instance_variable_get("@#{meth}") 
    instance_variable_set("@#{meth}", look_for(meth)) if !value && source(meth) 
    end 
end 

这是一个尝试。不知道它是否变得更好,但我认为更容易阅读。

哦!我刚刚意识到这些方法可能不会在meta的范围内?方法被调用。但哦,它仍然是一个很好的例子,我觉得:)

-1

这可能是清洁只是使用eval:

%w(gear_type brand).each do |meth| 
    eval <<-RUBY 
    def #{meth} 
     @#{meth} ||= self.class.#{meth.plural}.find{|item| item["id"]==source["#{meth}_id"]}["text"] if source["#{meth}_id"] 
    end 
    RUBY 
end