README.md in mocktail-1.0.0 vs README.md in mocktail-1.1.0
- old
+ new
@@ -551,18 +551,164 @@
them!)]
### Mocktail.explain
Test debugging is hard enough when there _aren't_ fake objects flying every
-which way, so Mocktail tries to make it a little easier by way of better
-messages throughout the library.
+which way, so Mocktail tries to make it a little easier on you. In addition to
+returning useful messages throughout the API, the gem also includes an
+introspection method `Mocktail.explain(thing)`, which returns a human-readable
+`message` and a `reference` object with useful attributes (that vary depending
+on the type of fake `thing` you pass in. Below are some things `explain()` can
+do.
+#### Fake instances created by Mocktail
+
+Any instances created by `Mocktail.of` or `Mocktail.of_next` can be passed to
+`Mocktail.explain`, and they will list out all the calls and stubbings made for
+each of their fake methods.
+
+Suppose these interactions have occurred:
+
+```ruby
+ice_tray = Mocktail.of(IceTray)
+
+Mocktail.stubs { ice_tray.fill(:tap_water, 30) }.with { :some_ice }
+
+ice_tray.fill(:tap_water, 50)
+```
+
+You can interrogate what's going on with the fake instance by passing it to
+`explain`:
+
+```ruby
+explanation = Mocktail.explain(ice_tray)
+
+explanation.reference.type #=> IceTray
+explanation.reference.double #=> The ice_tray instance
+explanation.reference.calls #=> details on each invocation of each method
+explanation.reference.stubbings #=> all stubbings configured for each method
+```
+
+Calling `explanation.message` will return:
+
+```
+This is a fake `IceTray' instance.
+
+It has these mocked methods:
+ - fill
+
+`IceTray#fill' stubbings:
+
+ fill(:tap_water, 30)
+
+`IceTray#fill' calls:
+
+ fill(:tap_water, 50)
+
+```
+
+#### Modules and classes with singleton methods replaced
+
+If you've called `Mocktail.replace()` on a class or module, it can also be
+passed to `Mocktail.explain()` for a summary of all the stubbing configurations
+and calls made against its faked singleton methods for the currently running
+thread.
+
+Imagine a `Shop` class with `self.open!` and `self.close!` singleton methods:
+
+```ruby
+Mocktail.replace(Shop)
+
+stubs { |m| Shop.open!(m.numeric) }.with { :a_bar }
+
+Shop.open!(42)
+
+Shop.close!(42)
+
+explanation = Mocktail.explain(Shop)
+
+explanation.reference.type #=> Shop
+explanation.reference.replaced_method_names #=> [:close!, :open!]
+explanation.reference.calls #=> details on each invocation of each method
+explanation.reference.stubbings #=> all stubbings configured for each method
+```
+
+And `explanation.message` will return:
+
+```ruby
+`Shop' is a class that has had its singleton methods faked.
+
+It has these mocked methods:
+ - close!
+ - open!
+
+`Shop.close!' has no stubbings.
+
+`Shop.close!' calls:
+
+ close!(42)
+
+ close!(42)
+
+`Shop.open!' stubbings:
+
+ open!(numeric)
+
+ open!(numeric)
+
+`Shop.open!' calls:
+
+ open!(42)
+
+ open!(42)
+```
+
+#### Methods on faked instances and replaced types
+
+In addition to passing the test double, you can also pass a reference to any
+fake method created by Mocktail to `Mocktail.explain`:
+
+```ruby
+ice_tray = Mocktail.of(IceTray)
+
+ice_tray.fill(:chilled, 50)
+
+explanation = Mocktail.explain(ice_tray.method(:fill))
+
+explanation.reference.receiver #=> a reference to the `ice_tray` instance
+explanation.reference.calls #=> details on each invocation of the method
+explanation.reference.stubbings #=> all stubbings configured for the method
+```
+
+The above may be handy in cases where you want to assert the number of calls of
+a method outside the `Mocktail.verify` API:
+
+```ruby
+assert_equal 1, explanation.reference.calls.size
+```
+
+The explanation will also contain a `message` like this:
+
+```
+`IceTray#fill' has no stubbings.
+
+`IceTray#fill' calls:
+
+ fill(:chilled, 50)
+```
+
+Replaced singleton methods can also be passed to `explain()`, so something like
+`Mocktail.explain(Shop.method(:open!))` from the earlier example would also work
+(with `Shop` being the `receiver` on the explanation's `reference`).
+
#### Undefined methods
-One message you'll see automatically if you try to call a method
-that doesn't exist is this one, which gives a sample definition of the method
-you had attempted to call:
+There's no API for this one, but Mocktail also offers explanations for methods
+that don't exist yet. You'll see this error message whenever you try to call a
+method that doesn't exist on a test double. The message is designed to
+facilitate "paint-by-numbers" TDD, by including a sample definition of the
+method you had attempted to call that can be copy-pasted into a source listing:
```ruby
class IceTray
end
@@ -587,11 +733,11 @@
def fill(water_type, amount)
end
end
```
-### Unexpected nils with Mocktail.explain_nils
+### Mocktail.explain_nils
Is a faked method returning `nil` and you don't understand why?
By default, methods faked by Mocktail will return `nil` when no stubbing is
satisfied. A frequent frustration, therefore, is when the way `stubs {}.with {}`
@@ -653,78 +799,9 @@
```
The `reference` object will have details of the `call` itself, an array of
`other_stubbings` defined on the faked method, and a `backtrace` to determine
which call site produced the unexpected `nil` value.
-
-#### Fake instances created by Mocktail
-
-Any instances created by `Mocktail.of` or `Mocktail.of_next` can be passed to
-`Mocktail.explain`, and they will list out all the calls and stubbings made for
-each of their fake methods.
-
-Calling `Mocktail.explain(ice_tray).message` following the example above will
-yield:
-
-```
-This is a fake `IceTray' instance.
-
-It has these mocked methods:
- - fill
-
-`IceTray#fill' stubbings:
-
- fill(:tap_water, 30)
-
-`IceTray#fill' calls:
-
- fill(:tap_water, 50)
-```
-
-#### Modules and classes with singleton methods replaced
-
-If you've called `Mocktail.replace()` on a class or module, it can also be
-passed to `Mocktail.explain()` for a summary of all the stubbing configurations
-and calls made against its faked singleton methods for the currently running
-thread.
-
-Imagine a `Shop` class with `self.open!` and `self.close!` singleton methods:
-
-```ruby
-Mocktail.replace(Shop)
-
-stubs { |m| Shop.open!(m.numeric) }.with { :a_bar }
-
-Shop.open!(42)
-
-Shop.close!(42)
-
-puts Mocktail.explain(Shop).message
-```
-
-Will print:
-
-```ruby
-`Shop' is a class that has had its singleton methods faked.
-
-It has these mocked methods:
- - close!
- - open!
-
-`Shop.close!' has no stubbings.
-
-`Shop.close!' calls:
-
- close!(42)
-
-`Shop.open!' stubbings:
-
- open!(numeric)
-
-`Shop.open!' calls:
-
- open!(42)
-```
### Mocktail.reset
This one's simple: you probably want to call `Mocktail.reset` after each test,
but you _definitely_ want to call it if you're using `Mocktail.replace` or