UNPKG

15.2 kBMarkdownView Raw
1About [<img src="https://secure.travis-ci.org/1602/compound.png" />](http://travis-ci.org/#!/1602/compound) [![Code Climate](https://codeclimate.com/repos/550d7c5c69568077bd01488f/badges/e7b56f30b1a89120a1f5/gpa.svg)](https://codeclimate.com/repos/550d7c5c69568077bd01488f/feed)
2=====
3
4<img src="https://raw.github.com/1602/compound/master/templates/public/images/compound.png" />
5
6CompoundJS - MVC framework for NodeJS&trade;. It allows you to build web application in minutes.
7
8Compound modules now available at https://github.com/compoundjs
9
10Full documentation is available at http://compoundjs.com/ and using man(1).
11
12Installation
13============
14
15Option 1: npm
16
17```sh
18sudo npm install compound -g
19```
20
21Option 2: GitHub
22
23```sh
24sudo npm install 1602/compound
25```
26
27Usage
28=====
29
30```sh
31# initialize app
32compound init blog && cd blog
33npm install
34
35# generate scaffold
36compound generate crud post title content published:boolean
37
38# run server on port 3000
39compound s 3000
40
41# visit app
42open http://localhost:3000/posts
43```
44
45Short functionality review
46==========================
47
48CLI tool
49--------
50
51```
52$ compound help
53Usage: compound command [argument(s)]
54
55Commands:
56 h, help Display usage information
57 i, init Initialize compound app
58 g, generate [smth] Generate something awesome
59 r, routes [filter] Display application routes
60 c, console Debug console
61 s, server [port] Run compound server
62 install [module] Installs a compound module and patches the autoload file
63```
64
65#### compound init [appname][ option(s)]
66
67```
68options:
69 --coffee # Default: no coffee by default
70 --tpl jade|ejs # Default: ejs
71 --css sass|less|stylus # Default: stylus
72 --db redis|mongodb|nano|mysql|sqlite3|postgres
73 # Default: memory
74```
75
76#### compound generate smth
77
78smth = generator name (controller, model, scaffold, ...can be extended via plugins)
79
80more information about generators available here:
81http://compoundjs.github.com/generators
82
83#### compound server 8000
84
85equals to `PORT=8000 node server` - run server on port `8000`
86
87#### compound console
88
89run debugging console (see details below)
90
91#### compound routes
92
93print routes map (see details below)
94
95
96Directory structure
97-------------------
98
99On initialization directories tree generated, like that:
100
101```
102.
103|-- app
104| |-- assets
105| | |-- coffeescripts
106| | | `-- application.coffee
107| | `-- stylesheets
108| | `-- application.styl
109| |-- controllers
110| | |-- admin
111| | | |-- categories_controller.js
112| | | |-- posts_controller.js
113| | | `-- tags_controller.js
114| | |-- comments_controller.js
115| | `-- posts_controller.js
116| |-- models
117| | |-- category.js
118| | |-- post.js
119| | `-- tag.js
120| |-- tools
121| | `-- database.js
122| |-- views
123| | |-- admin
124| | | `-- posts
125| | | |-- edit.ejs
126| | | |-- index.ejs
127| | | |-- new.ejs
128| | |-- layouts
129| | | `-- application_layout.ejs
130| | |-- partials
131| | `-- posts
132| | |-- index.ejs
133| | `-- show.ejs
134| `-- helpers
135| |-- admin
136| | |-- posts_helper.js
137| | `-- tags_helper.js
138| `-- posts_helper.js
139`-- config
140 |-- database.json
141 |-- routes.js
142 |-- tls.cert
143 `-- tls.key
144```
145
146HTTPS Support
147-------------
148
149Just place your key and cert into config directory, compound will use it.
150Default names for keys are `tls.key` and `tls.cert`, but you can store in in another place, in that case just pass filenames to createServer function:
151`server.js`
152
153```js
154require('compound').createServer({
155 key: fs.readFileSync('/tmp/tls.key').toString(),
156 cert: fs.readFileSync('/tmp/tls.cert').toString()
157});
158```
159
160Few helpful commands:
161
162```sh
163# generate private key
164openssl genrsa -out /tmp/tls.key
165# generate cert
166openssl req -new -x509 -key /tmp/tls.key -out /tmp/tls.cert -days 1095 -batch
167```
168
169Routing
170-------
171
172Now we do not have to tediously describe REST routes for each resource, enough to write in `config/routes.js` code like this:
173
174```js
175exports.routes = function (map) {
176 map.resources('posts', function (post) {
177 post.resources('comments');
178 });
179};
180```
181
182instead of:
183
184```js
185var ctl = require('./lib/posts_controller.js');
186app.get('/posts/new.:format?', ctl.new);
187app.get('/posts.:format?', ctl.index);
188app.post('/posts.:format?', ctl.create);
189app.get('/posts/:id.:format?', ctl.show);
190app.put('/posts/:id.:format?', ctl.update);
191app.delete('/posts/:id.:format?', ctl.destroy);
192app.get('/posts/:id/edit.:format?', ctl.edit);
193
194var com_ctl = require('./lib/comments_controller.js');
195app.get('/posts/:post_id/comments/new.:format?', com_ctl.new);
196app.get('/posts/:post_id/comments.:format?', com_ctl.index);
197app.post('/posts/:post_id/comments.:format?', com_ctl.create);
198app.get('/posts/:post_id/comments/:id.:format?', com_ctl.show);
199app.put('/posts/:post_id/comments/:id.:format?', com_ctl.update);
200app.delete('/posts/:post_id/comments/:id.:format?', com_ctl.destroy);
201app.get('/posts/:post_id/comments/:id/edit.:format?', com_ctl.edit);
202```
203
204and you can more finely tune the resources to specify certain actions, middleware, and other. Here are example routes for [my blog][1]:
205
206```js
207exports.routes = function (map) {
208 map.get('/', 'posts#index');
209 map.get(':id', 'posts#show');
210 map.get('sitemap.txt', 'posts#map');
211
212 map.namespace('admin', function (admin) {
213 admin.resources('posts', {middleware: basic_auth, except: ['show']}, function (post) {
214 post.resources('comments');
215 post.get('likes', 'posts#likes')
216 });
217 });
218};
219```
220
221since version 0.2.0, it is possible to use generic routes:
222
223```js
224exports.routes = function (map) {
225 map.get(':controller/:action/:id');
226 map.all(':controller/:action');
227};
228```
229
230if you have `custom_controller` with `test` action inside it you can now do:
231
232```
233GET /custom/test
234POST /custom/test
235GET /custom/test/1 // also sets params.id to 1
236```
237
238for debugging routes described in `config/routes.js` you can use `compound routes` command:
239
240```
241$ compound routes
242 GET / posts#index
243 GET /:id posts#show
244 sitemap.txt GET /sitemap.txt posts#map
245 adminPosts GET /admin/posts.:format? admin/posts#index
246 adminPosts POST /admin/posts.:format? admin/posts#create
247 newAdminPost GET /admin/posts/new.:format? admin/posts#new
248 editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit
249 adminPost DELETE /admin/posts/:id.:format? admin/posts#destroy
250 adminPost PUT /admin/posts/:id.:format? admin/posts#update
251likesAdminPost PUT /admin/posts/:id/likes.:format? admin/posts#likes
252```
253
254Filter by method:
255
256```
257$ compound routes GET
258 GET / posts#index
259 GET /:id posts#show
260 sitemap.txt GET /sitemap.txt posts#map
261 adminPosts GET /admin/posts.:format? admin/posts#index
262 newAdminPost GET /admin/posts/new.:format? admin/posts#new
263 editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit
264```
265
266Filter by helper name:
267
268```
269$ compound routes Admin
270 newAdminPost GET /admin/posts/new.:format? admin/posts#new
271 editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit
272likesAdminPost PUT /admin/posts/:id/likes.:format? admin/posts#likes
273```
274
275
276Helpers
277-------
278
279In addition to regular helpers `linkTo`, `formFor`, `javascriptIncludeTag`, `formFor`, etc. there are also helpers for routing: each route generates a helper method that can be invoked in a view:
280
281```html
282<%- link_to("New post", newAdminPost) %>
283<%- link_to("New post", editAdminPost(post)) %>
284```
285
286generates output:
287
288```html
289<a href="/admin/posts/new">New post</a>
290<a href="/admin/posts/10/edit">New post</a>
291```
292
293Controllers
294-----------
295
296The controller is a module containing the declaration of actions such as this:
297
298```js
299beforeFilter(loadPost, {only: ['edit', 'update', 'destroy']});
300
301action('index', function () {
302 Post.allInstances({order: 'created_at'}, function (collection) {
303 render({ posts: collection });
304 });
305});
306
307action('create', function () {
308 Post.create(req.body, function () {
309 redirect(pathTo.adminPosts);
310 });
311});
312
313action('new', function () {
314 render({ post: new Post });
315});
316
317action('edit', function () {
318 render({ post: request.post });
319});
320
321action('update', function () {
322 request.post.save(req.locale, req.body, function () {
323 redirect(pathTo.adminPosts);
324 });
325});
326
327function loadPost () {
328 Post.find(req.params.id, function () {
329 request.post = this;
330 next();
331 });
332}
333```
334
335## Generators ##
336
337Compound offers several built-in generators: for a model, controller and for
338initialization. Can be invoked as follows:
339
340```js
341compound generate [what] [params]
342```
343
344`what` can be `model`, `controller` or `scaffold`. Example of controller generation:
345
346```
347$ compound generate controller admin/posts index new edit update
348exists app/
349exists app/controllers/
350create app/controllers/admin/
351create app/controllers/admin/posts_controller.js
352create app/helpers/
353create app/helpers/admin/
354create app/helpers/admin/posts_helper.js
355exists app/views/
356create app/views/admin/
357create app/views/admin/posts/
358create app/views/admin/posts/index.ejs
359create app/views/admin/posts/new.ejs
360create app/views/admin/posts/edit.ejs
361create app/views/admin/posts/update.ejs
362```
363
364Currently it generates only `*.ejs` views
365
366Models
367------
368
369Checkout [JugglingDB][2] docs to see how to work with models.
370
371CompoundJS Event model
372----------------------
373
374Compound application loading process supports following events to be attached
375(in chronological order):
376
3771. configure
3782. after configure
3793. routes
3804. extensions
3815. after extensions
3826. structure
3837. models
3848. initializers
385
386REPL console
387------------
388
389To run REPL console use command
390
391```sh
392compound console
393```
394
395or its shortcut
396
397```sh
398compound c
399```
400
401It's just simple node-js console with some Compound bindings, e.g. models. Just one note
402about working with console: Node.js is asynchronous by its nature, and it's great
403but it made console debugging much more complicated, because you should use callbacks
404to fetch results from the database, for example. I have added one useful method to
405simplify async debugging using compound console. It's named `c`. You can pass it
406as a parameter to any function requiring callbacks, and it will store parameters passed
407to the callback as variables `_0, _1, ..., _N` where N is index in `arguments`.
408
409Example:
410
411```
412$ compound c
413compound> User.find(53, c)
414Callback called with 2 arguments:
415_0 = null
416_1 = [object Object]
417compound> _1
418{ email: [Getter/Setter],
419 password: [Getter/Setter],
420 activationCode: [Getter/Setter],
421 activated: [Getter/Setter],
422 forcePassChange: [Getter/Setter],
423 isAdmin: [Getter/Setter],
424 id: [Getter/Setter] }
425```
426
427Localization
428------------
429
430To add another language to app just create a .yml file in `config/locales`,
431for example `config/locales/jp.yml`, copy contents of `config/locales/en.yml` to new
432file and rename root node (`en` to `jp` in that case), also in `lang` section rename
433`name` to Japanese (for example).
434
435Next step - rename email files in `app/views/emails`, copy all files `*.en.html`
436and `*.en.text` to `*.jp.html` and `*.jp.text` and translate new files.
437
438NOTE: translation can contain `%` symbol(s), that means variable substitution
439
440If you don't need locales support you can turn it off in `config/environment`:
441
442```js
443app.set('i18n', 'off');
444```
445
446Logger
447-----
448
449```js
450app.set('quiet', true); // force logger to log into `log/#{app.settings.env}.log`
451compound.logger.write(msg); // to log message
452```
453
454setup custom log dir:
455
456```javascript
457app.get('log dir', '/var/log/compound-app/');
458```
459
460Configuring
461===========
462
463Compound has some configuration options allows to customize app behavior
464
465eval cache
466----------
467
468Enable controller caching, should be turned on in prod. In development mode,
469disabling the cache allows the avoidance of server restarts after each model/controller change.
470
471```js
472app.disable('eval cache'); // in config/environments/development.js
473app.enable('eval cache'); // in config/environments/production.js
474```
475
476model cache
477-----------
478
479Same option for models. When disabled, model files evaluated per each request.
480
481```js
482app.disable('model cache'); // in config/environments/development.js
483```
484
485view cache
486----------
487
488Express.js option, enables view caching.
489
490```js
491app.disable('view cache'); // in config/environments/development.js
492```
493
494quiet
495-----
496
497Write logs to `log/NODE_ENV.log`
498
499```js
500app.set('quiet', true); // in config/environments/test.js
501```
502
503merge javascripts
504-----------------
505
506Join all javascript files listed in `javascript_include_tag` into one
507
508```js
509app.enable('merge javascripts'); // in config/environments/production.js
510```
511
512merge stylesheets
513-----------------
514
515Join all stylesheet files listed in `stylesheets_include_tag` into one
516
517```js
518app.enable('merge stylesheets'); // in config/environments/production.js
519```
520
521## Custom tools
522
523Put your function to ./app/tools/toolname.js to be able to run it within application
524environment as `compound toolname` command via CLI. See example tool in generated
525example: ./app/tools/dabatase.js
526
527Optionally you can specify some usage information on your function to be able to see
528it in list of available commands (using `compound` command).
529
530```javascript
531module.exports.help = {
532 shortcut: 'db',
533 usage: 'db [migrate|update]',
534 description: 'Migrate or update database(s)'
535};
536```
537
538
539MIT License
540===========
541
542 Copyright (C) 2011 by Anatoliy Chakkaev <mail [åt] anatoliy [døt] in>
543
544 Permission is hereby granted, free of charge, to any person obtaining a copy
545 of this software and associated documentation files (the "Software"), to deal
546 in the Software without restriction, including without limitation the rights
547 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
548 copies of the Software, and to permit persons to whom the Software is
549 furnished to do so, subject to the following conditions:
550
551 The above copyright notice and this permission notice shall be included in
552 all copies or substantial portions of the Software.
553
554 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
555 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
556 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
557 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
558 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
559 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
560 THE SOFTWARE.
561
562 [1]: http://anatoliy.in
563 [2]: https://github.com/1602/jugglingdb
564
565
566[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/1602/compound/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
567