Object#andand

Get Version

1.3.1

→ ‘andand’

What

Object#andand lets us write:

@phone = Location.find(:first, ...elided... ).andand.phone
And get a guarded method invocation or safe navigation method. This snippet performs a .find on the Location class, then sends .phone to the result if the result is not nil. If the result is nil, then the expression returns nil without throwing a NoMethodError.

As Dejan Simic put it:

Why would you want to write this:

entry.at('description') && entry.at('description').inner_text
when you can write this:

entry.at('description').andand.inner_text
Why indeed! As a bonus, install andand and you will also receive an enhanced Object#tap method, at no extra charge!

Installing

sudo gem install andand

The basics

Object#andand

Ruby programmers are familiar with the two guarded assignment operators &&= and ||=. The typical use for them is when you have a variable that might be nil. For example:

first_name &&= @first_name.trim
@phone ||= '612-777-9311'
You are trimming the first name provided it isn’t nil, and you are assigning ‘612-777-9311’ to the phone if it is nil (or false, but that isn’t important right now). The other day we were discussing the guards and we agreed that we wished there was a guarded method invocation operator. Here’s an example of when you would use it:

@phone = Location.find(:first, ...elided... )&&.phone
Meaning, search the location table for the first record matching some criteria, and if you find a location, get its phone. If you don’t, get nil. (Groovy provides this exact functionality, although Groovy uses ?. instead of &&.) However, &&. won’t work because &&. is not a real Ruby operator.

Object#andand let’s us write:

@phone = Location.find(:first, ...elided... ).andand.phone
And get the same effect as:

@phone = ->(loc){ loc && loc.phone }.call(Location.find(:first, ...elided... ))
Note that because you accept any method using Ruby’s method invocation syntax, you can accept methods with parameters and/or blocks:

list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }
Object#andand emphasizes syntactic regularity: the goal was to make an &&. operation that worked like &&=. &&= looks just like normal assignment, you can use any expression on the RHS, only the semantics are different. The andand method also works just like a normal method invocation, only the semantics are modified.

Use andand to simplify your regular expression matching and extraction

Do you ever find yourself wanting to extract a single value from a string using a regular expression? For example, Ruby’s Tempfile class creates paths to files that end in .pid.n (where pid is your process id and n is some number). Do you have a path that might be a tempfile and you want to obtain the base name?

Do you currently retrieve the MatchData object, check if it is nil, and get the first matching group if it isn’t? How about:

require 'tempfile'
path = Tempfile.new('foo.bar').path
	=> "/var/folders/UZ/UZyZsbVPEWqC7tTXrQBYGU+++TI/-Tmp-/foo.bar.1280.0"
path.match('/([^/]+)\.[0-9]+\.[0-9]+$').andand[1]
	=> "foo.bar"
With .andand[1], you extract the group in the regular expression safely: if the expression matches, you get the group. If the expression fails to match, you get nil. Which is what you want, isn’t it? The contents of the group if the expression matches? Why should you need more than one line for something so simple?

Enhanced Object#tap

Ruby 1.9 introduces Object#tap. This library implements Object#tap for Ruby 1.8 and enhances it. As in Ruby 1.9, you can call .tap with a block:

	blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
But like its sibling .andand, you can now call .tap with a method as well:

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

Doctor, it hurts when I do that

So don’t do that!

The popular use case for Object#tap is poor man’s debugging:

	blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
Perhaps you want to remove the tap, you can delete it:

	blah.sort.grep( /foo/ ).map { |x| x.blah }
Or, you can change it to .dont:

	blah.sort.grep( /foo/ ).dont { |xs| p xs }.map { |x| x.blah }
Like .andand and .tap, .dont works with arbitrary methods, not just blocks:

	(1..10).to_a.reverse!
	    => [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
	(1..10).to_a.dont.reverse!
	    => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

A little more background

Object#andand & Object#me in Ruby explains the original motivations, as well as providing links to similar implementations you may want to consider. A few people have pointed out that Object#andand is similar to Haskell’s Maybe monad. The Maybe Monad in Ruby is a good introduction for Ruby programmers.

That’s cool, but…

No problem, I get that andand isn’t exactly what you need. Have a look at the Invocation Construction Kit or “Ick.” The Ick gem generalizes #andand and #tap: Ick provides four useful ways to block-structure your code, the methods #let, #returning, #inside, and #my. Ick also includes four quasi-monadic invocations, #maybe, #please, #tee, and #fork.

Ick provides abstractions for building your own invocations, so you can branch out and build some of your own abstractions with Ick’s building blocks.

How to submit patches

Read the 8 steps for fixing other people’s code.

The trunk repository is svn://rubyforge.org/var/svn/andand/trunk for anonymous access.

License

This code is free to use under the terms of the MIT license.

Shout Out

Mobile Commons. Huge.

Contact

Comments are welcome. Send an email to Reginald Braithwaite.

Reginald Braithwaite, 12th July 2008
Theme extended from Paul Battley