Reputation: 2869
I'm running into an interesting issue with the relatively simple assignment below. Each of the parenthesized chunks in the beginning evaluate to nil, leaving Rubygame::Surface.new
as the value that @image
ought to be assigned to. Unfortunately on the next line where I set @rect
, it throws a NoMethodError because @image
is nil.
@image = (image unless image.nil?) or
(Rubygame::Surface.autoload(image_file) unless image_file.nil?) or
(Rubygame::Surface.autoload("#{@name}.png") unless @name.nil?) or
Rubygame::Surface.new([16, 16])
@rect = Rubygame::Rect.new [0, 0], [@image.width, @image.height]
Similar tests run through IRB work as expected, so I'm pretty sure the 'or' statement is well-formed, but I can't figure out why it isn't returning the new Surface when everything else is nil.
Upvotes: 1
Views: 161
Reputation: 29915
Why are you using RubyGame? The Gosu game development framework for Ruby is faster and more popular.
Upvotes: -1
Reputation: 74985
The or
and and
keywords in Ruby have very, very low precedence. Even lower than the assignment operator =
. So simply replace them with ||
and &&
respectively (both binding tighter than =
), and it should work as you expect. Ruby's operator precedence is listed here.
In addition to that, I would say your code is very dense. Consider refactoring it to something like the following, which I think conveys the intent of your code much better.
@image = case
when image then image
when image_file then Rubygame::Surface.autoload(image_file)
when @name then Rubygame::Surface.autoload("#{@name}.png")
else Rubygame::Surface.new([16, 16])
end
@rect = Rubygame::Rect.new [0, 0], [@image.width, @image.height]
Upvotes: 5
Reputation: 30623
Have you tried further levels of parentheses?
@image = ((image unless image.nil?) or
(Rubygame::Surface.autoload(image_file) unless image_file.nil?) or
(Rubygame::Surface.autoload("#{@name}.png") unless @name.nil?) or
Rubygame::Surface.new([16, 16]))
Upvotes: 1