Ruby Programming/Syntax/Operators
Contents |
[edit] Operators
[edit] 1. 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:
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()
[edit] Scope
In Ruby there's a local scope, a global scope, an instance scope, and a class scope.
[edit] 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.
[edit] Global scope
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.
[edit] 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
[edit] 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
@@instvar = 1
def go
@@instvar = @@instvar*2
puts @@instvar
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.
[edit] 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.
[edit] 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
# 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
[edit] 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
[edit] 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" its the same as saying c = (a || b) c = a or b # c is set to nil its the same as saying (c = a) || b which is not what you want.