Skip to content

Commit ee7972c

Browse files
committed
first commit
0 parents  commit ee7972c

File tree

11 files changed

+4181
-0
lines changed

11 files changed

+4181
-0
lines changed

.gitignore

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/node_modules
2+
dump.rdb
3+
.env
4+
npm-debug.log
5+
.DS_Store
6+
/compiled
7+
8+
*.seed
9+
*.log
10+
*.csv
11+
*.dat
12+
*.out
13+
*.pid
14+
*.gz
15+
*.orig
16+
17+
dist
18+
work
19+
build
20+
pids
21+
logs
22+
results
23+
.circleci/coverage
24+
lib-cov
25+
html-report
26+
xunit.xml
27+
node_modules
28+
npm-debug.log
29+
.nyc_output
30+
31+
.project
32+
.idea
33+
.settings
34+
.iml
35+
*.sublime-workspace
36+
*.sublime-project
37+
38+
.DS_Store*
39+
ehthumbs.db
40+
Icon?
41+
Thumbs.db
42+
.AppleDouble
43+
.LSOverride
44+
.Spotlight-V100
45+
.Trashes
46+
47+
test/temp
48+
dump.rdb
49+
50+
.env
51+
workspace.xml

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Specification Design Pattern
2+
3+
"In computer programming, the **specification pattern** is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic. The pattern is frequently used in the context of domain-driven design." - Wikipedia
4+
5+
https://en.wikipedia.org/wiki/Specification_pattern
6+
7+
8+
### Commands
9+
10+
`yarn scripts` to list all scripts available
11+
12+
| yarn | Description |
13+
|----------|---------------------------------------------------------------------------|
14+
| build | (Trash and re)build the library |
15+
| cov | Run tests and generate coverage report |
16+
| cov:html | Run tests, generate the HTML coverage report, and open it in a browser |
17+
| lint | Lint all typescript source files |
18+
| tdd | Watch source files, rebuild library on changes and run tests on watch mode |
19+
| test | Test source files without compiling |
20+
| unit | Build the library, tests and run unit tests |
21+
22+
23+
### Tests
24+
25+
`yarn test` to run all unit tests
26+
27+
28+
### Debug
29+
To debug TS files, on **VSCode** press **F5** and select `TS Source File` (this task is declared on `.vscode/launch.json`).

nodemon.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"ignore": [
3+
".git",
4+
"node_modules",
5+
"src/test"
6+
],
7+
"verbose": true,
8+
"delay": 0,
9+
"watch": [
10+
"src"
11+
],
12+
"ext": "ts",
13+
"protocol": "inspector",
14+
"inspect": true,
15+
"events": {
16+
"_restart": "osascript -e 'display notification \"App restarted due to:\n'$FILENAME'\" with title \"nodemon\"'"
17+
},
18+
"env": {
19+
"NODE_ENV": "development",
20+
"DEBUG": "testing:*",
21+
"DEBUG_COLORS": true
22+
},
23+
"exec": "ts-node --inspect src/index.ts"
24+
}

package.json

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
{
2+
"name": "testing",
3+
"description": "Testing",
4+
"version": "0.1.0",
5+
"author": "Felipe Hlibco <[email protected]>",
6+
"engines": {
7+
"npm": ">=6",
8+
"yarn": ">=0.14.0"
9+
},
10+
"main": "./src/server",
11+
"license": "UNLICENSED",
12+
"private": true,
13+
"pre-commit": "lint",
14+
"scripts": {
15+
"build": "rimraf ./dist && tsc",
16+
"cov": "nyc ava",
17+
"cov:html": "rimraf ./coverage && nyc ava --reporter=html && opn coverage/index.html",
18+
"lint": "tslint --project . -s node_modules/custom-tslint-formatters/formatters 'src/**/*.+(ts|tsx)' -t grouped",
19+
"scripts": "npm-scripts-info",
20+
"start": "nodemon",
21+
"tdd": "yarn build && concurrently -r --kill-others 'npm run --silent build -- -w' 'sleepms 2000 && ava -w'",
22+
"test": "NODE_ENV=test DEBUG=test,testing:* DEBUG_COLORS=true ava-ts src/__tests__/**/*.ts",
23+
"unit": "yarn build && ava"
24+
},
25+
"scripts-info": {
26+
"build": "(Trash and re)build the library",
27+
"cov": "Run tests and generate coverage report",
28+
"cov:html": "Run tests, generate the HTML coverage report, and open it in a browser",
29+
"lint": "Lint all typescript source files",
30+
"tdd": "Watch source files, rebuild library on changes and run tests on watch mode",
31+
"test": "Test source files without compiling",
32+
"unit": "Build the library, tests and run unit tests"
33+
},
34+
"ava": {
35+
"color": true,
36+
"concurrency": 5,
37+
"failFast": true,
38+
"require": [
39+
"ts-node/register"
40+
],
41+
"source_": [
42+
"dist/__tests__/**/*.js"
43+
],
44+
"tap": false,
45+
"verbose": true,
46+
"watch": false
47+
},
48+
"nyc": {
49+
"all": true,
50+
"lines": 20,
51+
"statements": 5,
52+
"functions": 5,
53+
"branches": 5,
54+
"include": [
55+
"dist/**/*.js"
56+
],
57+
"instrument": true,
58+
"exclude": [
59+
"dist/__tests__/**/*.js"
60+
],
61+
"reporter": [
62+
"lcov",
63+
"text-summary"
64+
],
65+
"cache": true,
66+
"check-coverage": true,
67+
"report-dir": "./coverage",
68+
"sourceMap": true
69+
},
70+
"standard": {
71+
"globals": [
72+
"describe",
73+
"it",
74+
"expect",
75+
"process"
76+
]
77+
},
78+
"dependencies": {
79+
"spruce": "^1.0.3",
80+
"tslib": "^1.8.0"
81+
},
82+
"devDependencies": {
83+
"@types/node": "^8.0.47",
84+
"ava": "^0.23.0",
85+
"ava-ts": "0.23.0",
86+
"concurrently": "^3.5.0",
87+
"custom-tslint-formatters": "^2.1.1",
88+
"nodemon": "1.12.1",
89+
"npm-scripts-info": "^0.3.6",
90+
"nyc": "11.3.0",
91+
"opn-cli": "^3.1.0",
92+
"rimraf": "^2.6.2",
93+
"sinon": "4.1.1",
94+
"sleep-ms": "^2.0.1",
95+
"ts-node": "3.3.0",
96+
"tslint": "^5.8.0",
97+
"tslint-config-standard": "^7.0.0",
98+
"typescript": "2.6.1"
99+
}
100+
}

