In my codebase, I've got something like the following, where Foo
, Bar
, and Baz
are classes:
case o
when Foo then process!
when Bar then trash!
when Baz then flag!
else raise ArgumentError, "unexpected type #{o.class}"
end
A case statement uses the ===
operator (really just a method) to compare each when
's subject with case
's object, so in this case by checking Foo === o
and then (if not truthy) Bar === o
. The semantics of a class's ===
method is to tell you whether the argument (i.e. o
) is an instance of the class (or one of its subclasses).
This behavior's lovely and convenient. Fine.
But now suppose you have a spec that exercises this code, and in your spec, you don't want to have to build out a real Foo
or a real Bar
, as they happen to be complicated to use and you really only need one or two pieces of their behavior. It's normal enough to use mocks in your specs, after all, and since this isn't Foo
's spec or Bar
's spec, you really don't want to rely on them. So you want an object o
such that for some particular class klass
, klass === o
. Welp, tough! This happens down at the C level (assuming you're using MRI, at least—but at any rate, happening at the VM level). It seems like even if you wrote a C extension, the internals work in such a way that by making this test pass, your mock object would actually get all the behavior that a real instance of klass
has. Well then.
Two options, both sucky:
- Rewrite your code just because your current implementation is unspeccable, or
- Build out an actual instance of
klass
in your spec.