Ruby Self-Tutorial, Day 2 of 21: Hello, Objects!

Monday, March 28, 2005

(note: this is part of a 3 week series)

Day 2 - Hello, Objects!

Today is a brief intro of the concept of objects in Ruby.

We will be spending this day learning about objects in Ruby, designing them, creating them, examining them, give them names, and teaching them tricks.

Thankfully, it looks like they keep the OOP rhetoric down to just a few paragraphs, long enough to segue into it for the newbies, short enough to jump right into the material for everyone else. The concept of "self" and "other" objects are first up and definitely need explaining, then it goes into classes and methods for them.

Results

Before explaining what objects themselves are, we dive back into another 4-5 paragraphs on the OOP movement itself and where it went wrong, or as they succinctly sum up, Objects were supposed to make things easier for everybody, but somehow they turned into just one more weird concept to trip over. Methinks that sentence is interesting. It's not just another anti-OOP rant, it's something more nuanced: it's not the concept of using objects that's made previous OOP languages difficult to learn for most and unwieldy for all, it's the specific implementation. [1]

Jumping into using the first object, we use the biggest one of all to get comfortable with the concept: self. It seems to be analogous to this in other languages I've used, since it can mean different things depending on where you use it. Again, to be explained better in later chapters. And oh how rad was the self.methods - generic_methods line?

After self, we made our first simple object, playfully called other. This chapter seemed to have a tongue-in-cheek "philosophy" theme applied throughout and it particularly helped when moving to explain how classes and instances worked:

Look at it this way: What we have created is not a philosopher, but a school that produces philosophers. It is those philosophers, and not the school itself, who know how to philosophize.

And there you have it: very simple and easy distinction between classes and the instances spawned from them. Classes are a way to mass-produce objects and objects do stuff. An instance is a particular object made from a class. There are some best practices sprinkled in between the explanations as well: start a class name with a capital letter. It'll save your sanity and readability later.

One surprising section was the detailed explanation of Localized Scope - is the concept really that different from other languages or counter-intuitive to those new to programming in general? I was surprised at the amount of airtime this got. Whatever, I'm sure there's stuff I'm fascinated by that's old hat to others. I really did like the analogy of "local variables are like pronouns" though, it's the clearest explanation I've seen yet. In fact, all of the analogies throughout the chapter have been funny and useful. I know different chapters have different contributing authors, so I don't know if Mark or a ghost writer did this very important section but regardless, kudos on one of the smoothest intros to OOP I've ever read.

Homework

#1 worked like a charm and it was actually kind of fun: it doubled as a neat intro into refactoring. For those even greener than I to programming: refactoring is the art and science of going through code that works and cleaning it up to make it even leaner. In this example, we removed superfluous variables.

#2 was even more refactoring and believe it or not, I got an answer that's different from the book:

  • me: puts ClockWatcher.new.double_report
  • them: puts((ClockWatcher.new).double_report)

What did I say about refactoring being fun? I got my first taste of POLS: not knowing how to do something, taking a shot at it, seeing the line work as intended. Like it read my mind...

#3 was about localized scope - calling the methods of "Frank" while in the "Joe" object doesn't work, since we've only learned about local variables so far, not ones with global scope. Patience, that'll come later.

Useless Personal Observations

During the examples, I noticed a cool side effect of using IRB in the command line was that it would match the line numbers in the book if you followed along closely. It was a great way-finding aid when jumping back and forth from the screen to the book.

The book also explains that IRB increments to both show the "line number" and the level of nesting within the program. Anything above 0 for the last numeral means it's waiting for you to complete something so it can evaluate. This is a handy way to avoid one of the most common headaches in markup and code, misspelled/absent closing tags or end arguments. It's such a big deal that Joel Spolsky looks for this in interviews, whether candidates close their functions properly even when writing code down on paper.

Some signs of a good programmer: good programmers have a habit of writing their { and then skipping down to the bottom of the page and writing their }s right away, then filling in the blank later.
- The Guerrilla Guide to Interviewing

Actually, he used to look for this, he doesn't anymore now that he told the whole damn world by writing about it. Thanks, Joel, now everyone's a good programmer, great.

Well, maybe you need to know other things too. Still, just that one tiny quick tip has helped me a lot: write out the opening and closing tags at the same time, e.g. for markup you'd write <p></p> before filling it in with whatever, or in Javascript, a function should look like someFunction(){} and then you can cram your genius in between the curly braces.

