Skip to content

Commit b954aa1

Browse files
committed
Initial commit
0 parents  commit b954aa1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2457
-0
lines changed

.gitignore

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Logs
2+
logs
3+
*.log
4+
5+
# Runtime data
6+
pids
7+
*.pid
8+
*.seed
9+
10+
# Directory for instrumented libs generated by jscoverage/JSCover
11+
lib-cov
12+
13+
# Coverage directory used by tools like istanbul
14+
coverage
15+
16+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17+
.grunt
18+
19+
# Compiled binary addons (http://nodejs.org/api/addons.html)
20+
build/Release
21+
22+
# Dependency directory
23+
# Commenting this out is preferred by some people, see
24+
# https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
25+
node_modules
26+
27+
# Users Environment Variables
28+
.lock-wscript

README.md

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
Domain-driven design in JavaScript Sample Code
2+
==============================================
3+
4+
Sample code for the Domain-driven design in JavaScript book. The code samples
5+
and additional resources are organized by chapter and example.
6+
7+
Chapter 1
8+
---------
9+
- [Express
10+
App](https://github.com/sideshowcoder/ddd-js-sample-code/tree/master/chapter_1)
11+
from chapter 1.
12+
13+
Chapter 2
14+
---------
15+
No sample code in this chapter.
16+
17+
Chapter 3
18+
---------
19+
- [Underscore](https://github.com/jashkenas/underscore) Source code is available
20+
on Github.
21+
- [Prisoner
22+
Transfer](https://github.com/sideshowcoder/ddd-js-sample-code/tree/master/chapter_3)
23+
prisoner transfer module, including the basic layout for the tests, and
24+
features runnable.
25+
26+
Chapter 4
27+
---------
28+
- Weapons: Example how aggregation of weapons could work, calling deep inside
29+
objects, which is most likely a bad idea. `node weapons/weapons.js`
30+
- Composition and Inheritance: See the appropriate subfolder.
31+
- Domain Objects: See chapter 3 prisoner transfer.
32+
- My Mock: Example mock, built using a simple object, run via `node
33+
my_mock/my_mock.js`
34+
- Simple Object: Battle Orc `node simple_objects/battle_orc.js` Orc `node
35+
simple_objects/orc.js`
36+
- Sinon Example: Example usage `sinon` for mocking, run via `npm install` to
37+
install dependencies, and `npm test`.
38+
39+
Chapter 5
40+
---------
41+
- ExaggeratingOrc `exaggerating_orc.js`, shows working with private and public
42+
methods
43+
- not a value object `not_value_objects.js`, show how objects can be modified
44+
- Value object example based on coins, `coin.js`
45+
- Using value objects in wallet `wallet.js`
46+
- Events `event.js`
47+
- Orcs repository `orcs.js`
48+
- Alternative active record style getting orcs `orcs_ar.js`
49+
- Sending letter via a postman `postman.js`
50+
51+
Chapter 6
52+
---------
53+
- sample notifier `npm install` to load the dependencies and `npm run notifier`
54+
to run the code is in `notifier.js`
55+
56+
Chapter 7
57+
---------
58+
- sample math `node math.js`
59+
- using array functions to process `node transport_time.js`
60+
- loggable example `node oo_orc.js`
61+
- state in basic objects example `node thing.js`
62+
- events `node events.js`
63+
- jumping counter managing state `node counter.js`
64+
65+
Chapter 8
66+
---------
67+
- pjax-example: run `npm install` in the `chapter_8/pjax-example` folder and run
68+
`npm start` to try it out.
69+
- ember-example: run `npm install` in the `chapter_8/ember-example` folder and run
70+
`npm start` to try it out.
71+
- `deactivate_button.html` jquery example deativating a button inline, to try it
72+
simply open in a browser.
73+
- car configuration example to work with constraints and logic `node
74+
car_configurator.js`

chapter_1/.jshintrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"asi": true
3+
}

chapter_1/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Dungeon inmate manager
2+
======================
3+
4+
Setup
5+
-----
6+
Install all the dependencies via `npm install` and run via `npm start`
7+
8+
Models
9+
------
10+
The dungeon model is defined in `models` and contains the standart logic to load
11+
and modify following ActiveRecord loosly.
12+
13+
Middelware
14+
----------
15+
Middleware defined in `middleware` is used to load the dungeon on request and
16+
inject it in the request to be used.
17+
18+
Views
19+
-----
20+
The view is defined in `views` and contains the form as well as display logic
21+
for the dungeon status.
22+
23+
Routes
24+
------
25+
The route to display the view is defined in `routes` along with the form
26+
endpoint to modify the dungeon state.
27+

chapter_1/app.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
var express = require('express')
2+
var routes = require('./routes')
3+
var http = require('http')
4+
var path = require('path')
5+
6+
var loadContext = require('./middleware/load_context')
7+
8+
var app = express()
9+
10+
app.configure(function(){
11+
app.set('port', process.env.PORT || 3000)
12+
app.set('views', __dirname + '/views')
13+
app.set('view engine', 'ejs')
14+
app.use(express.favicon())
15+
app.use(express.logger('dev'))
16+
app.use(express.bodyParser())
17+
app.use(express.methodOverride())
18+
19+
// app middleware
20+
app.use(loadContext)
21+
22+
app.use(app.router)
23+
app.use(express.static(path.join(__dirname, 'public')))
24+
})
25+
26+
app.configure('development', function(){
27+
app.use(express.errorHandler())
28+
})
29+
30+
app.get('/', routes.index)
31+
app.post('/cells/book', routes.cells.book)
32+
33+
http.createServer(app).listen(app.get('port'), function(){
34+
console.log("Express server listening on port " + app.get('port'))
35+
})

chapter_1/middleware/load_context.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var Dungeon = require('../models/dungeon')
2+
3+
module.exports = function(req, res, next) {
4+
req.context = req.context || {}
5+
Dungeon.find('main', function(err, dungeon) {
6+
req.context.dungeon = dungeon
7+
next()
8+
})
9+
}

chapter_1/models/dungeon.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
var dungeons = {}
2+
var DEFAULT_CELLS = 100
3+
4+
var Dungeon = function(cells) {
5+
this.cells = cells
6+
this.bookedCells = 0
7+
}
8+
9+
Dungeon.prototype = {
10+
get free() {
11+
return this.cells - this.bookedCells
12+
}
13+
}
14+
15+
Dungeon.prototype.book = function(number) {
16+
this.bookedCells += number
17+
}
18+
19+
Dungeon.prototype.unbook = function(number) {
20+
this.bookedCells -= number
21+
}
22+
23+
Dungeon.find = function(id, cb) {
24+
if(!dungeons[id]) {
25+
dungeons[id] = new Dungeon(DEFAULT_CELLS)
26+
}
27+
28+
cb(null, dungeons[id])
29+
}
30+
31+
module.exports = Dungeon

chapter_1/package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "application-name",
3+
"version": "0.0.1",
4+
"private": true,
5+
"scripts": {
6+
"start": "node app"
7+
},
8+
"dependencies": {
9+
"express": "3.0.3",
10+
"ejs": "*"
11+
},
12+
"devDependencies": {
13+
"node-dev": "^2.3.0"
14+
}
15+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
body {
2+
padding: 50px;
3+
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4+
}
5+
6+
a {
7+
color: #00B7FF;
8+
}

chapter_1/routes/index.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
var routes = module.exports = {
2+
index: function(req, res){
3+
res.render('index', req.context)
4+
},
5+
6+
cells: {
7+
book: function(req, res){
8+
var dungeon = req.context.dungeon
9+
var cells = parseInt(req.body.cells)
10+
if (req.body.book) {
11+
dungeon.book(cells)
12+
} else {
13+
dungeon.unbook(cells)
14+
}
15+
16+
res.redirect('/')
17+
}
18+
}
19+
}

chapter_1/views/index.ejs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Inmatr</title>
5+
<link rel='stylesheet' href='/stylesheets/style.css' />
6+
</head>
7+
<body>
8+
<div class="content">
9+
<div class="header">
10+
<h1>Inmatr</h1>
11+
12+
<p>You currently have <%= dungeon.free %> of <%= dungeon.cells %> cells
13+
available.</p>
14+
</div>
15+
16+
<form action="/cells/book" method="post">
17+
<select name="cells">
18+
<% for(var i = 1; i < 11; i++) { %>
19+
<option value="<%= i %>"><%= i %></option>
20+
<% } %>
21+
</select>
22+
<button type="submit" name="book" value="book">Book cells</button>
23+
<button type="submit" name="free" value="free">Free cells</button>
24+
</form>
25+
</div>
26+
27+
</body>
28+
</html>

chapter_3/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Prisoner Transfer
2+
=================
3+
Intial version of the prisoner transfer as module.
4+
5+
Setup
6+
-----
7+
Install the dependencies via `npm install` and run the tests and cucumber features via `npm test`.
8+

chapter_3/app.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
var express = require('express')
2+
var routes = require('./routes')
3+
var http = require('http')
4+
var path = require('path')
5+
6+
var app = express()
7+
8+
app.configure(function(){
9+
app.set('port', process.env.PORT || 3000)
10+
app.set('views', __dirname + '/views')
11+
app.set('view engine', 'ejs')
12+
app.use(express.favicon())
13+
app.use(express.logger('dev'))
14+
app.use(express.methodOverride())
15+
16+
app.use(app.router)
17+
})
18+
19+
app.configure('development', function(){
20+
app.use(express.errorHandler())
21+
})
22+
23+
// handle prisoner transfer
24+
var prisonerTransfer = require("lib/prisoner_transfer")
25+
app.post("/prisoner_transfer", function(req, res) {
26+
var dungeon = Dungeon.findById(req.params.dungeonId)
27+
var prisoner = Prisoner.findById(req.params.prisonerId)
28+
29+
prisonerTransfer(prisoner, dungeon, function(err) {
30+
var message
31+
if(err) {
32+
res.statusCode = 400
33+
message = { error: err.message }
34+
} else {
35+
res.statusCode = 201
36+
message = { success: true }
37+
}
38+
res.end(JSON.stringify(message))
39+
})
40+
})
41+
42+
43+
http.createServer(app).listen(app.get('port'), function(){
44+
console.log("Express server listening on port " + app.get('port'))
45+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Feature: Prisoner transfer to other dungeon
2+
As a dungeon master
3+
I want to make prisoner transfer an automated process
4+
So no important steps get left out
5+
6+
Scenario: Notifying other dungeons of the transfer
7+
Given I have a prisoner ready to transfer to another dungeon
8+
When I initiate the transfer
9+
Then the other dungeon should receive the prisoner
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
var prisonerTransfer = require("../../lib/prisoner_transfer")
2+
var dungeon = require("../../lib/dungeon")
3+
var prisoner = require("../../lib/inmates")
4+
var messages = require("../../lib/messages")
5+
var assert = require("assert")
6+
7+
module.exports = function () {
8+
this.Given(/^I have a prisoner ready to transfer to another dungeon$/, function (callback) {
9+
this.prisoner = inmates.Prisoner()
10+
this.remoteDungeon = dungeon.remoteDungeon()
11+
this.localDungeon = dungeon.localDungeon()
12+
this.localDungeon.inPrison(this.prisoner)
13+
this.channel = messages.Channel(this.localDungeon, this.remoteDungeon)
14+
callback()
15+
})
16+
17+
this.When(/^I initiate the transfer$/, function (callback) {
18+
prisonerTransfer(this.prisoner,
19+
this.remoteDungeon,
20+
this.localDungeon,
21+
this.channel,
22+
callback)
23+
})
24+
25+
this.Then(/^the other dungeon should receive the prisoner$/, function (callback) {
26+
assert(this.remoteDungeon.hasPrisoner(this.prisoner))
27+
callback()
28+
})
29+
}

0 commit comments

Comments
 (0)