Skip to content

Instantly share code, notes, and snippets.

@kturney
Last active December 23, 2015 02:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kturney/6565278 to your computer and use it in GitHub Desktop.
Save kturney/6565278 to your computer and use it in GitHub Desktop.
Notes on Ruby from [Mr. Neighborly's Humble Little Ruby Book](http://www.humblelittlerubybook.com/book/html/)

In Ruby, EVERYTHING that will be manipulated is an object

Types

  • All types in Ruby originate from the Object class
  • Strings
    • sequences of bytes that represent a sequence of characters
    • String literals may be created using either single quotes or double quotes
    • Single quotes are not interpolated and may only contain escapes for the single quote and backslash
    • Single quoted string literals are slightly more performant
    • Double quoted string literals offer far more escape sequences for interpolation
    • Ruby code can be embedded in double quoted strings using "some text #{ruby code} some more text"
    • Multiplying a string creates multiple copies of the string
    • Alternatively, single quote strings can be created with %q{text} and double quote strings with %Q{text}
    • Ruby also supports heredoc string creation by specifying a delimiter after a set of '<<' characters to start the string and putting the delimiter on a line of its own to end it
    • All objects also have a to_s method to get a string representation of the object
  • Numbers
    • Fixnum for integers between -2^30 and (20^30)-1 and Bignum for anything outside of Fixnum
    • Ruby ignores underscores(_) in numbers so they may be used in place of commas: 1_299_000
    • For floats, each side of the decimal must contain a number
    • All math operators are really just functions
  • Collections
    • Range

      • Hold a sequential collection of values, such as all numbers between 1 and 9
      • Created by placing a series of dots between the lower and upper limit of the range: letters = A..Z or digits = 1...10
      • 2 dots are for an inclusive range including beginning and end value
      • 3 dots are for a range that excludes the last value
      • Think about it as the extra dot pushing the last element out of the range
      • Ranges are considered equal (using == or .eql?) if their beginning and end values are the same
      • Check whether a value is in the range using === or .include? (aliased by .member?)
    • Array

      • An integer indexed and ordered collection of elements
      • The elements in a Ruby array do not have to be the same type
      • Many ways to create an array
      its_so_empty = []
      oh_so_empty = Array.new
      hello = ['ni hao', 'bonjour', 'hi', 'howdy']
      random_types = [13, 'napkin', (1336 + 1).to_s]
      
      # from strings
      my_haiku = %w( my dog digs it here\n )
       ["my", "dog", "digs", "it", "here" ]
      my_haiku = %w( he is nice to me & cats\n )
       ["he", "is", "nice", "to", "me", "&", "cats"]
      my_haiku = %W( but he ate #{(2*3)/6} once )
       ["but", "he", "ate", "1", "once"]
      my_haiku = %w( but he ate #{(2*3)/6} once )
       ["but", "he", "ate", "#{(2*3)/6}", "once"]
      
      # to_a method
      my_range = 1..10
       1..10
      my_dazzling_array = my_range.to_a
       [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      • Can append new elements by assigning a value to a non-existent index, using the .push method, or << operator
      • Array elements can be accessed using either and integer or a range
    • The Hash (AKA associative array or dictionary)

      • Collections of values of any type indexed by other values of (almost) any type rather than solely numbers like arrays
      • Keys have 2 requirements: must implement .eql? and must have a constant hash code
      • Hashes are created using {} or { 'key1' => 'val1', 'key2' => 'val2' }
      • Can also create a hash with a default value for non-existant keys using Hash.new('default val')
      • When an element is deleted (using (hash name).delete['key']) the key's value is returned
      • Calling .clear returns the newly empty hash

Variables and Assignment

  • Variables can be set in parallel using a, b = 1, 2 or a, b = [1, 2, 3]
  • Any array can be assigned to a list of variables. Ruby ignores any extra elements in the array past the number of variables
  • Ruby has += and -= but not ++ or --
  • Can prevent assigning to an object by calling the .freeze method

Blocks

  • Pieces of code segmented away from their context by an initiator and the end keyword
  • Can be passed a variable number of requirements (arguments)

Methods

  • Ruby uses message passing instead of actual method calls (Schemeish)

  • If a method is not found, a NoMethodError is thrown

  • Defined by def followed by the method name and parameters, ended with end

    def my_new_method(name)
        puts "Hey, #{name}, this is my new method..."
    end
  • Naming (By convention)

    • All lowercase
    • Seperated by underscores
    • If querying an attribute, end in '?'
    • If modifies receiver in place, end in '!'
  • Args

    • Can set defaults
    def new_method(a="This", b="is", c="fun")
        puts "#{a} #{b} #{c}."
    end
    • Params must be in the same order
    • Params cannot be skipped
    • Parameter lists can be variable length by placing an '*' before the identifier of the last element it will be a variable length list
    def print_relations(relation, *names)
        puts "My #{relation} include: #{names.join(', ')}."
    end
    
    print_relations("cousins", "Morgan", "Miles", "Lindsey")
  • Calling

    • If no parameters, no parentheses are needed
    • Methods throw 'ArguementError' if they don't get the correct number of arguements
  • Return value

    • A value is always returned
    • If no value explicitly specified, returns nil or the last value used inside the method (if that exists)

Blocks and Proc Objects

  • Blocks are much like a method without a name tagged on it

  • Blocks can also be defined with {/} instead of do/end

  • Proc

    • Proc objects are like blocks that are pushed into variables
    • Proc is especially useful when you want to create a block of code and pass it around or generate new blocks from it
    • Another way to create a Proc object is to bind a block of code using the lambda method
    myproc = lambda {|x| puts "Argument #{x}"}
    # same as
    proc = Proc.new {|x| puts "Argument #{x}"}
    • Proc objects created with lambda have stricter argument checking than those created with Proc.new
    • Objects created with lambda don't affect the flow of the application outside of the block when returning a value
    • Proc objects created with Proc.new will exit their enclosing method when returning
    def procnew
        new_proc = Proc.new { return "I got here..." }
        new_proc.call
        return "...but not here."
    end
    
    def lambdaproc
        new_proc = lambda { return "You get here..." }
        new_proc.call
        return "And I got here!"
    end
    
    puts lambdaproc
       And I got here!
    puts procnew
       I got here...
  • Using Blocks

    • Take a Proc as an argument, but this does not perform well
    • Implicit block usage: use yield to give control to the block
    • If & is is the first character of a block argument name, then the block is converted to a Proc

Types

  • Ruby uses "duck typing": if it walks like a duck and talks like a duck then its a duck

  • In Ruby, every class is an object which is an instance of the Class class which is derived from the Object class

  • Ruby only supports single inheritance

  • A class inherits all of its super's methods and variables

  • Define a class using

    class MyFirstClass < Object
    end

Methods and Variables

  • Constructor logic for Ruby classes is contained in the initialize method
  • initialize is invoked by calling (class name).new with any required arguments
  • Define instance variables (state held within an object) are defined by prefixing the name with @
  • Instance variables do not have to be declared in the class definition. Just use them
  • Classes in Ruby are never closed. You can always add or redefine methods on a class

Attributes

  • Basicly getters and setters for instance variables

  • Get: define a method with the same name as the instance variable and return it

  • Set: define a method with the same name as the instance variable appended with an '='

    class Boogeyman
        def scare_factor
            @scare_factor
        end
        
        def scare_factor=(factor)
            @scare_factor = factor
        end
    end
  • Can alternatively use attr_reader and attr_writer to have Ruby generate the attributes for you

    class Boogeyman
        attr_reader :scare_factor
        attr_writer :scare_factor
    end

Access Control

  • Methods and attributes are public by default
  • Can make methods/attributes protected (accessible by instance and sub-classes) by placing the protected keyword on a line and putting protected methods/attributes after that line
  • Private methods/attributes can be similarly defined by using the private keyword instead of protected

Class Scoped Objects

  • Class constants can be defined by placing the constant name and value in the class definition

  • To create class varaibles (same as Java static variables) place @@ before the variable name

  • Class methods are defined using (class name).(method name)

    • Strange note that class methods are not visible to instance scoped objects so the methods full call must be used
    class Boogeyman
        MY_BOSS = 'Mr. Boogeyman'
        
        def Boogeyman.latest_monster
            puts "The latest monster is #{@@latest}"
            puts "He is in #{@@location}"
        end
        
        def initialize(name, location)
            @name = name;
            @location = location
            
            @@latest = @name
            @@location = @location
        end
    end

Modules

  • Modules are used to create namespaces to prevent naming conflicts

  • Modules are defined by

    module ModuleName
    ...
    end
  • Mixins

    • Modules also allow for mixins, code that is "mixed into" a class as if it is part of its original code
    • To use a mixin, define a module and then use the include keyword followed by the module's name
    • After inclusion, the class has access to all of the module's constants and methods
    • It is best to use a unique naming scheme for module constants to prevent naming conflicts when mixed into classes
    • Methods do not have to be unique because Ruby will use the instance defined method first

Files

  • To include a file in Ruby use load or require
  • load includes a source code file unconditionally
  • require will only include a source code file once (so not duplication of variables and methods)
  • Both keywords accept both relative and absolute paths
  • require can also be used in conditionals, loops, or other constructs and use variables in its path
  • Local variables in included files do not trickle into the context in which they are included. They are locked into the context in which they were written.

Conditionals

Ifs

if is the initiator of a conditional block that needs to be ended with end else for else and elsif for else if

Conditional Operators in Ruby
a == b Is true if the value of a to the value of b
a === b Is true if the value of a to the value of b and they are the same type
a != b
a <> b
Is true if a is not equal to b
a !== b Is true if a is not equal to b or they are not the same type
a < b Is true if a is less than b
a > b Is true if a is greater than b
a <= b Is true if a is less than or equal to b
a >= b Is true if a is greater than or equal to b

Ruby supports both C-style and strings for logical operators

  • && and and
  • || and or
  • ! and not Ruby supports the ternary operator: (condition) ? (true result) : (false result)

Unless

Operates as a "reverse" if

  • the main branch only executes if the provided condition is false
  • Can prevent writing a bunch of negative ifs

Statement Modifiers

Syntactic sugar that allows tagging an if on the end of a statement for conditional execution Modifiers can also be placed at the end of blocks

thelma_louise = 13
puts "She's less than 15 alright!" if thelma_louise < 15
puts "She ain't more than 12, though!" if thelma_louise < 12
  
begin
  puts "It's so true!"
end if (true == true)

The case Statement

Case blocks are started with the case keyword Conditions are specified with the when keyword Each case is checked in order from the top down when should be followed by : or then (optional if the statement starts on the next line) else is used for the like default in Java switch statements There is no fall through in Ruby case statements There are 2 forms of case statements in Ruby

  • Standard: set a target variable on the case and each when is a possible target value
  • Flexible: set no target and each when has conditional statement(s)
the_tao = 1234
case the_tao
  when 666: puts "That's such a lie!"
  when 1337
    puts "Liarrrr!"
  when 32767 then
    puts "Whatevurrrr!"
  else
    puts "You are harmonized with the Tao."
end

enlightenment = 42
case
  when enlightenment > 60:
    puts "You are too hasty, grasshopper."
  when enlightenment < 40 or enlightenment == nil:
    puts "You are like the sloth, my friend. Diligence is key!"
  when enlightenment == 42:
    puts "Hello, Enlightened One."
  else
    puts "Yeah, not quite, pal. Maybe next time."
end

Loops

Conditional Loops

Execute based on a provided conditional statement A while loop executes while a conditional is true An until loop executes while a conditional is false Ruby does not have C-style for loops

Iterating Loops and Blocks

Ruby for loop: for element in collection: (logic on element) end each iterator: collection.each do |element| (logic on element) end Alternative each: collection.each {|element| (logic on element)}

Statement Modifiers

while and until may be used as modifiers on statements and blocks When used on blocks, the block will be executed at least once (like do while loops)

Controlling Loops

next can be used to skip the current iteration break can be used to exit the loop next and break can have conditional modifiers attached to them

Exceptions

All exceptions derive from the base class Exception (go figure)

Handle Exceptions

Handle exceptions using a rescue block To create a rescue block, place the rescue keyword at the start of a line followed by the exception class to be handled If multiple rescue blocks are specified, Ruby follows the first one encountered able to handle the raised exception's type A variable can be specified to hold exception details: rescue NoMethodError => e: (logic) rescue blocks can be tagged with an else to be executed if no exception is encountered ensure blocks can be added to make sure something is always executed, like Java's finally

Rescue Statement Modifier

rescue can be used as a statement modifier, however the type of the exception can not be specified Can be used to return a default value if calling a method that may throw an exception

Retry

Using rescue and retry you can make an attempt to fix any errors that may cause exceptions and retry the block Take care that if the errors cannot be fixed that infinite retires do not occur

Raising Exceptions

# Raise a RuntimeError w/ message
raise "Error message"

# Re-raise the current exception or raise new RuntimeError w/ no message
raise

# Raise a typed error w/ message and a stack trace object (which is usually just caller, a reference to Kernel.caller method)
raise NoMethodError, "That method ain\'t here!", caller

My Own Exceptions

To create a new exception, simply derive from any of the exception classes

Throw and Catch

Create a catch block using catch :identifier do ... end If the identifier is thrown (throw :identifier) than the block is exited without executing anymore code Useful if you need to simply exit the code block if an error occurs or if your code is buried in deeply nested loops and you want to break out of them quickly and easily

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