I had a minor problem with the scripts saved into text files rather than entered directly into the command line: the first line with the weird hash marks and directory path - #!/usr/bin/env ruby - was supposed to make it so you didn't have to type "ruby" in as a command every time you want to compile the code, but it didn't work for me. I had to write "ruby foo.rb" every time I wanted to see foo.rb's output. I thought maybe the problem was that the directory path it's referencing doesn't exist - there isn't an "env" subdirectory in /usr/bin - but chopping that off doesn't help either. Is there something OS X-specific I need to do to get this damn thing to work?

Update: it's all good, I now feel like a very cool command line ninja. A little. Scroll down to the comments to see Russ helping out with a quick OS X tutorial on making your Ruby scripts run.

[1] An even further tangent about needing languages that are flexible and amenable to a lot of changes: rapid iteration and quick prototyping are the cornerstones of two prominent methodologies in the last decade, extreme programming and interaction design. Yes, they have their differences and most people only know about one or the other just because of their background and skill set (designer or programmer), so they don't usually learn anything about the other side other than seeing a few flamefests online. The fathers of each movement even provided an entertaining dual interview showdown where they hashed out their differences, but despite all this teapot tempesting, it's important for web developers to see similarities in their rapid fire approaches. The type of applications we make are such a car crash between two much older and formerly distinct industries, graphic design and software development, with useful best practices to glean from both. Notice I only said applications - that's only one branch of web design. The design of content-heavy sites, for example, is also influenced by fields such as journalism and library sciences.

shoutouts: Garrick's Day 2
(are you learning Ruby and blogging it out too? let me know)

elsewhere on the web: , , ,

Thanks n8, but I don't know if that's necessarily the problem and I've updated the blog post to be a little more clear. I think I need to find the exact path to the file it's trying to reference and I can't so far.

And no problem about writing about my progress, I'm glad the ramblings actually make somebody want to read along. To be honest, I started out this project with minimal expectations: to get my notes down somewhere permanent and to do it in public to give me the peer pressure to actually stick to the timeline. Anything else is totally gravy.
Use locate to find the ruby binary:

locate ruby

From memory, on my iBook ruby lives in /usr/bin, so put this as the first line of your script:

#!/usr/bin/ruby

Then make your script executable:

chmod 755 myscript.rb

You should then be able to run without explicitly invoking ruby. If the script is in a directory that isn't in your path, you will need to specify the full path to the file or cd into the directory and run it like this:

./myscript.rb
More UNIX stupidness on my part...

Russ: Yup, you were right, that's the location of the ruby command alright, but making those changes to the first line and permissions of the script didn't get the desired effect. I tried monkeying with several different versions of the first line to invoke the right incantation, but no go. Do you (or anyone else with a Mac, for that matter) mind giving it a go with a test script on your own iBook and seeing what works?

Again, this isn't a big deal and just to make me feel cool, which is a rapidly diminishing possibility the more I struggle with something probably so basic for a typical UNIX geek.
Hmm, that's odd. What error message do you get? I just did this on my iBook:

Angua:~ russgray$ which ruby
/usr/bin/ruby
Angua:~ russgray$ cat test.rb
#!/usr/bin/ruby

p "hello world!"
Angua:~ russgray$ ls -l test.rb
-rw-r--r-- 1 russgray russgray 34 1 Apr 08:13 test.rb
Angua:~ russgray$ ruby test.rb
"hello world!"
Angua:~ russgray$ chmod 755 test.rb
Angua:~ russgray$ ls -l test.rb
-rwxr-xr-x 1 russgray russgray 34 1 Apr 08:13 test.rb
Angua:~ russgray$ ./test.rb
"hello world!"
Angua:~ russgray$

So it works OK for me. What happens if you repeat these steps? Let me know any error messages.
[Ah ha! It's that last bit that was throwing me off, the dot and slash. I was just entering the filename. So I was putting in:

[Al-Abuts-ibook:~] alabut% test.rb
tcsh: test.rb: Command not found.

Rather than:

[Al-Abuts-ibook:~] alabut% ./test.rb
"hello world"

Thanks for walking me through it Russ, I finally feel cool now.

So for the OS X kids, there you go, the first line you need in your ruby scripts and the command line magic you need to make it work.
/usr/bin/ruby is where the default ruby install hangs out. but if you install 1.8.2 or newer instead of using the installed 1.6.8, it's recommended to install into /usr/local/bin/, rename the old ruby, and symlink to the new location.

keep us posted!

- n8

Post a Comment

-->