Tuesday, March 13, 2007

Symmetric, self-referential has-one relationships in Rails

Suppose you have a Person model, and you want to represent that a Person can have a spouse. That's a self-referential relationship: the Spouse would be obviously be another Person. What makes this example a little more interesting than a standard self-referential has-one relationship is that the relationship is symmetric. You could, in theory, create the relationship from either perspective.

If we have Alice and Bob:

alice = Person.create!
bob = Person.create!

Then

alice.spouse = bob

should be just as valid as

bob.spouse = alice

The problem is that if you set the relationship up as

class Person < class_name =""> 'Person'

end

Then whoever you add the spouse to first "has" the spouse.

alice.spouse = bob

would mean that

bob.spouse

returns nil

That's clearly wrong. We want to be able to query Bob for his spouse and return Alice.

We tried a number of solutions, including overriding the getter or setter, but the solution we found easiest was to build the relationship ourselves and not use any of the built-in Rails relationship functions.


def spouse
if @spouse.nil? && !spouse_id.blank? || !@spouse.nil? && @spouse.id != spouse_id
@spouse = spouse_id.blank? ? nil : Person.find(spouse_id)
end
@spouse
end

def spouse=(new_spouse)
raise(ApplicationError, "Both persons must be saved records in order to connect.") if !new_spouse.nil? && (new_record? || new_spouse.new_record?)

unless new_spouse.nil?
new_spouse.get_a_divorce
new_spouse.set_spouse_and_id(self)
new_spouse.save!
end

get_a_divorce
set_spouse_and_id(new_spouse)
save!
end

def spouse_id=(new_spouse_id)
self.spouse = (new_spouse_id.blank? ? nil : Person.find(new_spouse_id))
save!
end

private

def set_spouse_and_id(new_spouse)
@spouse = new_spouse
self[:spouse_id] = new_spouse.nil? ? nil : new_spouse.id
end

def get_a_divorce
unless spouse.nil?
spouse.set_spouse_and_id(nil)
spouse.save!
end
end

The main points are:
Your setter has to make sure that both sides of the relationship are disconnected before joining because you never know if the key is stored in the objects you're currently dealing with, or in their *former* partners.
Your getter has to do a search for your ID if your object doesn't have a foreign-key reference because the key could be stored on either side.

Labels: , , , ,

Friday, March 09, 2007

super accesses the inaccessible

Ali and I ran across something yesterday that surprised us.
class Base; def foo; 'Base.foo'; end; end
module Mod; def foo; 'Mod.foo'; end; end
class Sub < Base
include Mod
def foo; "Sub.foo calls super => #{super}"; end
end

Sub.superclass # => Base
Sub.new.foo # => "Sub.foo calls super => Mod.foo"

Chapter 22 of the Pickaxe tells us (on page 335) that
Within the body of a method, a call to super acts just like a call to that original method, except that the search for a method body starts in the superclass of the object that was found to contain the original method.


Then (on page 340) that
If a module is included within a class definition, the module’s constants, class variables, and instance methods are effectively bundled into an anonymous (and inaccessible) superclass for that class.


It goes on to say that a module's initialize will be called if an including class's initialize calls super, but doesn't mention that this is a consequence of how super works everywhere, not special handling for initialize. (Why might one assume initialize gets special handling? Because it gets special handling with respect to visibility. Special cases create confusion.)

So it turns out super goes hunting up the chain as if the method using it hadn't been found. (I avoid using the word 'superclass' because it's ambiguous in Ruby due to the anonymous proxy classes responsible for putting mixins into the inheritance chain.) I like that Ruby works this way, but it further supports Pat Farley's case that the difference between multiple inheritance and Ruby's mixins has been grossly overstated.

Wednesday, February 21, 2007

Reopen with module_eval

Ruby has open classes, and that's cool. If you're partially defining a class and don't care whether other parts of the definition have already been loaded, then by all means take advantage of the fact that you can reopen using the same syntax you use to define in the first place.

class Sub < Base # this may create Sub or reopen it.
def asdf ... end
end

