Ruby tricks for noobs

Over the past year, starting in early January, and progressing to now, I've been teaching myself ruby and rails. There are some tricks everyone picks up along the way, little things that make programming enjoyable, speedier, and helps you produce simpler code. These are the things that you don't often read about, but pick up along the way.

Ruby

I'll start off with ruby, because its the backbone on which all the other tricks depend on. These are mostly language-level tricks, features that are unique to ruby, or if they aren't, not commonly used in other languages.

Use percent-based syntax

Ruby handles quotes and other string-based values differently than most languages. In many languages, single-quoted and double-quoted strings are the same. Not so in ruby. Double quoted strings have the advantage of allowing interpolation (more on this later). But this is fairly common knowledge, and something most beginners pick up early on.

What they don't pick up is the fact that there is another string syntax, and it doesn't just apply to strings. It applies to nearly everything. Regular expressions, arrays, you name it.

Take regex for example. You can do regexes like this:

1
regex = /match/

which is fine and dandy till you have to do something like url parsing, which starts to look like this:

1
regex = /http:\/\//

ugh. Luckily enough, we have a better syntax:

1
regex = %r{http://}

Notice the %r{}. This is a percent-based string!

You may have seen and used the array-creating string of %w{}, as its by far the most common. But its not the only one. There are several more:

Modifier Meaning
%q{} Single-quoted, non-interpolated string. Equivalent to 'string'
%Q{} Double-quoted, interpolated string. Equivalent to "String"
%r{} Regular expression. You can put flags after the closing delimiter
%s{} Non-interpolated symbol.
%w{} Non-interpolated array. Takes a space separated string and turns it into an array
%W{} Interpolated array. Takes a space separated string and turns it into an array
%x{} Command. Runs a shell command and returns the STDOUT

Interpolated means that you can use the ruby interpolation syntax, #{code}, which I'll cover in a bit.

The advantage of using these over their brethren? They make your code easier to read! They also let you do some tricky things with fewer characters, such as dynamically named symbols.

Use string interpolation

Many people coming from other languages, particularly those coming from java or C, don't use this, and their code tends to look un-idiomatic. The methods I usually see are one of the following:

Concatenations:

1
my_string = 'hello there ' + username + ', how are you?'

C-style formatters:

1
my_string = 'hello there %s, how are you?' % username

These aren't the worst (I've seen someone use a statement spread over 3 lines with <<), but they aren't good. Instead of using these, try using interpolated strings. You have to double-quote (or use the aforementioned percentage syntax) to use these. The previous example, using interpolated strings, would look like:

1
my_string = "hello there #{username}, how are you"

See? Much more readable. I'm not dismissing the value of the previous methods, as they have specific cases in which they are more useful, however, due to the flexibility of ruby, you have more tools available. And keep in mind that just because something isn't idiomatic doesn't mean its bad. Idiom is just a way of ensuring many different programmers are on the same page. Its like a style guide.

Differentiate expressions and functions

In ruby, as you may have learned, you do not need to use parenthesis on your method calls. herp "derp" and herp("derp") are technically the same.

However, this gives us an excellent chance to add meaning and structure to our code. Use the parenthesis-less syntax when you're just calling something, and don't care what the return value is. This is good if you have something that modifies an array or string, such upcase!. And use the parenthesis syntax when you're calling something and do care about the return value.

This seems arbitrary, till you pause to think for a second. With the parenthesis syntax, this reads naturally:

1
herp("derp").upcase

Without the parens, how do we know if upcase is affecting the return value or is another parameter? Could the original code author have missed a comma? While it is technically valid ruby, it may break in some future version, or a different engine.

Monkeypatching!

Monkeypatching is something people seem afraid of at first, till they have to break down and do it, and then they see the utility of it. Do not be afraid. It is a powerful tool, and like all other powerful tools, you have to be careful using it. But if you use it right, you can clean up your code, save a ton of time, and maintain an object-oriented syntax.

How often have you written something conceptually similar to this:

1
2
3
def prettify_string v
  v.upcase.strip
end

That looks fine, simple, but fine, right? Its actually introducing non-object-oriented code into your programs! A cardinal sin, I know.

Instead of doing this, why don't we add the feature directly to string?

1
2
3
4
5
class String
  def prettify
    self.upcase.strip
  end
end

Presto! Now you can call this via "herp".prettify, and you'll get the result you wanted. This isn't really a trick so much as a language feature, and its used by several big libraries, including rails.

Ruby never closes an object, so you can come along at any time and add, or redefine, existing methods. Just keep in mind that if a method is written in C, and you redefine it in ruby, you will take a performance hit. Use this feature with care, but don't put it on a pedestal.

Version your ruby!

How would you go about installing ruby? If you said apt-get install ruby or brew install ruby or anything similar, wrong. Go to the back of the class. While this is the simplest way to get up and running with ruby, what happens down the road when they release a new version of ruby and you have to update. Or what if you have some mission-critical script you need to run, that only runs on ruby 1.8, and you're running 1.9?

