【问题标题】:How do you refactor long ruby method signatures like this one你如何重构像这样的长 ruby​​ 方法签名
【发布时间】:2018-06-16 03:50:37
【问题描述】:

如何清理这个 ruby​​ 方法签名?

def card(title: nil, textured: nil, threed: true,
         borderless: false, bodyless: false, title_classes: ['card-header'])

问题是我收到了 linting/rubocop 警告:

Metrics/ParameterLists: Avoid parameter lists longer than 5 parameters. [6/5]

我的方法有这么多关键字参数的原因是, 我使方法非常灵活。它很强大。

【问题讨论】:

  • 我真的忽略了这个键。您可以创建一个参数对象,但您仍会将这些属性传递给参数对象。这个警察似乎更适用于没有键控的参数。

标签: ruby refactoring rubocop keyword-argument


【解决方案1】:

尝试使用这些属性创建案例类/数据类。

class CardProperties
  attr_accessor :title, :textured, :threed, :borderless, :bodyless, :title_classes
end

创建一个新的CardProperties并将其传递给card方法:

card_properties = CardProperties.new
card_properties.title = ''
....

card(card_properties)

【讨论】:

  • 您能否详细说明如何将您的解决方案集成到我的代码中。我的方法定义在 app/lib/Company/Ui.rb
  • 这个卡片方法是一个视图助手。因此,在我的 erb 看来,开设这样的课程让我感到不舒服
  • 天啊。至少,可以在这里使用OpenStruct,而不是尝试用自制的类来模仿它的功能。
  • 从 Fowler 的 /Refactoring/ 书中查找“方法对象重构”...
  • @mudasobwa 这并不总是关于你的代码有多短。
【解决方案2】:

好吧,理论上你可以使用关键字参数和Hash#fetch 来处理默认值:

def card(**params)
  title = params.fetch(:title, nil)
  textured = params.fetch(:textured, nil)
  threed = params.fetch(:threed, true)
  borderless = params.fetch(:borderless, false)
  bodyless = params.fetch(:bodyless, false)
  title_classes = params.fetch(:title_classes, ['card-header'])
  ...

但我个人的建议是让 rubocop 闭嘴:

# rubocop:disable Metrics/ParameterLists
def card(...)
  ...
end   
# rubocop:enable Metrics/ParameterLists

【讨论】:

  • 第二个,用于整个项目。
【解决方案3】:

做 Rails 做的事

  # Creates a number field.
  #
  # ==== Options
  # * <tt>:min</tt> - The minimum acceptable value.
  # * <tt>:max</tt> - The maximum acceptable value.
  # * <tt>:in</tt> - A range specifying the <tt>:min</tt> and
  #   <tt>:max</tt> values.
  # * <tt>:within</tt> - Same as <tt>:in</tt>.
  # * <tt>:step</tt> - The acceptable value granularity.
  # * Otherwise accepts the same options as text_field_tag.
  #
  # ==== Examples
  #   number_field_tag 'quantity'
  #   # => <input id="quantity" name="quantity" type="number" />
  #
  #   number_field_tag 'quantity', '1'
  #   # => <input id="quantity" name="quantity" type="number" value="1" />
  #
  #   number_field_tag 'quantity', nil, class: 'special_input'
  #   # => <input class="special_input" id="quantity" name="quantity" type="number" />
  #
  #   number_field_tag 'quantity', nil, min: 1
  #   # => <input id="quantity" name="quantity" min="1" type="number" />
  #
  #   number_field_tag 'quantity', nil, max: 9
  #   # => <input id="quantity" name="quantity" max="9" type="number" />
  #
  #   number_field_tag 'quantity', nil, in: 1...10
  #   # => <input id="quantity" name="quantity" min="1" max="9" type="number" />
  #
  #   number_field_tag 'quantity', nil, within: 1...10
  #   # => <input id="quantity" name="quantity" min="1" max="9" type="number" />
  #
  #   number_field_tag 'quantity', nil, min: 1, max: 10
  #   # => <input id="quantity" name="quantity" min="1" max="10" type="number" />
  #
  #   number_field_tag 'quantity', nil, min: 1, max: 10, step: 2
  #   # => <input id="quantity" name="quantity" min="1" max="10" step="2" type="number" />
  #
  #   number_field_tag 'quantity', '1', class: 'special_input', disabled: true
  #   # => <input disabled="disabled" class="special_input" id="quantity" name="quantity" type="number" value="1" />
  def number_field_tag(name, value = nil, options = {})
    options = options.stringify_keys
    options["type"] ||= "number"
    if range = options.delete("in") || options.delete("within")
      options.update("min" => range.min, "max" => range.max)
    end
    text_field_tag(name, value, options)
  end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 2023-03-28
    • 2012-08-18
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多