Testing your dependencies with RSpec

I’m finding that managing my projects’ code dependencies is smelling worse and worse as time goes on. Code bases get bigger and acquire libraries as they grow; a part of your project sits untouched for a few months and its particulars leave your medium-term memory, and so on.

In Rails, we can freeze lots of stuff to our vendor directories. I do that as much as possible—gems that I only use for Rails apps get frozen to vendor/gems and then uninstalled system-wide; I use the gemsonrails plugin for this. If the little gem bits aren’t necessary, you can just pistonize a repository. Old news.

That’s not going to fly for platform-compiled gems, or even compiled libraries that aren’t gems at all (since you’re possibly running several different platforms between development and production). So I’ve been cooking up ways to keep myself sane:

The Simplest Thing That Could Possibly Work, I think, is just a quick test failure when a dependency is missing. If you’re already autotesting locally, and automatically running your test suite on each production machine as part of your deployment recipe, a quick, obvious exception could save you a little misery.

What I mean by “obvious”

This all came about because I went through two development platform switches recently: first, a clean install of Leopard, and just last week, a move to Intel from my old PowerBook. Both of those hosed my gems, and although I got test failures for each “broken” part of the app, certain libraries’ lazy/quiet-loading techniques don’t raise exceptions in a way that’s obvious.

For example, Rick Olson’s fantastic attachment_fu plugin is meant to work just fine for non-image files, so if you don’t have a compatible image processing library installed, it’ll just skip the thumbnailing for images and move right along. So my image-uploading tests failed on not creating the right number of files and records. It took me way too long to figure out what was going on, so I think it’d be better if I was checking for known dependencies directly.

First try

1
2
3
4
5
6
7
8
9
10
11
12
13
14
describe User do

  it "depends on one of three image processing libraries" do
    processors = %w(image_science RMagick mini_magick)
    lambda {
      begin
        require processors.shift
      rescue LoadError, MissingSourceFile => e
        retry if processors.any? or raise e, "Make sure an image processing library is available"
      end
    }.should_not raise_error
  end

end

Pretty good, although so much space between it and end makes me sad. Also, attachment_fu’s requirements are kind of an edge-case; I want to be able to spec a requirement for only one library, or several all at once.

Less sadness with matchers

Read up: if you aren’t using matchers, you aren’t using RSpec.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
describe User do
  it "depends on an image processing library for attachment_fu" do
    one_of(:image_science, :RMagick, :mini_magick).should be_loadable
  end

  it "depends on SHA libraries for password hashing" do
    both_of('digest/sha1', 'digest/sha2').should be_loadable
  end
end

describe Event do
  it "depends on chronic for date/time string processing" do
    :chronic.should be_loadable
  end
end

describe Post do
  it "depends on a text processing library for Markdown support" do
    either_of(:maruku, :RedCloth).should be_loadable
  end

  it "depends on some XML libraries" do
    all_of(:hpricot, :builder, :haml).should be_loadable
  end
end

The matcher I wrote to do this is a little beefy, around 60 lines. To check it out, you can grab it from svn (or in the <3 warehouse), or from pastie.

I’m now using this all over the place, and it’s saved me at least a couple headaches. It’s really helpful for making sure your CI and deployment environments are up to spec, as well.

I’m sure there’s more to do—like checking gem versions. How are you checking your dependencies from platform to platform?

Update on Nov. 30, 2008: well, this was a useful experiment in writing matchers, but these days I’m just using Rails’ built-in config.gem tool. Highly recommended.

Operating Ruby-style

Operator game board with Ruby operator symbols for bones
At work I sometimes have occasion to write number-crunching C code, so I’m used to the & and | operators standing for bitwise AND and OR. I’m also a reformed PHP hacker (aren’t we all?), so I’m used to === meaning “equality without type coercion”. These definitions are only occasionally true in Ruby, because meaning depends on context: one thing I’ve come to appreciate is how many Ruby “operators” are just methods, and so they often have different implementations depending on the object receiving the method call.

Thing is, you gotta learn how to operate, Ruby-style.

