Skip to content

Instantly share code, notes, and snippets.

@dpogue
Last active May 18, 2017 17:56
Show Gist options
  • Save dpogue/b9902efc2cac0635b9c82950e00b0d88 to your computer and use it in GitHub Desktop.
Save dpogue/b9902efc2cac0635b9c82950e00b0d88 to your computer and use it in GitHub Desktop.

Ruby is Object-Oriented (to a level you probably haven't seen before)

Everything in Ruby is an object:

  • "hello" is an instance of the String class.
  • 3.0 is an instance of the Float class.
  • String is an instance of the Class class (yes, classes are objects too)

Every object has some useful methods to help when starting out:

  • .to_s to convert to a string
  • .inspect to get a string showing the internal state of an object

Ruby's concept of null is called nil.

Ruby syntax is kinda similar to Python at its core, but it has a few weirder bits.

Example:

# Print a welcome message
def print_name(name)
  puts "Hello " + name
end

Functions are defined with def and ended with end.
Classes are similarly defined with class and ended with end.
Modules follow the same pattern: module/end

Ruby comments are #, like Python.

puts is the function to print something to stdout.

Ruby is dynamically typed, so you don't specify the type of a variable. Like Python, or JavaScript (not TypeScript). Ruby has 4 types of variables:

  • Global Variables
  • Class Variables
  • Instance Variables
  • Local Variables

Global variables always start with a $. You should probably never use these, although there are a few system ones that can be helpful (i.e., $! is the last exception)

Class variables start with @@ and are effectively the same as static properties in TypeScript.

Instance variables start with @ and work the same way as instance properties in TypeScript.

Local variables are just a name that you assign something to.

Let's make a simple Ruby class:

class Person
  def initialize(name)
    @name = name
  end
end

The constructor for a Ruby class is named initialize. In this case, it takes in a name and stores it to an instance variable.

To create an instance of our Person class, we would call Person.new('Some Name')

Worth noting, instead of a this keyword, Ruby uses self (again, similar to Python)

p = Person.new('Darryl')

So we have an instance of a person, how can we access the name variable? We can't! Instance variables are only available inside the class in Ruby. (Well, there's a super hacky way to get it, but ignore that)

We need to define a getter (and a setter, for the purposes of this example):

class Person
  def initialize(name)
    @name = name
  end
  
  def name
    return @name
  end
  
  def name=(value)
    @name = value
  end
end

Our getter is a method called name that returns the @name instance variable.

p.name() #=> "Darryl"

One cool (and also confusing) thing about Ruby is that you can call methods without parentheses:
p.name and p.name() are both calling the name method.

Our setter is called name= and takes a value. Normally we'd call that like p.name=("Ian") but we can leave off the parentheses and just use p.name = "Ian".

One final confusing bit: All Ruby methods automatically return the last statement of their body. This means we don't need to use the return keyword for simple cases like our name method.

def name
  @name # Return @name because it's the last statement in the method
end

In documentation, you'll see a bit of a unique syntax when talking about class methods and instance methods.

Ruby docs traditionally write class methods as Class.method and instance methods as Class#method. You'll see this in error messages and deprecation warnings too.

Okay, back to the Person example. It turns out defining getters and setters by hand when you really just want to expose the variable is annoying.

Ruby has some "helper methods" for doing this automatically: attr_reader and attr_writer:

class Person
  attr_reader :name
  attr_writer :name
  
  def initialize(name)
    @name = name
  end
end

p = Person.new("Darryl")
p.name #=> "Darryl"

Cool, but we can actually combine those into a single helper method with attr_accessor. It will automatically define both a getter and a setter for an attribute.

Some other things that you'll definitely run into in Ruby: Arrays and Hashes.

Arrays aren't particularly different than other languages:

a = [1, 2, 3, 4]

Hash are dictionary, key/value objects (like Dict in Python, or JSON literals in JS):

options = {
  :size => 'medium',
  :beverage => 'tea - earl grey',
  :temperature => 'hot'
}

What are those funny :things? Those are symbols

Unfortunately, it's pretty hard to actually explain Symbols. They're kinda just one of those weird Ruby quirks.

Think of them like constants that you can use to refer to things. In particular, hash keys are almost always symbols.
We also used them in our Person class when we told attr_accessor what getter/setter to generate and which instance variable they mapped to.

Class inheritance works like this:

class Person
  # ...
end

# Employee is a child class of Person
class Employee < Person
  # ...
end

Let's do a contrived example of class methods for the sake of it:

class Person
  attr_accessor :name
  
  def initialize(name)
    @name = name
  end
  
  def self.greet(who)
    puts "Hello #{who.name}"
  end
end

p = Person.new("Darryl")
Person.greet p #=> "Hello Darryl"

Okay, so the important thing is that static/class methods are defined as self.<thing>. You cannot access instance variables in a class method.

The other new thing we did is string interpolation with "#{...}". This is effectively the same as ${...} in TypeScript with backtick strings.
Note: In Ruby, string interpolation only works in double-quoted strings!

Some other Ruby conventions to be aware of:

  • Methods that return a boolean are usually named with a ? like Foo.exists? or Foo.nil?
  • Methods that change an object are usually named with a ! (and usually there's a non-! version that returns a new instance)

Example with strings:

str = "Hello World"

# gsub is effectively String.replace
str.gsub(/World/, 'Ayogo') #=> "Hello Ayogo"
str #=> "Hello World"

str.gsub!(/World/, "Ayogo") #=> "Hello Ayogo"
str #=> "Hello Ayogo"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment