【问题标题】:Ruby: Refactoring conditional statements containing regular expressionsRuby:重构包含正则表达式的条件语句
【发布时间】:2013-05-17 13:35:26
【问题描述】:

我有一个方法mock_request,为了单元测试的目的,我要覆盖它。对于每个请求,我想执行一些代码:

def mock_request(method, url, params={})
  case "#{method} #{url}"
  when 'post /customers'
    # create customer
  when %r{post /customers/(.*)/items}
    id = $1 # update customer
  when %r{post /customers/(.*)}
    id = $1 # update customer
  else
    throw 'Unrecognized request'
  end
end

问题是这个case语句变得很长,每个case的行数都在慢慢增加。此外,同时处理多个模型。

我想做的是为每个模型创建单独的文件,并以某种方式将它们包含在此mock_request 方法中。像这样的:

# handlers/customers.rb
module RequestHandlers
  # post /customers
  # post /customers/(.*)
end

# handlers/items.rb
module RequestHandlers
  # post /customers/(.*)/items
end

# mock_request.rb
class MockServer
  def mock_request(method, url, params={})
    handle_request(method, url)
  end
end

但是我不确定如何实现这一点。在 ruby​​ 中处理这个问题的最佳方法是什么?

【问题讨论】:

    标签: ruby testing module refactoring


    【解决方案1】:

    您可以创建一个哈希,其中包含方法和 URL 字符串作为键,以及您要评估的代码块作为值。

    def mock_request(method, url, params={})
     #create a request hash where the default value is your else, this way if a key that doesn't exist is called, the unrecognized request is called
    
      req =  Hash.new ({throw 'Unrecognized request'})
      req['post /customers'] = {#create customer block/proc}
      req[%r{post /customers/(.*)/items}] = {#update customer block/proc}
    
      req["#{method} #{url}"]
    end
    

    这对您来说可能是一个更好的选择,并且可以让您摆脱冗长的案例陈述。

    【讨论】:

    • 这是我的第一个想法,但它不起作用,因为我在 when 条件句中使用了正则表达式。
    • @mindeavor 改用req.find { |key, value| key === "#{method} #{url}" }
    • 即使使用 req[method.scan(%r{post /customers/(.*)/items})] = {#proc} 也可以工作,这取决于你想变得多么冗长.
    • 很好,所以我可以使用散列来存储请求处理程序。我将如何构建我的代码,以便我可以将这些处理程序拆分为多个文件?理想情况下,它不必为每个请求重建哈希。
    【解决方案2】:

    为了记录,这是我最终重构它的方式。

    处理程序的每个“主题”都有自己的模块和文件:

    module RequestHandlers
      module Customers
    
        def Customers.included(mock_server)
          mock_server.add_handler 'post /customers',      :new_customer
          mock_server.add_handler 'post /customers/(.*)', :update_customer
        end
    
        def new_customer(route, method_url, params)
          # create new customer
        end
    
        def update_customer(route, method_url, params)
          # update existing customer
        end
    
      end
    end
    

    主类是处理程序生活和使用的地方:

    class MockServer
    
      # Handlers are ordered by priority
      @@handlers = []
    
      include RequestHandlers::Customers
      include RequestHandlers::Items
      # etc.
    
      def self.add_handler(route, name)
        @@handlers << {
          :route => %r{^#{route}$},
          :name => name
        }
      end
    
      def mock_request(method, url, params={})
        method_url = "#{method} #{url}"
        handler = @@handlers.find {|h| method_url =~ h[:route] }
    
        if handler
          self.send(handler[:name], handler[:route], method_url, params)
        else
          throw 'Unrecognized request'
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-19
      • 2020-10-24
      • 2011-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-22
      • 2011-04-26
      相关资源
      最近更新 更多