Skip to content

Commit

Permalink
update extension docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Escalante committed Jan 27, 2014
1 parent c110bd9 commit 5a7e274
Showing 1 changed file with 27 additions and 27 deletions.
54 changes: 27 additions & 27 deletions docs/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ Roots Extension API

If there is more functionality you want to add to roots, you can probably do this with a plugin. There are a number of plugins that are officially maintained:

- [dynamic-content](#)
- [layouts](#)
- [precompiled-templates](#)
- [roots-dynamic-content](#)
- [roots-layouts](#)
- [roots-precompiled-templates](#)
- [roots-browserify](#)
- [json-content](#)
- [roots-json-content](#)

There are also plenty of extensions that are not officially maintained and are still awesome. We will soon have a directory listing of these on the roots website for your sorting and browsing pleasure.

Expand All @@ -29,7 +29,7 @@ class YellExtension

#### File Sorting

Ok, there's a start. Now, in order to get into the filesystem scanning portion, we want to define a category that we'll sort the targeted files into, as well as a function that we can use to detect whether this is a file we want to separate into our own category, which, for this extension, means that it's filename will be in all uppercase. We can do this by adding `category` and `detect` properties to a `fs` object on the class.
Ok, there's a start. Now, in order to get into the filesystem scanning portion, we want to define a category that we'll sort the targeted files into, as well as a function that we can use to detect whether this is a file we want to separate into our own category, which, for this extension, means that it's filename will be in all uppercase. We can do this by defining a `fs` method on the class which returns an object with `category` and `detect` properties.

```coffee
path = require 'path'
Expand All @@ -38,10 +38,10 @@ class YellExtension

constructor: (@opts = {}) ->

@fs =
category: 'upcased'
detect: (f) ->
path.basename(f) == path.basename(f).toUpperCase()
fs: ->
category: 'upcased'
detect: (f) ->
path.basename(f) == path.basename(f).toUpperCase()
```

So category is just a string (we can use this later), and detect is a function which is fed a full file path for each file that's run through. Here, we just run a simple comparison to see if the basename is all uppercase. The `detect` function also can return a promise if you are running an async operation. Do note that speed is important in roots, so make sure you have considered the speed impacts of your extension. That means try not to for example read the full contents of a file synchronously, because that could take quite a while in a larger project.
Expand All @@ -55,11 +55,11 @@ class YellExtension

constructor: (@opts = {}) ->

@fs =
category: 'upcased'
extract: true
detect: (f) ->
path.basename(f) == path.basename(f).toUpperCase()
fs: ->
category: 'upcased'
extract: true
detect: (f) ->
path.basename(f) == path.basename(f).toUpperCase()
```

Finally, it's possible that you actually need your category to be compiled **before** anything else compiles. For example, dynamic content is compiled before anything else, because it makes locals available to all other view templates. Since roots compiles all files as quickly as possible, compiling dynamic content alongside normal views would result in race conditions where only some dynamic content would be available in the rest of the views. For that reason, the extension must ensure that the entire "dynamic" category is finished compiling before the rest of the project begins. This of course has speed implications as well which should be considered, but if it's necessary, it's necessary.
Expand All @@ -77,19 +77,19 @@ class YellExtension

constructor: (@opts = {}) ->

@fs =
category: 'upcased'
extract: true
detect: (f) ->
path.basename(f) == path.basename(f).toUpperCase()
fs: ->
category: 'upcased'
extract: true
detect: (f) ->
path.basename(f) == path.basename(f).toUpperCase()

@compile_hooks =
after_file: (ctx) =>
if ctx.category == @fs.category
ctx.content = ctx.content.toUpperCase()
compile_hooks: ->
after_file: (ctx) =>
if ctx.category == @fs.category
ctx.content = ctx.content.toUpperCase()
```

So let's talk about this. First, we have the `compile_hooks` object, which has 4 potential hooks, one that we've seen: `before_file`, `after_file`, `before_pass`, and `after_pass`. The "pass" hooks fire once for each compile pass taken on the file (files can have multiple extensions and be compiled multiple times), and the "file" hooks fire once per file, no matter how many extensions it has or how many times it is compiled. Each hook is passed a context object, which is an instance of a class. The file hooks get an instance of the [CompileFile class](https://github.com/jenius/roots/blob/v3%23extension-api/lib/compiler.coffee#L20), and the pass hooks get the [CompilePass class](https://github.com/jenius/roots/blob/v3%23extension-api/lib/compiler.coffee#L59). The information available in each class will be listed in the next section.
So let's talk about this. First, we have the `compile_hooks` method, which returns an object with 4 potential hooks, one that we've seen: `before_file`, `after_file`, `before_pass`, and `after_pass`. The "pass" hooks fire once for each compile pass taken on the file (files can have multiple extensions and be compiled multiple times), and the "file" hooks fire once per file, no matter how many extensions it has or how many times it is compiled. Each hook is passed a context object, which is an instance of a class. The file hooks get an instance of the [CompileFile class](https://github.com/jenius/roots/blob/v3%23extension-api/lib/compiler.coffee#L20), and the pass hooks get the [CompilePass class](https://github.com/jenius/roots/blob/v3%23extension-api/lib/compiler.coffee#L59). The information available in each class will be listed in the next section.

After this hook, the file goes on to be written, and all is well! Only one caveat, if you return false or a promise for false from the `after_file` hook, the file **will not be written**.

Expand All @@ -102,14 +102,14 @@ You can get at and/or change any piece of data that roots holds on to through th
- roots: roots base class instance, holds on to all config info
- category: the name of the category that the file being compiled is in
- path: absolute path to the file
- adapters: array of all [accord]() adapters being used to compile the file
- adapters: array of all [accord](https://github.com/jenius/accord) adapters being used to compile the file
- options: options being passed to the compile adapter
- content: self-explanitory

#### "Pass" Hooks

- file: the entire object documented directly above this
- adapter: the [accord]() adapter being used to compile the current pass
- adapter: the [accord](https://github.com/jenius/accord) adapter being used to compile the current pass
- index: the number of the current pass
- content: self-explanitory

Expand All @@ -121,7 +121,7 @@ There is one more hook you can use that will fire only when all the files in a g

class FooBar

@category_hooks =
category_hooks: ->
after: (ctx, category) ->
console.log "finished up with #{category}!"

Expand Down

0 comments on commit 5a7e274

Please sign in to comment.