karmajunkie/replay — pull request #3 by ntl (2014-03-29 18:19:04+00:00)
Title: Safely prepend Publisher initializers

This change alters `Publisher` and `EventExaminer` to use
`Module#prepend` to inject their initializers into the call chain. The
intention is to allow classes that include `Publisher` to include their
own `#initialize` method that still preserves the behavior of
`Publisher#initialize`.

Consider:

```ruby
module Foo
def initialize(*args)
puts "Foo: #{args.inspect}"
super
end
end

class A
include Foo
def initialize(arg)
puts "A: #{arg}"
end
end

class B
prepend Foo
def initilaize(arg)
puts "B: #{arg}"
end
end
```

In the case of `A`, since `Foo` is attached via `#include`, the
initializer defined in `Foo` is essentially ignored:

irb(main):046:0> A.new :foo
A: :foo
=> #

However, in `B`, since `Foo` is attacted via `#prepend`, the initializer
actually ends up behaving as if it were a superclass method of
`B#initialize`:

irb(main):045:0> B.new :foo
Foo: [:foo]
B: :foo
=> #

This `#prepend` trick works well for your initializers that actually
want to inject behavior during initialization, but ultimately stay out
of the way of any `#initialize` defined by the consuming class.

I ran into this when I tried including `Publisher` in a class that had
an initializer with arguments; I was seeing a "1 for 0" `ArgumentError`.
When I dug into the proofs, I noticed that `ReplayTest` does not
actually have an `#initialize` method of its' own.

My initial effort at producing a failing test was to subclass
`ReplayTest` within the specific proof for testing custom initializers;
however, subclassing overrode the faulty behavior and thus did not
produce a failing test. Instead, I added a constructor argument to
override the `pkey` attribute. It seemed like the least janky way to
introduce a failing test. If I made the proofs worse, I can try and
think of a better way to expose the problem I was trying to solve.

It's worth noting that this change would break ruby 1.9, which does not
have `Module#prepend`.