Friday, October 28, 2011

Require - No Such File to Load Ruby

The exercise I'm working through in Learn Ruby the Hard Way has me spending a week creating my own game. I've been building various text-based adventure games, but was stuck on what to do next. This morning on the way to work I got the idea of building a MadLib generator.

The way I picture it working is like this: the generator will ask the user to select a Mad Lib from a list, then ask for the requisite input (nouns, adjectives, verbs) depending on the Mad Lib selected and finally spit out the finished product. Simple, right?

So my thinking is this project would be split into two parts: the main program that asks for which Mad Lib the user wants to do, and the Mad Lib that is loaded upon selection. To get this up and running, I decided just to make one Mad Lib work at first, then add support for multiple Mad Libs and the ability to choose between them.

This is just a simple matter of requiring the Mad Lib file from the Main file, but I ran into a small problem.

Using the require 'mermaid' command threw this error:

<internal:lib/rubygems/custom_require&rt;:29:in `require': no such file to load -- mermaid (LoadError)

I wasn't sure why this wasn't working, since I've used require to load separate .rb files before. After a bit of digging around, all I had to to do fix this problem is change require 'mermaid' to require_relative 'mermaid'. This makes sense - both files are in the same directory, so this command is simply saying to require this file located in the same directory as the main file.

On a side note, I'm glad to have fixed the problem, but I'm getting to the point that I think it's better to understand WHY things don't work, rather than finding the solution and moving on. Can anyone tell me why 'require' wasn't working, but 'require_relative' does? Is it an older style of Ruby code that's outdated? Do I need to change some configurations? Is require_relative a workaround? Where does require look for files, if not in the same directory the file that's making that call is located?

Anyway, it felt good to make some progress on this tonight. It's pretty awesome that I can come up with an idea on the way to work, come home and put it together in an hour and a half or so. I think this will be a fun little project. I plan to work on it more this weekend, expanding it, polishing it up and so on. Here's a link to the gist I made of it:

MadLib Generator

Wednesday, October 26, 2011

Initializing Classes in Ruby

I definitely tend to jump around a bit when it comes to learning to code. I was working on Manticore quite a bit, then jumped into Learn Ruby the Hard Way, and now I've hit a bit of a snag so I checked out Code School and the introductory Ruby lesson. (This lesson is based on Why's old lesson, by the way, and is awesome so far) I'm a big fan of Code School so far, because hands-on, practical tutorials have always been one of the best ways for me to learn.

Much like Learn Ruby the Hard Way, it's a lot of review, but I've been interested in seeing what Code School has to offer for a while. Not to mention, switching gears slightly seemed like a better use of my time than sitting around frustrated because I wasn't understanding defining Classes and initializing them properly. I also think the more time I can spend having fun with Ruby, the better. I end up coding longer and enjoying it more, which leads to me learning more and it all kind of snowballs from there until I can build a sort of half-ass snowman with string literals for arms and instance variables for eyes.

Still, Ruby isn't all string methods and arrays, so I'll get back to my problem with Learn Ruby the Hard Way pretty soon. Probably tomorrow!

Here's the basic problem: I have one Class, Game, and the extra credit for this particular exercise is to break the Game into two Classes: Engine and Map.

Here's a link to a gist of what I've got:

Gothons Attack!!

What I'm assuming I need to do is break the rooms a player goes through (methods such as :central_corridor, :bridge_access, etc) into the Map method, and put the code that drives the game into the Engine method. So now I need to learn what initializing a class does, how to do it, how to call a method in one class from another class, and how to make two classes work in concert. For example, Engine will be starting the game (I assume) and moving the player through the rooms that are defined in Map (I also assume) Any input on this problem is, as always, HIGHLY appreciated!

I used to think of learning Ruby as unearthing this huge artifact, but now I think of it as being inside of a mostly darkened room, where I'm stumbling around and looking for switches. Once in a while, I flip a switch and it might illuminate a far off corner, or a whole corridor, or just a tiny little piece of the room. Does that make sense? Or in other words, learning how to do new things is really frustrating right up until it's not, and then it's awesome.

Sunday, October 23, 2011

Here documents in Ruby

I'm still working through Learn Ruby the Hard Way, and the last few exercises have been about building simple text based dungeons. You may recall I spent about a week working on one of my own. This latest exercise introduced me to here documents.

A here document is an easy way to display a long, multiline string. This would have been PERFECT for use in my dungeon adventure. Here's how it works.

This is the original description from the first room in the dungeon game I built:

  puts "This room is dimly lit by two sputtering torches."
  puts "There are three doors leading out of here."
  puts "What do you do?"

You may notice a few "puts" methods. It's not terrible in this case, since I'm putting several small statements, but it's tedious to type and unnecessary to use so many methods when you could do it with one here document. So forget what I said. There's a better, simpler way to do it, so it IS terrible!

So this example can be re-written like this:

  This room is dimly lit by two sputtering torches.
  There are three doors leading out of here.
  What do you do?

You begin the here document with <<−TORCH_DESCRIPTION and end it with TORCH_DESCRIPTION. Ruby interprets everything in between as one string. Cleaner, right? Easier to read? Who wouldn't love it!

On a side note, you CAN write this as <<TORCH_DESCRIPTION instead, but by adding the minus sign, you can indent the code as usual. Without the minus sign, the terminator can't be indented, or else Ruby will start complaining about "can't find string TORCH_DESCRIPTION anywhere before EOF".

So I recommend using the minus sign. One more character makes your code a lot easier to read. I also ran into another little problem. Since a here document is a string literal, any variables won't be interpreted correctly. This is where interpolation comes into play. Here's an example from the current exercise I'm working through.

guess = gets.chomp()

if guess != good_pod
  puts "You jump into pod %s and hit the eject button." % guess
  puts "The pod escapes out into the void of space, then"
  puts "implodes as the hull ruptures, crushing your body"
  puts "into jam jelly."
return :death

This bit of code describes an escape pod room, where the user has to pick an escape pod to use. So we set the user's choice as "guess" and then call it in the method below. This is what happens when a user chooses poorly. However, if I were to rewrite the code using a here document, this is what I'd have:

  puts <<-BAD_POD
  "You jump into escape pod %s  and hit the eject button. %guess
  The pod escapes out into the void of space, then
  implodes as the hull ruptures, crushing your body
  into a jelly."
return :death

Now the %s and %guess won't be interpreted as variables, since they're inside of a string literal. Luckily, there's an easy solution: interpolation. Just swap out the %s for this little guy:


Ruby will look at this, understand that means you want to use a variable inside of a string literal, and then pull the information it collected when it asked the user which pod he wanted to jump into.

I'm hoping this post will be helpful for others who are grappling with here documents. It took me a bit of digging to figure out how to get the code to index properly (since it looked awful in Textmate, and my solution was to put the string in quotes, which was unnecessary) and I needed to figure out how to call a variable from inside the here document.