by Dave Thomas, with Chad Fowler and Andy Hunt
-
-
Save dekom/2143259 to your computer and use it in GitHub Desktop.
The first characters of a name indicate how the name is used.
- Begin with lowercase or underscore: local variables, method parameters, and method names
- Begin with uppercase: class names, module names, and constants
- Append with dollar sign ($): global variables
- Append with at sign (@): instance variables
- Append with double at sign (@@): class variables
Allowed characters:
- All:
- letters (exception @)
- digits
- underscores
- Instance variables: underscores_between_words
- Class names: CamelCase
- Method names: may end with ?, !, =
Ruby is entirely object-oriented. Objects instances are created using the constructor <Object>.new
.
- object identifier (object ID)
- instance variables
- instance methods
String literals are created either from single-quote '
or double-quotes "
.
In the single-quote construction, Ruby processes very little of the content, creating a true literal string. While the double-quote construction involves more Ruby processing.
For double-quote strings, Ruby will:
- Look for substitutions
\n, \t
and replace with binary value - Look for expression interpolation.
#{expression}
Both are indexed, non-homogeneous collections, using key to store value.
Arrays are more efficient.
- Constructor:
a[0] = "an"
- Keys are integers
- Referenced using
array[0]
%w{ an array of words } => ["an", "array", "of", "words"]
Hashes are more flexible
- Constructor:
{ key => value }
Hash.new(0)
=> sets the return value of a non-existent key to 0
- Keys are any object
- Keys must be unique
- Referenced using
hash[key]
They are constant names that do not need to be predeclared and that are guaranteed to be unique, regardless of location of appearance.
A symbol begins with a colon :
and followed by a name. :north
Most notably used as keys in hashes
Special syntax for creating a hash with symbols as keys
inst_section = {
cello: 'string',
clarinet: 'woodwind',
drum: 'percussion',
}
inst_section[:cello] #=> string
Ruby has all the standard control flow structures.
if () ...
elsif () ...
else ...
end
while () ...
end
statement modifiers: useful shortcut for a single expression flow structure.
puts 'Hello, world!' if noob.level < 1
Pattern matching in strings. Remember, regular expressions are objects as well.
- Creating a pattern:
/pattern/
- Matching a pattern:
=~
, which returns the patten's starting position if found, nil otherwise.
Visit Rubular for awesome regex practices.
Code blocks: chunks of code you can associate with method invocations, almost as if they were parameters.
Though powerful, they're simply chunks of code between
{ ... code.to_do ... }`
or `do ... code.to_do ... end
{}
(brace) syntax has higher precedence than do ... end
blocks.
Regardless, the emerging convention has brace syntax for single-line blocks
and do/end for multiline blocks.
method(parameters[]) { code.to_do }
Once such block has been passed to the method, it is called within the
method using yield
:
def call_block
puts "Start of method"
yield
yield
puts "End of method"
end
call_block { puts "In the block" }
produces:
Start of method
In the block
In the block
End of method
Parameters can be passed to the block between the vertical bars
| params ... |
def call_block
puts "Start of method"
yield("In the block)
puts "End of method"
end
call_block { |s| puts s }
Inputs: get
Outputs: puts, printf, print
Either ARGV
or ARGF
.
Objects are created from classes to be program representation of real-life items to be manipulated.
Classes are defined:
class ClassName
end
Objects of each class are created:
a_class = ClassName.new
another_class = ClassName.new
Each time that an instance of an object is created, the class's initialize method is called.
class ClassName
def initialize(parm0, parm1)
@parm0 = parm0
@parm1 = parm1
end
end
This method is called mostly to setup default values of each object instance.
Likewise, every object in Ruby has a standard message method, to_s
,
that can be overwritten to output human-readable string representation
of the object.
Attributes are the externally visible facets of an object. These are usually manipulated by 'getter' (or accessor) methods and 'setter' methods.
Accessor methods can be created with attr_reader :accessor0, :accessor1
,
which functions the same as:
def accessor0
...
end
def accessor1
...
end
Setter methods can be created with attr_writer :setter0
, which
functions the same as:
def setter0=(value)
...
end
Partial to Ruby, any method names that ends in =
can be accessed as
className.setter0 = value
. This abstracts out the difference between
accessing variables and accessing methods.
However, since one would want to have both read and write access for a
given attribute, Ruby also offers this method creation: attr_accessor :name
, which creates both getter and setter methods.
To import additional classes, call (for example)
require 'csv'
require_relative 'className'
class CurrentClass
...
end
require_relative
uses the current class's directory as file path to
look for the class name.
Controls for accessing your classes are done (primarily) through setting
the accessibility of your methods. Methods can be either public
-
callable by everyone and default for all methods except initialize
,
protected
- callable by the class itself and sub-classes (not class instances!),
private
- callable only by class instance self
.
Methods can be defined as private
(for example) by one of two ways:
private
def method0
...
end
def method1
...
end
or
def method0
...
end
def method1
...
end
...
private :method0, :method1
Either declaration makes method0
and method1
private methods.
The two main container classes in Ruby are Arrays and Hashes. Combine them with blocks, which are chunk of codes that can be passed around, they can easily and quickly create iterators.
Arrays are created as literal arrays - ["a", "b", "c" ...]
or using
standard Array.new
constructor.
Array elements are referenced using indices within []
.
List of array access attributes:
- Negative indices counts backwards.
- Pair of numbers
[start, count]
returns an array starting at indexstart
and contains up tocount
number of elements. - Ranges
[start...end]
returns an array starting from indexstart
and ends at indexend
. Ranges can be negative.
Array element assignment is a[1] = value
as well as working with pairs
and ranges selections.
Hashes are similar to arrays except that the keys can be any object, as opposed to strictly Integers in Arrays.
Hashes are created using the standard constructor or hash literal -
{'a' => 'z', 'b' => 'y' , ...}
.
Ruby 1.9 introduced new syntax for defining a key => value
association with symbols as key: key: value
.
Likewise, Hash in ruby 1.9 remembers the insert order, which isn't a guarantee in other language libraries.
When passing a parameter into Hash.new(0)
, the parameter becomes the
object's default value for unavailable keys. For example:
hash = Hash.new(0)
puts hash['word'] #=> 0
hash['word'] += 1
puts has['word'] #=> 1
Since hash remembers the order of insertion, in order to sort element by
another parameter, we must call the Hash instance's sort_by
element.
Blocks are chunks of code that can be passed around, while iterators invoke block of code.
A block is simply a chunk of code enclosed between either braces or
the keywords do
and end
.
Like a method, blocks can take parameters by having |varaible0, variable1|
in the beginning of the block (I call them pipes).
Key notes on blocks is variable scoping. As long as variable within the
block shares the same name as a variable outside of it, it will change
the said variable. In ruby 1.9, however, all block parameters are
local, and by adding a semicolon prior to a local variable within the
'pipes', e.g. [1, 2, 3, 4].each do |value; square|
, then the variable
becomes local to the block, in this case square
is block local.
Blocks can be converted to the class Proc
by placing a
&variable_name
as one of the parameters. This is the implementation
behind the lambda
(which takes in a block) and ->
(ruby 1.9
synonymous operator for lambda
).
Blocks can also be used for closures, which is when 'variables in the surrounding scope that are referenced in a block remain accessible for the life of that block and the life of any Proc object created from that block'.
This is best explained in an example
def n_times(thing)
lambda {|n| thing * n}
end
p1 = n_times(23)
p1.call(3) #=> 69
p1.call(4) #=> 92
p2 = n_times("Hello")
p2.call(3) #=> "Hello Hello Hello "
In the previous examples, 23 and "Hello" are in the closure and
were able to be referenced even outside of the method definition for
n_times
.
For all intents and purposes, blocks are as flexible as methods regarding how and what can be taken into.
'A Ruby iterator is simply a method that can invoke a block of code.'
Block codes in iterators are called using the yield
statement.
One can imagine yield
as an interrupt in the control flow of the code,
where the control is passed to the block of code and then back.
Useful, default iterators (look into Ruby API for details):
.each
, .each_with_index
, .collect
, and the mind-numbing .inject
,
which is (apparently) similar to the foldl function of SMLNJ.
Ruby 1.9 has an Enumerator object that can be crated by calling
to_enum
or enum_for
on a collection.
Most of the internal iterator methods will also return an Enumerator object if called without a block.
Look through the Ruby API on the Enumerator class. Especially checkout
.enum_for(:method_name)
.
.enum_for
is used to create a custom Enumerator, where a particular
method is called from within.
(Advanced material)
Going to read this at a later time
Blocks can be used to section the logical work, and transfer control from one state to the next.
If the last parameter of a method begins with an ampersand (&), that
parameters will store the Proc
object, which is the object class for
blocks.
Ruby provides two built-in methods that convert blocks into Proc objects:
lambda {block}
Proc.new {block}
Additionally, in Ruby 1.9, you can create Proc objects by:
proc = -> arg { puts "Proc with arg #{arg} }
The interesting chapter!
Inheritance allows you to create a class that is a refinement or specialization of another class. The original is the superclass of the created class, and the created class is the subclass of the original. (Or commonly referred as parent and child classes).
The child class inherits all of the parent's public and protected instances methods.
Syntax
class Child < Parent
...
end
Every object in Ruby is the child (multiplied by many generations) of
the BasicObject
, which is a "blank canvas" object created in ruby 1.9.
For most functional cases, the root of the 'family tree' is Object
.
To call superclass methods
class Class < Parent
def method_name()
super()
end
...
end
super()
calls the parent class's method that matches the name of the
child's method.
Modules are a way of grouping together methods, classes, and constants.
Modules:
- provide a namespace and prevent name clashes.
- support he mixin facility
A mixin is 'like a partial class definition' and a combination of flexibility of multi-inheritance and simplicity of single-inheritance.
Modules are used to handle method name conflicts.
A module is defined by
module AModule
...
end
Then conflicting methods are called with AModule.method_name
.
Note: Modules are not classes. Therefore, they cannot have
instance methods (methods that are defined by def self.method_name
.
"At a stroke, they (modules) pretty much eliminate the need for inheritance."
Mixins are created when modules are included in classes.
module ModuleName
def module_method
...
end
end
class ClassName
include ModuleName
def class_method
...
end
end
an_class_instance = ClassName.new
an_class_instance.module_method
By including a module in a class, that class has access to all of the module's instance methods (even though modules cannot have instances because they're not classes).
Note: in order to use include ModuleName
, one may need to first
load
or require
the file that contains the module.
When to use what?
- Inheritance: when it is a is-a relationship.
- Mixins: when it is a has a or use a relationship.
Fixnum
, Bignum
, Float
, Rational
, Complex
prefix the following to a number for the specific formats:
octal:
0
decimal:0d
hex:0x
binary:0b
Rational numbers: Rational(numerator, denominator)
Complex numbers: Complex(real, imaginary)
use require 'mathn'
package to get most natural result of a mathematical operation.
sequence of characters, usually created with string literal
string literal or
%q, %Q or just %
and here documents.
%q(arg) => 'arg', %Q(arg) = %(arg) => "arg"
Note that the character following %Q
is just the delimiter, which can be any non-alphanumeric or non-multibyte character.
here documents:
string = <<END_OF_STRING
The body of the string is the input lines
up to one starting with the same test that
followed the '<<'
END_OF_STRING`
Here, terminating delimiter can be indented if <<
is changed to <<-
default encoding is the encoding of the source file or US-ASCII
Chracters (string length 1) can be created with the ?
operator: ?\C-a # => (control a
. Not important, easier to use hex or string.
used in ruby to implement sequences, conditions, and intervals
constructors: ..
and ...
Any class can use these constructors as long as <=>
(comparison method), succ
(how to generate the next element) methods are defined within the class.
can be used to turn a condition to true on the first successive match and then turn it to false on the second success match:
while line = ets
puts line if line =~ /start/ .. line =~ /end/
end
This prints a sequence of lines where the first line has the word start and the last line has the word end.
Intervals can be tested for contained elements with the ===
operator:
(1..10) === 5 # => true
. Note that (1...10) === 9.9
is true while (1..9) is false.
can be used in case statement for conditional test
case test
when 0...1
...
else
...
end
A regular expression is a pattern that can be matched against a string.
- You can test a string to see whether it matches a pattern.
- You can extract from a string the sections that match all or part of a pattern.
- You can change the string, replacing parts that match a pattern.
Create using forward slashes, e.g. /cat/
.
Match a string against a pattern using =~
. It returns the character offset into the string at which the match occurred:
/cat/ =~ "dog and cat" #=> 8
/cat/ =~ "catch" #=> 0
/cat/ =~ "Cat" #=> nil
To test whether a pattern does not match a string, using !~
.
The sub
method takes a pattern and some replacement text. If a match if sound, it replaces the matched substring with the replacement text.
str = "Dog and Cat"
new_str = str.sub(/Cat/, "Gerbil")
puts new_str #=> Dog and Gerbil
Use gsub
to replace all the patterns, versus the first pattern for sub
.
Regular expressions are just instances of the class Regexp
.
Other ways to create Regexp instances: Regex.new(str)
or %r{...}
.
Options that modify the way the pattern matches strings are placed at the end of literal terminators or as second parameters of .new
.
i
: Case Insensitiveo
: Substitute Once. Any#{...}
substitutions in a particular regular expression literal will be performed just once, the first time it is evaluated. Otherwise, the substitutions will be performed every time the literal generates aRegexp
object.m
: Multiline Mode. Normally,.
matches any character except a newline. With this option,.
matches any character.x
: Extended Mode. Complex regular expressions can be difficult to read. This option allows you to insert spaces and newlines in the pattern to make it more readable. You can also use#
to introduce comments.
Once a Regexp
instance is created, match against strings using =~
, !~
, or Regexp#match(str)
.
Time to study the special characters: ., |, (, ), [, ], {, }, +, \, ^, $, *, and ?
.
^
matches the beginning of the line and $
matches the end of a line.
\A
matches the beginning of a string and \z
and \Z # matches pre \n
matches the end of a string.
\b
matches word boundaries (word characters surrounded by non-word characters) and \B
matches non-word boundaries (word characters surrounded by other word characters).
A character class is a set of characters between brackets []
that's to be matched in the string.