2011-11-04 64 views
2

的问题如何清理此Ruby代码?

我想分析的文本框的线条,以产生从中项目。

我有它的工作,但它看起来很丑陋。

如何清理“if/else”混乱?

代码

class LineParser 
    def self.parse(line) 
    line_matches = line.chomp.match(/(?<name>[[:print:]]+) \$(?<price>\d+\.*\d*)(+?(?<description_text>[^\+#]([[:print:]][^\+#])*))?(+?(\+(?<quantity>\d+)))?(+?#(?<cat1>[[:print:]][^#]*))?$/) 
    return matches_to_hash(line_matches) 
    end 
    def self.matches_to_hash(matches) 
    hash = {} 
    keys = [:name, :price, :description_text, :quantity, :cat1] 
    keys.each do |key| 
     if key == :price 
     hash[key] = matches[key].to_f 
     elsif key == :quantity 
     if matches[key].nil? 
      hash[key] = 1 
     else 
      hash[key] = matches[key].to_i 
     end 
     else 
     hash[key] = matches[key] 
     end 
    end 
    hash 
    end 
end 
+0

感谢大家的所有伟大的建议。我从一个问题中学到了很多东西! :) –

回答

3

从解析中删除显式返回。

class LineParser 
    def self.parse(line) 
    line_matches = line.chomp.match(/(?<name>[[:print:]]+) \$(?<price>\d+\.*\d*)(+?(?<description_text>[^\+#]([[:print:]][^\+#])*))?(+?(\+(?<quantity>\d+)))?(+?#(?<cat1>[[:print:]][^#]*))?$/) 
    matches_to_hash(line_matches) 
    end 
    def self.matches_to_hash(matches) 
    { 
     :price   => matches[:price].to_f, 
     :quantity   => (matches[:quantity] || 1).to_i, 
     :name    => matches[:name], 
     :description_text => matches[:description_text], 
     :cat1    => matches[:cat1] 
    } 
    end 
end 
+0

该死的,真可爱。我讨厌做整个散列= {}返回散列的事情,我知道一定是更好的方法。就是这个!谢谢。 –

+0

mmm红宝石:) 如果您处于文字无意义的情况,您还可以使用对象#轻击。 –

+0

P.S.帽子提示到@Thilo –

4

if matches[key].nil? 
    hash[key] = 1 
else 
    hash[key] = matches[key].to_i 
end 

相当于

hash[key] = (matches[key] || 1).to_i 

而对于if/else语句链有超过一对夫妇的分支,也许一个case语句更合适。

+0

我甚至没有想到这一点。高超!谢谢。 –

1
class LineParser 
    def self.parse(line) 
    line_matches = line.chomp.match(/(?<name>[[:print:]]+) \$(?<price>\d+\.*\d*)(+?(?<description_text>[^\+#]([[:print:]][^\+#])*))?(+?(\+(?<quantity>\d+)))?(+?#(?<cat1>[[:print:]][^#]*))?$/) 
    return matches_to_hash(line_matches) 
    end 
    def self.matches_to_hash(matches) 
    hash = {} 
    [:name, :price, :description_text, :quantity, :cat1].each do |key| 
     case key 
     when :price 
     hash[key] = matches[key].to_f 
     when :quantity 
      hash[key] = 1 if matches[key].nil? 
      hash[key] = matches[key].to_i unless matches[key].nil? 
     else 
     hash[key] = matches[key] 
    end 
    hash 
    end 
end 
2

整理matches_to_hash我会做:

def self.matches_to_hash(matches) 
    hash = {} 
    hash[:name] = matches[:name] 
    hash[:price] = matches[:price].to_f 
    hash[:description_text] = matches[:description_text] 
    hash[:quantity] = matches[:quantity].nil? ? 1 : matches[:quantity].to_i 
    hash[:cat1] = matches[:cat1] 
    hash 
end 

不过,我想我会只是改变解析到:

def self.parse(line) 
    line_matches = line.chomp.match(/([[:print:]]+) \$(\d+\.*\d*)(+?([^\+#]([[:print:]][^\+#])*))?(+?(\+(\d+)))?(+?#([[:print:]][^#]*))?$/) 
    hash = {} 
    hash[:name] = $1 
    hash[:price] = $2.to_f 
    hash[:description_text] = $3 
    hash[:quantity] = $4.nil? ? 1 : $4.to_i 
    hash[:cat1] = $5 
    hash 
end 
+0

为什么要以PHP风格创建哈希? – tokland

+0

伟大的一点 - 我最初把这些匹配命名为因为它让我像对象一样的哈希,但是如果我在把它放入哈希之前需要对它进行操作,那么没有多少意义。 –

+0

@tokland:什么是PHP风格? – drummondj

1

我不能完全肯定,为什么你循环通过按键时,每个键做不同的事情。为什么不一一处理呢?

class LineParser 
    def self.parse(line) 
    line_matches = line.chomp.match(/(?<name>[[:print:]]+) \$(?<price>\d+\.*\d*)(+?(?<description_text>[^\+#]([[:print:]][^\+#])*))?(+?(\+(?<quantity>\d+)))?(+?#(?<cat1>[[:print:]][^#]*))?$/) 
    return matches_to_hash(line_matches) 
    end 
    def self.matches_to_hash(matches) 
    hash = {} 
    hash[:price] = matches[:price].to_f 
    hash[:quantity] = (matches[:quantity] || 1).to_i 
    hash[:name] = matches[:name] 
    hash[:description_text] = matches[:description_text] 
    hash[:cat1] = matches[:cat1] 
    hash 
    end 
end 

注意:我也偷了Thilo发布的关于数量的聪明点。

+0

看起来不错,但不需要构建哈希更新它。只需一步即可构建散列。 – tokland

+0

是的,回头看,我不知道为什么。我想我认为这会减少重复并使代码更简单。男人,是我错了!感谢您的优秀建议。 –