0) Resources:
1) Use "ruby -w" instead of simply "ruby" to get helpful warnings. If not invoking "ruby" directly, we can use instead:
win32:
C:\> set RUBYOPT=wor pressing F5 (to execute script) in the Scite editor will give you warnings (and F4 will position at problematic line).
unix:
sh# export RUBYOPT="w"or
csh# setenv RUBYOPT "w"
2) The String#[Fixnum] method does not return the "character" (which is a string of length one) at the Fixnum position, but instead the character code at the position (however, this may change in the future). Currently, to get the character, use String#[Fixnum,1] instead.
3) Be aware of the lexical scoping interaction between local variables and block local variables. If a local variable is already defined before the block, then the block will use (and quite possibly modify) the local variable; in this case the block does not introduce a new scope.
4) In Ruby, there are two sets of logical operators: [!, &&, ||] and [not, and, or]. [!, &&, ||]'s precedence is higher than the assignments (=, %=, ~=, /=, etc.) while [not, and, or]'s precedence is lower. Also note that while &&'s precedence is higher than ||'s, the and's precedence is the same as the or's.
5) In the case statement
case obj
when obj1
....
it is the "===" method which is invoked, not the "==" method. Also,
the order is "obj1 === obj" and not "obj === obj1".
6) Array.new(2, Hash.new) returns an array with two elements referencing the same, indentical hash, and not two independent hashes.
7) After reading data from a file and putting them into variables, the data type is really String. To convert them into numbers, use the "to_i" or "to_f" methods. If you use the "+" operator to add the "numbers" without calling the conversion methods, for example, you will simply concatenate the strings.
An alternative is to use ["scanf"].
8) It is advisable not to write some white space before the opening '(' in a method call; else, Ruby with $VERBOSE set to true may give you a warning.
9) The "dot" for method call is the strongest operator. So for example, while in some other languages the number after the dot in a floating point number is optional, it is not in Ruby. For example, 1.e6 will try to call the method "e6" of the object 1 (which is a Fixnum). You have to write 1.0e6.
However, notice that although the dot is the strongest operator, its precedence with respect to method name may be different with different Ruby versions. At least in Ruby 1.6.7, "puts (1..3).length" will give you a syntax error; you should write "puts((1..3).length)" instead.
10) The notation "Class#method" in a documentation is used only to represent an instance method of an object of class Class. It is not a Ruby syntax at all. A class method in a documentation, on the other hand, is usually represented as "Class.method" (which is a valid Ruby syntax).
11) Be careful when using "mutable" objects as hash keys. To get the expected result, call Hash#rehash before accessing the hash elements. Example:
s = "mutable"
arr = [s]
hash = { arr => "object" }
s.upcase!
p hash[arr] # >> nil (maybe not what was expected)
hash.rehash
p hash[arr] # >> "object"
12) In Ruby, only false and nil are considered as false in a Boolean expression. In particular,
0 (zero),
"" or '' (empty string),
[] (empty array),
{} (empty hash)
are all considered as true.
13) ruby variables holds references to objects and '=' operator copies these references:
a='x' b=a a.upcase! # now both a and b points to string containing 'X'
parameters to methods and closures also passed as references to actual objects. in order to get new, unbounded copy of variable value, you can use "dup" method:
a='x' b=a.dup
it may be advisable to know whether you modify existing object or create new one. The convention (though not language-enforced) is:
a = [] a[1] = s = 'word' s.upcase! puts a[1] #=> 'WORD'
One notable exception is what KEY (but not value) of hash is copied from original value (using #clone ?).
An interesting (and maybe undesirable) effect is parameters to some methods which will be BOTH used several times and each copy may be modified: Array.new(Fixnum,Object), Array#fill, Hash.new(Object). These methods will assign the same pointer to several cells in hash/array and then changing value through one pointer will be seen in all these cells:
a = []
a.fill('x',0,2)
a[0].upcase!
p a
kgergely: For the dup history:
s='tell' # => "tell" a=[s,s] # => ["tell", "tell"] b=a.dup # => ["tell", "tell"] c=Marshal.load(Marshal.dump(a)) # => ["tell", "tell"] s[0]=?h # => 104 a # => ["hell", "hell"] b # => ["hell", "hell"] c # => ["tell", "tell"]
14) "0..k" represents a Range object, while "[0..k]" represents an array with a single element of type Range. For example, if
[0..2].each do |i|
puts "i = #{i}"
end
does not give what you expect, probably you should have written
(0..2).each do |i|
puts "i = #{i}"
end
or
0.upto(2) do |i|
puts "i = #{i}"
end
instead. Note also that Ruby does not have objects of type "Tuple" (which are immutable arrays) and parentheses are usually put around a Range object for the purpose of precedence grouping (as the "dot" is stronger than the "dot dot" in the above example).