この記事を読んで分かること
- pruntプラグインのデザインコンセプト
- pruntプラグインの書き方
- Cakeや他のCLIとのコラボ
pruntのデザインコンセプト
pruntプラグインは
- a) 配列を捌く関数、または
- b) (a) を返すファクトリー
である。
pruntプラグインの書き方
例えば .coffee
だけを戻すフィルターを書きます。
prunt.read('src/*')
.then(coffeeFilter) # <== これをかきます
.then(compileCoffee)
パターン(a): 配列を捌く関数
path = require 'path'
coffeeFilter = (files) ->
# files = [file1, file2, file3... ]
files.filter (file) ->
path.extname(file.filename) is '.coffee'
これを拡大してどんな拡張子にも対応できる様にしますと
パターン(b): (a) を返すファクトリー
path = require 'path'
filter = (extension) ->
(files) ->
files.filter (file) ->
path.extname(file.filename) is extension
使用例
coffeeFilter = filter '.coffee'
prunt.read('src/*')
.then(coffeeFilter) # <== これをかきます
.then(compileCoffee)
pruntプラグインの書き方 +α
以上のサンプルで分かる様にpruntではファイルクラスを使ってファイルを抽象化しています。
ファイルクラス
一つのファイル(正しくはファイルインスタンス)にはfilename
、dirname
、content
、isDirty
と四つのプロパティが有ります。isDirty
はファイルがディスクと同期されているかを表すバイナリフラッグで、コンテンツを変更すれば自動的に旗が立ち上がります。その他は説明する必要が有りませんので省略させて戴きます。
prunt.read('src/*.coffee')
.then (files) ->
files.forEach (file) ->
file.isDirty is true # false
file.content = 'foo'
file.isDirty is true # true
return files
又、ファイルにはfile.rename()
とfile.chdir()
、二つのメソッドを持っており、使う必要性は全く無いが、お役に立てれば嬉しい限りです。
非同期処理
ではlessコンパイラを書きましょう。lessコンパイラはコールバックで結果を返してくれます。
less = require 'less'
less.render file.content, (result) ->
file.content = result
ではQ.jsを使ってpromiseを生成しましょう。
Q = require 'q'
exports.less = (options = {}) ->
(files) ->
queue = files.map (file) ->
Q.nfcall(less.render, file.content) # <= returns a promise
.then (css) ->
# promise ですから結果をいじるのも簡単です。
file.content = css
file.rename file.filename.replace '.less', '.css'
return Q.all(queue)
promiseを使っているだけに非同期処理は簡単です、その簡単さが売りです。
Cakeや他のCLIとのコラボ
以下の三つだけ紹介させて戴きます。
- Cake
- Optimist
- Commander
Cake
cakeはcoffee-scriptと共にインストールされるビルドツールです。Cakefile
はMakefile
のcoffee版です。
{read} = prunt = require './index'
option '-o', '--output [DIR]', 'directory for compiled code'
task 'build', 'build prunt', (options) ->
concat = prunt.concat {filename: 'index.coffee', dirname: options.output}
coffee = prunt.coffee() # use default options
write = prunt.write() # use default options
read('src/*.coffee')
.then(concat)
.then(coffee)
.done(write)
cake
を実行するとタスクとオプションが表示されます。
$ cake
Cakefile defines the following tasks:
cake build # build prunt
-o, --output directory for compiled code
substack/node-optimist
browserifyの中の人が作ったライブラリです
#!/usr/bin/env node
var argv, coffee, concat, write;
argv = require('optimist')
.usage('prunt build tool.\nUsage: $0')
.demand('b')
.alias('b', 'build')
.describe('b', 'build prunt')
.argv;
prunt = require('./index');
if (argv.build) {
concat = prunt.concat({
filename: 'index.coffee',
dirname: '.'
});
coffee = prunt.coffee();
write = prunt.write();
read('src/*.coffee')
.then(concat)
.then(coffee)
.done(write);
}
実行するとこうなります。
$ chmod +x build.js
$ build.js
prunt build tool.
Usage: node ./test.js
Options:
-b, --build build prunt [required]
Missing required arguments: b
visionmedia/commander.js
expressとmochaの中の人が作ったライブラリです
#!/usr/bin/env node
var coffee, concat, program, prunt, write;
program = require('commander')
.version('0.1.1')
.option('-b, --build', 'build prunt')
.parse(process.argv);
prunt = require('prunt');
if (program.build) {
concat = prunt.concat({
filename: 'index.coffee',
dirname: '.'
});
coffee = prunt.coffee();
write = prunt.write();
read('src/*.coffee')
.then(concat)
.then(coffee)
.done(write);
}
実行するとこうなります。
$ chmod +x build.js
$ build.js --help
Usage: test.js [options]
Options:
-h, --help output usage information
-V, --version output the version number
-b, --build build prunt