- The basics
- Conditionals and Control Structures
- Looping mechanisms
- Collections
- Strings
- Exception handling
- Classes, Objects and Modules
- Scripting
- Caveats
- Clever idioms
- Other Keywords
The basics
Variables
Variables are named in snake_case
. Variables are not typed.
puts
is your goto method to print to the console.
1
2
3
my_first_variable = "Hello world!"
puts my_first_variable
Note that there is a print
as well, it is similar to puts
except that it doesn’t add a new line to the output.
Comments
Single line comments starts with #
. Multi-line comments are surrounded by =begin ... =end
1
2
3
4
5
6
# single line comment
=begin
Line 1
Line 2
=end
Naming Convention
- Variable names snake_case
- Class names PascalCase
- Constants UPPER_SNAKE_CASE or PascalCase (be consistent and check your team conventions)
- Global variables starts with
$
- Instance variables start with
@
- Class variables start with
@@
- Mutating method names ends with
!
. It is common to have two methodmethod
andmethod!
the first returns a changed copy and the latter mutates its receiver. - Methods that return boolean ends with
?
Parentheses
Optional, generally if you have a method with multiple arguments it is a good idea to keep them for readability purposes. Omit them for Control statements conditions. For commonly used methods are left by convention. puts
is a good example, but you’ll need to pick that up from the community. In general, leave them out except for method arguments.
Multi-Statement Lines
You can have multiple statements in one line separated by ;
. Use that only in simple cases where a class definition is three lines or for an abstract method.
Code Blocks
You can use either {}
, begin ... end
or do ... end
to surround code blocks. The convention is to use {}
if the block consists of a single statement (one liner), and begin ... end
or do ... end
otherwise.
begin ... end
vs. do ... end
begin
“starts an exception handling block” according to the language documentation. You can also use it to group multiple expressions and use it with guard clauses, but in that case it might be better to extract that into a method.
Another difference is that you can not pass begin ... end
block to a method. In most cases, you will be using do ... end
, you can check more details on begin ... end
in the exception handling section Note that a method body, is in effect, a begin ... end
block with begin
being omitted.
Readability… Use Your Judgement
The purpose of the coding convention is readability, so if following one of the above breaks readability, use your judgement… sparingly! Remember consistency is important.
Expressions not statements
Almost everything in Ruby is an expression. For example an if statement is an expression that has the value returned by the last expression in that if
1
2
some_value = if true then 4 else 6 end
puts some_value # This puts `4`
Conditionals and Control Structures
- Only
false
andnil
are treated asfalse
if, else, elseif and unless
There is the if
statement similar to any other language you came from
1
2
3
4
5
something_evil_lurking_in_the_dark = false
if something_evil_lurking_in_the_dark
puts "Run away!"
end
Now, let’s negate that
1
2
3
if not something_evil_lurking_in_the_dark
puts "We are safe!"
end
Ruby has an alternative to if not
which is unless
1
2
3
unless something_evil_lurking_in_the_dark
puts "We are safe!"
end
We can also use the good old else
and elseif
. While we can use those with unless
, it doesn’t make much sense because you can simply reverse your if statement
1
2
3
4
5
if something_evil_lurking_in_the_dark
puts "Run away..."
else
puts "We are safe!"
end
This last example can be written as a one liner, but we will need a new keyword then
1
if something_evil_lurking_in_the_dark then puts "Run away..." else puts "We are safe!" end
Ternary operator
THe last example above can be turned to one liner
1
something_evil_lurking_in_the_dark ? (puts "Run away..." ): (puts "We are safe!")
Modifier form
Ruby has a modifier form of its conditionals. What that does is reversing the order of the statement to make it more “readable” or rather look like the common English language
1
puts "We are safe!" unless something_evil_lurking_in_the_dark
Even further, we can use the same form with assignment
1
2
message = "We are safe"
message = "Run away!!" if something_evil_lurking_in_the_dark
The value of message
will change only if the value of something_evil_lurking_in_the_dark
is true
.
Case
1
2
3
4
5
6
7
case the_thing_lurking_in_the_dark
when 'monster'
puts 'Run away'
when 'cat'
puts 'sigh of relief'
else # default case
puts 'Do not know what that is'
this is the same as
1
2
3
4
5
6
7
8
response = case the_thing_lurking_in_the_dark
when 'monster'
'Run away'
when 'cat'
'sigh of relief'
else
'Do not know what that is?'
puts response
Which is also the same as
1
2
3
4
5
response = case title
when 'monster' then 'Run away'
when 'cat' then 'sigh of relief'
else 'Do not know what that is?'
puts response
We can use case
to match on types
1
2
3
4
5
6
7
case some_data
when Monster
puts "this is a string"
when Cat
puts "this is a cat"
else
puts "I don't know what is this!"
This will result in a nil
if no when
clause is matched and there is no else
Looping mechanisms
while and until
- We should iterate with
each
instead ofwhile
anduntil
. until
acts likewhile not
. Both, similarly, can be used in the modifier form.1 2 3
begin # something to be done end while some_condition
- There is also
loop
construct that doesn’t take a condition, we canbreak
out of it though1 2 3 4
loop do # something to be done break if some_condition end
break
, redo
and next
break
break out of the loop entirelyredo
jump to the beginning of the current iterationnext
jump to the end of the current iteration
Iterating with each
When iterating over loops we can use each
instead of for loop to go through the elements of a collection. Actually, Ruby under the hood would turn for statement into an each statement.
1
2
3
array.each do |element|
puts element
end
If we want to look at the index as well, we can use each_with_index
. each_index
is another method that would let us iterate over indices.
1
2
3
4
5
6
array.each_with_index do |element, i|
puts "#{i}: #{element}"
end
array.each_index do |i|
puts i
end
Collections
Range of numbers
0..n
includes n, this is of typeRange
0.upto(n)
includes n, this is of typeEnumerator
Strings
- String interpolation
"Variable: #{variable}
Useful methods
split(delimiter)
splits a string ondelimiter
chomp
removes trailing characters
Exception handling
raise
is used to throw an exception
1
raise SomeError.new(), "some message"
begin
…end
block is used to wrap the exception handling boundaries.rescue
is used to catch exceptions within the block.- Method body is treated as a
begin
…end
block withbegin
being omitted. rescue
will catch anything that inheritsStandardError
.- We can also use
rescue
without specifying the error as a catch all - IF we want to something to run only if no exceptions occurred, we use
else
clause - If we want something to run at the end of the block every time, we use the keyword
ensure
- Note that
rescue
could be used without=> err
if we don’t care about the exception
1
2
3
4
5
6
7
8
9
10
11
12
13
begin
# our code is here
rescue ArgumentError
# Exception handling Code
rescue ZeroDivisionError
# Exception handling here
rescue => err
# Handling whatever other error here
else
# This will be executed if no exceptions were raised
ensure
# This code will run at the end of the `begin` - `end` block everytime
end
- We can rerun the
begin
…end
block using the keywordretry
1 2 3 4 5 6
begin # our code is here rescue # Do some recovery retry # Re-execute the begin-end block end
- There is a modifier form for catching exceptions
exception_raising_method() rescue puts("An error has occurred")
Classes, Objects and Modules
Objects
- Everything in Ruby is an object
- We can create a new object by calling
new
method on its class.ClassName.new()
- objects can be made immutable by calling
freeze
methond on that object
Classes
Constructor
- The class constructor is a method named
initialize
1
2
3
4
5
class ClassName
def initialize(arg1, arg2) # Constructor
# Do your initialization stuff here
end
end
Class (static) Methods
There are two ways to define class methods inside a class
Prefixing one method with self
1
2
3
def self.class_method
# Do some class stuff
end
Wrapping multiple methods in self
1
2
3
4
5
class << self
def class_method
# Do some class stuff
end
end
Class Variables
- Class variables and in other languages called static variables, are variables associated with the class itself
- Class variables start with
@@
- Class variables are private
- You can only interact with class variables via class or instance methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ClassName
@@class_variable = "class variable"
def self.class_variable
@@class_variable
end
def class_variable
@@class_variable
end
def class_variable=(value)
@@class_variable = value
end
end
puts ClassName.class_variable # class variable
instance = ClassName.new
puts instance.class_variable # class variable
instance.class_variable = "new class variable"
puts instance.class_variable # new class variable
Instance Variables
- We use instance as an object of a given class
- Instance variables start with
@
- Instance variables are private to the instance
- To interact with an instance variables from outside of an instance, you need to do that through a method. Ruby have some methods that creates accessors (getters) and writers (setters) for you. Namely
attr_reader
,attr_writer
andattr_accessor
. The latter creates both a getter and a setter. For a methodfoo
the getter will be namedfoo
and the setter will be namedfoo=
, yes the latter would be like putting an assignment=
after the variable name. - You do not need to initialize the instance variable in the constructor, it will be initialized anywhere in the class where it is first used
1
2
3
4
5
6
7
8
9
10
11
class ClassName
attr_reader :instance_variable_with_reader_only # Creates a reader (getter)
attr_writer :instance_variable_with_writer_only # Creates a writer (setter)
attr_accessor :instance_variable_with_both_reader_and_writer # creates both a reader and a writer
def initialize # Constructor
@instance_variable_with_reader_only = "instance variable with reader"
@instance_variable_with_writer_only = "instance variable with writer"
@instance_variable_with_both_reader_and_writer = "instance variable with reader and writer"
end
end
- You can also define (or override) variable accessors manually by defining a method that has the same name as the variable name for readers and a method that have same name postfixed by
=
for writers ```ruby def instance_variable @instance_variable end
def instance_variable=(value) @instance_variable = value end ```
Scripting
Executing commands with back-tick
When sending a string to stdout, if that string is surrounded with backticks or %x
the string will be run and the result will be printed in the output. For example puts
ls
Will result in print the list of files and directories in the current directory. This is equivelant to puts %x"ls"
.
exit
vs. abort
- exit(code) calls any registered
at_exit
handlers, exits and returns code to the OS - exit!(code) same as above, but doesn’t call
at_exit
handlers - abort(message) prints message to STDERR and exist with code
1
(error)
Caveats
defined?
never returnstrue
it either a string that describe the thing passed in ornil
Clever idioms
x ||= y
will only set x to y if x is not defined. This is equivalent tox = x || y
Other Keywords
BEGIN
: Takes a block that runs before any other code in the current file.END
: Takes a block that runs after any other code in the current file.and
: Short-circuit Boolean and with lower precedence than&&
or
: Boolean or with lower precedence than||
not
: Inverts the following boolean expression. Has a lower precedence than!
Comments powered by Disqus.