However, this is a pretty unusual case on a real project. Typically a class from a third-party library is reopened to modify its original implementation. Often a method is aliased or undefined. If the original definition hasn't been loaded already, the reopening won't accomplish its intent. Hopefully it will fail at some point during the reopening. If you're unlucky (for example if you're trying to replace a method by simply re-def'ing) you may get through your code without an error, leaving you with a very difficult to find bug.

If you're reopening in this sort of situation, I recommend using class_eval/module_eval rather than a class-declaration-style reopening.

Sub.class_eval do
def asdf ... end
end

This way, if the original class definition hasn't already been loaded, your code will fail quickly and cleanly as soon as you try to touch the class (with a NameError: uninitialized constant WhateverYouTriedToReopen) rather than more mysteriously some time later. (Always prefer failing fast and clean when practical.)

The benefit of this is even greater if you're working with Rails: If you try to call class_eval on a class that hasn't been loaded yet, the const_missing in dependencies.rb will kick in and go looking for the class you're reopening, loading it just in time for you to bend it to your will.

Saturday, February 17, 2007

Unit Testing Delegation ... Handoff!

Delegation is easy to implement in Ruby, but if you're working test-first and trying to stick to strict unit tests, it can be a challenge to specify delegation succinctly. (Some feel that delegation is so simple that it's a waste to have tests for it. This depends on how you use your tests. This isn't an article about that. If your team isn't interested in unit testing delegation, don't do it. If you find it valuable, read on.)

I recently had a fairly long discussion with Jay during a developer lunch at our current project about unit testing delegation. He and Z had implemented unit tests that mocked the def_delegators method (of Forwardable) in the class under test to reduce the size of some very wordy tests.

The tests they discovered looked something like the below, mocking the method used to access the delegate and returning a mock delegate that expected the delegate method to be invoked.
test 'delegates title to content_provider' do
o = ClassBeingTested.new
o.expects(:content_provider).returns(mock(:title => :some_title))
assert_same :some_title, o.title
end
test 'delegates sub_title to content_provider' do
o = ClassBeingTested.new
o.expects(:content_provider).returns(mock(:sub_title => :some_title))
assert_same :some_title, o.title
end
test 'delegates help_text to content_provider' do
o = ClassBeingTested.new
o.expects(:content_provider).returns(mock(:sub_title => :some_title))
assert_same :some_title, o.title
end

Or maybe it was more like this. I don't remember which.
test 'delegates to content_provider for title, sub_title, and help_text' do
o = ClassBeingTested.new
o.expects(:content_provider).at_least_once.returns(
mock(
:title => :some_title,
:sub_title => :some_sub_title,
:help_text => :some_help_text))

assert_same :some_title, o.title
assert_same :some_sub_title, o.sub_title
assert_same :some_help_text, o.help_text
end

In any case, they needed to add some new delegating behavior to the class, and they thought what had been written was awfully wordy. Maybe you think five lines to test three delegating methods is pretty good, but consider that the code under test is something like:
class ClassUnderTest
extend Forwardable
def_delegators :content_provider, :title, :sub_title, :help_text
# ... plus stuff we're not talking about here, including the method
# 'content_provider' that gets the delegate.
end

