Ruby Programming/Syntax/Operators

Complete List and Precedence
Higher precedence (lower number in the above table) operators have their immediate arguments evaluated first. Precedence order can be altered with blocks. For example, because  has higher precedence than +, then:

Association direction controls which operators have their arguments evaluated first when multiple operators with the same precedence appear in a row. For example, because  has left association:

1 – 2 – 3 == (1 – 2) – 3 == -1 – 3 == -4

instead of:

1 – 2 – 3 == 1 – (2 – 3) == 1 - -1 == 0

Because  has right association:

2 ** 3 ** 2 == 2 ** (3 ** 2) == 2 ** 9 == 512

instead of:

2 ** 3 ** 2 == (2 ** 3) ** 2 == 8 ** 2 == 64

{} blocks have lower precedence than the above operators, followed by do/end blocks. Array accesses with [] can be thought of as having a higher precedence than any above operator.

The operators ** through !~ can be overridden (defined for new classes, or redefined for existing operations).

Note that rescue, if, unless, while, and until are operators when used as modifiers in one-liners (as in the above examples) but can also be used as keywords.

Other operators
The dot operator  is used for calling methods on objects, also known as passing a message to the object.

Ruby 2.3.0 introduced the safe navigation operator, also known as the "lonely operator". This allows replacing

with

An equivalent  method was introduced for hashes and arrays: are safer versions of:

The safe navigation operator will raise an error if a requested method, key, or index is not available; unlike the technique of using try for this purpose, which will return nil.

Yukihiro Matsumoto considered    and   before settling on   because:
 * ?. conflicts with *?
 * ?. is used by other languages, thus .? is confusingly similar but different
 * ! conflicts with "not" logic
 * ? is already used by convention for functions that return booleans
 * &. is reminiscent of the && syntax the operator is replacing

is sometimes seen, but this is simply the  operator twice. It is used to force the following expression to evaluate to a boolean. This technique is considered non-idiomatic and poor programming practice, because there are more explicit ways to force such a conversion (which is rarely needed to begin with).

Assignment
Assignment in Ruby is done using the equal operator "=". This is both for variables and objects, but since strings, floats, and integers are actually objects in Ruby, you're always assigning objects.

Examples:

Self assignment

A frequent question from C and C++ types is "How do you increment a variable? Where are ++ and -- operators?" In Ruby, one should use x+=1 and x-=1 to increment or decrement a variable.

Multiple assignments

Examples:

Conditional assignment

Operator ||= is a shorthand form that closely resembles the expression:

Operator ||= can be shorthand for code like:

In same way &&= operator works:

Operator &&= is a shorthand form of the expression:

Scope
In Ruby there's a local scope, a global scope, an instance scope, and a class scope.

Local Scope
Example: var = 2 4.times do |x| puts x = x*var end #=> 0  2  4  6   puts x  #=> undefined local variable or method `x' for main:Object (NameError)

This error appears because this x(toplevel) is not the x(local) inside the do..end block the x(local) is a local variable to the block, whereas when trying the puts x(toplevel) we're calling a x variable that is in the top level scope, and since there's not one, Ruby protests.

Global scope
$global = 0 4.times do |var| $global = $global + var puts "var #{var} global #{$global}" end #=> var 0  global 0 var 1 global 1 var 2 global 3 var 3 global 6 puts $global #=> 6

This output is given because prefixing a variable with a dollar sign makes the variable a global.

Instance scope
Within methods of a class, you can share variables by prefixing them with an @.

class A   def setup @instvar = 1 end def go     @instvar = @instvar*2 puts @instvar end end instance = A.new instance.setup instance.go #=> 2 instance.go #=> 4

Class scope
A class variable is one that is like a "static" variable in Java. It is shared by all instances of a class.

class A   @@classvar = 1 def go     @@classvar = @@classvar*2 puts @@classvar end end instance = A.new instance.go #=> 2 instance = A.new instance.go #=> 4 -- variable is shared across instances

Here's a demo showing the various types:

$variable class Test def initialize(arg1='kiwi') @instvar=arg1 @@classvar=@instvar+' told you so!!' localvar=@instvar end def print_instvar puts @instvar end def print_localvar puts @@classvar puts localvar end end var=Test.new var.print_instvar             #=>"kiwi", it works because a @instance_var can be accessed inside the class var.print_localvar            #=>undefined local variable or method 'localvar' for # (NameError). This will print the two lines "kiwi" and "kiwi told you so!!", then fail with a undefined local variable or method 'localvar' for # (NameError). Why? Well, in the scope of the method print_localvar there doesn't exists localvar, it exists in method initialize(until GC kicks it out). On the other hand, class variables '@@classvar' and '@instvar' are in scope across the entire class and, in the case of @@class variables, across the children classes.

class SubTest < Test def print_classvar puts @@classvar end end newvar=SubTest.new             #newvar is created and it has @@classvar with the same value as the var  instance of Test!! newvar.print_classvar          #=>kiwi told you so!! Class variables have the scope of parent class AND children, these variables can live across classes, and can be affected by the children actions ;-)

class SubSubTest < Test def print_classvar puts @@classvar end def modify_classvar @@classvar='kiwi kiwi waaai!!' end end subtest=SubSubTest.new subtest.modify_classvar         #lets add a method that modifies the contents of @@classvar in  SubSubTest subtest.print_classvar This new child of Test also has @@classvar with the original value newvar.print_classvar. The value of @@classvar has been changed to 'kiwi kiwi waaai!!' This shows that @@classvar is "shared" across parent and child classes.

Default scope
When you don't enclose your code in any scope specifier, ex:

@a = 33

it affects the default scope, which is an object called "main".

For example, if you had one script that says

@a = 33 require 'other_script.rb'

and other_script.rb says

puts @a #=> 33

They could share variables.

Note however, that the two scripts don't share local variables.

Local scope gotchas
Typically when you are within a class, you can do as you'd like for definitions, like.

class A a = 3 if a == 3

def go      3 end else def go      4 end end

end

And also, procs "bind" to their surrounding scope, like

a = 3 b = proc { a } b.call # 3 -- it remembered what a was

However, the "class" and "def" keywords cause an *entirely new* scope.

class A a = 3 def go    return a # this won't work! end end

You can get around this limitation by using define_method, which takes a block and thus keeps the outer scope (note that you can use any block you want, to, too, but here's an example).

class A  a = 3 define_method(:go) { a } end

Here's using an arbitrary block

a = 3 PROC = proc { a } # gotta use something besides a local
 * 1) variable because that "class" makes us lose scope.

class A define_method(:go, &PROC) end

or here class A end a = 3 A.class_eval do  define_method(:go) do       puts a   end end

Logical And
The binary "and" operator will return the logical conjunction of its two operands. It is the same as "&&" but with a lower precedence. Example: a = 1 b = 2 c = nil puts "yay all my arguments are true" if a and b puts "oh no, one of my argument is false" if a and c

Logical Or
The binary "or" operator will return the logical disjunction of its two operands. It is the same as "||" but with a lower precedence. Example: a = nil b = "foo" c = a || b # c is set to "foo" it's the same as saying c = (a || b) c = a or b  # c is set to nil   it's the same as saying (c = a) || b which is not what you want.