不区分大小写等于基于一个属性的方法

时间:2012-02-19 13:40:19

标签: ruby boolean-logic

原始问题

这是一个非常糟糕的方法,它根据代码检查相等性,但不区分大小写

def ==(another_country)
   (code.nil? ? nil : code.downcase) == (another_country.code.nil? ? nil : another_country.code.downcase) unless another_country.nil?
end

你能指出我正确的方向如何写这个更优雅的w / o在丑陋的if else结构上吗?

这是我最终使用的解决方案(+ RSpecs)

# Country model
class Country < ActiveRecord::Base
  attr_accessible :code

  def ==(another_country)
    code.to_s.downcase == another_country.code.to_s.downcase rescue false
  end
end

广泛的测试:

# RSpec
describe Country do
   describe 'equality based solely on Country.code' do
      before do
        @country_code_de = FactoryGirl.build(:country, :code => 'de')
      end

      it 'should be equal if Country.code is equal' do
        other_country_code_de = FactoryGirl.build(:country, :code => 'de')
        @country_code_de.should == other_country_code_de
      end

      it 'should be not equal if Country.code is not equal' do
        country_code_usa = FactoryGirl.build(:country, :code => 'usa')
        @country_code_de.should_not == country_code_usa
      end

      it 'should be case insensitive' do
        country_code_de_uppercase = FactoryGirl.build(:country, :code => 'DE')
        @country_code_de.should == country_code_de_uppercase
      end

      it 'should not rely on id for equality' do
        @country_code_de.id = 0
        country_code_usa = FactoryGirl.build(:country, :code => 'usa', :id => 0)
        @country_code_de.should_not == country_code_usa
      end

      it 'should be not equal if Country.code of one Country is nil' do
        country_code_nil = FactoryGirl.build(:country, :code => nil)
        @country_code_de.should_not == country_code_nil
      end

      it 'should be equal if Country.code for both countries is nil' do
        country_code_nil = FactoryGirl.build(:country, :code => nil)
        other_country_code_nil = FactoryGirl.build(:country, :code => nil)
        country_code_nil.should == other_country_code_nil
      end

      it 'should be not equal if other Country is nil' do
        @country_code_de.should_not == nil
      end

      it 'should be not equal if other object is not a Country' do
        @country_code_de.should_not == 'test'
      end

      it 'should be equal for descendants of Country with same Country.code' do
        class CountryChild < Country
        end
        country_child = CountryChild.new(:code => 'de')
        @country_code_de.should == country_child
      end
    end
end

7 个答案:

答案 0 :(得分:1)

如果您使用的是Rails:

def ==(another_country)
  return nil unless another_country
  code.try(:downcase) == another_country.code.try(:downcase)
end

答案 1 :(得分:1)

nil有一个to_s方法:

def ==(another_country)
   #return nil if another_country.nil?
   self.code.to_s.downcase == another_country.code.to_s.downcase
end

答案 2 :(得分:1)

也许您可以将逻辑分解为两个方法,一个返回对象的标识,另一个方法用于检查相等性:

class MyClass
  def identity
    return nil if code.nil?
    code.downcase
  end

  def ==(other)
    return false unless other.is_a?(MyClass)
    self.identity == other.identity
  end
end

答案 3 :(得分:1)

由于任何非nilfalse的值在条件中都与true相似,因此您可以使用代码执行一些操作。

表达式如

(code.nil? ? nil : code.downcase)

可以轻松地替换为

(code.downcase if code) # or by this one (code && code.downcase)

第二个

(do_something) unless another_country.nil?

一样
(do_something) if another_country 
# or 
another_contry && (do_something)

所以最终你可以把你的方法变成这个

def ==(another_country)
  code && another_country.code && 
  code.downcase == another_country.code.downcase
end

一些测试

class Country
  attr_accessor :code

  def initialize(code)
    @code = code
  end

  def ==(another_country)
    code && another_country.code &&
    code.downcase == another_country.code.downcase
  end
end

p Country.new("FOObar") == Country.new("fooBAR") # => true
p Country.new(nil)      == Country.new(nil)      # => nil
p Country.new("XXX")    == Country.new(nil)      # => nil
p Country.new(nil)      == Country.new("XXX")    # => nil

答案 4 :(得分:1)

这个怎么样,

def ==(another_country)
   return false if code.blank? # Remove this line if you want to return true if code and antoher_country.code are nil
   code.to_s.downcase == another_country.to_s.code.downcase rescue false
end

如果codeanother_countryanother_country.code中的任何一个为零,则会出现异常,rescue false语句将返回false值。< / p>

如果一切顺利,将进行比较,并根据输入返回true or false

答案 5 :(得分:0)

def == (another_country)    
    if code.nil? || another_country.nil? || another_country.code.nil?
      return nil
    end

    code.downcase == another_country.code.downcase
end

通过这种方式,您可以一目了然地看到自己在做什么 - 无需检查和比较。

答案 6 :(得分:0)

def == (another_country)
  return unless another_country.is_a?(Country)
  return if code.nil? || another_country.code.nil?

  code.casecmp(another_country.code).zero?
end

如果您最终得到一组混合类型,则类检查是一种很好的做法。

如果您不担心''vs nil的情况,可以将其压缩一下以下。我不认为这是值得的。

def == (another_country)
  code.try(:casecmp, another_country.code.to_s).try(:zero?) if another_country.is_a?(Country)
end

注意,如果你要覆盖==你还应该覆盖eql?并且哈希,否则你可以使用哈希和可枚举的方法获得意想不到的结果。

Ruby Monk - Equality of Objects