tags:

views:

459

answers:

5

At a point in my code, I expect current_part to sometimes be nil, and I want to run some code (inside an if block) when that's not the case.

Using script/server --debugger, I've established that current_part is in fact nil at that point when the following errors occur.

All the following versions generate the can't convert nil into String error on the second line:

#

  def map_concepts_to_part(part, current_part)
     if current_part
        part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
      end
  end

#

  def map_concepts_to_part(part, current_part)
     if test_if_exists(current_part)
        part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
      end
  end

  def test_if_exists(test_subject)
    test_subject rescue nil
  end

#

  def map_concepts_to_part(part, current_part)
     if test_if_complete(current_part)
        part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
      end
  end

  def test_if_complete(test_subject)
    test_subject.id rescue nil
  end

#

  def test_if_complete(part, current_part)
     unless current_part.to_s == ""
        part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
      end
  end

#

  def test_if_complete(part, current_part)
     unless current_part.nil?
        part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
      end
  end

#

PS, the truncated line in each of the above is:

part.concepts.map { |concept| content_tag(:li, "Concept: “" + concept.title + "”", :class => "one_concept") + content_tag(:li, "Attached images (" + concept.images.size.to_s + ")", :class => "all_images") + content_tag(:li, "Attached docs (XX)", :class => "all_docs")}.join
A: 

If the object is nil, then you can't use any of its member because the object itself does not exist. So the comparison should be of the object and nil, not a member of the object and nil.

It's like a null pointer exception.

You should use something like

x = get_some_object if x.nil?

to initialize the variable x if uninitialized.

Tobias Wärre
Thanks Tobias.unless current_part == "" doesn't throw an error.However, it also doesn't seem to be testing whether current_part is nil.Meanwhile, if current_part == "" throws a can't convert nil into String error
steven_noble
Also Tobias, wouldn't "unless current_part.nil?" nonetheless work? In fact, I'm even getting a "can't convert nil intro String" error on "if current_part".
steven_noble
A: 

Tobias is right. You cannot access any member of the object if it is nil (as it does not exist). You must check for nil value before performing any operation or before accessing any member varible or function.

In cpp, is it like:

if(!current_part) { perform operation }

` This is a very common NPE(Null Pointer Exception) in almost every programming language.

Atul
Thanks Atul. I'm hoping to check for nil value first.I started with "unless current_part.nil" but got the "can't convert nil intro String" error.I tried "if current_part != nil" and "unless current_part == nil" and found the same.Funnily enough, "if current_part == nil" doesn't throw an error -- but of course it doesn't do what I want.As far as I'm aware, I'm using the correct Ruby syntax for checking if an object is nil?
steven_noble
Have you found the solution to your problem yet?
Atul
+2  A: 

The test current_part.to_s == "" returns true on my ruby system when current_part is nil. Unlike some other languages, you can say nil.to_s and nil.nil? and have them work. I think there is something else that is causing the problem. Can you show more of the code?

(My tests were in ruby 1.8.6)

Edit: Looking around, what usually causes the above error is an expression such as "text" + nil, not nil.to_s. Do you have anything like that around?

Kathy Van Stone
Thanks Kathy. I'm pretty sure I don't have anything like "text" + nil in the failing code. I've edited the entry above to provide extra detail. Should I provide more than this? Thanks again.
steven_noble
Thanks all for your advice. I tried multiple versions of every suggestion without luck. After that, I restructured the code so if current_part doesn't exist, it never gets to this method in the first place. Less DRY -- as I've created very similar current_part and non-current_part methods -- but it passes my specs so I'm happy. Thanks again.
steven_noble
You are doing a lot of string summing in the map block. Are you certain none of them are nil?
Kathy Van Stone
A: 

Is that a local variable in some partial? if so, then even doing current_part.nil? will raise an error in case that variable is not passed to the partial.

to overcome this do:

counter_part = defined?(counter_part) ? : counter_part : nil

BTW: Normally, Ruby looks for an assignment statement to determine whether something is a variable—if a name hasn’t been assigned to, then Ruby assumes that name is a method call, so executing the following statement will raise an error if x wasn't initialized:

irb(main):001:0> puts "yes nil" if x.nil?
#=>NameError: undefined local variable or method `x' for main:Object
khelll
A: 
Julik