Unusual operator expressions

  • & — In an integer context (Fixnum and Bignum), this is indeed a bitwise AND. But in a logical context, it’s just like && (logical AND), but without short-circuiting when the receiver (that is, the left operand) evaluates to false or nil. Both operands are always evaluated. This is because & is implemented as an instance method for the singletons TrueClass, FalseClass, and NilClass, and arguments to a method are evaluated when it’s called. (&&, on the other hand, is not a method. Like all the non-method operators and other punctuation, it’s picked up by the parser and handled in C. && is logically implemented in Ruby’s expression-evaluation function.)

    Why would you want a logical AND without short-circuiting? Got me. In fact, I have a theory that the lack of short-circuiting is just a side-effect of the method-based implementation, and that the real reason for this operator to be defined for logical evaluation is to have a stricter AND that doesn’t allow duck typing in certain scenarios, since the receiver has to be true, false, or nil:

    1
    2
    
    5 & true     # => TypeError: can't convert true into Integer
    5 && true    # => true

    I pretty much just made that up, though, and I’m all ears if you have other ideas. It strikes me that all the obvious reasons to not want short-circuiting don’t cut it in this situation: wanting to ensure that the side-effect of the right operand happens seems very un-Ruby (say, opening a file or inline assignment—why force it into a logical expression?), and wanting to have arbitrary return values for the expression doesn’t actually work because & expressions always return true or false. It works for &&, though:

    1
    2
    3
    4
    
    # returns false or integer representation of privileges for user
    def administrative_privilege_level
        is_admin? && privileges.to_i
    end
  • | — Same as &, but for OR.

  • ^ — Exclusive OR: evaluates to true if exactly one of the operands is non-false and non-nil.

Since these are just methods, you can call them using the normal syntax. Take ==, another operator-as-method: evaluating Class == Class is the same as calling Class.==(Class), that is, passing the argument Class to the instance method == on the receiver, Class, which itself is an instance of type… Class. Amen.

