Tip
|
Do not use prepackaged Ruby on Linux distributions. |
On Linux use rbenv
package manager with the
ruby-build
extension to install Ruby.
For windows there is an installer Ruby Installer simplifies the installation to the "windows standard approach".
The simplest way to install Ruby on macOS is to use homebrew
package manager
$ brew install ruby
in case there is a need to have multiple installations
rbenv
is a good tool to use. Another popular tool is called rvm
but nowadays they do too
much magic and we recommend using rbenv
instead.
Tip
|
Usually you put ruby and relates command on PATH so you do not need to always
specify the whole path to the executable. With tools like rbenv this is done for you.
|
$ ruby -v
runs Ruby and prints it’s version. Simplest way to verify that your instalation works as expected.
$ ruby script.rb
interprets the script.rb. However instead of running the script explicitly, you can add the shebang line to your script
#!/usr/bin/env ruby
and make it executable (chmox +x script.rb
) and run it simply as ./script.rb
.
Ruby a programming language with following aspects
Ruby can be used for writing scripts, one-liners, web applications and even for mobile and desktop applications.
MRI
is the Ruby reference implementation, with several other implementations like JRuby
, Rubinius
,
IronRuby
or MagLev
. As well, there is ISO standard implemented in mruby
.
There are some implicit conversions (e.g. every object has to_s
method to provide
string representation) but in most cases in case you try to operate on different types
Ruby will complain, unless such operation is explicitly provided.
5 + "a" # => TypeError: String can't be coerced into Fixnum
The type of a variable is defined by the value assigned to that variable. There is no explicit type information in the code.
a = "string"
-
programming languages: Ruby (Rubinius), compilers (LessJS)
-
web applications: Github, Gitlab, Redmine, BaseCamp
-
devops tools: Puppet/Chef/Vagrant
-
cloud platforms: OpenShift (v2)
-
cloud management: Foreman, ManageIQ
-
VIM/Emacs scripts
-
static pages generators - Jekyll
-
programming tools
-
class names are CamelCase
-
file names reflect class names in snake_case format
-
method names are snake_case
-
constants are UPPER_CASE
-
indent by 2 spaces
-
methods returning boolean values end with
?
-
methods mutating state end with
!
Basic and most explicit syntax looks like
puts("hello world!");
However the parenthesis are optional in case the only one interpretation of the expression
puts "hello world!";
and semicolons are optional as well
puts "hello world!"
String use either quotation marks "
or apostrophes '
. Apostrophes does not provide
string substitution as quotations marks do.
a = 'Hello' # => "Hello"
b = "#{a} world" # => "Hello world"
b = '#{a} world' # => "\#{a} world"
Ruby allows usage of special characted in method names. The standard is to use
-
the question mark
?
for methods that return boolean value -
the exclamation mark
!
for methods that mutate the object
1.even? # => false
"ruby".upcase.reverse # => 'YBUR'
"ruby".size.even? # => true
As mentioned above in Ruby everything is an object, including arrays or numbers. However there are special syntax shorthands to create instances of special classes.
Ruby has two basic number classes Fixnum
and Float
.
a = 1 # => 1
a.class # => Fixnum
b = 1.1 # => 1.1
b.class # => Float
Special value that represents "nothing" is nil
.
a = nil # => nil
In a boolean expression, nil
is considered false, i.e. it’s only of two possible
values that are not considered true.
As usual there is either true
or false
.
a = true # => true
b = false # => false
a && b # => false
a || b # => true
Arrays is an ordered sequence of values. There are no restrictions on what types can be in a single array.
["a", 1, true] # => ["a", 1, true]
Hash is a structure that maps key to a value.
{"a" => true, "b": false} # => {"a"=>true, :b=>false}
There are two approaches how to write the mapping, either rocket
style
key => value
or json
style
key: value
You can use both syntaxes, however with the json
style the value is converted
to symbol
, so in case you need to use String
or some other type, or get the name
of the key from a variable, you need to use the rocket
style. Several well-known
coding guidelines recommend (and enforce) using rockets
everywhere.
Methods are called by using the .
. Operators are actually methods.
3 + 3 # => 6
3.+(3) # => 6
[1,2][0] #=> 1
[1,2].[](0) # => 1
Ruby has global variables prefixed by $
.
$stdout
Classes and object can use class variables, though there are not used
very much. Prefer @instance_variables
in class-level methods, as
they have more predicatable behavior.
@@class_variables = 1
Objects have instance variables.
@instance_variable = 1
Local variables have no prefix.
local_variable = 1
And finally constants are all upper case.
CONSTANT = 1
Everything is considered true
except false
and nil
.
a = nil
b = ""
if a
"we do not get in here"
elsif b
"we got here"
else
"we did not get here"
end
Ruby has negative variant to if
called unless
. Essentially unless bool_expr
is
equivalent to if !(bool_expr)
. It is used the same way as normal if
.
a = nil
b = ""
unless a
"we do get in here"
elsif b
"we did not get here"
else
"we did not get here"
end
Ruby has inline method of using conditionals called modifier statements.
puts "Hello" if true
puts "Hello" unless false
Ternary operator is available as well.
experssion ? 'was evaluated true' : 'was evaluated false'
Another way to do conditions is to use case
statement.
case input
when 'q', 'e'
quit
when 'f'
format
else
help
end
Case
statement can as well check on variable class.
case var
when String
"it's string"
when Class
"it's class"
when Number
"it's number"
end
Another way to use case
statement is to use it as if
and elsif
.
case
when a == "a"
"a equals a"
when b == "b"
"b equals b"
end
There are basic logical expressions
-
and
&&
-
or
||
-
not
!
as well &&
can be replaced with and
, ||
can be replaced with or
and !
can
be replaced with not
.
There are basic comparison operators
-
equal
==
-
not equal
!=
-
lesser then
<
-
greater then
>
-
lesser then or equal
⇐
-
greater then or equal
>=
-
regular expression match
=~
Regular expressions are enclosed with /
. The simplest way is to use the regexp
operator.
string = 'localhost:2000'
string =~ /.*:.+/ # 0
string =~ /(.)*:(.)+/ # sets $1 a $2
as well there is a match
method on string.
data = string.match(/^(.):(\d+)$/)
data[1] # => localhost
data[2] # => 2000
while
repeats as long as the condition is true.
while a < b
a += 1
end
To go through the body of the loop at least once
begin
a += 1
end while a < b
There is as well inline way to write the loop
a += 1 while a < b
And finally the negative counterpart until
until a > b
a += 1
end
Methods in Ruby always return some value. If it is not explicitly returned using the
return
keyword, the return value is the value of the last expression in the method.
Return as usual returns from method and ends the execution of the method.
# Simple method with two arguments
def mth(a, b)
end
# Method with default value for 2nd argument
def mth(a, b=1)
end
# Method accepting any number of arguments, available as Array args
def mth(*args)
end
# Method requiring at least two arguments
def mth(a, b, *args)
end
The require
method loads code from another file. Ruby keeps track of required files
and skips loading files that would be loaded 2nd time. Files are looked up using Ruby’s
load path, which is represented using an array in $LOAD_PATH
and $:
. The load
method does
not keep track of loaded files.
In case the required file ends with [rb, so, o, dll, bundle, jar] extension, the extension may be omitted. There two commands are equivalent
require "somefile"
require "somefile.rb"
To keep track of required files, Ruby keep list of all files that were required in the $"
variable.
Blocks have many uses-cases. One of the use cases is the replacement for for
cycles
another use case is anonnymous functions
. Block are not executed when defined, but
have to be called through the call
method (though the calling of call
method is
most of the times hidden from the develop as in the examples below).
Arrays have method called each
that accepts block and calls the block for every
single element in the array.
arr = [1,2,3,4]
arr.each do |el|
puts el
end
will print all four values to the standard output. Blocks can be written in one more way
arr = [1,2,3,4]
arr.each { |el| puts el }
this variant is usually used for single-line blocks.
Block see their own scope plus can access scope in which were defined.
sum = 0
arr = [1,2,3,4]
arr.each { |el| sum += el }
Any method can accept a block and call it
def mth
return nil unless block_given?
yield
end
This method will return nil if no block was given or will call the block without any argument and the return value of the block will be return from the method.
Method may also accept blocks as a named argument which is prefixed by &
.
def mth(num, &block)
block.call(num)
end
this method will call block saved in the variable block
and will pass one argument
which is the first argument passed to the method itself.
In Ruby everything is an object. Object is an instance of some class. Even every class is an instance of class that inherits from Class. Object can have methods
class Hello
def say
"Hello, world!"
end
end
puts Hello.new.say
and instance variables
class Hello
def initialize(msg=nil)
@msg = msg
end
def say
@msg
end
end
puts Hello.new("Hello, world!").say
To make your instance variables accessible from outside, you define them as attributes. Attributes can be either read-only, write-only or both.
class Hello
attr_reader :one # allows reading by using the .one method
attr_writer :two # allows writing by using the .two = "xy" method
attr_accessor :three # allows both, reading and writing
end
Ruby allows object inheritance. All methods including constructor are inherited. Methods
can be overridden by children. super
is then used to call the original method.
class A
def a
"hello"
end
end
puts A.new.a # => hello
class B < A
end
puts B.new.a # => hello
class C < A
def a
super + " world"
end
end
puts C.new.a # => hello world
As known from other language, except in Ruby class variables are not used because of some pitfalls in their inheritance.
class A
def self.a
"hello"
end
end
puts A.a # => hello
Modules are a way to organize your classes in a similar fashion to namespaces. Classes can be included into modules or into other classes.
class A
class B
end
end
module Some
class Thing
end
end
Module are however used as well as mixins. When module is included into class all methods defined for that module are available in the class as instance methods.
module Helper
def something
end
end
class A
include Helper
end
A.new.something
and when used with extend
the mehtods are included as class methods
module Helper
def something
end
end
class A
extend Helper
end
A.something
Ruby has only single inheritance, mixins allow to get around this and provide a way to get some kind of multiple inheritance.
By default methods are public
, explicitly methods can be made protected
or private
.
class A
def public_method
end
protected
def protected_method
end
private
def private_method
end
end
Ruby encourages to react based on behaviour rather then on identity.
class Hunter
def shoot(animal)
bang! if animal.class == Duck
end
end
in this case the code checks if it’s a duck and shoots it, however
class Hunter
def shoot(animal)
animal.respond_to?(:quack) && bang!
end
end
in this case we care if the animal quacks and the it’s shot.
Exceptions represnt a special state in the execution in a program. When an exception is raised, it will bubling thorugh the stack until is caught.
Exceptions are raised using the raise
keyword
raise "This is not expected"
On the other hand when an exception needs to be caught, code block is extended with
rescue
statement that is called when an exception is caught and optionally ensure
that is called after both exceptional and non-exceptional state. Unless an exception
class is specified explicitly after the rescue
keyword, the StandardError
class
and it’s ancestors are rescued.
begin
raise "This is not expected"
rescue => e
puts e.message
ensure
puts "always"
end
Important
|
Don’t inherit directly from Exception class but use
StandardError instead. The direct descendants of Exception are
usually exceptions one doesn’t want to rescue from, such as
SystemExit or NoMemoryError .
|