- 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 methodmethodandmethod!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
falseandnilare 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
eachinstead ofwhileanduntil. untilacts 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
loopconstruct that doesn’t take a condition, we canbreakout of it though1 2 3 4
loop do # something to be done break if some_condition end
break, redo and next
breakbreak out of the loop entirelyredojump to the beginning of the current iterationnextjump 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..nincludes n, this is of typeRange0.upto(n)includes n, this is of typeEnumerator
Strings
- String interpolation
"Variable: #{variable}
Useful methods
split(delimiter)splits a string ondelimiterchompremoves trailing characters
Exception handling
raise is used to throw an exception
1
raise SomeError.new(), "some message"
begin…endblock is used to wrap the exception handling boundaries.rescueis used to catch exceptions within the block.- Method body is treated as a
begin…endblock withbeginbeing omitted. rescuewill catch anything that inheritsStandardError.- We can also use
rescuewithout specifying the error as a catch all - IF we want to something to run only if no exceptions occurred, we use
elseclause - If we want something to run at the end of the block every time, we use the keyword
ensure - Note that
rescuecould be used without=> errif 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…endblock using the keywordretry1 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
newmethod on its class.ClassName.new() - objects can be made immutable by calling
freezemethond 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_writerandattr_accessor. The latter creates both a getter and a setter. For a methodfoothe getter will be namedfooand 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_exithandlers, exits and returns code to the OS - exit!(code) same as above, but doesn’t call
at_exithandlers - abort(message) prints message to STDERR and exist with code
1(error)
Caveats
defined?never returnstrueit either a string that describe the thing passed in ornil
Clever idioms
x ||= ywill 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.