Assignment¶↑
In Ruby, assignment uses the= (equals sign) character. This example assigns the number five to the local variablev:
v =5
Assignment creates a local variable if the variable was not previously referenced.
An assignment expression result is always the assigned value, includingassignment methods.
Local Variable Names¶↑
A local variable name must start with a lowercase US-ASCII letter or a character with the eight bit set. Typically local variables are US-ASCII compatible since the keys to type them exist on all keyboards.
(Ruby programs must be written in a US-ASCII-compatible character set. In such character sets if the eight bit is set it indicates an extended character. Ruby allows local variables to contain such characters.)
A local variable name may contain letters, numbers, an_ (underscore or low line) or a character with the eighth bit set.
Local Variable Scope¶↑
Once a local variable name has been assigned-to all uses of the name for the rest of the scope are considered local variables.
Here is an example:
1.timesdoa =1puts"local variables in the block: #{local_variables.join ", "}"endputs"no local variables outside the block"iflocal_variables.empty?
This prints:
local variables in the block: ano local variables outside the block
Since the block creates a new scope, any local variables created inside it do not leak to the surrounding scope.
Variables defined in an outer scope appear inner scope:
a =01.timesdoputs"local variables: #{local_variables.join ", "}"end
This prints:
localvariables:a
You may isolate variables in a block from the outer scope by listing them following a; in the block’s arguments. See the documentation for block local variables in thecalling methods documentation for an example.
See alsoKernel#local_variables, but note that afor loop does not create a new scope like a block does.
Local Variables and Methods¶↑
In Ruby local variable names and method names are nearly identical. If you have not assigned to one of these ambiguous names ruby will assume you wish to call a method. Once you have assigned to the name ruby will assume you wish to reference a local variable.
The local variable is created when the parser encounters the assignment, not when the assignment occurs:
a =0iffalse# does not assign to aplocal_variables# prints [:a]pa# prints nil
The similarity between method and local variable names can lead to confusing code, for example:
defbig_calculation42# pretend this takes a long timeendbig_calculation =big_calculation()
Now any reference tobig_calculation is considered a local variable and will be cached. To call the method, useself.big_calculation.
You can force a method call by using empty argument parentheses as shown above or by using an explicit receiver likeself. Using an explicit receiver may raise aNameError if the method’s visibility is not public or the receiver is the literalself.
Another commonly confusing case is when using a modifierif:
paifa =0.zero?
Rather than printing “true” you receive aNameError, “undefined local variable or method ‘a’”. Since ruby parses the barea left of theif first and has not yet seen an assignment toa it assumes you wish to call a method. Ruby then sees the assignment toa and will assume you are referencing a local variable.
The confusion comes from the out-of-order execution of the expression. First the local variable is assigned-to then you attempt to call a nonexistent method.
Local Variables and eval¶↑
Usingeval to evaluate Ruby code will allow access to local variables defined in the same scope, even if the local variables are not defined until after the call toeval. However, local variables defined inside the call toeval will not be reflected in the surrounding scope. Inside the call toeval, local variables defined in the surrounding scope and local variables defined inside the call toeval will be accessible. However, you will not be able to access local variables defined in previous or subsequent calls toeval in the same scope. Consider eacheval call a separate nested scope. Example:
defmeval"bar = 1"lvs =eval"baz = 2; ary = [local_variables, foo, baz]; x = 2; ary"eval"quux = 3"foo =1lvs<<local_variablesendm# => [[:baz, :ary, :x, :lvs, :foo], nil, 2, [:lvs, :foo]]
Instance Variables¶↑
Instance variables are shared across all methods for the same object.
An instance variable must start with a@ (“at” sign or commercial at). Otherwise instance variable names follow the rules as local variable names. Since the instance variable starts with an@ the second character may be an upper-case letter.
Here is an example of instance variable usage:
classCdefinitialize(value)@instance_variable =valueenddefvalue@instance_variableendendobject1 =C.new"some value"object2 =C.new"other value"pobject1.value# prints "some value"pobject2.value# prints "other value"
An uninitialized instance variable has a value ofnil.
Thevalue method has access to the value set by theinitialize method, but only for the same object.
Class Variables¶↑
Class variables are shared between a class, its subclasses and its instances.
A class variable must start with a@@ (two “at” signs). The rest of the name follows the same rules as instance variables.
Here is an example:
classA@@class_variable =0defvalue@@class_variableenddefupdate@@class_variable =@@class_variable+1endendclassB<Adefupdate@@class_variable =@@class_variable+2endenda =A.newb =B.newputs"A value: #{a.value}"puts"B value: #{b.value}"
This prints:
Avalue:0Bvalue:0
Continuing with the same example, we can update using objects from either class and the value is shared:
puts"update A"a.updateputs"A value: #{a.value}"puts"B value: #{b.value}"puts"update B"b.updateputs"A value: #{a.value}"puts"B value: #{b.value}"puts"update A"a.updateputs"A value: #{a.value}"puts"B value: #{b.value}"
This prints:
updateAAvalue:1Bvalue:1updateBAvalue:3Bvalue:3updateAAvalue:4Bvalue:4
Accessing an uninitialized class variable will raise aNameError exception.
Note that classes have instance variables because classes are objects, so try not to confuse class and instance variables.
Global Variables¶↑
Global variables are accessible everywhere.
Global variables start with a$ (dollar sign). The rest of the name follows the same rules as instance variables.
Here is an example:
$global =0classCputs"in a class: #{$global}"defmy_methodputs"in a method: #{$global}"$global =$global+1$other_global =3endendC.new.my_methodputs"at top-level, $global: #{$global}, $other_global: #{$other_global}"
This prints:
in a class: 0in a method: 0at top-level, $global: 1, $other_global: 3
An uninitialized global variable has a value ofnil.
Ruby has some special globals that behave differently depending on context such as the regular expression match variables or that have a side-effect when assigned to. See theglobal variables documentation for details.
Assignment Methods¶↑
You can define methods that will behave like assignment, for example:
classCdefvalue=(value)@value =valueendendc =C.newc.value =42
Using assignment methods allows your programs to look nicer. When assigning to an instance variable most people useModule#attr_accessor:
classCattr_accessor:valueend
When using method assignment you must always have a receiver. If you do not have a receiver, Ruby assumes you are assigning to a local variable:
classCattr_accessor:valuedefmy_methodvalue =42puts"local_variables: #{local_variables.join ", "}"puts"@value: #{@value.inspect}"endendC.new.my_method
This prints:
local_variables: value@value: nil
To use the assignment method you must set the receiver:
classCattr_accessor:valuedefmy_methodself.value =42puts"local_variables: #{local_variables.join ", "}"puts"@value: #{@value.inspect}"endendC.new.my_method
This prints:
local_variables:@value: 42
Note that the value returned by an assignment method is ignored whatever, since an assignment expression result is always the assignment value.
Abbreviated Assignment¶↑
You can mix several of the operators and assignment. To add 1 to an object you can write:
a =1a+=2pa# prints 3
This is equivalent to:
a =1a =a+2pa# prints 3
You can use the following operators this way:+,-,*,/,%,**,&,|,^,<<,>>
There are also||= and&&=. The former makes an assignment if the value wasnil orfalse while the latter makes an assignment if the value was notnil orfalse.
Here is an example:
a||=0a&&=1pa# prints 1
Note that these two operators behave more likea || a = 0 thana = a || 0.
ImplicitArray Assignment¶↑
You can implicitly create an array by listing multiple values when assigning:
a =1,2,3pa# prints [1, 2, 3]
This implicitly creates anArray.
You can use* or the “splat” operator or unpack anArray when assigning. This is similar to multiple assignment:
a =*[1,2,3]pa# prints [1, 2, 3]b =*1pb# prints [1]
You can splat anywhere in the right-hand side of the assignment:
a =1,*[2,3]pa# prints [1, 2, 3]
Multiple Assignment¶↑
You can assign multiple values on the right-hand side to multiple variables:
a,b =1,2pa:a,b:b# prints {:a=>1, :b=>2}
In the following sections any place “variable” is used an assignment method, instance, class or global will also work:
defvalue=(value)passigned:valueendself.value,$global =1,2# prints {:assigned=>1}p$global# prints 2
You can use multiple assignment to swap two values in-place:
old_value =1new_value,old_value =old_value,2pnew_value:new_value,old_value:old_value# prints {:new_value=>1, :old_value=>2}
If you have more values on the right hand side of the assignment than variables on the left hand side, the extra values are ignored:
a,b =1,2,3pa:a,b:b# prints {:a=>1, :b=>2}
You can use* to gather extra values on the right-hand side of the assignment.
a,*b =1,2,3pa:a,b:b# prints {:a=>1, :b=>[2, 3]}
The* can appear anywhere on the left-hand side:
*a,b =1,2,3pa:a,b:b# prints {:a=>[1, 2], :b=>3}
But you may only use one* in an assignment.
Array Decomposition¶↑
LikeArray decomposition inmethod arguments you can decompose anArray during assignment using parenthesis:
(a,b) = [1,2]pa:a,b:b# prints {:a=>1, :b=>2}
You can decompose anArray as part of a larger multiple assignment:
a, (b,c) =1, [2,3]pa:a,b:b,c:c# prints {:a=>1, :b=>2, :c=>3}
Since each decomposition is considered its own multiple assignment you can use* to gather arguments in the decomposition:
a, (b,*c),*d =1, [2,3,4],5,6pa:a,b:b,c:c,d:d# prints {:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]}