MINASWAN
"Matz is nice and so we are nice."
Ruby is a dynamic, object oriented programming language. It was invented in the mid 1990s by Yukihiro "Matz" Matsumoto.
When you are programming in ruby, you are programming in a language that was designed with your happiness in mind. This is reflected in the languages' beautiful not-quite-prose syntax, its wide range of expression and its expansive standard library.
I suppose it would be fitting to start with the classic "hello world" application.
puts "Hello, world!"
That was simple enough. How about the classic interview question, FizzBuzz?
1.upto(100) do |number|
line = ""
line << "Fizz" if number % 3 == 0
line << "Buzz" if number % 5 == 0
puts line.empty? ? number : line
end
This one may need a little explaining, which we will get to in good time.
Ruby provides you with several types which allow you to represent and interact with data in a predictable way.
Type | Examples |
---|---|
String | "I" , "love" , "ruby" , "1" , "1.23" , "'{};'#" |
Symbol | :this , :is , :a , :symbol |
Fixnum | 1 , 2 , 3 , 100 , 1_000_000 , 999999999999999999 |
Bignum | 9999999999999999999 |
Float | 1.23 |
TrueClass | true |
FalseClass | false |
NilClass | nil |
Array | [] , [1, 2, 3] , [[], [], []] , [123, "foo"] |
Hash | { "foo" => "bar" } , { :baz => 123 } |
These are all basic types, but they contain vast power. Each of these types is backed by a class.
"I love ruby".class
# => String
A class is a collection of information and behaviour. Of attributes and methods. Each of the above types is a class, and each class comes packed with functionality. You can get a preview of this by calling the #instance_methods
method of any of these classes.
Fixnum.instance_methods
# => [:to_s, :inspect, :-@, :+, :-, :*, :/, :div, :%,
# :modulo, :divmod, :fdiv, :**, :abs, :magnitude,
# :==, :===, :<=>, :>, :>=, :<, :<=, :~, :&, :|,
# :^, :[], :<<, :>>, :to_f, :size, :bit_length,
# :zero?, :odd?, :even?, :succ, :integer?, :upto,
# :downto, :times, :next, :pred, :chr, :ord, :to_i,
# :to_int, :floor, :ceil, :truncate, :round, :gcd,
# :lcm, :gcdlcm, :numerator, :denominator, :to_r,
# :rationalize, :singleton_method_added, :coerce, :i,
# :+@, :eql?, :remainder, :real?, :nonzero?, :step,
# ... and many more!
Try it yourself. I won't make you count, though. The Fixnum
class has 130 instance methods available to it. This means that there are 130 different things that you can do with the number 1
in ruby.
Operator | Purpose |
---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
\ | Division |
% | Modulus |
** | Power |
Operator | Purpose |
---|---|
== | equals |
!= | not equals |
> | greater than |
< | less than |
>= | greater or equal |
<= | less or equal |
<=> | returns 0 if equal, 1 if the first operand is greater, -1 if it is smaller |
=== | tests equality within a case statement |
There are many times that you will wish to control what part of your application executes based on some condition.
if condition
# do something
end
There are times that you will want to do something if the condition is true, and if it is false, something else entirely.
if condition
# do something
else
# do something else entirely
end
There are times that you will want to do something unless a condition is true.
unless condition
# do something
end
for number in [1,2,3,4,5] do
# do something with number
end
This is the basic for
loop. It is (almost) functionally equivalant to the each
loop.
[1,2,3,4,5].each do |number|
# do something with number
end
We have other types of loop, too.
while conditional
# do something while conditional is true
end
until conditional
# do something until conditional is true
end
Left alone, these loops will continue to execute until their conditions evaluate to false or until their sequence is empty. There are other ways to terminate a loop early, should the need arise.
while conditional
break # terminate the current loop
next # skip to the next iteration of the loop
redo # restart the current iteration
end
As you might expect, Ruby allows you to define your own methods.
def say_hello
puts "Hello, world!"
end
A method can also take one or more arguments.
def greet(someone)
puts "Hello, #{someone}!"
end
You can supply default arguments to your methods.
def greet(someone="world")
puts "Hello, #{someone}!"
end
greet
# Hello, world!
You will commonly find yourself supplying more than one argument to your methods.
def foo(bar, boo, baz)
end
Resist the urge to pass in too many arguments. If you need that many arguments, it is likely that your method is doing too much and your code should be restructured. If you must pass in a larger number of arguments, consider passing in a hash.
As with variable names, it is the convention in Ruby to name your variables in lower case, with words separated by underscores.
A class is like a blueprint for an object. It defines the data and behaviour that will describe an object.
class Speaker
def initialize
@utterance = "Hello, World!"
end
def speak
puts @utterance
end
end
speaker = Speaker.new
speaker.speak
# Hello, World!
Above, we created an instance, speaker
, of our class, Speaker
.
Modules provide a way to include and share behaviour in your classes and objects while still organising your application in a modular way. They are similar to classes, except you cannot create an instance of a module. You can merely include (or "mix in") the functionality into other objects.
module Talkative
def speak
puts "Hello, this is #{self.class}!"
end
end
class Human
include Talkative
end
class Dog
include Talkative
end
Human.new.speak
# Hello, this is Human!
Dog.new.speak
# Hello, this is Dog!
You may notice that our classes are named as nouns, and our modules are named as adjectives. This is the generally agreed upon convention as our classes can be instantiated to represent objects. They represent individuals. A human, a dog. Our modules represent behaviour, and when mixed in they represent a quality that can be ascribed to an object.
I have just shown you how to include a module in a class. Now I shall show you that you can also prepend a module to a class.
module Talkative
def speak
puts "Hello from the module!"
end
end
class Human
include Talkative
def speak
puts "Hello from the class!"
end
end
class Dog
prepend Talkative
def speak
puts "Hello from the class!"
end
end
Human.new.speak
# Hello from the class!
Dog.new.speak
# Hello from the module!
As you see, the different between include
and prepend
is that the former places a higher priority to conflicting methods defined within the class. With the latter, methods defined in the module take priority.