Ruby, part 1So, Ruby. Ruby is a fun language, and its pretty easy to get started.
You can handle downloading and setting it up, I hope. This tutorial is going to be a bit strange, because I'm in a weird mood - gonna be using the language to look at the language, yo!
Ruby is an interpreted language, which lets us do some interesting things. It also means that unless you tie it to an external platform specific library, code you write on one system will work on any other system, so long as your using the same version of Ruby to run it.
So let's write a ruby program! Open up a text editor, type
puts "Hello World"
, save the file with a .rb extension, and then run it with ruby. You can actually cut the "uts" off the puts, and just type
p "Hello World"
if you're REALLY lazy. They aren't exactly the same, but they'll both accomplish what we need here.
We're done!
Of course, it's only that simple on the surface - like with most languages, there's an awful lot going on there in that deceptively simply line. "puts", in this case, is a method. A method, in Ruby, is a set of instructions for how an object should handle a message. The message, in this case, is just passing along a simple string object.
But what is the object that the string is getting passed TO, the object from which we are calling the puts method, the object to which we are passing this relatively simple message?
That's a question that's important to ask in Ruby, because there is always, any time you send a message, an object somewhere responsible for the response. The only time you don't need to specify the object is when you are executing code inside of it - Ruby assumes any non-directed method call will reference the object its defined within. That means our code is being written inside of some already defined object, and runs when it gets instantiated - along with a lot more code that we can't see, including the method definition for "puts".
To find out a bit more about what's going on, let's load the Interactive Ruby Shell (irb) (
Instructions on how to do so based on OS). This is one of the benefits of an interpreted language - it lets us code, quite literally, in real time. You should see something like
irb(main):001:0>
First, let's recreate our earlier success. Type
p "Hello World"
and hit enter. The code executed, immediately, and we get...
"Hello World"
=> "Hello World"
It did it twice? Not quite; it did push out two lines, but they are actually quite different. irb does a few things to help our coding and debugging, so let me explain that now.
That first line is the actual results of our "puts" call - puts references the I/O object, and pushes it's arguments out to the console or whatever is handling IO. The second line, though, is all irb. Whenever you execute code in irb, it helpfully displays the return value of the last line of code executed. In this case, the method "p" returns the string in addition to outputting it to the console.
We can assign that returned value to a variable, and by simply typing the variable name irb will confirm it does, in fact, contain the string "Hello World".
1.9.3p0 :028 > x = p "Hello World"
"Hello World"
=> "Hello World"
1.9.3p0 :029 > x
=> "Hello World"
If we'd used "puts" instead of "p", things would have been slightly different - "puts" doesn't return anything except a nil value, which we'll talk about more later.
What's important here, though, is that irb lets us learn things about the code we're running. For example... it let's us see what object our code is running within. To do that, type
self
and hit enter. You should see
=> main
That's the object our code is working in. So, let's have some fun with this object we've discovered. For easy reference later, we'll start by saving it to a variable.
app = self
Now, if we want to see all the public methods defined for app, we can type
app.methods
. Don't worry about reading all of that - most of it isn't important, but it's good to know how to do. Perhaps the most important lesson to take away is this: To call a method (such as "methods") on an object, the syntax is simply "object reference" period "name of method defined by object".
If you DO read it, you'll notice "puts" isn't on the list, though! What's going on? Didn't I say that this was the object that was handling that message we sent earlier?
Well, let's test. Remember, it's object, period, method.
1.9.3p0 :081 > app.puts
NoMethodError: private method `puts' called for main:Object
from (irb):81
from /home/glyphgryph/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in `<main>'
Ah, that's it! Like many other languages, Ruby has the ability to make methods private. This means they can ONLY be executed within the defined object - it doesn't accept messages by reference. Even though we are technically still executing our code with the object, we're acting like we aren't, so it's telling us to fuck off.
(Also, notice and appreciate that wonderful backtrace, letting us know exactly where our problem occurred)
Now, you may be wondering, what IS "main"? The answer is complicated - and it depends on what you're using to run your code. But we CAN find out a little bit more about it. Lets try
app.class
or, if you prefer
self.class
giving us
=> Object
This lets us know that "main" is an instance of the incredibly vague "Object". Object is one of the most basic ruby classes, and nearly every other object in the language inherits from it. It comes with or bundles up a helpful package of methods that we can use on any object we come across (because they are all, ultimately, Objects). This includes the "methods" and "class" methods we've been using to figure out what's going on.
Now, this is getting long, but before we go I want to do one more thing - engage in the act of CREATION. Yes, we're going to make a new object! Technically, of course, we already did - when we typed "Hello World", we implicitly created an object. But now we're going to make one on purpose! To do that, you simply take a class, and call the "new" method on it. This method returns a new instance of the class! Since we don't know how to create a class, yet, let's just use the one we've already discovered. Make sure to assign it to a variable so we can reference it later!
1.9.3p0 :094 > thing = Object.new
=> #<Object:0xa19d8f4>
This lets us know we've got an object, and tells us the object's type and what we'll call it's unique identifier. Success!
Of course, we can't do much with it yet - generic Objects are pretty... well, generic. They don't have a whole lot going on! But we'll get into some more complicated stuff next time around.
P.S.
Remember, those Object methods can be used on pretty much anything in Ruby. For example
"Hello World".class
will tell you the class of "Hello World" (A String).