Ruby Programming/Syntax/Operators
Contents |
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:
-
myvar = 'myvar is now this string' -
var = 321 -
dbconn = Mysql::new('localhost','root','password')
Self assignment
-
x = 1 #=>1
-
x += x #=>2
-
x -= x #=>0
-
x += 4 #=>x was 0 so x= + 4 # x is positive 4
-
x *= x #=>16
-
x **= x #=>18446744073709551616 # Raise to the power
-
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.
-
x = 'a' -
x.succ! #=>"b" : succ! method is defined for String, but not for Integer types
Multiple assignments
Examples:
-
var1, var2, var3 = 10, 20, 30
-
puts var1 #=>var1 is now 10
-
puts var2 #=>var2 is now 20,var3...etc
-
-
myArray=%w(John Michel Fran Doug) # %w() can be used as syntactic sugar to simplify array creation
-
var1,var2,var3,var4=*myArray -
puts var1 #=>John
-
puts var4 #=>Doug
-
-
names,school=myArray,'St. Whatever' -
names #=>["John", "Michel", "Fran", "Doug"] -
school #=>"St. Whatever"
Conditional assignment
-
x = find_something() #=>nil
-
x ||= "default" #=>"default" : value of x will be replaced with "default", but only if x is nil or false
-
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:
-
x || x = "default"
Operator ||= can be shorthand for code like:
-
x = "(some fallback value)" unless respond_to? :x or x
In same way &&= operator works:
-
x = get_node() #=>nil
-
x &&= x.next_node #=> nil : x will be set to x.next_node, but only if x is NOT nil or false
-
x = get_node() #=>Some Node
-
x &&= x.next_node #=>Next Node
Operator &&= is a shorthand form of the expression:
-
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 |$global| $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.