如何在ruby中干燥只有一行代码不同的函数列表?

时间:2016-03-03 20:38:08

标签: ruby-on-rails ruby dry

我在ROR应用程序中有一个用户模型,它有多个像这样的方法

#getClient() returns an object that knows how to find certain info for a date
#processHeaders() is a function that processes output and updates some values in the database
#refreshToken() is function that is called when an error occurs when requesting data from the object returned by getClient()


  def transactions_on_date(date)
    if blocked?
      # do something
    else
      begin
        output = getClient().transactions(date)
        processHeaders(output)
        return output
      rescue UnauthorizedError => ex
        refresh_token()
        output = getClient().transactions(date)
        process_fitbit_rate_headers(output)
        return output
      end
    end
  end

  def events_on_date(date)
    if blocked?
      # do something
    else
      begin
        output = getClient().events(date)
        processHeaders(output)
        return output
      rescue UnauthorizedError => ex
        refresh_token()
        output = getClient().events(date)
        processHeaders(output)
        return output
      end
    end
  end

我的User类中有几个看起来完全相同的函数。这些函数之间的唯一区别是行output = getClient().something(date)。有没有办法让我的代码看起来更干净,这样我就没有重复的函数列表。

3 个答案:

答案 0 :(得分:3)

答案通常是在一个块中传递并执行功能样式:

def handle_blocking(date)
  if blocked?
   # do something
  else
    begin
      output = yield(date)
      processHeaders(output)

      output
    rescue UnauthorizedError => ex
      refresh_token
      output = yield(date)
      process_fitbit_rate_headers(output)

      output
    end
  end
end

然后你这样称呼它:

handle_blocking(date) do |date|
  getClient.something(date)
end

这允许大量的自定义。 yield调用会执行您提供的代码块,并将date参数传递给它。

干燥代码的过程通常包括寻找模式并将其归结为有用的方法。使用功能方法可以保持清洁。

答案 1 :(得分:2)

是的,您可以使用Object#sendgetClient().send(:method_name, date)

BTW,getClient不是正确的Ruby方法名称。它应该是get_client

答案 2 :(得分:0)

两个答案的组合怎么样:

class User

  def method_missing sym, *args
    m_name = sym.to_s
    if m_name.end_with? '_on_date'
      prop = m_name.split('_').first.to_sym
      handle_blocking(args.first) { getClient().send(prop, args.first) }
    else
      super(sym, *args)
    end
  end

  def respond_to? sym, private=false
    m_name.end_with?('_on_date') || super(sym, private)
  end

  def handle_blocking date
    # see other answer
  end

end

然后你可以调用“transaction_on_date”,“events_on_date”,“foo_on_date”,它会起作用。