A few more

  • === — Used for checking, um, equaly-ness in case expressions. === is a synonym of == for many objects, but some will override === to create cool case idioms. For example, Range#=== evaluates to true if the argument is a member of the range, so you can do things like this:

    1
    2
    3
    4
    5
    6
    7
    
    def election_table
      last_initial = @last_name[0].chr.downcase
      case last_initial
        when 'a'..'m' then 1
        when 'n'..'z' then 2
      end
    end

    Note that === is called on the when expressions, passing the case object as the argument. This is backwards from what you might assume at first glance, but it’s actually much more useful this way.

    Take Module#===: it evaluates to true if the operand is an instance of the module or one of its descendants—essentially a backwards is_a?, something like is_class_of?. So you could use it in a case statement to classify objects by class. (You should have a good reason to do this, though. The benefits of duck-typing come from letting go of this explicit type-checking style.) Another is Regexp, where === evaluates to true when the operand matches. So we can classify strings by regular expression.

  • Regexp: ~ — a unary operator that is just like the more-common =~, except it always matches against $_. (The Pickaxe says: $_, a String, is “the last line read by Kernel#gets or Kernel#readline. Many string-related functions in the Kernel module operate on $_ by default. The variable is local to the current scope.”) Anyway, you can do this:

    1
    2
    
    $_ = 'rebarbative barbarism'
    ~ /barb/             # => 2

    This leaves a bad taste in my mouth, though, like something shiny you find inside a mollusk. Add a few more layers of nacre, and skip the punctuation entirely using a Regex literal as a condition:

    1
    2
    
    gets                   # reads until \n and stores input in $_
    return if /q(uit)?/    # operates on $_ magically

    But that’s even worse. It’s deprecated now and you’ll get a warning if you try it. In my opinion, the only implicit receiver you should roll with is self.

  • String: % — Used for sprintfing with a single argument or Array of arguments, like this:

    1
    2
    
    "%04x" % 61453               # => "f00d"
    "%s%.2f" % ['$', 821.3333]   # => "$821.33"
  • and, or, not — Not redefinable, but worth mentioning: these function identically to &&, ||, and !, but with super-low precedence. not has the next-higher precedence from and and or, which for some reason share the same precedence (&& beats out || usually). You can get into trouble with these:

    1
    2
    3
    4
    5
    6
    
    b = 3
    a = b or 5      # => 3, and a is set to 3
    
    b = false
    a = b || 5      # => 5, and a is set to 5
    a = b or 5      # => 5, but a is set to false (!)

    That happened because Ruby evaluated the expression as (a = b) or 5, since = has a higher precedence than or. I have to guess that this is just another feature imported from Perl that isn’t as idiomatically useful in Ruby.

Rolling your own

Now, just because many Ruby operators are implemented as methods (and can thus be overridden) doesn’t mean you can define new operators using whatever characters you want. The ability to call methods using operator syntax is hardcoded into the parser for the operators that are already defined (they’re tokens in the parser), so receiver operator argument and the unary version operator receiver won’t work. You can’t even use receiver.operator or receiver::operator, because the parser only recognizes that syntax with a name that follows the method naming conventions: a lowercase letter or underscore followed by upper- or lower-case letters, digits, or underscores, and optionally ending in !, ?, or =.

So, you can go and define all the new operators you want, but you’ll be using send to call them, since the parser won’t recognize the syntax.

1
2
3
4
5
6
7
8
9
10
class Hash
  define_method(:"<--") do
    inspect
  end
end

gadget = {:watch => :laser, :hat => :helicopter}
gadget <--               # => parse error
gadget.<--               # => parse error
gadget.send(:"<--")      # => "{:watch=>:laser, :hat=>:helicopter}"

Not much point to that. However, feel free to redefine the existing operator methods in your classes. Everything will just work like you’d expect, and your objects will be good Ruby citizens.

Update: check out Jay Phillips’ Superators gem, an interesting hack to add certain new operators to Ruby DSLs by overriding the existing binary and unary operators in sequence.

References and further reading

Thanks to Azita Mirzaian for the illustration.

Templated attributes in ActiveRecord

Vandal spraypainting a wall using an 'http://' template
On a recent project, we decided it would be nice to have “templated attributes” for certain fields in a form. A templated attribute has a helpful initial value—kind of like a default value—except that these aren’t valid data or saved in the database. They’re suggestions to the user about the expected formatting or content of a field.

So the game is:

  1. keep these values out of the database
  2. specify these values once in the model, super-duper-DRY
  3. create a user experience that clearly implies that these values are just templates for valid data

Case one: a website attribute

We wanted a website attribute to be prefilled with http:// as a suggestion to the user about proper URL formatting—most users will just enter “example.com” when prompted for a URL. This is to avoid XSS problems with javascript: URIs and the like, and to keep browsers from resolving short URLs to be internal—nothing quite like being sent to http://yoursite.com/www.theirsite.com.

(Aside: there are better ways to handle this specific situation: a :before_validation callback to fix invalid URLs and check for XSS attacks, or the fantastic white_list plugin. But for now I’m interested in the general case.)

This attribute needed certain behavior:

  • When the user hits the form, the field should be pre-filled with http:// if the real value is empty or nil.
  • If the field is left as http://, we should convert it to nil before validation.
  • Client-side: to imply that the initial value is a suggestion, we’ll make the text color gray until the user makes a change. If the user’s only change is to empty the field, we should reset it to http:// and gray again on blur.

Case two: label attributes

There’s another use case, which you’ve seen before: a text field’s initial value is used as a replacement for its label. When the user clicks in the field, the “label” disappears. My example of this is a phone attribute, where we’d like to suggest a standard US area code format. Something like (123) 555-1234.

We don’t want the user to have to delete our dummy numbers and put in their own; it’s too much work. Instead we think that the reminder will help coax the right format out of the user by itself—so this field gets blanked on focus, unlike the website attribute.

You also see this pattern used for content suggestions instead of formatting hints: for example, search fields and login forms which are space-constrained, like the built-in search in Firefox and Safari.

Get on with the plugin, already

OK, OK. So we have two kinds of templated attributes: those with starting values, which are potentially the start of valid data, and labels, which are just helpful, ephemeral reminders.

Check out the goods:

1
2
3
4
class User < ActiveRecord::Base
  templated_attribute :website, :starting_value => 'http://'
  templated_attribute :phone, :label => '(123) 555-1234'
end

Validations work as expected, since unchanged template values get removed in a :before_validation callback. So you can sprinkle on a little :validates_presence_of and :validates_format_of for a really good time.

There’s also some nice, unobtrusive Javascript you can generate to get the behavior I mentioned above. If you’re using form_for, it’s totally automatic. It gets installed when you install the plugin, or you can install and remove manually with these rake tasks:

1
2
rake templated_attribute:install
rake templated_attribute:remove

To turn off the Javascript for a given templated_attribute—say, because the generated stuff doesn’t jibe with your fancy-pantsy, AJAX-validating, Grey Poupon of a form—just throw :templated_javascript => false in the options hash for text_field or text_area. You’ll have to do any styling and event handling by yourself.

I’d like to make this work for fields other than text_field and text_area; the other contenders were file_field, which we can’t do because the Javascript security model doesn’t let us touch its value at runtime, and password_field, which I haven’t done because showing the template value would require dynamically switching the element to a text_field and back (to avoid all those asterisks). That one’s on the list, though.

Plugin resources

Thanks to Azita Mirzaian for the illustration.