Ruby 基于一个属性的不区分大小写的equals方法 原始问题

Ruby 基于一个属性的不区分大小写的equals方法 原始问题,ruby,boolean-logic,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 你能为我指出正确的方向吗?如何在丑陋的if-else结构上写这个更优雅的w/o 这就是我最终使用的解决方

这是一个非常可怕的方法,它在代码的基础上检查是否相等,但不区分大小写

def ==(another_country)
   (code.nil? ? nil : code.downcase) == (another_country.code.nil? ? nil : another_country.code.downcase) unless another_country.nil?
end
你能为我指出正确的方向吗?如何在丑陋的if-else结构上写这个更优雅的w/o

这就是我最终使用的解决方案(+rspec)
#国家/地区模式
类国家/地区
广泛测试:

# 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
#RSpec
描述国家做什么
描述“完全基于国家的平等。代码”是什么
在做之前
@country\u code\u de=FactoryGirl.build(:country,:code=>'de')
终止
“如果Country.code相等,则应相等”do
其他国家/地区\u代码\u de=FactoryGirl.build(:country,:code=>de)
@国家/地区代码应==其他国家/地区代码
终止
“如果Country.code不相等,则不应相等”do
country\u code\u usa=FactoryGirl.build(:country,:code=>“usa”)
@国家代码不应=国家代码美国
终止
它“应该不区分大小写”吗
country\u code\u de\u大写=FactoryGirl.build(:country,:code=>'de')
@country_code_de.should==country_code_de_大写
终止
它“不应该依赖id来实现平等”吗
@国家代码id=0
country\u code\u usa=FactoryGirl.build(:country,:code=>'usa',:id=>0)
@国家代码不应=国家代码美国
终止
如果一个国家的Country.code为零,则“不应相等”do
country\u code\u nil=FactoryGirl.build(:country,:code=>nil)
@国家/地区代码不应=国家/地区代码无
终止
如果两个国家的Country.code均为零,则“应该相等”do
country\u code\u nil=FactoryGirl.build(:country,:code=>nil)
other\u country\u code\u nil=FactoryGirl.build(:country,:code=>nil)
国家/地区代码\u nil.should==其他国家/地区代码\u nil
终止
“如果其他国家为零,则不应平等”do
@国家/地区代码不应=零
终止
“如果其他对象不是一个国家,那么它就不应该是相等的”这样做吗
@国家/地区代码不应==“测试”
终止
“同一国家的后代应该是平等的。代码”do
类CountryChild'de')
@国家/地区代码应==国家/地区子项
终止
终止
终止

通过这种方式,您所做的操作一目了然—无检查和比较。

如果您使用的是Rails:

def ==(another_country)
  return nil unless another_country
  code.try(:downcase) == another_country.code.try(:downcase)
end
nil有一个to_s方法:

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

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

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

由于任何不是
nil
false
的值在条件中的行为类似于
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
这个怎么样,

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
这里,如果
code
另一个国家或
另一个国家/地区.code
中的任何一个为零,它将执行异常,并且
rescue false
语句将返回
false

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

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
如果最终得到一个混合类型数组,那么类检查是一种很好的做法

如果您不担心“”与nil的情况,可以将其压缩为以下内容。但我认为这不值得

def == (another_country)
  code.try(:casecmp, another_country.code.to_s).try(:zero?) if another_country.is_a?(Country)
end
注意,如果您正在重写==您还应该重写eql吗?和散列,否则您可以使用散列和可枚举方法获得意外的结果


如果另一个国家的
nil
,会发生什么?我最后使用了另一个国家的
nil?因为它与Rails无关,所以如果
==
方法返回nil,我会非常惊讶,但是您是对的,OP的代码就是这样做的。编辑code@steenslag至少根据调试器,我的方法不会返回nil,是吗?我认为您缺少了一个
返回值
。另外,从
=
方法返回
nil
有什么意义?我认为它应该总是返回一个布尔值。我只是在模仿他的原始表达式——它的末尾有一个除非<代码>除非为真,否则将导致
nil
如果
零件缺少退货,则返回“是”。对。添加了
返回nil,除非另一个国家/地区
作为方法的第一行。身份是否应该是私有的?我想这取决于具体情况。如果两个代码都是
nil
,则您的解决方案不起作用。我从你的代码中学到了很多,我相信你把一个大问题分解成小问题的方法在将来会对我有用(+1)@visor:这是我迄今为止在SC上提出的最有成效的问题。我的问题的答案是我们能想出的最短答案,但答案中有很多智慧;)
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
def == (another_country)
  code.try(:casecmp, another_country.code.to_s).try(:zero?) if another_country.is_a?(Country)
end