The answer is simple: use a tool to version your ruby! There are currently 2 well supported and popular tools, rbenv and rvm. I prefer rbenv, but that does not mean its any better or worse than rvm. These tools take a little longer to get set up, particularly rbenv, which, on some platforms, requires some extra packages to be able to install ruby, but the end result is something beautiful: you can have as many different versions of ruby on your machine as you want, and switch between them on the fly. You can even configure certain directories to use one version of ruby, while others use another.

These tools often come with something called a “gemset”, but this idea has fallen out of favor with the advent of bundler.

Use gemfiles and bundler

Its all too easy to write a simple script that only has 2 or 3 dependencies, and then distribute said script with a readme telling people what gems to install. This is simple, but its also inelegant, and doesn't grow well. What if you want to add more dependencies? Do you tell people to install more gems? These gems are now polluting their system pool, and they may accidentally uninstall them later.

The solution? Use bundler! Bundler is a program that is built to manage gems, dependencies, and even ruby versions for scripts. It replaces the archaic gemsets, and does a much better job. Basically, with bundler, you write a Gemfile that says which gems (and optionally which versions) your script needs, then you distribute this alongside your script. Anyone installing your script will run bundle install alongside it, and this will ensure they have all the dependencies. Better yet, depending on their config, it will prevent gems they install from leaking out into their system, and polluting their other projects.

Seek help when you need it

Ruby has one of the best communities out there, full of friendly, awesome people. You may have heard of pythonistas or other language fanatics bashing the ruby community for having “rockstars”, but I haven't found this to be the case. I'd say its because the community is so charismatic and friendly that, to people who aren't used to it, or are used to their own jaded communities, it appears as rock-star-ism. Thats a word now.

If you're stuck on a problem, and can't find the answer via googling, don't be afraid to ask for help. There is a great ruby channel on freenode, #ruby, full of helpful people. There is also tons of help on stackoverflow, and the various ruby mailing lists. You should never feel like you're without help.

Rails tips

All the above tips apply to ruby as a whole, but rails is complex enough to really be considered a subset of ruby. It has its own very specific conventions, and, due to its focused nature on web apps, its a little more constraining. That said, its still flexible enough to bend it to do whatever you want, be it a simple blog (like the one you're reading right now), or a full-fledged social network.

Embrace MVC

Novices to web programming tend to disregard MVC, and go about sticking logic in views, disregarding controllers, and writing sloppy models. Then, whenever they inevitably pass the app on to someone else or become proficient enough to want to clean up their code, a large amount of hair is torn out, and the world doesn't need more baldness.

MVC, or model-view-controller, is a programming methodology that favors the compartmentalization of tasks. Data is stored in a model, usually this is a database, but it can be a file system or even a sensor input. Views handle the presentation of the data, and are usually what the user sees and interacts with. The controller stitches the two together, controls what data gets sent to the views, which views to render, and other tasks.

You should put most of your logic into your controllers, and keep the views as close to plain text as possible. This is not to say don't use tokens or interpolation in views, you should, but you shouldn't have massive blocks of logic in your views.

You should not have view-specific info in your controllers. You shouldn't make strings that the view just renders verbatim (this is bad for translation and makes maintaining code difficult). You should instead just pass raw data to the view, and let it figure out what to do with it. This may sound like it clashes with what I just told you about views. It doesn't, but its a tricky line.

Finally, in your models, you should only have logic that dictates how things are saved, fetched, and modified. This includes validators that ensure the data matches what you expect, hooks that do things such as massage ugly data into a more manageable form on save or retrieval, and similar. Of all three prongs of MVC, models are often the simplest.

Helpers everywhere

Rails ships with a ton of helpers out of the box, and these do all sorts of things to save time, such as formatting numbers, or rendering “pretty” dates, such as “12 hours ago”. There are various types of helpers, but generally the most useful are the view helpers. These let you manage irritating aspects of modern language, such as pluralization, number formatting, currency, as well as things made overly complicated by HTML, such as forms, tables, and so forth.

If you're in a rails app, the helpers make writing your code easier, they are included with the app, and you don't take a performance hit for using them. So do so! There is nothing wrong with it, and nothing write about “wanting to write your own way of doing it.” Why reproduce code someone else already wrote, and thousands of other people looked over?

Gems can reduce boilerplate

There are a large number of gems out there that serve to simplify building complex web applications. They range from everything to features for a social site to google analytics.

If you find yourself writing the same code over and over again for some functionality, why not check to see if there's a gem out there. If other people have had to write your code, someone has probably written a gem to do it. If not, you could write one, and distribute it, and others will surely thank you.

You can always learn

I wasn't sure where to put this block, as it applies to both sections, so I'll stick it here. You can always learn more about ruby, rails, programming, and even life. Just because you're proficient doesn't mean someone else hasn't discovered a new, more efficient way to do something.

I subscribe to railscasts for exactly this reason, because Ryan Bates knows what he's talking about, and I'm constantly learning things. Even if you just discover some little gem that simplifies your problem, you've saved yourself time.