0

I cannot seem to find a way to do this. All I want to do is try the first statement, if it is blank or null (at any stage) then return the other one. For instance

a.b.c.blank? ? a.b.c : 'Fill here'

This is causing me nil:NillClass exception. Is there a way to fix this in a simple one liner way?

Jaffa
  • 12,442
  • 4
  • 49
  • 101
Sarp Kaya
  • 3,686
  • 21
  • 64
  • 103

4 Answers4

2

If you have active_support available, you can use Object#try:

a.try(:b).try(:c) or 'Fill here'

If you don't have that, it's pretty easy to monkey-patch Object to add one. Here's the code in active_support, just put it some where before you are using try method.

class Object
  def try(*a, &b)
    if a.empty? && block_given?
      yield self
    else
      public_send(*a, &b) if respond_to?(a.first)
    end
  end
end

After that, you can use it:

a = nil
a.try(:b).try(:c).try(:nil?)    #=> true

b = 1
b.try(:+, 2)    #=> 3
Arie Xiao
  • 13,909
  • 3
  • 31
  • 30
0

There's not nil:NilClass exception thrown by default.

a or b or c may be nil, so for a one line statement you can do:

# require this to use present?, not needed with rails
require 'active_support/all'

a.present? ? (a.b.present? ? (a.b.c.present? ? a.b.c : 'Fill here') : 'Fill here') : 'Fill here'

(And this is ternary expression, not exactly an if statement)

But this is ugly, although you can remove parts of the expression if you are sure that a or a.b is never nil.

I used present? over blank? to keep the same order as your expression. The ternary operator evaluates the first expression if the condition is true, so this may be your error.

Jaffa
  • 12,442
  • 4
  • 49
  • 101
  • That's a nested way. What if I have something that is really deep? – Sarp Kaya Aug 30 '14 at 12:49
  • Don't do it in one line then, or check before if your object is not `nil`. The base condition is just `var.present? ? var : 'default value'` – Jaffa Aug 30 '14 at 12:52
0

I would require the ActiveSupport package that allow the use of presence do something like this:

require 'active_support'
require 'active_support/core_ext/object/blank'
a.presence && a.b.presence && a.b.c.presence || 'Fill here'

See: http://apidock.com/rails/Object/presence

spickermann
  • 100,941
  • 9
  • 101
  • 131
  • I don't know Rails, but have a suspicion that you could do something like this: `[a,b,c,..].reduce(?) { |e| (e ||= ?) ... }`. Just food for thought. – Cary Swoveland Aug 30 '14 at 19:28
0

Since Ruby 2.3.0 (released 2015-12-25), this can be achieved using the save navigation operator, which is similar to Groovy's and Kotlin's null safe ?:

new method call syntax, object&.foo', method foo is called onobject' if it is not nil.

# a as object { b: { c: 'foobar' } }
a&.b&.c&.empty? ? 'Fill here' : a.b.c #=> 'foobar'
nil&.b&.c&.empty? ? 'Fill here' : a.b.c #=> 'Fill here'

Safe calls return nil when they're called upon nil objects. This is why the second case in the above example evaluates to nil and thus false.

source: NEWS for Ruby 2.3.0 (Feature #11537)
see also: What is the difference between try and &. (safe navigation operator) in Ruby

danield
  • 21
  • 6