ricardobeat/cake-flour — pull request #29 by timmolendijk (2014-02-11 22:45:04+00:00)
Title: Make adapters extensible and overridable

The off-the-shelf implementation of the Stylus compiler is not sufficient for my needs (I need to define `stylus.url()` before rendering CSS). That is why I was overriding `flour.compilers.styl` by simply assigning a new function inside my `Cakefile`.

Today I upgraded Flour and I noticed that some changes were done to the software which made it suddenly impossible (as far as I can see) to override a compiler or even simply add one. The cause is a combination of the following factors:

* All compiling (et al.) takes place in `lib/file`, which in turn fetches its compilers from `adapters/compilers`. This dependency is hard-coded, so no opportunity to adjust the set of compilers from the default implementation.
* All the while, the set of compilers is still publicly available from `flour.compilers` (which is initialized from `adapters/compilers` as well!) -- to me it's pretty obvious that this should be the central collection that should be used everywhere, as that would allow us to mess with it before it is put to action by `lib/file`.
* Lastly, the implementation of `adapters/adapter` blocks extensibility as well. It only accepts new adapters from its constructor, which basically means that as soon as an adapter has been instantiated it is set in stone forever. Not even a compiler can be _added_(!)

In the corresponding pull request I addressed all these issues so to re-enable monkey-patching Flour in the `Cakefile`. To illustratie, this is what I am doing:

```
flour = require 'flour'

# Overwrite default `styl` compiler because we need a custom version:
# * We want to be able to explicitly decide in our style sheet whether we want
# to compile a file as data URL or not.
# * We always want to import `nib`.
flour.compilers.install 'styl', (file, cb) ->
stylus = require 'stylus'
nib = require 'nib'

options =
filename: file.name
paths: [file.dir]
compress: @compress ? yes

file.read (code) ->
renderer = stylus code, options
renderer.define 'inline-url', stylus.url()
renderer.use nib()
renderer.import 'nib'
renderer.render (err, css) ->
throw err if err
cb css
```

Note that the thing lacking in my suggested solution is a decent way of making `Adapter.getOptions` available to the overriding compiler function. One possible approach could be to pass `Adapter` as the `this` of the compile call. But I'm leaving it up to the package author to decide on this design issue.