main
1# ** Cakefile Template ** is a Template for a common Cakefile that you may use in a coffeescript nodejs project.
2#
3# It comes baked in with 5 tasks:
4#
5# * build - compiles your src directory to your lib directory
6# * watch - watches any changes in your src directory and automatically compiles to the lib directory
7# * test - runs mocha test framework, you can edit this task to use your favorite test framework
8# * docs - generates annotated documentation using docco
9# * clean - clean generated .js files
10files = [
11 'lib'
12 'src'
13]
14
15fs = require 'fs'
16{print} = require 'util'
17{spawn, exec} = require 'child_process'
18
19try
20 which = require('which').sync
21catch err
22 if process.platform.match(/^win/)?
23 console.log 'WARNING: the which module is required for windows\ntry: npm install which'
24 which = null
25
26# ANSI Terminal Colors
27bold = '\x1b[0;1m'
28green = '\x1b[0;32m'
29reset = '\x1b[0m'
30red = '\x1b[0;31m'
31
32# Cakefile Tasks
33#
34# ## *docs*
35#
36# Generate Annotated Documentation
37#
38# <small>Usage</small>
39#
40# ```
41# cake docs
42# ```
43task 'docs', 'generate documentation', -> docco()
44
45# ## *build*
46#
47# Builds Source
48#
49# <small>Usage</small>
50#
51# ```
52# cake build
53# ```
54task 'build', 'compile source', -> build -> log ":)", green
55
56# ## *watch*
57#
58# Builds your source whenever it changes
59#
60# <small>Usage</small>
61#
62# ```
63# cake watch
64# ```
65task 'watch', 'compile and watch', -> build true, -> log ":-)", green
66
67# ## *test*
68#
69# Runs your test suite.
70#
71# <small>Usage</small>
72#
73# ```
74# cake test
75# ```
76task 'test', 'run tests', -> build -> mocha -> log ":)", green
77
78# ## *clean*
79#
80# Cleans up generated js files
81#
82# <small>Usage</small>
83#
84# ```
85# cake clean
86# ```
87task 'clean', 'clean generated files', -> clean -> log ";)", green
88
89
90# Internal Functions
91#
92# ## *walk*
93#
94# **given** string as dir which represents a directory in relation to local directory
95# **and** callback as done in the form of (err, results)
96# **then** recurse through directory returning an array of files
97#
98# Examples
99#
100# ``` coffeescript
101# walk 'src', (err, results) -> console.log results
102# ```
103walk = (dir, done) ->
104 results = []
105 fs.readdir dir, (err, list) ->
106 return done(err, []) if err
107 pending = list.length
108 return done(null, results) unless pending
109 for name in list
110 file = "#{dir}/#{name}"
111 try
112 stat = fs.statSync file
113 catch err
114 stat = null
115 if stat?.isDirectory()
116 walk file, (err, res) ->
117 results.push name for name in res
118 done(null, results) unless --pending
119 else
120 results.push file
121 done(null, results) unless --pending
122
123# ## *log*
124#
125# **given** string as a message
126# **and** string as a color
127# **and** optional string as an explanation
128# **then** builds a statement and logs to console.
129#
130log = (message, color, explanation) -> console.log color + message + reset + ' ' + (explanation or '')
131
132# ## *launch*
133#
134# **given** string as a cmd
135# **and** optional array and option flags
136# **and** optional callback
137# **then** spawn cmd with options
138# **and** pipe to process stdout and stderr respectively
139# **and** on child process exit emit callback if set and status is 0
140launch = (cmd, options=[], callback) ->
141 cmd = which(cmd) if which
142 app = spawn cmd, options
143 app.stdout.pipe(process.stdout)
144 app.stderr.pipe(process.stderr)
145 app.on 'exit', (status) -> callback?() if status is 0
146
147# ## *build*
148#
149# **given** optional boolean as watch
150# **and** optional function as callback
151# **then** invoke launch passing coffee command
152# **and** defaulted options to compile src to lib
153build = (watch, callback) ->
154 if typeof watch is 'function'
155 callback = watch
156 watch = false
157
158 options = ['-c', '-b', '-o' ]
159 options = options.concat files
160 options.unshift '-w' if watch
161 launch 'coffee', options, callback
162
163# ## *unlinkIfCoffeeFile*
164#
165# **given** string as file
166# **and** file ends in '.coffee'
167# **then** convert '.coffee' to '.js'
168# **and** remove the result
169unlinkIfCoffeeFile = (file) ->
170 if file.match /\.coffee$/
171 fs.unlink file.replace('src','lib').replace(/\.coffee$/, '.js'), ->
172 true
173 else false
174
175# ## *clean*
176#
177# **given** optional function as callback
178# **then** loop through files variable
179# **and** call unlinkIfCoffeeFile on each
180clean = (callback) ->
181 try
182 for file in files
183 unless unlinkIfCoffeeFile file
184 walk file, (err, results) ->
185 for f in results
186 unlinkIfCoffeeFile f
187
188 callback?()
189 catch err
190
191# ## *moduleExists*
192#
193# **given** name for module
194# **when** trying to require module
195# **and** not found
196# **then* print not found message with install helper in red
197# **and* return false if not found
198moduleExists = (name) ->
199 try
200 require name
201 catch err
202 log "#{name} required: npm install #{name}", red
203 false
204
205
206# ## *mocha*
207#
208# **given** optional array of option flags
209# **and** optional function as callback
210# **then** invoke launch passing mocha command
211mocha = (options, callback) ->
212 #if moduleExists('mocha')
213 if typeof options is 'function'
214 callback = options
215 options = []
216 # add coffee directive
217 options.push '--compilers'
218 options.push 'coffee:coffee-script'
219
220 launch 'mocha', options, callback
221
222# ## *docco*
223#
224# **given** optional function as callback
225# **then** invoke launch passing docco command
226docco = (callback) ->
227 #if moduleExists('docco')
228 walk 'src', (err, files) -> launch 'docco', files, callback
229