Skip to content

Instantly share code, notes, and snippets.

@fedemartinm
Last active May 27, 2020 06:47
Show Gist options
  • Save fedemartinm/8418bf3b47a6b04af2946ba7a0b91068 to your computer and use it in GitHub Desktop.
Save fedemartinm/8418bf3b47a6b04af2946ba7a0b91068 to your computer and use it in GitHub Desktop.
Ruby at a glance

A quick overview of Ruby! Complete docs here.

Facts

  • Everything you manipulate is an object
  • Every object has a unique object identifier (objectId)
  • Arrays and Hashes are indexed collections, both accessible using a key.
  • Hash constructors define default values
  • Built-in /Regular Expressions/
  • Ruby comes with c-like printf
  • Special arrays and hashes:ARGV invocation arguments, ENV os environment
  • Use require for gems, require_relative for files
  • Methods are public by default. There are also private and protected.
  • Variables are references to objects.
  • Dup method shallow-copy an object, freeze prevent changes.
  • Most ruby operators are instance methods of their respective classes.
  • Arrays can be indexed by positive or negative integers, (start,count) values or ranges (from..to).
  • Case statements can use ranges 1..4 in options.
  • Any value that is not nil or the constant false is true
  • Hint: has-a or uses-a=> mixin modules, is-a=> inheritance.
  • unless and respond_to? can be used to validate a method call.

If you come from JS

  • javascript array.map is ruby array.collect
  • javascript array.forEeach is ruby array.each
  • javascript array.reduce is ruby array.inject
defined? b #ruby
is like b === undefined ? b : typeof b //js
proc1 = (arg1,arg2) => { } //js
proc2 = -> arg1, arg2 { } //ruby
proc3 = ->(arg1, arg2) { } //sugar

Scope

  • Blocks Parameters to a block are always local to block Block-local variables can be defined by putting them after a semicolon in the block's parameters list. Non-local variables in a block, refer to exterior block.
  • Loops Loop structures do not introduce a new scope, so previously existing locals can be used in the loop and any new variable will be available afterward.

Symbols

Simply and unique constant names that can have an associated value.

:Read #symbol declaration
Mode = {:Read => 'read-mode'} #symbol as hash key

Control structures

  • If
if condition elsif condition else sentence end
unless condition end
  • Case
case
  when condition sentence
  when condition sentence 
  ...
  else #default 
end
  • Loops
while condition sentence end
until condition sentence end
for element in producer end

# loop controls
break #terminates loop iterion
redo #repeats current loop iteration
next #skips to next loop iteration

Statement modifiers

A statement modifier lets you move control structures at the end of an expression

puts "Error" if error
puts "Ok" unless error
value = value + value while value < 100

Objects

#Class 
class Book
  #Constructor, optional
  def initialize(isbn, title)
    @isbn = isbn
    @title = title
  end
  #Kind of getter
  def isbn
    @isbn
  end
  #ToString override
  def to_s
    "Title: #{@title} ISBN: #{@isbn}"
  end
end

Classes

Basic structure of a class can be:

class Child < Parent
  ...
  def initialize #class constructor
     super #ref to parent constructor
  end
end

Modules

Modules provide a namespace, grouping methods, classes and constants.

module Loopeable
   #prefixed, It's part of Loopeable
   def Loopeable.loop
   end
   
   #no prefixed by modulename
   def next
   end
end

Mixins

Modules can be included in other modules or classes using include statement. This can be used to add functionality to classes, whithout inheritance. Modules can have instance variables and accessors - To prevent variable clashes, Strategy to prevent variable clashes: use a hash variable inside the module, indexed by the object ID. Extend can be used to add instance methods to a particular object.

class Book
  include Comparable
  attr_reader :title,:isbn
  def initialize(title,isbn)
    @isbn = isbn
    @title = title
  end
  def to_s
    "#{@title}"
  end
  # comparable mixin add operators >, <, >=, <= and ==
  # based on our definition of <=>
  def <=>(other)
    self.title <=> other.title
  end
end

Code Blocks

Blocks are like anonymous methods, that can be converted to an object, stored or invoked. Blocks are passed to methods as an implicit parameter. On implicit definitions, you can use block_given? to check if a block is associated with the current method. It's possible to make a block-parameter explicit by using ampersand operator.

#Iterators
[ 'one', 'two' ].each {|n| print n, " " }
('a'..'z').each {|letter| print letter }
1.upto(3) {|i| print i }
3.downto(1) {|i| print i }
3.times { print "z" }

#Custom invoke
#implicit block used in yield
def call_block
  puts "a"
  yield
  yield
  puts "c"
end

call_block { puts "b" }
out: a b b c
#with args
call_block { |arg1, arg2| puts "b" }

#explicit block
def call_block2 (&block)
  @stored_block = block
end
def greetings(name)
  result = "Hi, " + name
  return result
end
#greetings
puts greetings("Jane")

Methods

  • Arguments as lists
method(*args)
method(first,*mid,last)
  • Calling methods