The delegation of all three methods is just one line of code! (That is, if you don't count the line where the class extends Forwardable.) Since implementing delegation is that easy, why should we have to write so much code to test the behavior?

They thought about it and tried another strategy: since the delegation plumbing is provided by Forwardable, they would test that its class methods were called correctly by mocking them out. Their new test did something like:
test 'delegates price and has_rebate? to model' do
ClassBeingTested.expects(:def_delegators).with(:model, :price, :has_rebate?)
load 'class_being_tested'
end

The method load is like require, but without caching its results and turning no-op when the file has already been loaded. It forces the class definition to run again, calling def_delegators again.

A clever solution, but it felt wrong to me.

Mock-based testing requires us to dictate to some extent what our implementation will look like. This is an evil we live with when it also provides a fairly readable description of a class's responsibilities. But here, we seemed to have lost site of the responsibility. The responsibility we want to show is that the object delegates. How it accomplishes that delegation is a detail we'd rather leave to the class. The more closely a test is tied to implementation, the more likely it is that we'll need to change the test when we change the class, even if the class's responsibilities are not being changed.

What made the test great was its brevity, but looking back at the original tests, I saw that we could have something just as brief, more readable, and which was not tied to the specific implementation. I wanted a test that looked something like this:
test 'delegates price and has_rebate? to model' do
assert(ClassUnderTest.new).delegates_to(:model).for_methods(:price, :has_rebate?)
end

but that actually exercised the delegating behavior similar to the long-hand tests we started with, so that whether delegation was declared with def_delegator, def_delegators, or implemented manually, the tests would be happy.

A fluent interface for testing simple delegation is achievable because the responsibility we're testing is so straightforward:
"When I send price or has_rebate? to the object, it should send the same messages to the object it gets from its model method and return what that returns, without any knowledge of the thing returned."


The drawback to a fluent interface is that it can be difficult to debug failures, particularly those due to misuse of the interface itself. It's easy to imagine a developer writing the following and expecting it to work.
assert(ClassUnderTest.new).delegates_to(:model)

Although that reads nicely, it doesn't actually say enough to be able to test anything. We have to be able to implement the interface in such a way that this sort of misuse won't result in tests silently doing nothing.

This seemed like a solvable problem, so I set out to implement it. The result is now available as Handoff (via gem install handoff).

As the interface worked out, assertions look like this:
assert_handoff.from(ClassUnderTest.new).to(:content_provider).for(:title, :sub_title)

It supports method names that differ between the delegating object and the delegate, as well as specification of arguments that should be propagated, for example.
assert_handoff.from(ClassUnderTest.new).to(:foo).for(:bar => :foo_bar, :baz => :foo_baz).with('arg1', :arg2, 3)

Give it a try.

Labels: ,

Saturday, February 10, 2007

A Ruby Metaprogramming Introduction

I was playing around with some unit tests to explore Ruby singleton classes on a recent flight when I decided they could be fleshed out into a pretty nice introduction to some basics of Ruby metaprogramming for those who haven't done much with Ruby (which probably includes most people who've only written Rails applications). I particularly like the format because readers can

  • read it in their syntax-highlighting editor of choice, and
  • play with the code locally to explore further.

If you want to get straight to mucking around, download this zip file, which also contains demo_test_unit_extensions.rb.

If you're not that invested yet, here it is.


require 'demo_test_unit_extensions'

class MetaprogrammingIntroduction < Test::Unit::TestCase

=begin
This is a demonstration of dynamic method definition using the private method
Module#define_method and an introduction to singleton classes (also known as
metaclasses). This is the basis of Ruby metaprogramming.

Note that I'm going to avoid use or discussion of Ruby's very important eval
methods in this article. This is only to reduce the scope of what's explained.
In practice I'd prefer module_eval or class_eval to reopening of classes or
modules or use of Object#send to invoke private methods.

Chapter 24 in the Pickaxe is your reference for the nuts and bolts of Ruby
classes. There's surprisingly little discussion of things you can do with
metaprogramming, but all the information you need is there. _why the lucky
stiff's Seeing Metaclasses Clearly is dense and opaque, but fun:
http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
=end
show "Calling define_method on a class adds an instance method to both
existing and new instances.
" do
GuineaPig = Class.new
pig = GuineaPig.new
class GuineaPig
define_method :next_integer do
@count = (@count || 0) + 1
end
end

assert_equal 1, pig.next_integer
assert_equal 2, pig.next_integer
assert_equal 1, GuineaPig.new.next_integer
end
=begin
This isn't all that cool, as we could have defined next_integer using the def
keyword. But Module#define_method allows us to do a couple of things the def
keyword doesn't.

First, we can define our method name dynamically. Module#define_method takes a
symbol or string as the method name, whereas the method name following the def
keyword must be spelled out literally. You can satisfy this by evaluating a
string of Ruby code that defines the method using def, but I usually find this
less readable than using define_method. Try them both and see which reads better
in your context.

The second interesting aspect of using define_method is that you pass it a
block, Ruby's closure.
=end
show "Method bodies created with define_method can reference the context in
which they were created.
" do
GuineaCounter = Class.new
shared_count = 0 # A new local variable.
GuineaCounter.send :define_method, :double_count do
shared_count += 1
@count ||= 0
@count += 1
[shared_count, @count]
end
first_counter = GuineaCounter.new
second_counter = GuineaCounter.new

