Nice Little Libraries

Ruby has a lot of lovely features. The syntax is clean and simple, using meta-programming techniques is easy, the object model is great… You know, I can keep going with an endless list of features and reasons to love Ruby. By the way, one of the underestimated reasons why a programmer should learn Ruby is definitely its community. There are a lot of smart folks that use Ruby to write little great libraries, and in this article I’m going to talk about this.

I called the article nice little libraries and in particular I want to focus on the nice little part. It’s the most interesting aspect of these libraries. They are tiny chunks of code that solve problems elegantly.

andand

The andand library solves the safe navigation method problem in a really nice way. Consider the following piece of code:

person.address && person.address.zip_code

It’s a simple (and ugly) line and here comes the andand method:

require 'andand' # gem install andand
person.address.andand.zip_code

It’s a neat way of handling this kind of situation. And I like the implementation too. Please take some time to look through it, you’ll find a lot of interesting stuff. You probably know that Rails, thanks to the ActiveSupport library, provides a similar method. Indeed, the example we have just seen could be written in the following way using ActiveSupport:

require 'active<em>support/core</em>ext/object/try'
person.address.try(:zip_code)

I have to say that I prefer andand: the try method doesn’t use the dot operator. I have to pass zip_code as a symbol and it gives me the feeling that something fancy is going on with it. Some languages even have an operator to deal with this kind of problem. For example, Groovy offers a SafeNavigationOperator and CoffeScript offers an Existential Operator. I’m not a fan of this kind of solution but it’s always nice to know how other languages face these problems.

Requiring the andand library has a nice side-effect: it will give you an enhanced version of Object#tap (and defines it for Ruby versions prior 1.9.x). You can actually call tap without a block:

[1, 2, 3, 4, 5].tap.pop.map { |n| n * 2 } # => [2, 4, 6, 8]

As a last, sweet, surprise the gem offers a dont method too:

[1, 2, 3, 4, 5].dont.reverse! # => [1, 2, 3, 4, 5]

The author of this gem (raganwald) has done a lot of interesting work with Ruby and JavaScript. He also wrote another interesting library: The Invocation Construction Kit but it’s not tiny enough to cover here. Anyway, you should definitely check his github profile, you’ll find a lot of interesting code and writings.

map_by_method

map_by_method is a infamous little library. I feel that a lot of people are not familiar with it, but it is surely worth mentioning. The gem provides a map_by_magic method for the Array class. It is especially useful while working with IRB (or a Rails console). It works with ActiveRecord associations too. Nothing is better than some examples to explain how this great library works:

[1, 2, 3, 4, 5].map_by_to_s # => ["1", "2", "3", "4", "5"]

%w{foo bar baz}.map_by_reverse => ["oof", "rab", "zab"]

Nice stuff. The most interesting (and useful) feature is that map_by_method supports the following:

Product # => Product(id: integer, name: string, description: text, price: integer, created_at: datetime, updated_at: datetime)
Product.all.map_by_name_and_price # => [["foo", 50], ["bar", 100], ["faz", 150]]
Product.all.map_by_id_and_name # => [[2, "foo"], [3, "bar"], [4, "faz"]]

I recommend you take a look at the implementation. It will help you to find out that map_by_method supports other magic methods too. Actually, you can do something like:

%w{1foo 2foo 2bar 1baz 4baz}.group_by_to_i #  {1=>["1foo", "1baz"], 2=>["2foo", "2bar"], 4=>["4baz"]}

Very nice.

What Methods

Another little library that can be very useful in the console is what_methods. It provides a Object#what? that is a method finder. It’ll help you to determine which methods can be called on a given object in order to return an expected value. You can call it in the following way:

my_obj.what? expected_result

Probably a few examples are the best way to explain how this little library works:

1.9.3-p0 :001 > require 'what_methods'
 => true
1.9.3-p0 :002 > 3.5.what? 3
3.5.to_i == 3
3.5.to_int == 3
3.5.floor == 3
3.5.truncate == 3
 => [:to_i, :to_int, :floor, :truncate]
1.9.3-p0 :003 > 1.what? 2
1.succ == 2
1.next == 2
 => [:succ, :next]
1.9.3-p0 :005 > "Foo".what? "foo"
"Foo".downcase == "foo"
"Foo".downcase! == "foo"
 => [:downcase, :downcase!]
1.9.3-p0 :006 > "Foo".what? "FOO"
"Foo".upcase == "FOO"
"Foo".upcase! == "FOO"
 => [:upcase, :upcase!]

Believe it or not, the "Foo".what? "FOO" is a lifesaver for me. I can’t explain why I tend to forget the name of that method, but it is another story.

Up to now, we have seen three nice little libraries but, in my humble opinion, a collection of Ruby gems can’t be considered complete if it doesn’t list something related to testing. So below I’m going to show you a couple of testing-related projects that are really interesting.

Bacon

Bacon is a small RSpec clone (and it’s really small, check out the source code). It’s very fast (see this talk for real data) and it has a very RSpec-like syntax. I understand the objection about the external dependency now that we have MiniTest. But if you, like me, don’t love the must verb for testing and want something lighter that RSpec, then you should definitely check this one out.

interactive_rspec

Sometimes it happens that you want to test a matcher in the console. At least it happened a lot to me when I was getting familiar with RSpec. And here it is: interactive_spec.

Running the irspec command will open a special IRB console and you will be able to do something like the following:

1.9.3-p0 :005 > [].should be_empty
.

Finished in 0.00007 seconds
1 example, 0 failures
 => true
1.9.3-p0 :006 > [].should_not be_empty
RSpec::Expectations::ExpectationNotMetError: expected empty? to return false, got true

That’s gorgeous! Furthermore, the gem has a lot of other nice features. For example, it has a nice integration with Rails. Indeed, you can open a Rails console and do something like this:

irspec 'spec/requests/users_spec.rb'

That’s all for now. I hope you enjoyed the article. Actually, I’m thinking about writing other articles on the topic, so your feedback is more than welcome!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://jhu-ror.heroku.com Kalman Hazins

    Nice post.

    >> [1, 2, 3, 4, 5].map_by_to_s # => ["1", "2", "3", "4", "5"]
    >> %w{foo bar baz}.map_by_reverse => ["oof", "rab", "zab"]

    is equivalent to

    [1, 2, 3, 4, 5].map(&:to_s) and %w{foo bar baz}.map(&:reverse) which is supported without any external gems.