receiver.do( )
do( ) # same as self.do( )

def find(key1: nil,  **rest)
  #key1 is a key-object shortcut
  #invoke is find(object_with_key_1)
  #if object doesn't contain key1, nil default value is used
  #extra object's properties go to **rest
end
  • Recollect results
first, second = method
  • Aliases
#inside a class we can do
alias new_method old_method
#to redefine a method
#then, the new_method refers to a copy of the original method

Strings

#read until character after %, can be multiline
%q/single-quoted/ # => single-quoted 
%Q!double-quoted #{'pep'}! # => double-quoted pep
%!multi 
-line! # multi-line

#read document not including the terminating string (END_W in this code)
string = <<-END_W
Very long
document
END_W

Find Ruby General Delimited Input for all options.

Exceptions

To handle exceptions we enclose code in a begin end block,with one or more rescue clauses. You can use retry to restart begin block!

begin
 bang_method!
 rescue Exception # $! is a global object that reference last exception
   # $@ contains the stack-trace of last exception
   puts "Error"
   raise # re-raise exception, $!
end
# Matching multiple, alternative to $1
begin
  method!
  rescue ErrorClass1, ErrorClass2 => ex1
    print "Error " + ex1
  rescue ErrorClass3 => ex2
    print "Another error: " + ex2
  ensure # finally block
   ...
  end
  • Raising
raise
raise "Bad schema"
raise ExceptionClass, "error message", caller
raise "Missing field" if missing
raise ConnectionException.new(true), "connection error"

The method Object#catch executes its associated block:

#catch argument may be a string or symbol
result = catch(:exit) do
  ...code
  #throw exit
  throw(:exit, result)
  end
end
#we can check raised value
if result 
end

(E.g.: It can be used to handle quit requests)

Syntactic sugar

  • Code blocks
do 
  puts 'a'
end
# or
{
  puts 'b'
}
  • Access Control
class ExampleClass
  # Without arguments way
  # subsequent methods will be 'private'
  private
  def m1; end
  
  # With arguments
  def m2; end
  def m3; end
  private :m2, :m3
end
  • Array of words
# using array
a=[ 'javascript', 'c', 'csharp', 'java' ]
# using %w
a = %w{ javascript c csharp java }
  • Array push
collection = []
#javascript like
collection.push 1
#c++ like
collection << 1
  • Hashes
# using braces
collection = {
  'key1' => 'value1',
  'key2' => 'value2'
}

# using indexes
hash1 = Hash.new
hash1['key1'] = 'value1'
hash1['key2'] = 'value2'
  • Symbols
# symbol used as hash key
hash1 = {:symbol => 'value'}
# shortcut syntax
hash1 = { symbol: 'value'}
  • Readers
class Book
  # using attr_reader, it creates accessor, but not variable (unlike Java o C#)
  attr_reader :isbn
  # or method
  def isbn
   @isbn
  end
end
  • Parallel assignment
a=1;b=2;
#or prettier
a,b = 1,2
  • Accessors
class Book
  # using accesor
  attr_accessor :title
  # or method
  def price= (title)
   @price = title
  end
end
  • Proc objects
# using a method
def create_obj(&b)
  b
end
pr = create_obj { |x| puts "Called with #{x}" }
# using lambda
pr = lambda { |x| puts "Called with #{x}" }
# using arrow
pr = -> { |x| puts "Called with #{x}" }
pr.call 'pep'

Output:
Called with pep

  • Operators
expr1 and expr2
expr1 && expr2
expr1 or expr2
expr1 || expr2
  • Double-quoted allow to write expression interpolations.
  • The value returned by a Ruby method is the value of the last expression evaluated.

Conventions

  • Two-character is the community standard
  • Local variables, method parameters, and method names should all use snake case.
  • Global variables are prefixed with a dollar sign ($).
  • Instance variables start with "@"
  • Class variables start with "@@"
  • Class names and module names use UpperCamelCase.
  • Predicate-methods: Methods that return a boolean result, are often named with a trailing ?
  • Bang-Methods: dangerous methods, modify their receiver or raise exceptions. named with a trailing !

Examples:

$enviroment #Global variable
MAX_USERS = 10 #Constant
class SetupRunner #Class
  @@counter #Class variable
  @title #Instance variable
end #Class

Code docs

RDoc Cheatsheet Use rdoc cli command to build doc-files

# ClassName.
#
#
# @param [Type] param1 ...
#
# @see http://example.com
#
# @return [true] if ...

Recommended structure

package # top-level module
package/bin/ # command-line interface goes here
package/lib/ # library files go here
package/test/ # test files go here

Tools

  • RDoc ruby documentation tool
  • Gem standardized packaging, gems can be libraries or utility programs
  • GemSpec gem specification file
  • Rake is an automation tool (project tasks)

Ruby Core API

See Ruby core File, TCPSocket, Threads, Fibers, Mutual Exclusion, Queues, Multiprocesses, Meta-programming,etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment