【问题标题】:How to optimize ruby method? [closed]如何优化ruby方法? [关闭]
【发布时间】:2020-12-29 05:53:14
【问题描述】:

我有以下 ruby​​ 方法,它看起来超级难看,我想重构它并减少它的感知复杂性。

def validate_hash_params(**kwargs)
  kwargs.each do |k, v|

    raise Sith::ProcessingError, "#{k} should be of type String" unless v&.is_a? String
    
    raise Sith::ProcessingError, "id length should be less than equal to 25" if kwargs[:id].length > 25

    raise Sith::ProcessingError, "info length should be less than equal to 100" if kwargs[:info].length > 100

    raise Sith::ProcessingError, "first_name length should be less than equal to 60" if kwargs[:first_name].length > 60

    raise Sith::ProcessingError, "email length should be less than equal to 50" if kwargs[:email].length > 50
    
    raise Sith::ProcessingError, "Invalid Email" unless Sith::EMAIL_REGEX.match(kwargs[:email])

    raise Sith::ProcessingError, "amount should contain digits with upto 2 decimal places" unless Sith::AMOUNT_REGEX.match(kwargs[:amount])

    [kwargs[:key1], kwargs[:key2], kwargs[:key3], kwargs[:key4], kwargs[:key5]].each do |key|
      raise SithError, "key length should be less than equal to 255" if key.length > 255
    end
  end
end

任何帮助将不胜感激。谢谢!

【问题讨论】:

  • “优化”是什么意思?
  • 我很困惑。 |k,v|循环中的大部分语句不是k或v的函数,所以只是重复而已。
  • 您使用 ruby​​-on-rails 标记了您的问题。我想知道你为什么不使用Rails model validations?
  • kwargs 会被用来初始化模型吗?

标签: ruby-on-rails ruby oop optimization refactoring


【解决方案1】:

您可以按如下方式重新组织您的计算。如有必要,当然可以重新排序各种验证。

def validate(**kwargs)
  validate_values_are_strings(**kwargs)
  validate_max_lengths(**kwargs)
  validate_amount(kwargs[:amount])
  validate_max_key_lengths(**kwargs)
  validate_email_pattern(kwargs[:email])
end
def validate_values_are_strings(**kwargs)
  kwargs.each do |k,v|
    raise Sith::ProcessingError,
      "value of #{k} should be of type String" unless v.is_a? String
  end
end
def validate_max_lengths(**kwargs)
  k,v = { id: 24, info: 100, first_name: 60, email: 50 }.find do |k,v|
    kwargs[k].length > v
  end
  raise Sith::ProcessingError,
    "#{k.to_s} length should be less than or equal to #{v}" unless k.nil?
end
def validate_amount(amount)
  raise Sith::ProcessingError,
    "amount should contain digits with upto 2 decimal places" unless
      Sith::AMOUNT_REGEX.match?(amount)
end
def validate_max_key_lengths(**kwargs)
   raise SithError, "key length should be less than equal to 255" if
     [:key1, :key2, :key3].map { |k| kwargs[k].length }.max > 255
end
def validate_email_pattern(email)
  raise Sith::ProcessingError, "Invalid Email" unless
    Sith::EMAIL_REGEX.match?(email)
end

假设:

kwargs =
  { id: '23', info: '99', first_name: '59', email: 'hank@some_url.com',
    amount: '2.63', key1: 'cow', key2: 'chicken', key3: 'goat' } 

让我们来看看其中一些方法的简化。

def validate_values_are_strings(**kwargs)
  kwargs.each do |k,v|
    raise "value of #{k} should be of type String" unless v.is_a? String
  end
end

validate_values_are_strings(**kwargs)
  #=> nil (no errors)
validate_values_are_strings(**(kwargs.merge(email: 7)))
  #=> RuntimeError (value of email should be of type String)
def validate_max_key_lengths(**kwargs)
   raise "key length should be less than equal to 255" if
     [:key1, :key2, :key3].map { |k| kwargs[k].length }.max > 255
end

validate_max_key_lengths(**kwargs)
  #=> nil (no errors)
validate_max_key_lengths(**(kwargs.merge(key2: 'a'*256)))
  #=> RuntimeError (key length should be less than equal to 255)
def validate_amount(amount)
  raise "amount should contain digits with upto 2 decimal places" unless
      /\A\d+(?:\.\d{1,2})?\z/.match?(amount)
end

validate_amount(kwargs[:amount])
  #=> nil (no errors)
validate_amount("2.634")
  #=> RuntimeError (amount should contain digits with upto 2 decimal places)

【讨论】:

    【解决方案2】:
    def validate_hash_params(**kwargs)
      validate_string(kwargs)
      validate_length(kwargs, :id, 25)
      validate_length(kwargs, :info, 100)
      validate_length(kwargs, :first_name, 60)
      validate_length(kwargs, :email, 50)
    
      raise Sith::ProcessingError, 'Invalid Email' unless Sith::EMAIL_REGEX.match(kwargs[:email])
      raise Sith::ProcessingError, 'amount should contain digits with upto 2 decimal places' unless Sith::AMOUNT_REGEX.match(kwargs[:amount])
      validate_key_length(kwaargs)
    end
    
    def validate_length(kwargs, key, length)
      raise Sith::ProcessingError, "id length should be less than equal to #{length}" if kwargs[key].length > length
    end
    
    def validate_string(kwargs)
      not_a_string = kwargs.find { |_k, v| !v.is_a?(String) }
    
      raise Sith::ProcessingError, "#{not_a_string.first} should be of type String" if not_a_string
    end
    
    def validate_key_length(kwargs)
      raise SithError, 'key length should be less than equal to 255' if [:key1, :key2, :key3, :key4, :key5].any? { |k| kwargs[k].length > 255 }
    end
    

    【讨论】:

      【解决方案3】:

      如果这是 Ruby on Rails,我建议使用 validations 而不是自定义检查和引发异常。这需要制作一个小模型。

      class Sith
        include ActiveModel::Model
        
        attr_accessor :id, :info, :first_name, :email, :amount, :keys
        
        validates :id, length: { maximum: 25 }
        validates :info, length: { maximum: 100 }
        validates :first_name, length: { maximum: 60 }
        validates :email, length: { maximum: 50 }, format: { with: URI::MailTo::EMAIL_REGEXP }
        validate :validate_amount_decimal_places
        validate :validate_keys
      
        private def validate_amount_decimal_places
          if amount != amount.round(2)
            errors.add(:amount, "amount should contain digits with upto 2 decimal places")
          end
        end
      
        private def validate_keys
          errors.add(:keys, "there can be, at most, 5 keys") if keys.size > 5
          
          if keys.any? { |key| key.length >= 255 }
            errors.add(:keys, "keys must be shorter than 255 characters")
          end
        end
      end
      

      请注意,我将单独的 key1、key2、key3 参数组合成一个键数组。

      现在您可以创建Sith 并检查它是否有效。

      sith = Sith.new(kwargs)
      if !sith.valid?
        ...
      end
      

      如果您想使用异常,请使用Strict Validations。

      validates :id, length: { maximum: 25, strict: Sith::ProcessingError }
      

      然而,很多这样的“验证”似乎是不必要的,而且可能令人望而却步。为什么要限制某人电子邮件的长度?

      【讨论】:

      • 这行得通!不知道为什么我没想到。
      猜你喜欢
      • 2015-03-03
      • 1970-01-01
      • 2015-11-13
      • 2012-04-28
      • 1970-01-01
      • 2013-04-03
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      相关资源
      最近更新 更多