Below are a variety of random notes scribbled down while learning Ruby. Most of this is done from the point of view of someone coming from a background in Python, which is fairly similar.
- Everything is done through methods (technically these aren't methods, but rather Smalltalk style messages); there is no direct access to properties from outwith the class (or an instance thereof).
- The
printandputsbehave similarly: the only difference is thatputsoutputs a newline after the expression. - All objects are created by calling the
newmethod on a class (with the exception of a few primitive types like String, Integer, Array, Hash, Float which have special syntax). - All of those primitive types are just objects, and hence are like everything else mutable.
- Everything is an expression; there are no statements.
- Unlike Python, there is nothing at the end of the line of an
iforwhileexpression. The only syntax whatsoever is the new line. - Blocks, such as
ifandwhile, when split over more than one line, are ended by anendexpression with the same indentation as the line that started the block (i.e., the line on whichif,while, etc. occurred on). - Methods return the last expression evaluated (ordered by when evaluation began).
- Constants (including classes) start with an uppercase (ASCII?) letter, variables with lowercase.
- Strings are bytes in Ruby < 1.9, and characters in Ruby >= 1.9 (use String#bytes to get byte strings then).
Single quoted and double quotes string have different meanings, like PHP and unlike Python. Their behaviour is similar to that of PHP: single quoted strings do not evaluate escapes (with the exception of
\'and\\, though the latter is only needed if the\is followed by') and cannot contain variables; double quoted strings evaluate escapes (a superset of those allowed in C; see below), interpolated code (within#{…}where … is an expression), and really whacky %-notation (this seems really fucked up as far as I can see — can anyone explain this to me?).Escape Sequence Meaning \n Line feed (0x0A) \s Space (0x20) \r Carriage return (0x0D) \t Horizontal tab (0x09) \v Vertical tab (0x0B) \f Form feed (0x0C) \b Backspace (0x08) \a Bell/alert (0x07) \e Escape (0x1B) \nnn Byte (Ruby < 1.9) or character (Ruby >= 1.9) with octal value nnn \xnn Byte (Ruby < 1.9) or character (Ruby >= 1.9) with hexadecimal value nn \unnnn Unicode code point U+nnnn (Ruby 1.9 and later) \cx Control-x \C-x Control-x \M-x Meta-x \M-\C-x Meta-control-x \x Character x (e.g., \")- Strings can be used as arrays of ordinal values (e.g.,
"a"[0] == 0x61evaluates to true). - The
trueandfalsekeywords are both all lowercase. a..brepresents a range between two Integers a and b.- A slice of an Array or String can be got by either
foo[1,3](comma as delimiter between start index and length) orfoo[1..3](a range), for String foo. Note with the former syntax both must be present, and both most be positive (negative indices do not work); with the latter syntax negative indices do work as the end of the range, but are slightly weird. (-1is the end-of-string, so-2must be used to not get the final character. This makesfoo[x..y]identical tofoo[x..(foo.length + y)]when y is negative.) nilis the null keyword.- Only
falseandnilevaluate to false, everything else (including0) evaluates to true. =~is a matching operator for Strings to evaluate regular expressions (which are, like in Perl, delimited by/). It evaluates to the first position where a match was found ornil.- Hashes are identical to dicts in Python, but use
=>for assignment instead of:. ARGV(note uppercase) contains command line arguments (as an Array).- The methods
to_i(to Integer),to_s(to String),to_f(to Float) are used to convert to primitive types. - Method names often end in
!if they mutate the variable value (this leads to String having methods likechop!andchop: the former mutates the variable, the latter returns a mutated copy). - Parenthesis are optional for method calls, provided their non-occurrence does not make it ambiguous.
unlessis a negativeifexpression- A
caseblock goes through allwhensub-blocks (which have equal indenting to the case block), checking them to see if, when compared with===(which in general is identical to==), thecasematches thewhen. Execution stops after the first matchingwhen. The===means you can do cool stuff like having a range for awhen. - Global variables are prefixed with
$, instance variables@, and class variables@@. whileblocks are like those of any other language, anduntilblocks are their negated equivalents, likeunlessare those ofif.breakdoes what would be expected,nextis equivalent tocontinuein most languages, andredorestarts the current iteration.for x in yworks like in Python.- Iterators have an interesting syntax:
[1,2,3,4].each {|e| puts e.to_s }. - Iterators are defined like generators are in Python, using
yield. Execution of them terminates upon reachingreturn.retryreturns to the start of the function block of the iterator. selfcan be omitted when working within a class/object.<is used for inheritance (e.g.,class Foo < Bar).super, when called from a method of a subclass, calls the same method on the superclass (optionally with arguments).public,protected,privatecan be put on the line before the first method within a class of each type (the keywords apply untilend).- Namespaces are defined by
module Foo … end. A module can be imported into the current scope byinclude(e.g.,Math::PI; include Math; PI). ::is used to access constants in another module.begin … rescue … endis the same as Python'stry … except.- Classes can be added to just by having another
classblock with the same name. - Accessors for instance variables can easily be added with
attr_reader :foo,attr_writer :foo, andattr_accessor :foo, the last of which is equal to specifying both of the former. - The
initializemethod is called on object initialization. - Comments until end of line begin with
#, longer comments can be added by=beginand=enddelimiting them. elsif, notelse if,, elifor anything else. Justelsif.