summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--doc/syntax/assignment.rdoc439
2 files changed, 443 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 053e0c5810..2df06821da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Sat Jan 19 08:47:33 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/syntax/assignment.rdoc: Added a syntax document on assignment.
+
Fri Jan 18 14:11:01 2013 Eric Hodel <drbrain@segment7.net>
* doc/syntax/methods.rdoc: Added Array Decomposition.
diff --git a/doc/syntax/assignment.rdoc b/doc/syntax/assignment.rdoc
new file mode 100644
index 0000000000..8c7fa3a7aa
--- /dev/null
+++ b/doc/syntax/assignment.rdoc
@@ -0,0 +1,439 @@
+= Assignment
+
+In Ruby assignment uses the <code>=</code> (equals sign) character. This
+example assigns the number five to the local variable +v+:
+
+ v = 5
+
+Assignment creates a local variable if the variable was not previously
+referenced.
+
+== 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 <code>_</code>
+(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.times do
+ a = 1
+ puts "local variables in the block: #{local_variables.join ", "}"
+ end
+
+ puts "no local variables outside the block" if local_variables.empty?
+
+This prints:
+
+ local variables in the block: a
+ no 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 = 0
+
+ 1.times do
+ puts "local variables: #{local_variables.join ", "}"
+ end
+
+This prints:
+
+ local variables: a
+
+You may isolate variables in a block from the outer scope by listing them
+following a <code>;</code> in the block's arguments. See the documentation
+for {calling methods}[rdoc-ref:syntax/calling_methods.rdoc] for an example.
+
+See also Kernel#local_variables, but note that a +for+ 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.
+
+This leads to some potentially confusing code, for example:
+
+ def big_calculation
+ 42 # pretend this takes a long time
+ end
+
+ big_calculation = big_calculation
+
+Now any reference to +big_calculation+ is considered a local variable and will
+be cached. To call the method, use <code>self.big_calculation</code>.
+
+Another commonly confusing case is when using a modifier +if+:
+
+ p a if a = 0.zero?
+
+Rather than printing "true" you receive a NameError, "undefined local variable
+or method `a'". Since ruby parses the bare +a+ left of the +if+ first and has
+not yet seen an assignment to +a+ it assumes you wish to call a method. Ruby
+then sees the assignment to +a+ and will assume you are referencing a local
+method.
+
+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.
+
+== Instance Variables
+
+Instance variables are shared across all methods for the same object.
+
+An instance variable must start with a <code>@</code> ("at" sign or
+commercial at). Otherwise instance variable names follow the rules as local
+variable names. Since the instance variable starts with an <code>@</code> the
+second character may be an upper-case letter.
+
+Here is an example of instance variable usage:
+
+ class C
+ def initialize(value)
+ @instance_variable = value
+ end
+
+ def value
+ @instance_variable
+ end
+ end
+
+ object1 = C.new "some value"
+ object2 = C.new "other value"
+
+ p object1.value # prints "some value"
+ p object2.value # prints "other value"
+
+An uninitialized instance variable has a value of +nil+. If you run Ruby with
+warnings enabled you will get a warning when accessing an uninitialized
+instance variable.
+
+The +value+ method has access to the value set by the +initialize+ 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 <code>@@</code> (two "at" signs). The rest
+of the name follows the same rules as instance variables.
+
+Here is an example:
+
+ class A
+ @@class_variable = 0
+
+ def value
+ @@class_variable
+ end
+
+ def update
+ @@class_variable = @@class_variable + 1
+ end
+ end
+
+ class B < A
+ def update
+ @@class_variable = @@class_variable + 2
+ end
+ end
+
+ a = A.new
+ b = B.new
+
+ puts "A value: #{a.value}"
+ puts "B value: #{b.value}"
+
+This prints:
+
+ A value: 0
+ B value: 0
+
+Continuing with the same example, we can update using objects from either
+class and the value is shared:
+
+ puts "update A"
+ a.update
+
+ puts "A value: #{a.value}"
+ puts "B value: #{b.value}"
+
+ puts "update B"
+ b.update
+
+ puts "A value: #{a.value}"
+ puts "B value: #{b.value}"
+
+ puts "update A"
+ a.update
+
+ puts "A value: #{a.value}"
+ puts "B value: #{b.value}"
+
+This prints:
+
+ update A
+ A value: 1
+ B value: 1
+ update B
+ A value: 3
+ B value: 3
+ update A
+ A value: 4
+ B value: 4
+
+Accessing an uninitialized class variable will raise a NameError 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 <code>$</code> (dollar sign). The rest of the
+name follows the same rules as instance variables.
+
+Here is an example:
+
+ $global = 0
+
+ class C
+ puts "in a class: #{$global}"
+
+ def my_method
+ puts "in a method: #{$global}"
+
+ $global = $global + 1
+ $other_global = 3
+ end
+ end
+
+ C.new.my_method
+
+ puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"
+
+This prints:
+
+ in a class: 0
+ in a method: 0
+ at top-level, $global: 1, $other_global: 3
+
+An uninitialized global variable has a value of +nil+.
+
+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 the {global variables documentation}[rdoc-ref:globals.rdoc]
+for details.
+
+== Assignment Methods
+
+You can define methods that will behave like assignment, for example:
+
+ class C
+ def value=(value)
+ @value = value
+ end
+ end
+
+ c = C.new
+ c.value = 42
+
+Using assignment methods allows your programs to look nicer. When assigning
+to an instance variable most people use Module#attr_accessor:
+
+ class C
+ attr_accessor :value
+ end
+
+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:
+
+ class C
+ attr_accessor :value
+
+ def my_method
+ value = 42
+
+ puts "local_variables: #{local_variables.join ", "}"
+ puts "@value: #{@value.inspect}"
+ end
+ end
+
+ C.new.my_method
+
+This prints:
+
+ local_variables: value
+ @value: nil
+
+To use the assignment method you must set the receiver:
+
+ class C
+ attr_accessor :value
+
+ def my_method
+ self.value = 42
+
+ puts "local_variables: #{local_variables.join ", "}"
+ puts "@value: #{@value.inspect}"
+ end
+ end
+
+ C.new.my_method
+
+This prints:
+
+ local_variables:
+ @value: 42
+
+== Abbreviated Assignment
+
+You can mix several of the operators and assignment. To add 1 to an object
+you can write:
+
+ a = 1
+
+ a += 2
+
+ p a # prints 3
+
+This is equivalent to:
+
+ a = 1
+
+ a = a + 2
+
+ p a # prints 3
+
+You can use the following operators this way: <code>+</code>, <code>-</code>,
+<code>*</code>, <code>/</code>, <code>%</code>, <code>**</code>,
+<code>&</code>, <code>|</code>, <code>^</code>, <code><<</code>,
+<code>>></code>
+
+There are also <code>||=</code> and <code>&&=</code>. The former makes an
+assignment if the value was +nil+ or +false+ while the latter makes an
+assignment if the value was not +nil+ or +false+.
+
+Here is an example:
+
+ a ||= 0
+ a &&= 1
+
+ p a # prints 1
+
+Note that these two operators behave more like <code>a || a = 0<code> than
+<code>a = a || 0</code>.
+
+== Implicit Array Assignment
+
+You can implicitly create an array by listing multiple values when assigning:
+
+ a = 1, 2, 3
+
+ p a # prints [1, 2, 3]
+
+This implicitly creates an Array.
+
+You can use <code>*</code> or the "splat" operator or unpack an Array when
+assigning. This is similar to multiple assignment:
+
+ a = *[1, 2, 3]
+
+ p a # prints [1, 2, 3]
+
+You can splat anywhere in the left-hand side:
+
+ a = 1, *[2, 3]
+
+ p a # prints [1, 2, 3]
+
+== Multiple Assignment
+
+You can assign multiple values on the left-hand side to multiple variables:
+
+ a, b = 1, 2
+
+ p a: 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:
+
+ def value=(value)
+ p assigned: value
+ end
+
+ self.value, $global = 1, 2 # prints {:assigned=>1}
+
+ p $global # prints 2
+
+You can use multiple assignment to swap two values in-place:
+
+ old_value = 1
+
+ new_value, old_value = old_value, 2
+
+ p new_value: new_value, old_value: old_value
+ # prints {:new_value=>1, :old_value=>2}
+
+If you have more values on the left hand side than variables on the right hand
+side the extra values are ignored:
+
+ a, b = 1, 2, 3
+
+ p a: a, b: b # prints {:a=>1, :b=>2}
+
+You can use <code>*</code> to gather extra values on the right-hand side.
+
+ a, *b = 1, 2, 3
+
+ p a: a, b: b # prints {:a=>1, :b=>[2, 3]}
+
+The <code>*</code> can appear anywhere on the right-hand side:
+
+ *a, b = 1, 2, 3
+
+ p a: a, b: b # prints {:a=>[1, 2], :b=>3}
+
+But you may only use one <code>*</code> in an assignment.
+
+== Array Decomposition
+
+As with {method arguments}[rdoc-ref:syntax/methods.rdoc] you can decompose an
+Array using parenthesis:
+
+ (a, b) = [1, 2]
+
+ p a: a, b: b # prints {:a=>1, :b=>2}
+
+You can decompose an Array as part of a larger multiple assignment:
+
+ a, (b, c) = 1, [2, 3]
+
+ p a: a, b: b, c: c # prints {:a=>1, :b=>2, :c=>3}
+
+Since each decomposition is considered its own multiple assignment you can use
+<code>*</code> to gather arguments in the decomposition:
+
+ a, (b, *c), *d = 1, [2, 3, 4], 5, 6
+
+ p a: a, b: b, c: c, d: d
+ # prints {:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]}
+