Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Long nil safe method chains [closed]

So I know of a few different approaches that I am aware of and I want explore the advantages and disadvantages of the various ways for various criteria which are:

  • readability
  • performance
  • ease of debugging
  • OO principles (low coupling and high cohesion)

Explicitly using the try method from active support

person.try(:pet).try(:name).try(:upcase)

Using a rescue nil

person.pet.name.upcase rescue nil

Using an && operator chain

person && person.pet && person.pet.name && person.pet.name.upcase

Monkey patching the Object class, see https://gist.github.com/thegrubbsian/3499234 for the original gist

 class Object

      def try_all(*methods)
        values = [self]
        methods.each do |method|
          value = values.last.try(method)
          return nil if value.nil?
          values << value
        end
        values.last
      end

  end

person.try_all(:pet, :name, :upcase)

Don't have nil safe code, instead validate the data before you call the code

#not a good implementation by any means    
def person_has_pet_with_name? person
  begin 
    return true if !person.pet.name.nil?
  rescue
    return false
  end
end

person.pet.name.upcase if person_has_pet_with_name?(person)
like image 930
jdfolino Avatar asked Sep 30 '22 22:09

jdfolino


1 Answers

My personal opinion about monkey patching in general is do NOT do it unless there is no other way (and even than I think twice if I really want to monkey patch).
Besides Rails already bloated objects a lot. So I'd not suggest custom bloating objects even more.
Why not avoiding to break the law of Demeter by the classic delegator approach:

class Person
  attr_accessor :pet
  delegate :name_upcased, to: :pet, 
    prefix: true, allow_nil: true
end

class Pet
  attr_accessor :name
  def name_upcased
    @name.upcase if @name
  end
end

@person.try :pet_name_upcased

You can also read about the law of Demeter at Do not break the law of Demeter! and Module#delegate.
At least I would not stick to Object#try as long as a simple condition solves it, because looking at the source of 'try' it is more costly than the condition.

like image 87
Christian Rolle Avatar answered Oct 03 '22 10:10

Christian Rolle