assert_equal [1, 1], first_counter.double_count
assert_equal [2, 2], first_counter.double_count
assert_equal [3, 1], second_counter.double_count
assert_equal [4, 2], second_counter.double_count
end
=begin
Even if the method that defined the local variable shared_count completed
execution, the method in GuineaCounter will still be bound to the context of the
method. (This binding isn't simple, as the block also assigns instance variables
which obviously land in the right place. Look for a forthcoming write-up
exploring this in depth.)

Note the use of Object#send to invoke define_method, where we just reopened the
class in earlier demonstrations. This is necessary if we want the block to bind
to our local context. As mentioned earlier, I prefer module_eval or class_eval
for this, but I'm leaving those out of this article.

This next one may seem obvious, but it'll only take a moment.
=end
show "Sending define_method to a module is consistent with sending it to a
class.
" do
o = Object.new.extend(Enumerable)
# Object#extend mixes a module into an instance without affecting other
# instances of the same class.

assert(o.is_a?(Enumerable) && {}.is_a?(Enumerable))

hash = {}
Enumerable.send :define_method, :next_integer_for_enumerables do
@count_for_enumerables = (@count_for_enumerables || 0) + 1
end

assert_equal 1, o.next_integer_for_enumerables
assert_equal 1, hash.next_integer_for_enumerables
assert_equal 2, hash.next_integer_for_enumerables
assert_equal 1, Array.new.next_integer_for_enumerables
# But since we only extended that one instance of Object up above ...
assert_raises(NoMethodError) { Object.new.next_integer_for_enumerables }
end
=begin
This next point is something of a tangent, but it's important to keep in mind,
as it could bite you at some point.
=end
show "Remember that adding methods to Object puts them all over the place, so
be careful!
" do
o = Object.new
Object.send :define_method, :next_integer_for_all do
@count_for_all = (@count_for_all || 0) + 1
end

# So obviously, ...
assert_equal 1, o.next_integer_for_all
assert_equal 2, o.next_integer_for_all

# But we also now have the method in this Test::Unit::TestCase.
assert_nil @count_for_all
assert_equal 1, next_integer_for_all
assert_equal 1, @count_for_all

# Classes are Objects too, so they've all gained a class method, which
# maintains a count independent from its instances.
assert_equal 1, String.next_integer_for_all
assert_equal 2, String.next_integer_for_all
assert_equal 1, "".next_integer_for_all
end
=begin
This isn't mind-blowing, but it can be easy to accidentally call the method with
the wrong receiver if you lose track of your current context.

The takeaways from that are:
* don't add methods to Object unless you've got a damn good reason, and
* prove that you're getting the desired behavior with tests.

Now here's where the cool stuff starts! Let's talk about singleton methods and
classes.

Above, we used Object#extend to mix a module into one instance of Object without
affecting other instances or the Object class itself. You've probably also seen
that Ruby allows you to define methods on just single instances. When done the
simple way, this looks like the following:
=end
show "Methods can be defined on single instances using the def keyword.
These are referred to as 'singleton methods.'
" do
o, p = Object.new, Object.new

def o.say_hi
'hello there'
end

assert_equal 'hello there', o.say_hi
assert_raises(NoMethodError) { p.say_hi }
assert_equal ['say_hi'], o.singleton_methods
assert_true p.singleton_methods.empty?
end
=begin
So that's neat, but what if we want some of the power of Module#define_method
discussed earlier? What module or class should define_method to add a method to
just one object? The singleton class!

Classes and Modules are special objects that can hold methods for other objects
to respond to. It would have been a shame for Matz to have had to implement
another sort of method owning facility to handle singleton methods, so Ruby does
some hidden trickery when we define a method on an instance: it creates a
virtual class to hold methods specific to that object, inserting it into the
chain of classes that will be checked for methods when it's looking to handle a
message sent to the object. The object's class method will still return the
original class, but the singleton class actually gets "first dibs" at responding
to a call. These classes are hidden from ObjectSpace and created without calling
Class.new, making them hard to get a hold of.

