Fork me on GitHub

wicked by wideopenspaces

Wicked Good extensions to Object in the vein of #andand

A few common patterns

[A] exists and has quality [B]?

In Ruby, the && operator joins two true clauses, equivalent to asking "are A and B both true?" One of the more common uses for && is checking to see if an object exists before asking it for an attribute.

  if a && a.b
    "hi"
  end
  

If we didn't check for 'a' before checking a.b, we could be asking the wrong guy about b... as in "'Hey, Mr. Nothin' - you know anything about this 'b' thing?"

Let's just say Nil (Mr. Nothing) usually throws a fit when you ask him that sort of question. But if we check for 'a' AND 'a.b' and 'a' doesn't exist, Ruby doesn't evaluate the second half of the expression. Nil gets left alone. (to be fair, most Ruby objects shout pretty loud when you ask them about a method they don't have. Some get creative and come up with things on the fly, though!)

In Rails applications, you'll commonly see:

  if (user = User.find(params[:id])) && phone = user.phone_number
    puts phone
  end

Which boils down to "if 'user' exists, then get me attribute 'phone_number' of 'user' as 'phone'"

And that's the pattern 'andand' was created to simplify. To keep Nil and friends quiet and make the pattern more elegant.

  if phone = user.andand.phone_number
    puts phone
  end

Logical Sugar for #andand

Object#et

#et is an alias for #andand for brevity. "Et" is Latin for 'and'. This works the same as 'andand', but is much shorter! ;)

  if phone = user.et.phone_number
    puts phone
  end

Object#ask

#ask is another alias for #andand. I like it the most because it describes what the pattern actually does: we ask "user, are you there, and what's your phone number?" Since we're asking nicely and not demanding an answer, our objects won't throw a fit.

    if phone = user.ask.phone_number
      puts phone
    end

Object#is

Yet another alias, this one providing the positive equivalent of 'aint', syntactically useful for places where you'd use 'andand' when checking that a boolean attribute is true.

  user.destroy if user.is.revoked?

works the same as

  user.destroy if user && user.revoked?

 

[A] exists and does NOT have quality [B]?

  if user && !user.cancelled?

Here we're checking if our user exists before checking to make sure that they haven't cancelled their account. Effectively, we want user to exist and cancelled to be false, which is why we have that (!) before the second 'user'.

Using #andand in this case won't work, because the 2nd half will evaluate to false, and stop our friendly 'if' block.

So what do we do? How would we say it in English? "if it ain't broke, don't fix it", right?

Why not do that in Ruby?

Never say ain't

Object#aint

   puts "Don't fix it!" if it.aint.broken?

works the same as

   if it && !it.broken?
    puts "Don't fix it"
   end

For those who aint from the northeast and say 'ant' when they mean their 'aunt', Object#aint is also aliased as:

   #is_not
   #isnt
   #andnot

NOTE: be wary of using 'unless' with Object#is or Object#aint -- if the method doesn't exist on the receiver (it does not respond to revoked?), both #is and #aint return nil, which can be wicked bad if you don't grok your logic.

ONE MORE NOTE: #is and #aint are intended for safely checking boolean methods. Other uses are expressly not covered under any warranty ;)

Dependencies

andand >= 1.3.1

Install

   sudo gem install wideopenspaces-wicked

If using in Rails 2.2+, add the following line to config/environment.rb:

  config.gem "wideopenspaces-wicked", :lib => 'wicked'

License

MIT

Authors

Jacob Stetser (jake@wideopenspac.es)

Contact

Jacob Stetser (jake@wideopenspac.es)

Download

You can download this project in either zip or tar formats.

You can also clone the project with Git by running:

$ git clone git://github.com/wideopenspaces/wicked