0
votes

anyone care to explain what this syntax means in Ruby?

class Animal
  def name_category
    @animals ||={}
  end
end

Also, is there a way for setting up object variable without using attr_accessor, attr_reader, attr_writer or def initialize?

2
Can you clarify what you mean by "setting up object variable"?Jake Romer
by object variable, I mean the variable that is using @ sigil. Sorry I just started to learn ruby, I didn't know that it was the wrong termChristian Sakai
No problem, just wanted to make sure I understood. In Ruby, prepending a variable name with with @ declares it an instance variable, and it's initialized to nil unless assigned to something else.Jake Romer
The attr_ methods are just a shorthand way of declaring setters and getters for your instance variables, so if you just have attr_accessor :name without assigning anything to @name anywhere inside of your class definition, #name will just return nil unless you assign it something with #name=.Jake Romer

2 Answers

6
votes

||= is Ruby's conditional assignment operator. a ||= b can usually be taken as short for

a || (a = b)

That is, a is assigned b if a is nil or false (i.e., a = b conditional on the falsiness of a).

The operator exploits a property of the way || is evaluated. Namely, that the right-hand operand of || is not evaluated unless the left-hand one is truthy (i.e., not false or nil). This is known as short-circuiting.

In your case, unless @animals already possesses a non-falsy value, it will be bound to an empty hash {}.

It's important to note that despite the superficial similarity of ||= to operators like += and -=, a ||= b is not equivalent to a = a || b.

For a counterexample, take a = Hash.new(true). Then:

a[:key] ||= :value
#=> true
a
#=> {}

Compare with

a[:key] = a[:key] || :value
#=> true

a
#=> {:key=>true}

However, strictly speaking a ||= b is also not equivalent to a || a = b. If a is undefined, then

>> a || a = false
#=> NameError: undefined local variable or method `a' for main:Object

but

>> a ||= false
#=> false

and

>> a = a || false
#=> false 

Something to keep in mind.

So it’s more accurate, if less syntactically elegant, to say that a ||= b is equivalent to

(defined?(a) && a) ? a : a = b

Here's a good post on Ruby Inside elaborating on this point further.

0
votes

It's equivalent to (really long hand unpretty form):

if @animal == nil  # (falsey really, but nil is what we're looking for here)
  @animal = {}
end
return @animal

Basically: return @animal, unless it's not initialized in which case initialized it to {} before return it.

You could also write it as:

@animal = {} unless @animal
return @animal

Or

@animal ||= {}
return @animal

But then @animal ||= {} evaluates to @animal anyway, and you can skip the return