Ruby Programming/Syntax/Operators

From Wikibooks, open books for an open world
Jump to: navigation, search

Operators[edit]

1. Assignment[edit]

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:

  1.   myvar = 'myvar is now this string'
    
  2.   var = 321
    
  3.   dbconn = Mysql::new('localhost','root','password')
    

Self assignment

  1.   x = 1           #=>1
    
  2.   x += x          #=>2
    
  3.   x -= x          #=>0
    
  4.   x += 4          #=>x was 0 so x= + 4 # x is positive 4
    
  5.   x *= x          #=>16
    
  6.   x **= x         #=>18446744073709551616 # Raise to the power
    
  7.   x /= x          #=>1
    

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.

  1.   x = 'a'
    
  2.   x.succ!         #=>"b" : succ! method is defined for String, but not for Integer types
    

Multiple assignments

Examples:

  1.   var1, var2, var3 = 10, 20, 30
    
  2.   puts var1           #=>var1 is now 10
    
  3.   puts var2           #=>var2 is now 20,var3...etc
    
  4.  
    
  5.   myArray=%w(John Michel Fran Doug) # %w() can be used as syntactic sugar to simplify array creation
    
  6.   var1,var2,var3,var4=*myArray
    
  7.   puts var1           #=>John
    
  8.   puts var4           #=>Doug
    
  9.  
    
  10.   names,school=myArray,'St. Whatever'
    
  11.   names               #=>["John", "Michel", "Fran", "Doug"]
    
  12.   school              #=>"St. Whatever"
    

Conditional assignment

  1.   x = find_something() #=>nil
    
  2.   x ||= "default"      #=>"default" : value of x will be replaced with "default", but only if x is nil or false
    
  3.   x ||= "other"        #=>"default" : value of x is not replaced if it already is other than nil or false
    

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

  1.  x = x || "default"
    

Operator ||= can be shorthand for code like:

  1.   x = "(some fallback value)" unless respond_to? :x or x
    

In same way &&= operator works:

  1.   x = get_node() #=>nil
    
  2.   x &&= x.next_node #=> nil : x will be set to x.next_node, but only if x is NOT nil or false
    
  3.   x = get_node() #=>Some Node
    
  4.   x &&= x.next_node #=>Next Node
    

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

  1.  x = x && x.get_node()
    

Scope[edit]

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

Local Scope[edit]

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[edit]

 4.times do |var|
   $global=$global*var
 end  #=>0,2,4,6 last assignment of $global is 6
 puts $global
 #=> 6

This works because prefixing a variable with a dollar sign makes the variable a global.

Instance scope[edit]

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[edit]

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 accesed inside the class
 var.print_localvar             #=>undefined local variable or method 'localvar' for #<Test:0x2b36208 @instvar="kiwi"> (NameError).

This will print the two lines "kiwi" and "kiwi told you so!!", then fail with a undefined local variable or method 'localvar' for #<Test:0x2b36208 @instvar="kiwi"> (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[edit]

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[edit]

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
# 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[edit]

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[edit]

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.