What do we call these things? The term 'singleton class' makes some sense, as
there's only one per object. This name can be confusing though, because of the
Singleton design pattern (easily implemented in Ruby by including the stdlib
module Singleton). The term 'metaclass' is used frequently, but it comes from
other languages and really applies only to the class of a class. Matz is
considering calling singleton classes 'eigenclasses' in future versions of Ruby
to reduce confusion with other concepts. (Chances are you don't have a
preconceived notion of what 'eigenclass' ought to mean, so there's nothing to
get mixed up with these funny classes in Ruby.) I'll continue to refer to these
as 'singleton classes' for now.

How unusual is it for singleton classes to come into play? It happens far more
frequently than we think about them, because all class methods are actually
singleton methods of instances of Class. Here's a simple class with a couple
class methods.
=end
class Greeter
def greet; 'hello!'; end

def self.describe_greeting
'Mostly it''s just saying hello to people.'
end
end

def Greeter.say_more
'Actually, saying hello pretty much covers it.'
end
=begin
Notice how similar the second and third method definitions look to our singleton
method definition above. That's not a coincidence: describe_greeting and
say_more are both singleton methods of the object Greeter, an instance of the
class Class. These methods are both held in Greeter's singleton class, the first
place Ruby looks for methods when Greeter receives a message.
=end
show "So-called 'class methods' are really just singleton methods of
instances of Class.
" do
assert_equal ['describe_greeting', 'say_more'].sort, Greeter.singleton_methods.sort
end
=begin
Once you digest it, this hidden consistency makes it much easier to keep track
of what's going on in Ruby.

Now, we said above that singleton classes are hidden. How do we get at them?
Ruby gives us just one way in: the "class double-ell." Let's use this to add a
singleton method to a Greeter.
=end
show "The 'class double-ell' gets us into the definition of an object's
singleton class.
" do
jim, jane = Greeter.new, Greeter.new
class << jim
def greet_enthusiastically
self.greet.upcase
end
end

assert_equal 'HELLO!', jim.greet_enthusiastically
assert_raises(NoMethodError) { jane.greet_enthusiastically }
end
=begin
This is also a third way (besides the two we saw above) to create class methods.
It's the only one that allows Ruby's visibility modifiers to work the way
they're normally used for instance methods (where they look like keywords even
though they're really method calls).
=end
show "The 'class double-ell' can be used to create non-public class methods." do
class Greeter
class << self
private
def secret_truth
'Greeting gets old fast!'
end
public
def truth
secret_truth.gsub /old fast/, 'better with every passing year'
end
end
end
assert_raises(NoMethodError) { Greeter.secret_truth } # because it's private
assert_equal 'Greeting gets better with every passing year!', Greeter.truth
end
=begin
Now let's make these singleton classes easier to get to. We create an instance
method on Object that returns the receiver's singleton class. I use the
convention of calling this method 'metaclass,' even though it's a poor name for
reasons already discussed.
=end
class ::Object
def metaclass
class << self
self
end
end
end

show "The singleton class is a class, but not the same one returned by the
Object#class method.
" do
hash = Hash.new

assert_true hash.metaclass.is_a?(Class)
assert_false hash.class == hash.metaclass
end

show "Our method returns the same object on repeated calls to the same
receiver.
" do
hash = {}

assert_same hash.metaclass, hash.metaclass
end

show "Instances do not share the same singleton class instance." do
assert_not_same({}.metaclass, {}.metaclass)
end
=begin
I'd also like to demonstrate here that an object doesn't have a singleton class
until it's actually needed, but I can't think of a way to do that given the
hiding discussed earlier.

Get ready for a mouthful.
=end
show "The singleton class instance of a class is the superclass of the
singleton class instances of instances of that class. Phew!
" do
assert_same( {}.metaclass.superclass, Hash.metaclass)
end
=begin
I can't think of any reason that's useful, but there it is. The same goes for
singleton classes of classes (true metaclasses).
=end
show "Same diff when the instance in question is a class." do
assert_same Hash.metaclass.superclass, Class.metaclass
end

show "Bizarrely, same diff even when the instance in question is Class
itself!
" do
assert_same Class.metaclass.superclass, Class.metaclass
end
=begin
Right this moment, it appears the inheritance chain of singleton classes may
change in the next version of Ruby. See this relatively awesome distillation of
changes in play for Ruby 1.9:
http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9