src/__tests__/specifications.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import test from 'ava'
2+
3+
import Specification, { AndSpecification, AndNotSpecification, OrSpecification, OrNotSpecification, NotSpecification } from '../specification'
4+
5+
class IsOneSpecification extends Specification {
6+
public IsSatisfiedBy (candidate) {
7+
return candidate === 1
8+
}
9+
}
10+
11+
class IsTwoSpecification extends Specification {
12+
public IsSatisfiedBy (candidate) {
13+
return candidate === 2
14+
}
15+
}
16+
17+
const IsOne = new IsOneSpecification()
18+
const IsTwo = new IsTwoSpecification()
19+
20+
// -- IsSatisfiedBy
21+
test('IsSatisfiedBy', t => {
22+
t.is(IsOne.IsSatisfiedBy(1), true)
23+
})
24+
25+
// -- And
26+
test('AndSpecification', t => {
27+
const And = new AndSpecification(IsOne, IsOne)
28+
t.is(And.IsSatisfiedBy(1), true)
29+
})
30+
31+
test('AndSpecification', t => {
32+
const And = new AndSpecification(IsOne, IsTwo)
33+
t.is(And.IsSatisfiedBy(1), false)
34+
})
35+
36+
test('AndNotSpecification', t => {
37+
const AndNot = new AndNotSpecification(IsOne, IsOne)
38+
t.is(AndNot.IsSatisfiedBy(1), false)
39+
})
40+
41+
// -- Or
42+
test('OrSpecification', t => {
43+
const Or = new OrSpecification(IsOne, IsTwo)
44+
t.is(Or.IsSatisfiedBy(1), true)
45+
})
46+
47+
test('OrSpecification', t => {
48+
const Or = new OrSpecification(IsOne, IsTwo)
49+
t.is(Or.IsSatisfiedBy(2), true)
50+
})
51+
52+
test('OrSpecification', t => {
53+
const Or = new OrSpecification(IsOne, IsTwo)
54+
t.is(Or.IsSatisfiedBy(3), false)
55+
})
56+
57+
// -- OrNot
58+
test('OrNotSpecification', t => {
59+
const OrNot = new OrNotSpecification(IsOne, IsTwo)
60+
t.is(OrNot.IsSatisfiedBy(1), true)
61+
})
62+
63+
test('OrNotSpecification', t => {
64+
const OrNot = new OrNotSpecification(IsOne, IsTwo)
65+
t.is(OrNot.IsSatisfiedBy(2), false)
66+
})
67+
68+
// -- Not
69+
test('NotSpecification', t => {
70+
const Not = new NotSpecification(IsOne)
71+
t.is(Not.IsSatisfiedBy(2), true)
72+
})

src/index.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import Specification from './specification'
2+
3+
class NumericSpecification extends Specification {
4+
public IsSatisfiedBy (candidate) {
5+
console.log('running NumericSpecification...')
6+
return typeof candidate === 'number'
7+
}
8+
}
9+
10+
class IntegerSpecification extends Specification {
11+
public IsSatisfiedBy (candidate) {
12+
console.log('>> Running IntegerSpecification...')
13+
return parseInt(candidate, 0) === candidate
14+
}
15+
}
16+
17+
class PositiveSpecification extends Specification {
18+
IsSatisfiedBy (candidate) {
19+
console.log('>> Running PositiveSpecification...')
20+
return Number(candidate) > 0
21+
}
22+
}
23+
24+
class IsZeroSpecification extends Specification {
25+
public IsSatisfiedBy (candidate) {
26+
console.log('>> Running IsZeroSpecification...')
27+
return candidate === 0
28+
}
29+
}
30+
31+
class IsNineSpecification extends Specification {
32+
public IsSatisfiedBy (candidate) {
33+
console.log('>> Running IsNineSpecification...')
34+
return candidate === 9
35+
}
36+
}
37+
38+
const IsZero = new IsZeroSpecification()
39+
const Numeric = new NumericSpecification()
40+
const Integer = new IntegerSpecification()
41+
const Positive = new PositiveSpecification()
42+
const IsNine = new IsNineSpecification()
43+
44+
// Compose specification
45+
console.log('\nStart Program')
46+
const calculateScore = Positive.And(Integer).And(Numeric).AndNot(IsZero).And(IsNine.Not())
47+
48+
// Return specification result
49+
const candidate = -9
50+
console.log(`Is Satisfied By ${candidate}: `, calculateScore.IsSatisfiedBy(candidate))

src/interfaces/specification.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default interface ISpecification {
2+
IsSatisfiedBy: Function
3+
And: Function
4+
AndNot: Function
5+
Or: Function
6+
OrNot: Function
7+
Not: Function
8+
}

0 commit comments

Comments
 (0)