帮助重构这个令人讨厌的Ruby if/else语句

Shp*_*ord 10 ruby refactoring ruby-on-rails

所以我有一个很大的毛茸茸的if/else语句.我将跟踪号码传递给它,然后确定它是什么类型的跟踪号码.

我怎样才能简化这件事?特别想减少代码行数.

if num_length < 8
  tracking_service = false
else
  if number[1, 1] == 'Z'
    tracking_service = 'ups'
  elsif number[0, 1] == 'Q'
    tracking_service = 'dhl'
  elsif number[0, 2] == '96' && num_length == 22
    tracking_service = 'fedex'
  elsif number[0, 1] == 'H' && num_length == 11
    tracking_service = 'ups'
  elsif number[0, 1] == 'K' && num_length == 11
    tracking_service = 'ups'
  elsif num_length == 18 || num_length == 20
    check_response(number)
  else
    case num_length
    when 17
      tracking_service = 'dhlgm'
    when 13,20,22,30
      tracking_service = 'usps'
    when 12,15,19
      tracking_service = 'fedex'
    when 10,11
      tracking_service = 'dhl'
    else
      tracking_service = false  
    end  
  end
end
Run Code Online (Sandbox Code Playgroud)

是的我知道.这很讨厌.

jtb*_*des 37

试试这个.我用case正则表达式重写了它.我也使用:symbols而不是"strings"返回值,但你可以改回来.

tracking_service = case number
  when /^.Z/ then :ups
  when /^Q/ then :dhl
  when /^96.{20}$/ then :fedex
  when /^[HK].{10}$/ then :ups
else
  check_response(number) if num_length == 18 || num_length == 20
  case num_length
    when 17 then :dhlgm
    when 13, 20, 22, 30 then :usps
    when 12, 15, 19 then :fedex
    when 10, 11 then :dhl
    else false
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 我将lambdas和monkey补丁替换为:/^96(.{20})$/和/^ [HK](.{10})$ /,假设`num_length`是`number`的长度 (3认同)
  • 但是它看起来不对,因为num_length == 18 || num_length == 20种情况下,其行为与OP的代码不同。还是不是? (2认同)
  • @radiospiel我3年没想过这段代码......但看起来你是对的.虽然OP的代码长度为== 20,但是它被列为`usps`,尽管它已经被`check_response`处理了......无论如何,我相信OP得到了他们需要的东西:) (2认同)

fro*_*r78 6

根据跟踪代码是否是ruby对象,您还可以在其类定义中放置帮助程序:

class TrackingCode < String 
  # not sure if this makes sense for your use case
  def ups?
    self[1,1] == 'Z'
  end
  def dhl?
    self[0,1] == 'Q'
  end
  def fedex?
    self.length == 22 && self[0, 2] == '96'
  end
  # etc...
end
Run Code Online (Sandbox Code Playgroud)

然后您的条件成为:

if number.ups?
  # ...
elsif number.dhl?
  # ...
elseif number.fedex?
end
Run Code Online (Sandbox Code Playgroud)

一个简化的条件,您使用跟踪代码的隐含功能.同样,如果你采用循环方法,你的循环也会更清晰:

%w(ups? dhl? fedex?).each do |is_code|
  return if number.send(is_code)
end
Run Code Online (Sandbox Code Playgroud)

甚至:

%w(ups? dhl? fedex?).each do |is_code|
  yield if number.send(is_code)
end
Run Code Online (Sandbox Code Playgroud)