Anyway, back to what we were trying to do: use Module#define_method to create a
singleton method.
=end
show "Calling define method on a singleton class creates a singleton
method.
" do
o = Object.new

assert_equal 0, o.singleton_methods.size

o.metaclass.send :define_method, :countdown do
(@numbers ||= (1..3).to_a.reverse.push('POW!')).shift
end

assert_equal ['countdown'], o.singleton_methods
assert_raises(NoMethodError) { Object.new.countdown }
assert_equal 3, o.countdown
assert_equal 2, o.countdown
assert_equal 1, o.countdown
assert_equal 'POW!', o.countdown
end
=begin
I'm surprised that Matz didn't put a method on Object called
define_singleton_method, allowing us to do the same thing we did above without
exposing singleton classes. To me they feel like an implementation detail we
shouldn't have needed to see.

Let's create that method now.
=end
class ::Object
def define_singleton_method name, &body
singleton_class = class << self; self; end
singleton_class.send(:define_method, name, &body)
end
end
=begin
This is functionally equivalent to _why's meta_def method, but that name bugs
me a lot, so I'm not using it.
=end
show "Use of our newly created Object#define_singleton_method to create a
singleton method without ever seeing the singleton class.
" do
o = Object.new
o.define_singleton_method :get_excited do
@excitation_rant = (@excitation_rant || "I'm getting excited.").gsub(/excited/, "really excited")
end

assert_equal "I'm getting really excited.", o.get_excited
assert_equal "I'm getting really really excited.", o.get_excited
assert_equal "I'm getting really really really excited.", o.get_excited
end
=begin
With the ability to dynamically define methods on classes and instances at
runtime, you have the tools needed for some pretty interesting metaprogramming.
Have fun with it, just keep an eye on the developers around you to see if you're
going too meta on them.

---

If you have any comments, questions, suggestions, corrections, or additions for
this write-up, please leave comments on Practical Ruby
(http://practicalruby.blogspot.com/).

Thanks to a whole bunch of people for useful feedback, particularly: Jay Fields,
Z, Chris George, Ali Aghereza, and Omar Ghaffar.
=end
end

Labels:

Monday, October 09, 2006

yaml | for here strings

From http://yaml4r.sourceforge.net/doc/

Multi-line types

Strings which span several lines can be represented in YAML as blocks. Blocks begin with either a literal '|' character or a folded '>' character. The block is then dumped into a new level of indentation:
- literal: |
A literal block keeps all
new lines when it is brought
into Ruby.
- folded: >
A folded block will get rid
of its newlines, trading them
for spaces when it is brought
into Ruby.

acts_as_state_machine initial state

When using acts_as_state_machine calling new does not set initial state; however, calling create does.

>> Offer.new
=> #<Offer:0x2554604 @new_record=true, @attributes={"name"=>nil, "updated_at"=>nil, "reference_name"=>nil, "updated_by"=>nil, "display_name"=>nil, "offer_display"=>nil, "state"=>nil, "created_at"=>nil}>
>> Offer.create
=> #<Offer:0x254c2c4 @errors=#<ActiveRecord::Errors:0x254b66c @errors={}, @base=#<Offer:0x254c2c4 ...>>, @new_record_before_save=true, @new_record=false, @attributes={"name"=>nil, "updated_at"=>Mon Oct 09 13:46:21 CDT 2006, "refeence_name"=>nil, "id"=>66, "updated_by"=>nil, "display_name"=>nil, "offer_display"=>nil, "state"=>"draft", "created_at"=>Mon Oct 09 13:46:21 CDT 2006}>


class def....
class Offer < ActiveRecord::Base
acts_as_state_machine :initial => :draft

state :draft"
...
end

Tuesday, September 26, 2006

Invalid chars in method names, allowed?

Interesting, especially in terms of creating a DSL.
irb(main):026:0> class Strange
irb(main):027:1> define_method :'10%, eh?' do
irb(main):028:2* 'yep'
irb(main):029:2> end
irb(main):030:1> end
=> #
irb(main):031:0> Strange.instance_methods.sort
=> ["10%, eh?", "==", "==="...]
irb(main):032:0> Strange.new.send :'10%, eh?'
=> "yep"