I have this book, called Beginning Ruby, written by Peter Cooper. It’s one of the first book I’ve bought about programming. I’ve read… 20 pages probably… For some reason, I barely started it. The book is getting old, in programming terms, but I feel like learning a little bit of Ruby, and I feel like it will get the job done to teach me the basics. I never used Ruby before, so I’m starting from scratch here.
irb ( Interactive RuBy )
Note: I’ll assume you have Ruby installed on your machine. You can check by running
ruby -v in a terminal. You should get something like:
➜ ~ git:(master) ✗ ruby -v ruby 2.3.3p222 (2016-11-21 revision 56859) [universal.x86_64-darwin17]
To start the ruby’s REPL, called irb, simply type irb and press Enter:
➜ ~ git:(master) ✗ irb irb(main):001:0>
To exit the REPL, type exit and press Enter.
For this article, I think I will only use irb.
As basic as it gets
From what I read, Ruby aims to be a very readable language, close to the English language. To follow the ancient traditions of our people, we must print a friendly greeting to our terminal. Let’s type the following in our terminal:
10.times do print "Hello Ruby" end
Well, it is true it reads like English. You could read that to anyone understanding English and they would understand what you are talking about. We can guess pretty easily what this command will do:
Hello RubyHello RubyHello RubyHello RubyHello RubyHello RubyHello RubyHello RubyHello RubyHello Ruby=> 10
Prints 10 times “Hello Ruby” !!! For now, I think it’s safe to forget the => 10 at the end. I don’t know what it means yet 😀
Of course, we can also do some maths:
irb(main):005:0> 2+2 => 4 irb(main):006:0> 3-2 => 1 irb(main):007:0> 8-45 => -37 irb(main):009:0> 4*5 => 20 irb(main):008:0> 10/3 => 3
Notice the result of the last operation. Returns 3. We know it’s not true. If you provide Ruby with integers, you will get an integer as a result. You want a floating point number? Provide floating points numbers in the operation:
irb(main):013:0> 10.0 / 3 => 3.3333333333333335 irb(main):014:0> 10 / 3.0 => 3.3333333333333335
Another issue you might encounter, if you are trying the following:
irb(main):019:0> print 42 + " is the answer to the universe" TypeError: String can't be coerced into Fixnum from (irb):19:in `+' from (irb):19 from /usr/bin/irb:11:in `<main>'
irb(main):020:0> print "The answer to the universe is " + 6*7 TypeError: no implicit conversion of Fixnum into String from (irb):20:in `+' from (irb):20 from /usr/bin/irb:11:in `<main>'
Strings and Numbers can’t be associated this way. To solve this, you can do:
irb(main):021:0> print "The answer to the universe is ", 6*7 The answer to the universe is 42=> nil irb(main):022:0> print 42, " is the answer to the universe" 42 is the answer to the universe=> nil
We added a comma instead of a +, and it works as expected!
Objects!! Objects everywheeeere!!
Ruby is an object-oriented programming language. Any concept you can think of can be represented as an object in Ruby. If you’ve used another object-oriented language, this may look familiar. Let’s see how Ruby does it.
Let’s create a concept called Book:
irb(main):023:0> class Book irb(main):024:1> attr_accessor :title, :author, :year irb(main):025:1> end => nil
So, in Ruby, we call a concept a class. So we create a Book class. Always starts with a capital letter. Then, we define three attributes to our Book class: title, author and year. Finally, the end keyword tells Ruby we are done defining our concept.
Book is the concept, an object is a thing based on that concept. The book 1984 written by George Orwell could be an object based on the Book concept for example.
Using our concept
Let’s create a variable to store an instance of our Book concept.
irb(main):028:0> book_instance = Book.new => #<Book:0x007fdc17898208>
We created a new Book instance by called the new method on the Book class. We stored that instance inside a variable called book_instance. Now, as long as your REPL lives, book_instance is an instance of the Book class. Let’s change a few things about our book instance:
irb(main):029:0> book_instance.title = "1984" => "1984" irb(main):034:0> book_instance.author = "George Orwell" => "George Orwell" irb(main):035:0> book_instance.year = 1948 => 1948
Here, we gave the book_instance attributes a value. As you can see, there are no restrictions on the type of data you give to those attributes. I could have written 1984 instead of “1984” and no errors would have appeared.
To print the attributes:
irb(main):036:0> puts book_instance.year 1948 => nil irb(main):037:0> puts book_instance.title 1984 => nil
puts is like print. The difference is that puts adds a newline character at the end ( and starts a new line ).
Having a Book concept is fine, but there are a lot of different books available. We can make concepts inherit from other concepts.
irb(main):038:0> class Novel < Book irb(main):039:1> attr_accessor :genre irb(main):040:1> end => nil
The Novel concept inherits from the Book concept. This means that the Novel will have access to the Book attributes. Let’s create a Novel instance:
irb(main):041:0> novel_instance = Novel.new => #<Novel:0x007fdc17818aa8> irb(main):043:0> novel_instance.title = "Notre Dame de Paris" => "Notre Dame de Paris" irb(main):044:0> novel_instance.genre = "Romance" => "Romance"
Our novel_instance has access to the Book attributes ( such as title ), and has its own attributes ( here genre ). BUT, the Book concept doesn’t have access to the Novel attributes:
irb(main):045:0> newbook = Book.new => #<Book:0x007fdc17013650> irb(main):046:0> Book.genre = "Romance" NoMethodError: undefined method `genre=' for Book:Class from (irb):46 from /usr/bin/irb:11:in `<main>'
And, if we create another concept, inheriting from Book, that concept will only have access to its attributes, and the Book attributes, not the Novel attributes.
irb(main):007:0> class Magazine < Book irb(main):008:1> attr_accessor :type irb(main):009:1> end => nil irb(main):017:0> mag_instance = Magazine.new => #<Magazine:0x007fcabc05db90> irb(main):018:0> mag_instance.type = "Periodical" => "Periodical" irb(main):019:0> mag_instance.title = "GQ" => "GQ" irb(main):020:0> mag_instance.genre = "ERROOOOR" NoMethodError: undefined method `genre=' for #<Magazine:0x007fcabc05db90 @type="Periodical", @title="GQ"> from (irb):20 from /usr/bin/irb:11:in `<main>'
We created a Magazine concept which inherits from Book. Magazine doesn’t have access to the Novel attributes, only to its attributes and the one of its parent.
Classes can have methods, instructions you tell your classes to perform. You need to define them inside the class, like so:
irb(main):021:0> class Kindle < Book irb(main):022:1> def sayMotto irb(main):023:2> puts "No more paper!!!" irb(main):024:2> end irb(main):025:1> end => :sayMotto irb(main):026:0> new_kindle = Kindle.new => #<Kindle:0x007fcabc1630d0> irb(main):027:0> new_kindle.sayMotto No more paper!!! => nil
Look, we create a Kindle concept. Inside we use the def keyword to define a method. This method is called sayMotto. The body of this method tells it to print No more paper!!!. Notice that there are two end keywords. The first one to indicate we are done defining the method, the second is for the end of the class definition. Then, we can call our method by using its name on our newly created Kindle instance!
Okay, that’s enough for one article. I feel like I’ve covered enough stuff for one article. I’ll see you in the next one.