├── .github
└── workflows
│ └── whitesource.yml
├── .gitignore
├── .jshintrc
├── .npmignore
├── .nvmrc
├── .travis.yml
├── Gruntfile.js
├── History.md
├── LICENSE
├── README.md
├── benchmark
├── base
│ └── array.benchmark.js
├── collections
│ ├── AVLTree.benchmark.js
│ ├── AnderssonTree.benchmark.js
│ ├── BinaryTree.benchmark.js
│ ├── HashTable.benchmark.js
│ └── RedBlackTree.benchmark.js
├── define.benchmark.js
└── promise.benchmark.js
├── docs-md
├── coverage.html
├── define.md
├── introduction.md
├── logging.md
├── promise.md
└── utilities.md
├── docs
├── History.html
├── assets
│ ├── css
│ │ ├── bootstrap-responsive.css
│ │ ├── bootstrap-responsive.min.css
│ │ ├── bootstrap.css
│ │ ├── bootstrap.min.css
│ │ └── prettify.css
│ ├── img
│ │ ├── glyphicons-halflings-white.png
│ │ └── glyphicons-halflings.png
│ └── js
│ │ ├── bootstrap.js
│ │ ├── bootstrap.min.js
│ │ ├── jquery.js
│ │ └── prettify.js
├── comb.html
├── comb_Promise.html
├── comb_PromiseList.html
├── comb_array.html
├── comb_async.html
├── comb_characters.html
├── comb_collections_AVLTree.html
├── comb_collections_AnderssonTree.html
├── comb_collections_BinaryTree.html
├── comb_collections_Collection.html
├── comb_collections_HashTable.html
├── comb_collections_Heap.html
├── comb_collections_Iterable.html
├── comb_collections_MaxHeap.html
├── comb_collections_MinHeap.html
├── comb_collections_Pool.html
├── comb_collections_PriorityQueue.html
├── comb_collections_Queue.html
├── comb_collections_RedBlackTree.html
├── comb_collections_Stack.html
├── comb_collections_Tree.html
├── comb_date.html
├── comb_hash.html
├── comb_logger.html
├── comb_logging_BasicConfigurator.html
├── comb_logging_Level.html
├── comb_logging_Logger.html
├── comb_logging_PropertyConfigurator.html
├── comb_logging_appenders_Appender.html
├── comb_logging_appenders_ConsoleAppender.html
├── comb_logging_appenders_FileAppender.html
├── comb_logging_appenders_JSONAppender.html
├── comb_logging_appenders_RollingFileAppender.html
├── comb_number.html
├── comb_plugins.html
├── comb_plugins_Broadcaster.html
├── comb_plugins_Middleware.html
├── comb_regexp.html
├── comb_string.html
├── define.html
├── index.html
├── introduction.html
├── logging.html
├── promise.html
└── utilities.html
├── index.js
├── lib
├── async.js
├── base
│ ├── array.js
│ ├── broadcast.js
│ ├── characters.js
│ ├── date
│ │ ├── index.js
│ │ └── transforms.js
│ ├── functions.js
│ ├── index.js
│ ├── inflections.js
│ ├── misc.js
│ ├── number.js
│ ├── object.js
│ ├── regexp.js
│ └── string.js
├── collections
│ ├── AVLTree.js
│ ├── AnderssonTree.js
│ ├── BinaryTree.js
│ ├── Collection.js
│ ├── HashTable.js
│ ├── Heap.js
│ ├── Iterable.js
│ ├── MaxHeap.js
│ ├── MinHeap.js
│ ├── Pool.js
│ ├── PriorityQueue.js
│ ├── Queue.js
│ ├── RedBlackTree.js
│ ├── Stack.js
│ ├── Tree.js
│ └── index.js
├── define.js
├── extensions
│ ├── arguments.js
│ ├── array.js
│ ├── cast.js
│ ├── date.js
│ ├── function.js
│ ├── index.js
│ ├── is.js
│ ├── number.js
│ ├── object.js
│ ├── string.js
│ └── utils.js
├── index.js
├── logging
│ ├── appenders
│ │ ├── appender.js
│ │ ├── consoleAppender.js
│ │ ├── fileAppender.js
│ │ ├── index.js
│ │ ├── jsonAppender.js
│ │ └── rollingFileAppender.js
│ ├── config.js
│ ├── index.js
│ └── level.js
├── plugins
│ ├── Broadcaster.js
│ ├── Middleware.js
│ └── index.js
└── promise.js
├── package.json
└── test
├── async.test.js
├── base.test.js
├── base
├── array.test.js
├── broadcast.test.js
├── date.test.js
├── functions.test.js
├── inflections.test.js
├── misc.test.js
├── number.test.js
├── object.test.js
├── regexp.test.js
└── string.test.js
├── collections
├── AVLTree.test.js
├── AnderssonTree.test.js
├── BinaryTree.test.js
├── Collection.test.js
├── HashTable.test.js
├── Heap.test.js
├── Iterable.test.js
├── MaxHeap.test.js
├── MinHeap.test.js
├── Pool.test.js
├── PriorityQueue.test.js
├── Queue.test.js
├── RedBlackTree.test.js
├── Stack.test.js
├── Tree.test.js
└── treeTest.helper.js
├── define.test.js
├── extensions
└── is.test.js
├── logging
├── appenders
│ ├── appender.test.js
│ ├── consoleAppender.test.js
│ ├── fileAppender.test.js
│ ├── jsonAppender.test.js
│ └── rollingFileAppender.test.js
├── config.test.js
├── level.test.js
└── logger.test.js
├── plugins
├── Broadcaster.test.js
└── Middleware.test.js
├── promise.test.js
└── promiseList.test.js
/.github/workflows/whitesource.yml:
--------------------------------------------------------------------------------
1 | name: NPM WhiteSource Scan
2 |
3 | on:
4 | pull_request:
5 | branches: [ master* ]
6 |
7 | jobs:
8 | WhiteSource-Unified-Agent:
9 | runs-on: ubuntu-latest
10 |
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | node-version: [14.x]
15 |
16 | steps:
17 | - name: Checkout https://github.com/${{ github.repository }}@${{ github.ref }}
18 | uses: actions/checkout@v2
19 | with:
20 | persist-credentials: false
21 |
22 | - name: Set up Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v1
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 |
27 | - uses: actions/cache@v2
28 | with:
29 | path: ~/.npm
30 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
31 | restore-keys: |
32 | ${{ runner.os }}-node-
33 | - name: Install dependencies
34 | run: npm install --only=prod
35 |
36 | - name: WhiteSource Unified Agent Scan
37 | env:
38 | WS_APIKEY: ${{secrets.WHITESOURCE_ORG_API_KEY}}
39 | WS_USERKEY: ${{secrets.WHITESOURCE_PRIORTIZE_USERKEY}}
40 | WS_WSS_URL: https://saas.whitesourcesoftware.com/agent
41 | WS_PRODUCTNAME: GH_${{github.event.repository.name}}
42 | WS_PROJECTNAME: GH_${{github.event.repository.name}}
43 | run: |
44 | curl -LJO https://unified-agent.s3.amazonaws.com/wss-unified-agent.jar
45 | echo Unified Agent downloaded successfully
46 | java -jar wss-unified-agent.jar
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | atlassian-ide-plugin.xml
3 | node_modules
4 | lib-cov
5 | *.iml
6 | .idea
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "predef": [
3 | "console",
4 | "setImmediate"
5 | ],
6 | "globals": {
7 | "Promise": true,
8 | "setImmediate": false
9 | },
10 | "node": true,
11 | "browser": false,
12 | "devel": true,
13 | "jquery": false,
14 | "bitwise": false,
15 | "camelcase": true,
16 | "curly": true,
17 | "eqeqeq": true,
18 | "forin": false,
19 | "immed": true,
20 | "indent": 4,
21 | "latedef": "nofunc",
22 | "newcap": true,
23 | "noarg": true,
24 | "noempty": true,
25 | "nonew": false,
26 | "plusplus": false,
27 | "quotmark": false,
28 | "regexp": false,
29 | "undef": true,
30 | "unused": false,
31 | "strict": true,
32 | "trailing": true,
33 | "white": false,
34 | "asi": false,
35 | "boss": false,
36 | "debug": false,
37 | "eqnull": true,
38 | "esnext": true,
39 | "evil": false,
40 | "expr": true,
41 | "funcscope": false,
42 | "globalstrict": false,
43 | "iterator": false,
44 | "lastsemic": false,
45 | "laxbreak": false,
46 | "laxcomma": false,
47 | "loopfunc": false,
48 | "multistr": false,
49 | "onecase": false,
50 | "proto": false,
51 | "regexdash": false,
52 | "scripturl": false,
53 | "smarttabs": false,
54 | "shadow": false,
55 | "sub": true,
56 | "supernew": true,
57 | "validthis": false
58 | }
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test
2 | node_modules
3 | examples
4 | benchmark
5 | docs
6 | support
7 | lib-cov
8 | Makefile
9 | .travis.yml
10 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v14
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | before_script:
2 | - npm install -g grunt-cli
3 |
4 | sudo: false
5 |
6 | after_script:
7 | - grunt coveralls
8 |
9 | language: node_js
10 | node_js:
11 | - "10"
12 | - "12"
13 | - "14"
14 | - "15"
15 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /*global module:false*/
3 | module.exports = function (grunt) {
4 |
5 | // Automatic module definition loading. Significantly speeds up build cycles
6 | require('jit-grunt')(grunt);
7 |
8 | // Time how long tasks take. Can help when optimizing build times
9 | require('time-grunt')(grunt);
10 |
11 | // Project configuration.
12 | var DEFAULT_COVERAGE_ARGS = ["cover", "-x", "Gruntfile.js", "--report", "none", "--print", "none", "--include-pid", "grunt", "--", "it"],
13 | path = require("path");
14 |
15 | grunt.initConfig({
16 | pkg: grunt.file.readJSON('package.json'),
17 |
18 | comb: {
19 | paths: {
20 | root: './',
21 | lib: './lib',
22 | test: './test'
23 | }
24 | },
25 |
26 | jshint: {
27 | src: [
28 | "./index.js",
29 | "<%= comb.paths.lib %>/**/*.js",
30 | "<%= comb.paths.test %>/**/*.js",
31 | "Gruntfile.js"
32 | ],
33 | options: {
34 | jshintrc: '.jshintrc'
35 | }
36 | },
37 |
38 | exec: {
39 | sendToCoveralls: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
40 | removeCoverage: "rm -rf ./coverage",
41 | removeDocs: "rm -rf docs/*",
42 | createDocs: 'coddoc -f multi-html -d ./lib --dir ./docs'
43 | },
44 |
45 | it: {
46 | all: {
47 | src: 'test/**/*.test.js',
48 | options: {
49 | timeout: 3000, // not fully supported yet
50 | reporter: 'tap'
51 | }
52 | }
53 | }
54 | });
55 |
56 | grunt.registerTask("benchmarks", "runs benchmarks", function () {
57 | var done = this.async();
58 | require("./benchmark/benchmark")()
59 | .then(function () {
60 | done(true);
61 | })
62 | .catch(function (err) {
63 | console.log(err.stack || err);
64 | done(false);
65 |
66 | });
67 | });
68 |
69 | grunt.registerTask("spawn-test-coverage", "spawn tests with coverage", function () {
70 | var done = this.async();
71 | var env = process.env;
72 | grunt.util.spawn({
73 | cmd: "./node_modules/istanbul/lib/cli.js",
74 | args: DEFAULT_COVERAGE_ARGS,
75 | opts: {stdio: 'inherit', env: env}
76 | }, function (err) {
77 | if (err) {
78 | console.log(err);
79 | done(false);
80 | } else {
81 | done();
82 | }
83 | });
84 | });
85 |
86 |
87 | grunt.registerTask("process-coverage", "process coverage obects", function () {
88 | var files = grunt.file.expand("./coverage/coverage*.json"),
89 | istanbul = require('istanbul'),
90 | collector = new istanbul.Collector(),
91 | reporter = new istanbul.Reporter(),
92 | sync = false,
93 | done = this.async();
94 |
95 | files.forEach(function (file) {
96 | collector.add(grunt.file.readJSON(file));
97 | });
98 |
99 | reporter.add('text');
100 | reporter.addAll(['lcovonly']);
101 | reporter.write(collector, sync, function (err) {
102 | if (err) {
103 | console.error(err.stack);
104 | return done(false);
105 | }
106 | console.log('All reports generated');
107 | done();
108 | });
109 | });
110 |
111 | grunt.registerTask('default', ['jshint', "test", "test-coverage", "docs"]);
112 |
113 | grunt.registerTask('test', ['it']);
114 |
115 | grunt.registerTask('coveralls', ['exec:removeCoverage', 'spawn-test-coverage', 'process-coverage', 'exec:sendToCoveralls', 'exec:removeCoverage']);
116 | grunt.registerTask('test-coverage', ['exec:removeCoverage', 'spawn-test-coverage', 'process-coverage', 'exec:removeCoverage']);
117 |
118 |
119 | grunt.registerTask("docs", ["exec:removeDocs", "exec:createDocs"]);
120 | };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2011-2012 Pollenware
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/benchmark/base/array.benchmark.js:
--------------------------------------------------------------------------------
1 | var Benchmark = require("benchmark"),
2 | comb = require("../../index.js"),
3 | array = comb.array;
4 | var suite = new Benchmark.Suite();
5 |
6 | var arr = array.flatten(array.powerSet([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
7 |
8 | // add tests
9 | suite
10 | .add('for loop ++i', function () {
11 | for (var i = 0; i < arr.length; ++i) {
12 | var item = arr[i];
13 | }
14 | })
15 | .add('for loop i++', function () {
16 | for (var i = 0; i < arr.length; i++) {
17 | var item = arr[i];
18 | }
19 | })
20 |
21 | .add('while loop', function () {
22 | var i = arr.length;
23 | while (--i) {
24 | var item = arr[i];
25 | }
26 | })
27 |
28 | .add('for loop optimized i++', function () {
29 | for (var i = 0, l = arr.length; i < l; i++) {
30 | var item = arr[i];
31 | }
32 | })
33 | .add('for loop optimized ++i', function () {
34 | for (var i = 0, l = arr.length; i < l; ++i) {
35 | var item = arr[i];
36 | }
37 | })
38 | .add('for loop backward --i', function () {
39 | for (var i = arr.length - 1; i >= 0; --i) {
40 | var item = arr[i];
41 | }
42 | })
43 | .add('for loop backward i--', function () {
44 | for (var i = arr.length - 1; i >= 0; i--) {
45 | var item = arr[i];
46 | }
47 | })
48 | .add('arr.forEach', function () {
49 | arr.forEach(function (item) {
50 | });
51 | })
52 | .add('comb([arr]).forEach', function () {
53 | comb(arr).forEach(function (item) {
54 | });
55 | })
56 | .on('cycle', function (event) {
57 | console.log(String(event.target));
58 | })
59 | .on('complete', function () {
60 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
61 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
62 | })
63 | .run();
--------------------------------------------------------------------------------
/benchmark/collections/AVLTree.benchmark.js:
--------------------------------------------------------------------------------
1 | var comb = require("../../lib"),
2 | Tree = comb.collections.AVLTree,
3 | Benchmark = require("benchmark");
4 |
5 | var suite = new Benchmark.Suite();
6 |
7 | var words = comb(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"].reverse())
8 | .powerSet()
9 | .map(function (w) {
10 | return w.join("");
11 | }).filter(function (a) {
12 | return a;
13 | });
14 | console.log("AVLTree Benchmark");
15 |
16 | suite
17 | .add("insert words in order in array", function () {
18 | var arr = [];
19 | for (var i = 0, l = words.length; i < l; i++) {
20 | arr.push(words[i]);
21 | arr.sort();
22 | }
23 | })
24 | .add("insert words into AVLTree", function () {
25 | var tree = new Tree();
26 | for (var i = 0, l = words.length; i < l; i++) {
27 | tree.insert(words[i]);
28 | }
29 | })
30 | .on('cycle', function (event) {
31 | console.log(String(event.target));
32 | })
33 | .on('complete', function () {
34 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
35 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
36 | })
37 | .run();
38 |
39 | (function () {
40 | var arr = [], tree = new Tree();
41 | for (var i = 0, l = words.length; i < l; i++) {
42 | var word = words[i];
43 | arr.push(word);
44 | tree.insert(word);
45 | }
46 | arr.sort();
47 |
48 | new Benchmark.Suite()
49 | .add("look up words in array", function () {
50 | for (var i = 0, l = words.length; i < l; i++) {
51 | var index = arr.indexOf(words[i]);
52 | if (index === -1) {
53 | console.log("INDEX ERROR");
54 | }
55 | }
56 | })
57 | .add("look up words in AVLTree", function () {
58 | for (var i = 0, l = words.length; i < l; i++) {
59 | if (!tree.contains(words[i])) {
60 | console.log("INDEX ERROR");
61 | }
62 | }
63 | })
64 | .on('cycle', function (event) {
65 | console.log(String(event.target));
66 | })
67 | .on('complete', function () {
68 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
69 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
70 | })
71 | .run();
72 |
73 | new Benchmark.Suite()
74 | .add("remove words from array", function () {
75 |
76 | });
77 |
78 | })();
79 |
80 |
--------------------------------------------------------------------------------
/benchmark/collections/AnderssonTree.benchmark.js:
--------------------------------------------------------------------------------
1 | var comb = require("../../lib"),
2 | Tree = comb.collections.AnderssonTree,
3 | Benchmark = require("benchmark");
4 |
5 | var suite = new Benchmark.Suite();
6 |
7 | var words = comb(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"].reverse())
8 | .powerSet()
9 | .map(function (w) {
10 | return w.join("");
11 | }).filter(function (a) {
12 | return a;
13 | });
14 | console.log("AnderssonTree Benchmark");
15 |
16 | suite
17 | .add("insert words in order in array", function () {
18 | var arr = [];
19 | for (var i = 0, l = words.length; i < l; i++) {
20 | arr.push(words[i]);
21 | arr.sort();
22 | }
23 | })
24 | .add("insert words into AnderssonTree", function () {
25 | var tree = new Tree();
26 | for (var i = 0, l = words.length; i < l; i++) {
27 | tree.insert(words[i]);
28 | }
29 | })
30 | .on('cycle', function (event) {
31 | console.log(String(event.target));
32 | })
33 | .on('complete', function () {
34 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
35 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
36 | })
37 | .run();
38 |
39 | (function () {
40 | var arr = [], tree = new Tree();
41 | for (var i = 0, l = words.length; i < l; i++) {
42 | var word = words[i];
43 | arr.push(word);
44 | tree.insert(word);
45 | }
46 | arr.sort();
47 |
48 | new Benchmark.Suite()
49 | .add("look up words in array", function () {
50 | for (var i = 0, l = words.length; i < l; i++) {
51 | var index = arr.indexOf(words[i]);
52 | if (index === -1) {
53 | console.log("INDEX ERROR");
54 | }
55 | }
56 | })
57 | .add("look up words in AnderssonTree", function () {
58 | for (var i = 0, l = words.length; i < l; i++) {
59 | if (!tree.contains(words[i])) {
60 | console.log("INDEX ERROR");
61 | }
62 | }
63 | })
64 | .on('cycle', function (event) {
65 | console.log(String(event.target));
66 | })
67 | .on('complete', function () {
68 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
69 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
70 | })
71 | .run();
72 |
73 | new Benchmark.Suite()
74 | .add("remove words from array", function () {
75 |
76 | });
77 |
78 | })();
79 |
80 |
--------------------------------------------------------------------------------
/benchmark/collections/BinaryTree.benchmark.js:
--------------------------------------------------------------------------------
1 | var comb = require("../../lib"),
2 | Tree = comb.collections.BinaryTree,
3 | Benchmark = require("benchmark");
4 |
5 | var suite = new Benchmark.Suite();
6 |
7 | var words = comb(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"].reverse())
8 | .powerSet()
9 | .map(function (w) {
10 | return w.join("");
11 | }).filter(function (a) {
12 | return a;
13 | });
14 | console.log("BinaryTree Benchmark");
15 |
16 | suite
17 | .add("insert words in order in array", function () {
18 | var arr = [];
19 | for (var i = 0, l = words.length; i < l; i++) {
20 | arr.push(words[i]);
21 | arr.sort();
22 | }
23 | })
24 | .add("insert words into BinaryTree", function () {
25 | var tree = new Tree();
26 | for (var i = 0, l = words.length; i < l; i++) {
27 | tree.insert(words[i]);
28 | }
29 | })
30 | .on('cycle', function (event) {
31 | console.log(String(event.target));
32 | })
33 | .on('complete', function () {
34 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
35 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
36 | })
37 | .run();
38 |
39 | (function () {
40 | var arr = [], tree = new Tree();
41 | for (var i = 0, l = words.length; i < l; i++) {
42 | var word = words[i];
43 | arr.push(word);
44 | tree.insert(word);
45 | }
46 | arr.sort();
47 |
48 | new Benchmark.Suite()
49 | .add("look up words in array", function () {
50 | for (var i = 0, l = words.length; i < l; i++) {
51 | var index = arr.indexOf(words[i]);
52 | if (index === -1) {
53 | console.log("INDEX ERROR");
54 | }
55 | }
56 | })
57 | .add("look up words in BinaryTree", function () {
58 | for (var i = 0, l = words.length; i < l; i++) {
59 | if (!tree.contains(words[i])) {
60 | console.log("INDEX ERROR");
61 | }
62 | }
63 | })
64 | .on('cycle', function (event) {
65 | console.log(String(event.target));
66 | })
67 | .on('complete', function () {
68 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
69 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
70 | })
71 | .run();
72 |
73 | new Benchmark.Suite()
74 | .add("remove words from array", function () {
75 |
76 | });
77 |
78 | })();
79 |
80 |
--------------------------------------------------------------------------------
/benchmark/collections/HashTable.benchmark.js:
--------------------------------------------------------------------------------
1 | var comb = require("../../lib"),
2 | Collection = comb.collections.HashTable,
3 | Benchmark = require("benchmark");
4 |
5 | var suite = new Benchmark.Suite();
6 |
7 | var words = comb(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"].reverse())
8 | .powerSet()
9 | .map(function (w) {
10 | return w.join("");
11 | }).filter(function (a) {
12 | return a;
13 | });
14 | console.log("HashTable Benchmark");
15 |
16 | suite
17 | .add("insert words into {}", function () {
18 | var map = {};
19 | for (var i = 0, l = words.length; i < l; i++) {
20 | var word = words[i];
21 | map[word] = word;
22 | }
23 | })
24 | .add("insert words into HashTable", function () {
25 | var collection = new Collection();
26 | for (var i = 0, l = words.length; i < l; i++) {
27 | var word = words[i];
28 | collection.put(word, word);
29 | }
30 | })
31 | .on('cycle', function (event) {
32 | console.log(String(event.target));
33 | })
34 | .on('complete', function () {
35 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
36 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
37 | })
38 | .run();
39 |
40 | (function () {
41 | var map = {}, collection = new Collection();
42 | for (var i = 0, l = words.length; i < l; i++) {
43 | var word = words[i];
44 | map[word] = word;
45 | collection.put(word, word);
46 | }
47 |
48 | new Benchmark.Suite()
49 | .add("look up words in {}", function () {
50 | for (var i = 0, l = words.length; i < l; i++) {
51 | if (!map.hasOwnProperty(words[i])) {
52 | console.log("INDEX ERROR");
53 | }
54 | }
55 | })
56 | .add("look up words in HashTable", function () {
57 | for (var i = 0, l = words.length; i < l; i++) {
58 | if (!collection.contains(words[i])) {
59 | console.log("INDEX ERROR");
60 | }
61 | }
62 | })
63 | .on('cycle', function (event) {
64 | console.log(String(event.target));
65 | })
66 | .on('complete', function () {
67 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
68 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
69 | })
70 | .run();
71 |
72 | new Benchmark.Suite()
73 | .add("remove words from array", function () {
74 |
75 | });
76 |
77 | })();
78 |
79 |
--------------------------------------------------------------------------------
/benchmark/collections/RedBlackTree.benchmark.js:
--------------------------------------------------------------------------------
1 | var comb = require("../../lib"),
2 | Tree = comb.collections.RedBlackTree,
3 | Benchmark = require("benchmark");
4 |
5 | var suite = new Benchmark.Suite();
6 |
7 | var words = comb(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"].reverse())
8 | .powerSet()
9 | .map(function (w) {
10 | return w.join("");
11 | }).filter(function (a) {
12 | return a;
13 | });
14 | console.log("RedBlackTree Benchmark");
15 |
16 | suite
17 | .add("insert words in order in array", function () {
18 | var arr = [];
19 | for (var i = 0, l = words.length; i < l; i++) {
20 | arr.push(words[i]);
21 | arr.sort();
22 | }
23 | })
24 | .add("insert words into RedBlackTree", function () {
25 | var tree = new Tree();
26 | for (var i = 0, l = words.length; i < l; i++) {
27 | tree.insert(words[i]);
28 | }
29 | })
30 | .on('cycle', function (event) {
31 | console.log(String(event.target));
32 | })
33 | .on('complete', function () {
34 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
35 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
36 | })
37 | .run();
38 |
39 | (function () {
40 | var arr = [], tree = new Tree();
41 | for (var i = 0, l = words.length; i < l; i++) {
42 | var word = words[i];
43 | arr.push(word);
44 | tree.insert(word);
45 | }
46 | arr.sort();
47 |
48 | new Benchmark.Suite()
49 | .add("look up words in array", function () {
50 | for (var i = 0, l = words.length; i < l; i++) {
51 | var index = arr.indexOf(words[i]);
52 | if (index === -1) {
53 | console.log("INDEX ERROR");
54 | }
55 | }
56 | })
57 | .add("look up words in RedBlackTree", function () {
58 | for (var i = 0, l = words.length; i < l; i++) {
59 | if (!tree.contains(words[i])) {
60 | console.log("INDEX ERROR");
61 | }
62 | }
63 | })
64 | .on('cycle', function (event) {
65 | console.log(String(event.target));
66 | })
67 | .on('complete', function () {
68 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
69 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
70 | })
71 | .run();
72 |
73 | new Benchmark.Suite()
74 | .add("remove words from array", function () {
75 |
76 | });
77 |
78 | })();
79 |
80 |
--------------------------------------------------------------------------------
/benchmark/define.benchmark.js:
--------------------------------------------------------------------------------
1 | var Benchmark = require("benchmark"),
2 | comb = require("../index.js"),
3 | define = comb.define,
4 | sys = require("sys"),
5 | array = comb.array;
6 | var suite = new Benchmark.Suite();
7 | suite.add('prototype', (function () {
8 | function User(name) {
9 | if (name) {
10 | this.name = name.trim();
11 | }
12 | }
13 |
14 | function Admin(name) {
15 | User.call(this, name);
16 | }
17 |
18 | Admin.prototype = new User();
19 | return function () {
20 | var admin = new Admin('doug');
21 | };
22 | }()));
23 | suite.add('sys.inherits()', (function () {
24 | function User(name) {
25 | if (name) {
26 | this.name = name.trim();
27 | }
28 | }
29 |
30 | function Admin(name) {
31 | User.call(this, name);
32 | }
33 |
34 | sys.inherits(Admin, User);
35 | return function () {
36 | var admin = new Admin('doug');
37 | };
38 | }()));
39 | suite.add('comb.define', (function () {
40 | var User = define(null, {
41 | instance:{
42 | constructor:function (name) {
43 | this.name = name.trim();
44 | }
45 | }
46 | });
47 | var Admin = define(User);
48 | return function () {
49 | var admin = new Admin('doug');
50 | };
51 | })());
52 | suite.on('cycle', function (event) {
53 | console.log(String(event.target));
54 | });
55 | suite.on('complete', function () {
56 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
57 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
58 | });
59 | suite.run();
60 |
61 | var suite2 = new Benchmark.Suite()
62 | .add('prototype instance',function () {
63 |
64 | function User(name) {
65 | if (name) {
66 | this.name = name.trim();
67 | }
68 | }
69 |
70 | function Admin(name) {
71 | User.call(this, name);
72 | }
73 |
74 | Admin.prototype = new User();
75 |
76 | var admin = new Admin('doug');
77 | }).add('sys.inherits() instance', function () {
78 |
79 | function User(name) {
80 | this.name = name.trim();
81 | }
82 |
83 | function Admin(name) {
84 | User.call(this, name)
85 | }
86 |
87 | sys.inherits(Admin, User);
88 | var admin = new Admin('doug');
89 | })
90 |
91 | .add('comb.define instance', function () {
92 | var User = comb.define(null, {
93 | instance:{
94 | constructor:function (name) {
95 | this.name = name.trim();
96 | }
97 | }});
98 | var Admin = define(User);
99 | var admin = new Admin('doug');
100 | })
101 | .on('cycle', function (event) {
102 | console.log(String(event.target));
103 | })
104 | .on('complete', function () {
105 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
106 | console.log('Slowest is ' + this.filter('slowest').pluck('name'));
107 | })
108 | .run();
109 |
110 |
--------------------------------------------------------------------------------
/benchmark/promise.benchmark.js:
--------------------------------------------------------------------------------
1 | function runComb() {
2 | var Promise = require("../lib/promise").Promise;
3 | var start = new Date();
4 | var i = -1,
5 | p = new Promise().callback(1);
6 |
7 | while (++i < 100000) {
8 | p = p.chain(function () {
9 | return i;
10 | });
11 | }
12 | return p.chain(function () {
13 | console.log("%d MB", (process.memoryUsage().rss / 1024 / 1024));
14 | console.log("%d ms", new Date() - start);
15 | });
16 | }
17 |
18 | function runQ() {
19 | var Q = require("q");
20 | var start = new Date();
21 | var i = -1,
22 | p = Q(1);
23 |
24 | while (++i < 100000) {
25 | p = p.then(function () {
26 | return i;
27 | });
28 | }
29 | p.then(function () {
30 | console.log("%d MB", (process.memoryUsage().rss / 1024 / 1024));
31 | console.log("%d ms", new Date() - start);
32 | });
33 | }
34 |
35 | runComb();
36 | //runQ();
37 |
38 |
--------------------------------------------------------------------------------
/docs/assets/css/prettify.css:
--------------------------------------------------------------------------------
1 | .com{color:#93a1a1}.lit{color:#195f91}.pun,.opn,.clo{color:#93a1a1}.fun{color:#dc322f}.str,.atv{color:#D14}.kwd,.linenums .tag{color:#1e347b}.typ,.atn,.dec,.var{color:teal}.pln{color:#48484c}.prettyprint{padding:8px;background-color:#f7f7f9;border:1px solid #e1e1e8}.prettyprint.linenums{-webkit-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;-moz-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0}ol.linenums{margin:0 0 0 33px}ol.linenums li{padding-left:12px;color:#bebec5;line-height:18px;text-shadow:0 1px 0 #fff}
--------------------------------------------------------------------------------
/docs/assets/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/C2FO/comb/7fb23d2f56025721592ede14165311469ad30e76/docs/assets/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/docs/assets/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/C2FO/comb/7fb23d2f56025721592ede14165311469ad30e76/docs/assets/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./lib");
--------------------------------------------------------------------------------
/lib/base/broadcast.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var func = require("./functions"),
3 | obj = require("./object");
4 |
5 | var comb = exports;
6 |
7 |
8 | var wrapper = function () {
9 | return function c() {
10 | var listeners = c.__listeners, func = c.func, r;
11 | if (func) {
12 | r = func.apply(this, arguments);
13 | }
14 | for (var i = 0; i < listeners.length; i++) {
15 | var lis = listeners[i];
16 | if (lis) {
17 | lis.apply(this, arguments);
18 | }
19 | }
20 | return r;
21 | };
22 | };
23 |
24 |
25 | var listeners = {};
26 | obj.merge(comb, {
27 | /**@lends comb*/
28 | /**
29 | * Disconnects a listener to a function
30 | * @param {handle} A handle returned from comb.connect
31 | */
32 | disconnect: function (handle) {
33 | if (handle && handle.length === 3) {
34 | var obj = handle[0], method = handle[1], cb = handle[2];
35 | if (typeof method !== "string") {
36 | throw "comb.disconnect : When calling disconnect the method must be string";
37 | }
38 | var scope = obj || global, ls;
39 | if (typeof scope[method] === "function") {
40 | ls = scope[method].__listeners;
41 | if (ls && cb-- > 0) {
42 | //we dont want to splice it because our indexing will get off
43 | ls[cb] = null;
44 | }
45 | } else {
46 | throw new Error("unknown method " + method + " in object " + obj);
47 | }
48 | } else {
49 | throw new Error("comb.disconnect : invalid handle");
50 | }
51 | },
52 |
53 | /**
54 | * Function to listen when other functions are called
55 | *
56 | * @example
57 | *
58 | * comb.connect(obj, "event", myfunc);
59 | * comb.connect(obj, "event", "log", console);
60 | *
61 | * @param {Object} obj the object in which the method you are connecting to resides
62 | * @param {String} method the name of the method to connect to
63 | * @param {Function} cb the function to callback
64 | * @param {Object} [scope] the scope to call the specified cb in
65 | *
66 | * @returns {Array} handle to pass to {@link comb.disconnect}
67 | */
68 | connect: function (obj, method, cb, scope) {
69 | var index,
70 | listeners;
71 | if (typeof method !== "string") {
72 | throw new Error("When calling connect the method must be string");
73 | }
74 | if (!func.isFunction(cb)) {
75 | throw new Error("When calling connect callback must be a string");
76 | }
77 | scope = obj || global;
78 | if (typeof scope[method] === "function") {
79 | listeners = scope[method].__listeners;
80 | if (!listeners) {
81 | var newMethod = wrapper();
82 | newMethod.func = obj[method];
83 | listeners = (newMethod.__listeners = []);
84 | scope[method] = newMethod;
85 | }
86 | index = listeners.push(cb);
87 | } else {
88 | throw new Error("unknow method " + method + " in object " + obj);
89 | }
90 | return [obj, method, index];
91 | },
92 |
93 |
94 | /**
95 | * Broadcasts an event to all listeners
96 | * NOTE : the function takes a variable number of arguments
97 | * i.e. all arguments after the topic will be passed to the listeners
98 | *
99 | * @example
100 | *
101 | *
102 | * comb.broadcast("hello", "hello world");
103 | * //the args "hello" and "world" will be passed to any listener of the topic
104 | * //"hello"
105 | * comb.broadcast("hello", "hello", "world");
106 | *
107 | * @param {String} topic the topic to brodcast
108 | * @param params the information to bradcast
109 | */
110 | broadcast: function () {
111 | var args = Array.prototype.slice.call(arguments);
112 | var topic = args.splice(0, 1)[0];
113 | if (topic) {
114 | var list = listeners[topic];
115 | if (list) {
116 | for (var i = list.length - 1; i >= 0; i--) {
117 | var han = list[i], cb = han.cb;
118 | if (cb) {
119 | cb.apply(this, args);
120 | }
121 | }
122 | }
123 | }
124 | },
125 |
126 | /**
127 | * Listen for the broadcast of certain events
128 | *
129 | * @example
130 | * comb.listen("hello", function(arg1, arg2){
131 | * console.log(arg1);
132 | * console.log(arg2);
133 | * });
134 | *
135 | * @param {String} topic the topic to listen for
136 | * @param {Function} callback the funciton to call when the topic is published
137 | *
138 | * @returns a handle to pass to {@link comb.unListen}
139 | */
140 | listen: function (topic, callback) {
141 | if (!func.isFunction(callback)) {
142 | throw new Error("callback must be a function");
143 | }
144 | var handle = {
145 | topic: topic,
146 | cb: callback,
147 | pos: null
148 | };
149 | var list = listeners[topic];
150 | if (!list) {
151 | list = (listeners[topic] = []);
152 | }
153 | list.push(handle);
154 | handle.pos = list.length - 1;
155 | return handle;
156 | },
157 |
158 | /**
159 | * Disconnects a listener
160 | *
161 | * @param handle a handle returned from {@link comb.listen}
162 | */
163 | unListen: function (handle) {
164 | if (handle) {
165 | var topic = handle.topic, list = listeners[topic];
166 | if (list) {
167 | for (var i = list.length - 1; i >= 0; i--) {
168 | if (list[i] === handle) {
169 | list.splice(i, 1);
170 | }
171 | }
172 | if (!list.length) {
173 | delete listeners[topic];
174 | }
175 | }
176 | }
177 | }
178 |
179 | });
180 |
181 |
--------------------------------------------------------------------------------
/lib/base/date/transforms.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var floor = Math.floor, round = Math.round, min = Math.min, pow = Math.pow, ceil = Math.ceil, abs = Math.abs;
3 |
4 | var addMap = {
5 | day: function addDay(date, amount) {
6 | return [amount, "Date", false];
7 | },
8 | weekday: function addWeekday(date, amount) {
9 | // Divide the increment time span into weekspans plus leftover days
10 | // e.g., 8 days is one 5-day weekspan / and two leftover days
11 | // Can't have zero leftover days, so numbers divisible by 5 get
12 | // a days value of 5, and the remaining days make up the number of weeks
13 | var days, weeks, mod = amount % 5, strt = date.getDay(), adj = 0;
14 | if (!mod) {
15 | days = (amount > 0) ? 5 : -5;
16 | weeks = (amount > 0) ? ((amount - 5) / 5) : ((amount + 5) / 5);
17 | } else {
18 | days = mod;
19 | weeks = parseInt(amount / 5, 10);
20 | }
21 | if (strt === 6 && amount > 0) {
22 | adj = 1;
23 | } else if (strt === 0 && amount < 0) {
24 | // Orig date is Sun / negative increment
25 | // Jump back over Sat
26 | adj = -1;
27 | }
28 | // Get weekday val for the new date
29 | var trgt = strt + days;
30 | // New date is on Sat or Sun
31 | if ((trgt === 0 || trgt === 6) || ((trgt > 6 || trgt <= 0) && strt !== 6 && strt !== 0)) {
32 | adj = (amount > 0) ? 2 : -2;
33 | }
34 | // Increment by number of weeks plus leftover days plus
35 | // weekend adjustments
36 | return [(7 * weeks) + days + adj, "Date", false];
37 | },
38 | year: function addYear(date, amount) {
39 | return [amount, "FullYear", true];
40 | },
41 | week: function addWeek(date, amount) {
42 | return [amount * 7, "Date", false];
43 | },
44 | quarter: function addYear(date, amount) {
45 | return [amount * 3, "Month", true];
46 | },
47 | month: function addYear(date, amount) {
48 | return [amount, "Month", true];
49 | }
50 | };
51 |
52 | function addTransform(interval, date, amount) {
53 | interval = interval.replace(/s$/, "");
54 | if (addMap.hasOwnProperty(interval)) {
55 | return addMap[interval](date, amount);
56 | }
57 | return [amount, "UTC" + interval.charAt(0).toUpperCase() + interval.substring(1) + "s", false];
58 | }
59 |
60 |
61 | var differenceMap = {
62 | "quarter": function quarterDifference(date1, date2, utc) {
63 | var yearDiff = date2.getFullYear() - date1.getFullYear();
64 | var m1 = date1[utc ? "getUTCMonth" : "getMonth"]();
65 | var m2 = date2[utc ? "getUTCMonth" : "getMonth"]();
66 | // Figure out which quarter the months are in
67 | var q1 = floor(m1 / 3) + 1;
68 | var q2 = floor(m2 / 3) + 1;
69 | // Add quarters for any year difference between the dates
70 | q2 += (yearDiff * 4);
71 | return q2 - q1;
72 | },
73 |
74 | "weekday": function weekdayDifference(date1, date2, utc) {
75 | var days = differenceTransform("day", date1, date2, utc), weeks;
76 | var mod = days % 7;
77 | // Even number of weeks
78 | if (mod === 0) {
79 | days = differenceTransform("week", date1, date2, utc) * 5;
80 | } else {
81 | // Weeks plus spare change (< 7 days)
82 | var adj = 0, aDay = date1[utc ? "getUTCDay" : "getDay"](), bDay = date2[utc ? "getUTCDay" : "getDay"]();
83 | weeks = parseInt(days / 7, 10);
84 | // Mark the date advanced by the number of
85 | // round weeks (may be zero)
86 | var dtMark = new Date(date1);
87 | dtMark.setDate(dtMark[utc ? "getUTCDate" : "getDate"]() + (weeks * 7));
88 | var dayMark = dtMark[utc ? "getUTCDay" : "getDay"]();
89 |
90 | // Spare change days -- 6 or less
91 | if (days > 0) {
92 | if (aDay === 6 || bDay === 6) {
93 | adj = -1;
94 | } else if (aDay === 0) {
95 | adj = 0;
96 | } else if (bDay === 0 || (dayMark + mod) > 5) {
97 | adj = -2;
98 | }
99 | } else if (days < 0) {
100 | if (aDay === 6) {
101 | adj = 0;
102 | } else if (aDay === 0 || bDay === 0) {
103 | adj = 1;
104 | } else if (bDay === 6 || (dayMark + mod) < 0) {
105 | adj = 2;
106 | }
107 | }
108 | days += adj;
109 | days -= (weeks * 2);
110 | }
111 | return days;
112 | },
113 | year: function (date1, date2) {
114 | return date2.getFullYear() - date1.getFullYear();
115 | },
116 | month: function (date1, date2, utc) {
117 | var m1 = date1[utc ? "getUTCMonth" : "getMonth"]();
118 | var m2 = date2[utc ? "getUTCMonth" : "getMonth"]();
119 | return (m2 - m1) + ((date2.getFullYear() - date1.getFullYear()) * 12);
120 | },
121 | week: function (date1, date2, utc) {
122 | return round(differenceTransform("day", date1, date2, utc) / 7);
123 | },
124 | day: function (date1, date2) {
125 | return 1.1574074074074074e-8 * (date2.getTime() - date1.getTime());
126 | },
127 | hour: function (date1, date2) {
128 | return 2.7777777777777776e-7 * (date2.getTime() - date1.getTime());
129 | },
130 | minute: function (date1, date2) {
131 | return 0.000016666666666666667 * (date2.getTime() - date1.getTime());
132 | },
133 | second: function (date1, date2) {
134 | return 0.001 * (date2.getTime() - date1.getTime());
135 | },
136 | millisecond: function (date1, date2) {
137 | return date2.getTime() - date1.getTime();
138 | }
139 | };
140 |
141 |
142 | function differenceTransform(interval, date1, date2, utc) {
143 | interval = interval.replace(/s$/, "");
144 | return round(differenceMap[interval](date1, date2, utc));
145 | }
146 |
147 |
148 | exports.addTransform = addTransform;
149 | exports.differenceTransform = differenceTransform;
--------------------------------------------------------------------------------
/lib/base/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var objectBase = require("./object");
3 |
4 | objectBase.merge(exports, objectBase,
5 | require("./broadcast"),
6 | require("./functions"),
7 | require("./string"),
8 | require("./number"),
9 | require("./misc"),
10 | require("./date"),
11 | require("./array"),
12 | require("./regexp"),
13 | require("./inflections"),
14 | require("./characters"));
--------------------------------------------------------------------------------
/lib/base/misc.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var comb = exports,
3 | arraySlice = Array.prototype.slice;
4 |
5 | /**
6 | *
7 | * Converts an arguments object to an array
8 | *
9 | * @example
10 | *
11 | * function test(){
12 | * return comb.argsToArray(arguments);
13 | * }
14 | *
15 | * function testSlice(){
16 | * return comb.argsToArray(arguments, 3);
17 | * }
18 | *
19 | * console.log(test(1,2,3)); //[1,2,3]
20 | * console.log(test(1,2,3,4,5,6)); //[4,5,6]
21 | *
22 | * @function
23 | * @param {Arguments} args the arguments object to convert
24 | * @param {Number} [slice=0] the number of arguments to slice.
25 | * @memberOf comb
26 | * @static
27 | * @returns {Array} array version of the arguments object
28 | */
29 | function argsToArray(args, slice) {
30 | slice = slice || 0;
31 | return arraySlice.call(args, slice);
32 | }
33 |
34 | /**
35 | * Determines if obj is a boolean
36 | *
37 | * @param {Anything} obj the thing to test if it is a boolean
38 | *
39 | * @returns {Boolean} true if it is a boolean false otherwise
40 | * @memberOf comb
41 | * @static
42 | */
43 | function isBoolean(obj) {
44 | var undef, type = typeof obj;
45 | return obj !== undef && type === "boolean" || type === "Boolean";
46 | }
47 |
48 | /**
49 | * Determines if obj is undefined
50 | *
51 | * @param {Anything} obj the thing to test if it is undefined
52 | * @returns {Boolean} true if it is undefined false otherwise
53 | * @memberOf comb
54 | * @static
55 | */
56 | function isUndefined(obj) {
57 | var undef;
58 | return obj !== null && obj === undef;
59 | }
60 |
61 |
62 | /**
63 | * Determins if the obj is not undefined
64 | *
65 | * @param obj the thing to test if it is not undefined
66 | *
67 | * @return {Boolean} true if it is defined false otherwise
68 | * @memberOf comb
69 | * @static
70 | */
71 | function isDefined(obj) {
72 | return !isUndefined(obj);
73 | }
74 |
75 | /**
76 | * Determines if obj is undefined or null
77 | *
78 | * @param {Anything} obj the thing to test if it is undefined or null
79 | * @returns {Boolean} true if it is undefined or null false otherwise
80 | * @memberOf comb
81 | * @static
82 | */
83 | function isUndefinedOrNull(obj) {
84 | return isUndefined(obj) || isNull(obj);
85 | }
86 |
87 | /**
88 | * Determines if obj is null
89 | *
90 | * @param {Anything} obj the thing to test if it is null
91 | *
92 | * @returns {Boolean} true if it is null false otherwise
93 | * @memberOf comb
94 | * @static
95 | */
96 | function isNull(obj) {
97 | var undef;
98 | return obj !== undef && obj == null;
99 | }
100 |
101 | /**
102 | * Determines if obj is an Arguments object;
103 | *
104 | * @param {Anything} obj the thing to test if it is null
105 | *
106 | * @returns {Boolean} true if it is an Arguments Object false otherwise
107 | * @memberOf comb
108 | * @static
109 | */
110 | function isArguments(object) {
111 | return !isUndefinedOrNull(object) && Object.prototype.toString.call(object) === '[object Arguments]';
112 | }
113 |
114 |
115 | function isInstance(obj, clazz) {
116 | if (typeof clazz === "function") {
117 | return obj instanceof clazz;
118 | } else {
119 | return false;
120 | }
121 | }
122 |
123 | /**
124 | * Determines if obj is an instance of a particular class
125 | *
126 | * @param {Anything} obj the thing to test if it and instance of a class
127 | * @param {Object} Clazz used to determine if the object is an instance of
128 | *
129 | * @returns {Boolean} true if it is an instance of the clazz false otherwise
130 | * @memberOf comb
131 | * @static
132 | */
133 | function isInstanceOf(obj, clazz) {
134 | return argsToArray(arguments, 1).some(function (c) {
135 | return isInstance(obj, c);
136 | });
137 | }
138 |
139 | (function () {
140 |
141 | var listeners = [];
142 | var setup = false;
143 |
144 | function setupListener() {
145 | if (!setup) {
146 | var orig = process.emit;
147 | process.emit = function (event) {
148 | try {
149 | if (event === 'exit') {
150 | listeners.forEach(function (cb) {
151 | cb();
152 | });
153 | }
154 | } finally {
155 | orig.apply(this, arguments);
156 | }
157 | };
158 | setup = true;
159 | }
160 | }
161 |
162 | /**
163 | * Adds listeners to process.exit without having to change setMaxListeners useful if you
164 | * are writing a library and do not want to change core setting.
165 | *
166 | * @param {Funciton} cb funciton to call when process is exiting
167 | * @memberOf comb
168 | * @static
169 | */
170 | function listenForExit(cb) {
171 | setupListener();
172 | listeners.push(cb);
173 | }
174 |
175 | comb.listenForExit = listenForExit;
176 | })();
177 |
178 | comb.argsToArray = argsToArray;
179 | comb.isBoolean = isBoolean;
180 | comb.isUndefined = isUndefined;
181 | comb.isDefined = isDefined;
182 | comb.isUndefinedOrNull = isUndefinedOrNull;
183 | comb.isNull = isNull;
184 | comb.isArguments = isArguments;
185 | comb.isInstanceOf = isInstanceOf;
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/lib/base/number.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var comb = exports;
3 |
4 | /**
5 | * Determines if obj is a number
6 | *
7 | * @param {Anything} obj the thing to test if it is a Number
8 | *
9 | * @returns {Boolean} true if it is a number false otherwise
10 | */
11 | comb.isNumber = function(obj) {
12 | var undef;
13 | return obj !== undef && obj != null && (typeof obj === "number" || obj instanceof Number);
14 | };
15 |
16 | /**
17 | * @private
18 | */
19 | var round = Math.round, pow = Math.pow;
20 |
21 |
22 | /**
23 | * Rounds a number to the specified places, rounding up.
24 | *
25 | * @example
26 | * comb.number.roundCeil(10.000001, 2); //10.01
27 | * comb.number.roundCeil(10.000002, 5); //10.00001
28 | * comb.number.roundCeil(10.0003, 3); //10.001
29 | * comb.number.roundCeil(10.0004, 2); //10.01
30 | * comb.number.roundCeil(10.0005, 3); //10.001
31 | * comb.number.roundCeil(10.0002, 2); //10.01
32 | *
33 | * @param {Number} num the number to round.
34 | * @param {Number} precision the number of places to round to.
35 | * @static
36 | * @memberOf comb.number
37 | */
38 | function roundCeil(num, precision){
39 | return Math.ceil(num * Math.pow(10, precision))/Math.pow(10, precision);
40 | }
41 |
42 |
43 | /**
44 | * Rounds a number half down to the specified places.
45 | * @example
46 | *
47 | * comb.number.roundHalfDown(0.225, 2); //0.22
48 | * comb.number.roundHalfDown(10.384, 2); //10.38
49 | * comb.number.roundHalfDown(10.386, 2); //10.38
50 | * comb.number.roundHalfDown(10.3869, 3); //10.386
51 | * comb.number.roundHalfDown(10.3861, 3); //10.386
52 | * comb.number.roundHalfDown(10.269019, 5); //10.26901
53 | *
54 | * @param {Number} num the number to round.
55 | * @param {Number} precision the number of places to round to.
56 | * @static
57 | * @memberOf comb.number
58 | */
59 | function roundHalfDown(num, precision) {
60 | var multiplier = pow(10, precision);
61 | return Math.floor(num * multiplier) / multiplier;
62 | }
63 |
64 |
65 | /**
66 | * Rounds a number half up to the specified places.
67 | * @example
68 | *
69 | * comb.number.roundHalfUp(0.225, 2); //0.23
70 | * comb.number.roundHalfUp(10.384, 2); //10.38
71 | * comb.number.roundHalfUp(10.386, 2); //10.39
72 | * comb.number.roundHalfUp(10.3869, 3); //10.387
73 | * comb.number.roundHalfUp(10.3861, 3); //10.386
74 | * comb.number.roundHalfUp(10.269019, 5); //10.26902
75 | * comb.number.roundHalfUp(-2.384, 2); //-2.38
76 | * comb.number.roundHalfUp(-2.385, 2); //-2.38
77 | * comb.number.roundHalfUp(-2.386, 2); //-2.39
78 | *
79 | * @param {Number} num the number to round.
80 | * @param {Number} precision the number of places to round to.
81 | * @static
82 | * @memberOf comb.number
83 | */
84 | function roundHalfUp(num, precision) {
85 | var multiplier = pow(10, precision),
86 | numMod = parseInt((num * multiplier), 10),
87 | lastDigit = parseInt(num * (multiplier * 10), 10) - (numMod * 10);
88 | if (lastDigit < -5) {
89 | numMod -= 1;
90 | } else if (lastDigit >= 5) {
91 | numMod += 1;
92 | }
93 | return numMod / multiplier;
94 | }
95 |
96 |
97 | /**
98 | * @namespace Utilities for numbers
99 | *
100 | * The `comb.number` namespace can be used to decorate numbers with additional chainable functionality
101 | * @ignoreCode
102 | */
103 | comb.number = {
104 | round: roundHalfUp,
105 | roundCeil: roundCeil,
106 | roundHalfDown: roundHalfDown,
107 | roundHalfUp: roundHalfUp
108 | };
--------------------------------------------------------------------------------
/lib/base/regexp.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var comb = exports;
3 |
4 |
5 | /**
6 | * Tests if something is a regular expression.
7 | *
8 | * @example
9 | *
10 | * comb.isRegExp(/hello/); //true
11 | * comb.isRegExp("hello"); //false
12 | *
13 | * @param obj the thing to test.
14 | * @return {Boolean}
15 | * @static
16 | * @memberOf comb
17 | *
18 | */
19 | function isRegExp(obj) {
20 | var undef;
21 | return obj !== undef && obj != null && (obj instanceof RegExp);
22 | }
23 |
24 | comb.isRexExp = isRegExp;
25 | comb.isRegExp = isRegExp;
26 |
27 | /**
28 | * @namespace Regeular expression utilities
29 | *
30 | */
31 | comb.regexp = {
32 | /**@lends comb.regexp*/
33 | /**
34 | * Escapes a string
35 | *
36 | * @param {String} str the string to escape
37 | * @param {String} [except] characters to ignore
38 | *
39 | * @returns {String} the escaped string
40 | */
41 | escapeString:function (str, except) {
42 | return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function (ch) {
43 | if (except && except.indexOf(ch) !== -1) {
44 | return ch;
45 | }
46 | return "\\" + ch;
47 | }); // String
48 | }
49 | };
--------------------------------------------------------------------------------
/lib/collections/AnderssonTree.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Tree = require("./Tree"),
4 | base = require("../base"),
5 | multiply = base.string.multiply,
6 | RED = "red",
7 | BLACK = "black",
8 | nil = {level: 0, data: null};
9 |
10 | /**
11 | *
12 | * @ignoreCode
13 | * @class
Andersson Trees are a version of a balanced Binary tree, while similar to RedBlack Trees the balancing is not as strict.
14 | *
15 | * Performance
16 | *
17 | * | Best | Worst |
18 | * space | O(n) | O(n) |
19 | * Search | O(log n) | O(log n) |
20 | * Insert | O(log n) | O(log n) |
21 | * Delete | O(log n) | O(log n) |
22 | *
23 | * @name AnderssonTree
24 | * @augments comb.collections.Tree
25 | * @memberOf comb.collections
26 | */
27 |
28 |
29 | module.exports = exports = define(Tree, {
30 |
31 | instance: {
32 | /**@lends comb.collections.AnderssonTree.prototype*/
33 |
34 | isEmpty: function () {
35 | return this.__root === nil || this._super(arguments);
36 | },
37 |
38 | insert: function (data) {
39 | if (this.__root == null) {
40 | this.__root = nil;
41 | }
42 | this.__root = insert(this.__root, data, this.compare);
43 | },
44 |
45 | remove: function (data) {
46 | this.__root = remove(this.__root, data, this.compare);
47 | },
48 |
49 |
50 | traverseWithCondition: function (node, order, callback) {
51 | var cont = true;
52 | if (node !== nil) {
53 | return this._super(arguments);
54 | }
55 | return cont;
56 | },
57 |
58 |
59 | traverse: function (node, order, callback) {
60 | if (node !== nil) {
61 | this._super(arguments);
62 | }
63 | },
64 |
65 | contains: function (value) {
66 | if (this.__root !== nil) {
67 | return this._super(arguments);
68 | }
69 | return false;
70 | },
71 |
72 | __printNode: function (node, level) {
73 | var str = [];
74 | if (node.data == null || node == null) {
75 | str.push(multiply('\t', level));
76 | str.push("~");
77 | console.log(str.join(""));
78 | } else {
79 | this.__printNode(node.right, level + 1);
80 | str.push(multiply('\t', level));
81 | str.push(node.data + ":" + node.level + "\n");
82 | console.log(str.join(""));
83 | this.__printNode(node.left, level + 1);
84 | }
85 | }
86 |
87 | }
88 |
89 | });
90 |
91 | function makeNode(data, level) {
92 | return {
93 | data: data,
94 | level: level,
95 | left: nil,
96 | right: nil
97 | };
98 | }
99 |
100 | function skew(root) {
101 | if (root.level !== 0 && root.left.level === root.level) {
102 | var save = root.left;
103 | root.left = save.right;
104 | save.right = root;
105 | root = save;
106 | }
107 | return root;
108 | }
109 |
110 | function split(root) {
111 | if (root.level !== 0 && root.right.right.level === root.level) {
112 | var save = root.right;
113 | root.right = save.left;
114 | save.left = root;
115 | root = save;
116 | ++root.level;
117 | }
118 | return root;
119 | }
120 |
121 | function insert(root, data, compare) {
122 | if (root === nil) {
123 | root = makeNode(data, 1);
124 | }
125 | else {
126 | var dir = compare(data, root.data) === -1 ? "left" : "right";
127 | root[dir] = insert(root[dir], data, compare);
128 | root = skew(root);
129 | root = split(root);
130 | }
131 | return root;
132 | }
133 |
134 | function remove(root, data, compare) {
135 | var rLeft, rRight;
136 | if (root !== nil) {
137 | var cmp = compare(data, root.data);
138 | if (cmp === 0) {
139 | rLeft = root.left, rRight = root.right;
140 | if (rLeft !== nil && rRight !== nil) {
141 | var heir = rLeft;
142 | while (heir.right !== nil) {
143 | heir = heir.right;
144 | }
145 | root.data = heir.data;
146 | root.left = remove(rLeft, heir.data, compare);
147 | } else {
148 | root = root[rLeft === nil ? "right" : "left"];
149 | }
150 | } else {
151 | var dir = cmp === -1 ? "left" : "right";
152 | root[dir] = remove(root[dir], data, compare);
153 | }
154 | }
155 | if (root !== nil) {
156 | var rLevel = root.level;
157 | var rLeftLevel = root.left.level, rRightLevel = root.right.level;
158 | if (rLeftLevel < rLevel - 1 || rRightLevel < rLevel - 1) {
159 | if (rRightLevel > --root.level) {
160 | root.right.level = root.level;
161 | }
162 |
163 | root = skew(root);
164 | root = split(root);
165 | }
166 | }
167 | return root;
168 | }
169 |
170 |
--------------------------------------------------------------------------------
/lib/collections/BinaryTree.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Tree = require("./Tree"),
4 | base = require("../base");
5 |
6 | /**
7 | *
8 | * @ignoreCode
9 | * @class A Search tree that maintains the following properties
10 | *
11 | * - The left subtree of a node contains only nodes with keys less than the node's key.
12 | *
- The right subtree of a node contains only nodes with keys greater than the node's key.
13 | *
- Both the left and right subtrees must also be binary search trees.
14 | *
15 | *
16 | * Performance
17 | *
18 | * | Best | Worst |
19 | * Space | O(n) | O(n) |
20 | * Search | O(log n) | O(n) |
21 | * Insert | O(log n) | O(n) |
22 | * Delete | O(log n) | O(n) |
23 | *
24 | * @name BinaryTree
25 | * @augments comb.collections.Tree
26 | * @memberOf comb.collections
27 | */
28 | module.exports = exports = define(Tree, {
29 | instance: {
30 | /**@lends comb.collections.BinaryTree.prototype*/
31 |
32 | insert: function (data) {
33 | if (this.__root == null) {
34 | this.__root = {
35 | data: data,
36 | parent: null,
37 | left: null,
38 | right: null
39 | };
40 | return this.__root;
41 | }
42 | var compare = this.compare;
43 | var root = this.__root;
44 | while (root != null) {
45 | var cmp = compare(data, root.data);
46 | if (cmp) {
47 | var leaf = (cmp === -1) ? "left" : "right";
48 | var next = root[leaf];
49 | if (next == null) {
50 | root[leaf] = {data: data, parent: root, left: null, right: null};
51 | return root[leaf];
52 | } else {
53 | root = next;
54 | }
55 | } else {
56 | return null;
57 | }
58 | }
59 | },
60 |
61 | remove: function (data) {
62 | if (this.__root != null) {
63 | var head = {right: this.__root}, it = head;
64 | var p, f = null;
65 | var dir = "right";
66 | while (it[dir] != null) {
67 | p = it;
68 | it = it[dir];
69 | var cmp = this.compare(data, it.data);
70 | if (!cmp) {
71 | f = it;
72 | }
73 | dir = (cmp === -1 ? "left" : "right");
74 | }
75 | if (f != null) {
76 | f.data = it.data;
77 | p[p.right === it ? "right" : "left"] = it[it.left == null ? "right" : "left"];
78 | }
79 | this.__root = head.right;
80 | }
81 |
82 | }
83 | }
84 | });
85 |
86 |
87 |
--------------------------------------------------------------------------------
/lib/collections/Collection.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | base = require("../base");
4 |
5 | /**
6 | * @ignoreCode
7 | * @class Base class for all collections
8 | * @name Collection
9 | * @memberOf comb.collections
10 | */
11 | define(null, {
12 | instance: {
13 | /**@lends comb.collections.Collection.prototype*/
14 |
15 | /**
16 | * Concats two collections
17 | */
18 | concat: function () {
19 | throw new Error("Not Implemented");
20 | },
21 |
22 | /**
23 | * Joins two collections
24 | */
25 | join: function () {
26 | throw new Error("Not Implemented");
27 | },
28 |
29 | /**
30 | * Slice a portion from a collection
31 | */
32 | slice: function () {
33 | throw new Error("Not Implemented");
34 | },
35 |
36 | /**
37 | * Convert a collection to a string
38 | */
39 | toString: function () {
40 | throw new Error("Not Implemented");
41 | },
42 |
43 | /**
44 | * Find the index of an item in a collection
45 | */
46 | indexOf: function () {
47 | throw new Error("Not Implemented");
48 | },
49 |
50 | /**
51 | * Find the last index of an item in a collection
52 | */
53 | lastIndexOf: function () {
54 | throw new Error("Not Implemented");
55 | }
56 | }
57 | }).as(module);
--------------------------------------------------------------------------------
/lib/collections/Iterable.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | base = require("../base");
4 |
5 | /**
6 | * @ignoreCode
7 | * @class Base class for all collections
8 | * @name Iterable
9 | * @memberOf comb.collections
10 | */
11 | define(null, {
12 | instance: {
13 | /**@lends comb.collections.Iterable.prototype*/
14 |
15 | /**
16 | * Filter items from a collection
17 | */
18 | filter: function () {
19 | throw new Error("Not Implemented");
20 | },
21 |
22 | /**
23 | * Loop through the items in a collection
24 | */
25 | forEach: function () {
26 | throw new Error("Not Implemented");
27 | },
28 |
29 | /**
30 | * Determine if every item in a collection meets the criteria
31 | */
32 | every: function () {
33 | throw new Error("Not Implemented");
34 | },
35 |
36 | /**
37 | * Map every item in a collection
38 | */
39 | map: function () {
40 | throw new Error("Not Implemented");
41 | },
42 |
43 | /**
44 | * Determing if some items in a colleciton meet the criteria
45 | */
46 | some: function () {
47 | throw new Error("Not Implemented");
48 | },
49 |
50 | /**
51 | * Reduce a collection
52 | */
53 | reduce: function () {
54 | throw new Error("Not Implemented");
55 | },
56 |
57 | /**
58 | * Reduce a collection starting from the right most position
59 | */
60 | reduceRight: function () {
61 | throw new Error("Not Implemented");
62 | }
63 | }
64 | }).as(module);
65 |
--------------------------------------------------------------------------------
/lib/collections/MaxHeap.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Heap = require("./Heap"),
4 | base = require("../base");
5 |
6 | /**
7 | * @ignoreCode
8 | *
9 | * @class Max Heap implementation, lowest value in heap is always at the root.
10 | *
11 | * Performance
12 | *
13 | * | Best | Worst |
14 | * Insert | O(log n) | O(log n) |
15 | * Remove | O(log n) | O(log n) |
16 | * Peek | O(1) | O(1) |
17 | * Contains | O(n) | O(n) |
18 | *
19 | * @name MaxHeap
20 | * @augments comb.collections.Heap
21 | * @memberOf comb.collections
22 | */
23 | exports = module.exports = define(Heap, {
24 | instance: {
25 |
26 |
27 | __upHeap: function (index) {
28 | var heap = this.__heap;
29 | var node = heap[index];
30 | while (index >= 0) {
31 | var parentIndex = this.__getParentIndex(index), parent = heap[parentIndex];
32 | if (parent && parent.key < node.key) {
33 | heap[index] = parent;
34 | index = parentIndex;
35 | } else {
36 | break;
37 | }
38 | }
39 | heap[index] = node;
40 | },
41 |
42 | __downHeap: function (index) {
43 | var heap = this.__heap;
44 | var node = heap[index], length = heap.length;
45 | while (index < Math.floor(length / 2)) {
46 | var leftIndex = this.__getLeftChildIndex(index),
47 | rightIndex = this.__getRightChildIndex(index), left = heap[leftIndex], right = heap[rightIndex], child, childIndex;
48 | if (rightIndex < length && right.key < left.key) {
49 | childIndex = leftIndex;
50 | child = left;
51 | } else {
52 | childIndex = leftIndex;
53 | child = heap[leftIndex];
54 | }
55 | if (child.key > node.key) {
56 | heap[index] = child;
57 | index = childIndex;
58 | } else {
59 | break;
60 | }
61 |
62 | }
63 | heap[index] = node;
64 | }
65 |
66 | }
67 | });
68 |
--------------------------------------------------------------------------------
/lib/collections/MinHeap.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Heap = require("./Heap"),
4 | base = require("../base");
5 |
6 | var floor = Math.floor, MinHeap;
7 | /**
8 | * @class Min Heap implementation, lowest value in heap is always at the root.
9 | *
10 | * Performance
11 | *
12 | * | Best | Worst |
13 | * Insert | O(log n) | O(log n) |
14 | * Remove | O(log n) | O(log n) |
15 | * Peek | O(1) | O(1) |
16 | * Contains | O(n) | O(n) |
17 | *
18 | * @name MinHeap
19 | * @augments comb.collections.Heap
20 | * @memberOf comb.collections
21 | * @ignoreCode
22 | */
23 | module.exports = exports = define(Heap, {
24 | instance: {
25 |
26 | __upHeap: function (index) {
27 | var heap = this.__heap;
28 | var node = heap[index], key = node.key, gpi = this.__getParentIndex;
29 | while (index >= 0) {
30 | var parentIndex = gpi(index), parent = heap[parentIndex];
31 | if (parent && parent.key > key) {
32 | heap[index] = parent;
33 | index = parentIndex;
34 | } else {
35 | break;
36 | }
37 | }
38 | heap[index] = node;
39 | },
40 |
41 | __downHeap: function (index) {
42 | var heap = this.__heap;
43 | var node = heap[index], key = node.key, length = heap.length, max = floor(length / 2), glci = this.__getLeftChildIndex, grci = this.__getRightChildIndex;
44 | while (index < max) {
45 | var leftIndex = glci(index),
46 | rightIndex = grci(index), left = heap[leftIndex], right = heap[rightIndex], child, childIndex;
47 | if (rightIndex < length && right.key < left.key) {
48 | childIndex = rightIndex;
49 | child = right;
50 | } else {
51 | childIndex = leftIndex;
52 | child = left;
53 | }
54 | if (child.key < key) {
55 | heap[index] = child;
56 | index = childIndex;
57 | } else {
58 | break;
59 | }
60 |
61 | }
62 | heap[index] = node;
63 | }
64 | }
65 | });
66 |
67 |
--------------------------------------------------------------------------------
/lib/collections/Pool.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Collection = require("./Collection"),
4 | Queue = require("./Queue"),
5 | base = require("../base");
6 |
7 | /**
8 | * @class Base class for a pool.
9 | *
10 | * @name Pool
11 | * @memberOf comb.collections
12 | *
13 | * @property {Number} count the total number of objects in the pool, including free and in use objects.
14 | * @property {Number} freeCount the number of free objects in this pool.
15 | * @property {Number} inUseCount the number of objects in use in this pool.
16 | * @property {Number} [minObjects=0] the minimum number of objects this pool should contain.
17 | * @property {Number} [maxObjects=1] the maximum number of objects this pool should contain
18 | * @ignoreCode
19 | */
20 | exports = module.exports = define(null, {
21 | instance: {
22 | /**@lends comb.collections.Pool.prototype*/
23 |
24 | __minObjects: 0,
25 |
26 | __maxObjects: 1,
27 |
28 | constructor: function (options) {
29 | options = options || {};
30 | this.__freeObjects = new Queue();
31 | this.__inUseObjects = [];
32 | this.__minObjects = options.minObjects || 0;
33 | this.__maxObjects = options.maxObjects || 1;
34 | this.minObjects = this.__minObjects;
35 | this.maxObjects = this.__maxObjects;
36 | },
37 |
38 | /**
39 | * Retrieves an object from this pool.
40 | * `
41 | * @return {*} an object to contained in this pool
42 | */
43 | getObject: function () {
44 | var ret;
45 | if (this.count <= this.__maxObjects && this.freeCount > 0) {
46 | ret = this.__freeObjects.dequeue();
47 | this.__inUseObjects.push(ret);
48 | } else if (this.count < this.__maxObjects) {
49 | ret = this.createObject();
50 | this.__inUseObjects.push(ret);
51 | }
52 | return ret;
53 | },
54 |
55 | /**
56 | * Returns an object to this pool. The object is validated before it is returned to the pool,
57 | * if the validation fails then it is removed from the pool;
58 | * @param {*} obj the object to return to the pool
59 | */
60 | returnObject: function (obj) {
61 | var index;
62 | if (this.validate(obj) && this.count <= this.__maxObjects && (index = this.__inUseObjects.indexOf(obj)) > -1) {
63 | this.__freeObjects.enqueue(obj);
64 | this.__inUseObjects.splice(index, 1);
65 | } else {
66 | this.removeObject(obj);
67 | }
68 | },
69 |
70 | /**
71 | * Removes an object from the pool, this can be overriden to provide any
72 | * teardown of objects that needs to take place.
73 | *
74 | * @param {*} obj the object that needs to be removed.
75 | *
76 | * @return {*} the object removed.
77 | */
78 | removeObject: function (obj) {
79 | var index;
80 | if (this.__freeObjects.contains(obj)) {
81 | this.__freeObjects.remove(obj);
82 | } else if ((index = this.__inUseObjects.indexOf(obj)) > -1) {
83 | this.__inUseObjects.splice(index, 1);
84 | }
85 | //otherwise its not contained in this pool;
86 | return obj;
87 | },
88 |
89 | /**
90 | * Validates an object in this pool.
91 | *
92 | * THIS SHOULD BE OVERRIDDEN TO VALIDATE
93 | *
94 | * @param {*} obj the object to validate.
95 | */
96 | validate: function (obj) {
97 | return true;
98 | },
99 |
100 | /**
101 | * Creates a new object for this pool.
102 | * *
103 | * THIS SHOULD BE OVERRIDDEN TO ADD THE CORRECT TYPE OF OBJECT
104 | *
105 | * @return {Object} be default just creates an object.
106 | */
107 | createObject: function () {
108 | return {};
109 | },
110 |
111 | setters: {
112 | minObjects: function (l) {
113 |
114 | if (l <= this.__maxObjects) {
115 | this.__minObjects = l;
116 | var i;
117 | if ((i = this.count) < l) {
118 | while (i++ < l) {
119 | this.__freeObjects.enqueue(this.createObject());
120 | }
121 | }
122 | } else {
123 | throw "comb.collections.Pool : minObjects cannot be greater than maxObjects.";
124 | }
125 | },
126 | maxObjects: function (l) {
127 | if (l >= this.__minObjects) {
128 | this.__maxObjects = l;
129 | var i = this.count, j = this.freeCount, fo = this.__freeObjects;
130 | while (i > l && j >= 0) {
131 | this.removeObject(fo.dequeue());
132 | j--;
133 | i--;
134 | }
135 | } else {
136 | throw "comb.collections.Pool : maxObjects cannot be less than maxObjects.";
137 | }
138 |
139 | }
140 | },
141 |
142 | getters: {
143 | freeCount: function () {
144 | return this.__freeObjects.count;
145 | },
146 | inUseCount: function () {
147 | return this.__inUseObjects.length;
148 | },
149 | count: function () {
150 | return this.__freeObjects.count + this.__inUseObjects.length;
151 |
152 | },
153 |
154 | minObjects: function () {
155 | return this.__minObjects;
156 | },
157 | maxObjects: function () {
158 | return this.__maxObjects;
159 | }
160 | }
161 | }
162 | });
--------------------------------------------------------------------------------
/lib/collections/PriorityQueue.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | MinHeap = require("./MinHeap"),
4 | base = require("../base"),
5 | PriorityQueue;
6 |
7 | /**
8 | * @class PriorityQueue Implementation where the value with the highest priority moves to the front
9 | * Priority starts at 0, and the greatest value being the lowest priority;
10 | * @name PriorityQueue
11 | * @augments comb.collections.MinHeap
12 | * @memberOf comb.collections
13 | * @ignoreCode
14 | */
15 | PriorityQueue = define(MinHeap, {
16 | instance: {
17 | /**@lends comb.collections.PriorityQueue.prototype*/
18 |
19 | /**
20 | * Adds the value with the specified priority to the queue
21 | *
22 | * @param {Number} priority the priority of the item
23 | *
24 | * 0 = Highest, n = lowest
25 | * @param value
26 | */
27 | enqueue: function (priority, value) {
28 | return this.insert(priority, value);
29 | },
30 |
31 | /**
32 | * Removes the item with the highest priority from the queue
33 | *
34 | * @returns the value of the item
35 | */
36 | dequeue: function () {
37 | return this.remove();
38 | }
39 | }
40 | });
41 |
42 | module.exports = exports = PriorityQueue;
--------------------------------------------------------------------------------
/lib/collections/Queue.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Collection = require("./Collection"),
4 | base = require("../base");
5 |
6 | /**
7 | * @class FIFO Data structure
8 | * @name Queue
9 | * @augments comb.collections.Collection
10 | * @memberOf comb.collections
11 | *
12 | * @property {Number} count the current number of elements in this queue
13 | * @property {Boolean} isEmpty true if this queue is empty
14 | * @property {Array} values a copy of the values contained in this queue
15 | * @ignoreCode
16 | */
17 | module.exports = exports = define(Collection, {
18 | instance: {
19 | /**@lends comb.collections.Queue.prototype*/
20 |
21 | constructor: function () {
22 | this.__queue = [];
23 | this.__next = 0;
24 | this.__last = 0;
25 | },
26 |
27 | /**
28 | * Add data to this queue
29 | * @param {*} data element to add
30 | */
31 | enqueue: function (data) {
32 | this.__queue[this.__last++] = data;
33 | },
34 |
35 | /**
36 | * Removes first item from the head of the queue
37 | *
38 | * @return {*} The element removed from this queue. Returns undefined if the queue is empty.
39 | */
40 | dequeue: function () {
41 | var next = this.__next,
42 | ret,
43 | queue;
44 | if (next !== this.__last) {
45 | queue = this.__queue;
46 | ret = queue[next];
47 | queue[this.__next++] = undefined;
48 | }
49 | return ret;
50 | },
51 |
52 | /**
53 | * Retrieves the item at the head of the queue without removing it
54 | *
55 | * @return {*} The element at the head of the queue. Returns undefined if the queue is empty.
56 | */
57 | peek: function () {
58 | var next = this.__next,
59 | ret;
60 | if (next !== this.__last) {
61 | ret = this.__queue[next];
62 | }
63 | return ret;
64 | },
65 |
66 | /**
67 | * Removes all items from this queue
68 | */
69 | clear: function () {
70 | this.__queue.length = 0;
71 | this.__next = 0;
72 | this.__last = 0;
73 | },
74 |
75 | /**
76 | * Determine if this queue contains the element
77 | * @param {*} obj the object to find
78 | *
79 | * @return {Boolean} true if this queue contains the element
80 | */
81 | contains: function (obj) {
82 | return this.__queue.indexOf(obj) !== -1;
83 | },
84 | /**
85 | * Removes an element from this queue.
86 | * @param {*} obj the data to remove.
87 | *
88 | * @return {Boolean} true if the element was removed, false otherwise.
89 | */
90 | remove: function (obj) {
91 | var index = this.__queue.indexOf(obj), ret = false;
92 | if (index !== -1) {
93 | if (index === this.__next) {
94 | this.dequeue();
95 | } else {
96 | this.__queue.splice(index, 1);
97 | this.__last--;
98 | }
99 | ret = true;
100 | }
101 | return ret;
102 | },
103 |
104 | toString: function () {
105 | return this.__queue.toString();
106 | },
107 |
108 | getters: {
109 |
110 | count: function () {
111 | return this.__last - this.__next;
112 | },
113 |
114 | isEmpty: function () {
115 | return this.__last - this.__next === 0;
116 | },
117 |
118 | values: function () {
119 | return this.__queue.slice(this.__next, this.__last);
120 | }
121 | }
122 | }
123 | });
--------------------------------------------------------------------------------
/lib/collections/RedBlackTree.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Tree = require("./Tree"),
4 | base = require("../base"),
5 | multiply = base.string.multiply,
6 | RED = "red",
7 | BLACK = "black",
8 | RedBlackTree;
9 |
10 | function isRed(node) {
11 | return node != null && node.red;
12 | }
13 |
14 | function makeNode(data) {
15 | return {
16 | data: data,
17 | red: true,
18 | left: null,
19 | right: null
20 | };
21 | }
22 |
23 | var insert = function (root, data, compare) {
24 | if (root == null) {
25 | return makeNode(data, null);
26 |
27 | } else {
28 | var cmp = compare(data, root.data);
29 | if (cmp) {
30 | var dir = cmp === -1 ? "left" : "right";
31 | var otherDir = dir === "left" ? "right" : "left";
32 | root[dir] = insert(root[dir], data, compare);
33 | var node = root[dir];
34 |
35 | if (isRed(node)) {
36 |
37 | var sibling = root[otherDir];
38 | if (isRed(sibling)) {
39 | /* Case 1 */
40 | root.red = true;
41 | node.red = false;
42 | sibling.red = false;
43 | } else {
44 | if (isRed(node[dir])) {
45 | root = rotateSingle(root, otherDir);
46 | } else if (isRed(node[otherDir])) {
47 |
48 | root = rotateDouble(root, otherDir);
49 | }
50 | }
51 |
52 | }
53 | }
54 | }
55 | return root;
56 | };
57 |
58 | function rotateSingle(root, dir) {
59 | var otherDir = dir === "left" ? "right" : "left";
60 | var save = root[otherDir];
61 | root[otherDir] = save[dir];
62 | save[dir] = root;
63 | root.red = true;
64 | save.red = false;
65 | return save;
66 | }
67 |
68 | function rotateDouble(root, dir) {
69 | var otherDir = dir === "left" ? "right" : "left";
70 | root[otherDir] = rotateSingle(root[otherDir], otherDir);
71 | return rotateSingle(root, dir);
72 | }
73 |
74 |
75 | function remove(root, data, done, compare) {
76 | if (root == null) {
77 | done.done = true;
78 | } else {
79 | var dir;
80 | if (compare(data, root.data) === 0) {
81 | if (root.left == null || root.right == null) {
82 | var save = root[root.left == null ? "right" : "left"];
83 | /* Case 0 */
84 | if (isRed(root)) {
85 | done.done = true;
86 | } else if (isRed(save)) {
87 | save.red = false;
88 | done.done = true;
89 | }
90 | return save;
91 | } else {
92 | var heir = root.right, p;
93 | while (heir.left != null) {
94 | p = heir;
95 | heir = heir.left;
96 | }
97 | p && (p.left = null);
98 | root.data = heir.data;
99 | data = heir.data;
100 | }
101 | }
102 | dir = compare(data, root.data) === -1 ? "left" : "right";
103 | root[dir] = remove(root[dir], data, done, compare);
104 | !done.done && (root = removeBalance(root, dir, done));
105 | }
106 | return root;
107 | }
108 |
109 | function removeBalance(root, dir, done) {
110 | var notDir = dir === "left" ? "right" : "left";
111 | var p = root, s = p[notDir];
112 | if (isRed(s)) {
113 | root = rotateSingle(root, dir);
114 | s = p[notDir];
115 | }
116 | if (s != null) {
117 | if (!isRed(s.left) && !isRed(s.right)) {
118 | isRed(p) && (done.done = true);
119 | p.red = 0;
120 | s.red = 1;
121 | } else {
122 | var save = p.red, newRoot = ( root === p );
123 | p = (isRed(s[notDir]) ? rotateSingle : rotateDouble)(p, dir);
124 | p.red = save;
125 | p.left.red = p.right.red = 0;
126 | if (newRoot) {
127 | root = p;
128 | } else {
129 | root[dir] = p;
130 | }
131 | done.done = true;
132 | }
133 | }
134 | return root;
135 | }
136 |
137 | /**
138 | * @class A RedBlack tree is a form of a self balancing binary tree.
139 | *
140 | * Performance
141 | *
142 | * | Best | Worst |
143 | * Space | O(n) | O(n) |
144 | * Search | O(log n) | O(log n) |
145 | * Insert | O(log n) | O(log n) |
146 | * Delete | O(log n) | O(log n) |
147 | *
148 | * @name RedBlackTree
149 | * @augments comb.collections.Tree
150 | * @memberOf comb.collections
151 | * @ignoreCode
152 | */
153 | module.exports = exports = define(Tree, {
154 | instance: {
155 | /**@lends comb.collections.RedBlackTree.prototype*/
156 | insert: function (data) {
157 | this.__root = insert(this.__root, data, this.compare);
158 | this.__root.red = false;
159 | },
160 |
161 | remove: function (data) {
162 | var done = {done: false};
163 | var root = remove(this.__root, data, done, this.compare);
164 | if (root != null) {
165 | root.red = 0;
166 | }
167 | this.__root = root;
168 | },
169 |
170 |
171 | __printNode: function (node, level) {
172 | var str = [];
173 | if (node == null || node === undefined) {
174 | str.push(multiply('\t', level));
175 | str.push("~");
176 | console.log(str.join(""));
177 | } else {
178 | this.__printNode(node.right, level + 1);
179 | str.push(multiply('\t', level));
180 | str.push((node.red ? "RED" : "BLACK") + ":" + node.data + "\n");
181 | console.log(str.join(""));
182 | this.__printNode(node.left, level + 1);
183 | }
184 | }
185 |
186 | }
187 | });
188 |
189 |
--------------------------------------------------------------------------------
/lib/collections/Stack.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | Collection = require("./Collection"),
4 | base = require("../base");
5 |
6 | /**
7 | * @class LIFO Data structure
8 | * @name Stack
9 | * @augments comb.collections.Collection
10 | * @memberOf comb.collections
11 | *
12 | * @property {Number} count the current number of elements in this queue
13 | * @property {Boolean} isEmpty true if this queue is empty
14 | * @property {Array} values a copy of the values contained in this queue
15 | * @ignoreCode
16 | */
17 | module.exports = exports = define(Collection, {
18 | instance: {
19 | /**@lends comb.collections.Stack.prototype*/
20 |
21 | constructor: function () {
22 | this.__stack = [];
23 | this.__next = -1;
24 | },
25 |
26 | /**
27 | * Add an item to the tail of this stack
28 | * @param {*} data item to qppend to this stack
29 | *
30 | */
31 | push: function (data) {
32 | this.__stack[++this.__next] = data;
33 | },
34 |
35 | /**
36 | * Removes the tail of this static
37 | * @return {*} the data at the tail of this stack
38 | */
39 | pop: function () {
40 | var next = this.__next,
41 | ret,
42 | stack;
43 |
44 | if (next >= 0) {
45 | stack = this.__stack;
46 | ret = stack[next];
47 | stack[this.__next--] = undefined;
48 | }
49 | return ret;
50 | },
51 |
52 | /**
53 | * Retrieves the item at the tail of the stack without removing it
54 | *
55 | * @return {*} The element at the tail of the stack. Returns undefined if the stack is empty.
56 | */
57 | peek: function () {
58 | var next = this.__next,
59 | ret;
60 | if (next >= 0) {
61 | ret = this.__stack[next];
62 | }
63 | return ret;
64 | },
65 |
66 | /**
67 | * Removes all items from this stack.
68 | */
69 | clear: function () {
70 | this.__stack.length = 0;
71 | this.__next = -1;
72 | },
73 |
74 | /**
75 | * Determine if this stack contains the element
76 | * @param {*} obj the object to find
77 | *
78 | * @return {Boolean} true if this stack contains the element
79 | */
80 | contains: function (obj) {
81 | return this.__stack.indexOf(obj) !== -1;
82 | },
83 |
84 | /**
85 | * Removes an element from this stack.
86 | * @param {*} obj the data to remove.
87 | *
88 | * @return {Boolean} true if the element was removed, false otherwise.
89 | */
90 | remove: function (obj) {
91 | var index = this.__stack.indexOf(obj), ret = false;
92 | if (index !== -1) {
93 | if (index === this.__next) {
94 | this.pop();
95 | } else {
96 | this.__stack.splice(index, 1);
97 | this.__next--;
98 | }
99 | ret = true;
100 | }
101 | return ret;
102 | },
103 |
104 | toString: function () {
105 | return this.__stack.toString();
106 | },
107 |
108 | getters: {
109 | count: function () {
110 | return this.__next + 1;
111 | },
112 |
113 | isEmpty: function () {
114 | return this.__next < 0;
115 | },
116 |
117 | values: function () {
118 | return this.__stack.slice(0, this.__next + 1).reverse();
119 | }
120 | }
121 | }
122 | });
--------------------------------------------------------------------------------
/lib/collections/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var comb = exports;
3 | /**
4 | * @ignore
5 | * @namespace Various collections*/
6 | comb.collections = {
7 | Collection: require("./Collection"),
8 | Iterable: require("./Iterable"),
9 | Tree: require("./Tree"),
10 | BinaryTree: require("./BinaryTree"),
11 | RedBlackTree: require("./RedBlackTree"),
12 | AnderssonTree: require("./AnderssonTree"),
13 | AVLTree: require("./AVLTree"),
14 | HashTable: require("./HashTable"),
15 | Queue: require("./Queue"),
16 | Stack: require("./Stack"),
17 | Heap: require("./Heap"),
18 | MinHeap: require("./MinHeap"),
19 | MaxHeap: require("./MaxHeap"),
20 | PriorityQueue: require("./PriorityQueue"),
21 | Pool: require("./Pool")
22 | };
--------------------------------------------------------------------------------
/lib/extensions/arguments.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | utils = require("./utils"),
4 | extend = utils.extend,
5 | array = base.array;
6 |
7 | var methods = [
8 | ["argsToArray", "toArray"]
9 | ];
10 |
11 | module.exports = function (o) {
12 | return extend(o, methods, base);
13 | };
14 |
15 |
16 |
--------------------------------------------------------------------------------
/lib/extensions/array.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | array = base.array,
4 | string = base.string,
5 | utils = require("./utils"),
6 | extend = utils.extend;
7 |
8 | var stringMethods = ["style"];
9 | var methods = ["forEach", "map", "filter", "reduce", "reduceRight", "some", "every", "indexOf", "lastIndexOf",
10 | "zip", "sum", "avg", "sort", "min", "max", "difference", "removeDuplicates", "unique", "rotate",
11 | "permutations", "transpose", "valuesAt", "union", "intersect", "powerSet", "cartesian", "compact",
12 | "multiply", "flatten", "pluck", "invoke", "partition"];
13 |
14 |
15 | module.exports = function (o) {
16 | extend(o, methods, array);
17 | extend(o, stringMethods, string);
18 | return o;
19 | };
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/lib/extensions/cast.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | define = require("../define").define,
4 | utils = require("./utils"),
5 | extend = utils.extend,
6 | arrayExtension = require("./array"),
7 | argumentsExtension = require("./arguments"),
8 | dateExtension = require("./date"),
9 | functionExtension = require("./function"),
10 | numberExtension = require("./number"),
11 | objectExtension = require("./object"),
12 | stringExtension = require("./string");
13 |
14 | var methods = {
15 | array:function () {
16 | return arrayExtension(this);
17 | },
18 |
19 | date:function () {
20 | return dateExtension(this);
21 | },
22 | args:function () {
23 | return argumentsExtension(this);
24 | },
25 | func:function () {
26 | return functionExtension(this);
27 | },
28 | number:function () {
29 | return numberExtension(this);
30 | },
31 |
32 | string:function () {
33 | return stringExtension(this);
34 | },
35 |
36 | object:function () {
37 | return objectExtension(this);
38 | }
39 | };
40 |
41 | module.exports = function (o) {
42 | extend(o, Object.keys(methods), methods, function (name, func) {
43 | return base.partial(func);
44 | });
45 | return o;
46 | };
--------------------------------------------------------------------------------
/lib/extensions/date.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | define = require("../define").define,
4 | utils = require("./utils"),
5 | extend = utils.extend,
6 | date = base.date,
7 | string = base.string;
8 |
9 | var methods = [
10 | "add",
11 | "compare",
12 | "difference",
13 | "format",
14 | "getDaysInMonth",
15 | "getTimezoneName",
16 | "isLeapYear",
17 | "isWeekend"
18 | ];
19 |
20 | module.exports = function (o) {
21 | extend(o, methods, date);
22 | return o;
23 | };
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/lib/extensions/function.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | argsToArray = base.argsToArray,
4 | utils = require("./utils"),
5 | array = base.array,
6 | extend = utils.extend,
7 | comb;
8 |
9 | var methods = [
10 | "hitch",
11 | "bind",
12 | "hitchIgnore",
13 | "bindIgnore",
14 | "partial",
15 | "applyFirst",
16 | "bindFirst",
17 | "curry",
18 | "extend"
19 | ];
20 | var baseMethods = ["extend"];
21 |
22 | module.exports = function (o) {
23 | comb = comb || (require("../index"));
24 | extend(o, methods, base, function (name, func) {
25 | var ret;
26 | if (name !== 'partial' && name !== "applyFirst") {
27 | ret = function (arg1) {
28 | var args = argsToArray(arguments, 1);
29 | return comb(func.apply(null, [arg1, this].concat(args)));
30 | };
31 | } else {
32 | ret = function (arg1) {
33 | return comb(func.apply(null, [this].concat(argsToArray(arguments))));
34 | };
35 | }
36 | return ret;
37 |
38 | });
39 | extend(o, baseMethods, base);
40 | return o;
41 | };
42 |
43 |
44 |
--------------------------------------------------------------------------------
/lib/extensions/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | stringExtension = require("./string"),
4 | functionExtension = require("./function"),
5 | objectExtension = require("./object"),
6 | argumentsExtension = require("./arguments"),
7 | dateExtension = require("./date"),
8 | isExtension = require("./is"),
9 | castExtension = require("./cast.js"),
10 | numberExtension = require("./number"),
11 | arrayExtension = require("./array");
12 |
13 | var TRUE = isExtension(true),
14 | FALSE = isExtension(false);
15 |
16 | function createExtension(obj) {
17 | if (base.isBoolean(obj)) {
18 | return obj ? TRUE : FALSE;
19 | }
20 | if (!base.isUndefinedOrNull(obj) && !obj.__isExtended__) {
21 | obj = isExtension(obj);
22 | obj = castExtension(obj);
23 | if (obj.isObject()) {
24 | obj.object();
25 | }
26 | if (obj.isArguments()) {
27 | obj.args();
28 | }
29 | if (obj.isArray()) {
30 | obj.array();
31 | }
32 | if (obj.isFunction()) {
33 | obj.func();
34 | }
35 | if (obj.isString()) {
36 | obj.string();
37 | }
38 | if (obj.isDate()) {
39 | obj.date();
40 | }
41 | if (obj.isNumber()) {
42 | obj.number();
43 | }
44 | }
45 | return obj;
46 | }
47 |
48 | exports.createExtension = createExtension;
--------------------------------------------------------------------------------
/lib/extensions/is.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | define = require("../define").define,
4 | utils = require("./utils"),
5 | extend = utils.extend;
6 |
7 | var methods = [
8 | "isDefined",
9 | "isUndefined",
10 | "isNull",
11 | "isUndefinedOrNull",
12 | "isArguments",
13 | "isObject",
14 | "isHash",
15 | "isBoolean",
16 | "isDate",
17 | "isEmpty",
18 | "isArray",
19 | "isFunction",
20 | "isInstanceOf",
21 | "isNumber",
22 | "isPromiseLike",
23 | "isRegExp",
24 | "isString",
25 | "deepEqual"
26 | ];
27 |
28 | module.exports = function (o) {
29 | var valueOf = false, val;
30 | if (!base.isInstanceOf(o, Object)) {
31 | /*jshint -W053 */
32 | if (base.isBoolean(o)) {
33 | val = new Boolean(o);
34 | valueOf = true;
35 | } else if (base.isNumber(o)) {
36 | val = new Number(o);
37 | valueOf = true;
38 | } else if (base.isString(o)) {
39 | val = new String(o);
40 | valueOf = true;
41 | }
42 | } else {
43 | val = o;
44 | }
45 | var ret = extend(val, methods, base, null, valueOf);
46 | if (valueOf) {
47 | Object.defineProperty(ret, "valueOf", {
48 | value: function () {
49 | return o;
50 | },
51 | writable: false,
52 | enumerable: false,
53 | configurable: true
54 | });
55 | }
56 | Object.defineProperty(ret, "eq", {
57 | value: function (other) {
58 | return o === other;
59 | },
60 | writable: false,
61 | enumerable: false,
62 | configurable: true
63 | });
64 |
65 | Object.defineProperty(ret, "neq", {
66 | value: function (other) {
67 | return o !== other;
68 | },
69 | writable: false,
70 | enumerable: false,
71 | configurable: true
72 | });
73 | Object.defineProperty(ret, "print", {
74 | value: function () {
75 | console.log(o);
76 | return val;
77 | },
78 | writable: false,
79 | enumerable: false,
80 | configurable: true
81 | });
82 | Object.defineProperty(ret, "__isExtended__", {
83 | value: true,
84 | writable: false,
85 | enumerable: false,
86 | configurable: true
87 | });
88 | return ret;
89 | };
--------------------------------------------------------------------------------
/lib/extensions/number.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | define = require("../define").define,
4 | utils = require("./utils"),
5 | extend = utils.extend,
6 | number = base.number,
7 | string = base.string;
8 |
9 | var methods = [
10 | "round",
11 | "roundCeil",
12 | "roundHalfDown",
13 | "roundHalfUp"
14 | ];
15 |
16 | module.exports = function (o) {
17 | extend(o, methods, number, null, true);
18 | return o;
19 | };
20 |
21 |
--------------------------------------------------------------------------------
/lib/extensions/object.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | define = require("../define").define,
4 | utils = require("./utils"),
5 | extend = utils.extend,
6 | hash = base.hash,
7 | argsToArray = base.argsToArray,
8 | comb;
9 |
10 | var methods = [
11 | "hitch",
12 | "hitchIgnore",
13 | "bind",
14 | "bindIgnore",
15 | "merge",
16 | "extend",
17 | "deepMerge"
18 | ];
19 | var lastMethod = ["curry"];
20 | var hashMethods = [
21 | "forEach",
22 | "filter",
23 | "invert",
24 | "values",
25 | "toArray",
26 | "omit",
27 | "pick",
28 | "keys"
29 | ];
30 |
31 | module.exports = function (o) {
32 | comb = comb || (require("../index"));
33 | extend(o, methods, base);
34 | extend(o, hashMethods, hash);
35 | extend(o, lastMethod, base, function (name, func) {
36 | return function () {
37 | return comb(func.apply(null, argsToArray(arguments).concat([this])));
38 | };
39 | });
40 | return o;
41 | };
42 |
43 |
--------------------------------------------------------------------------------
/lib/extensions/string.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("../base"),
3 | string = base.string,
4 | date = base.date,
5 | utils = require("./utils"),
6 | extend = utils.extend,
7 | regexp = base.regexp,
8 | array = base.array,
9 | argsToArray = base.argsToArray,
10 | comb;
11 |
12 |
13 | var methods = ["style", "multiply", "toArray", "format", "truncate", "pad"];
14 | var baseMethods = ["camelize", "underscore", "classify", "pluralize", "singularize", "applyFirst", "bindFirst", "partial"];
15 | var functionMethods = ["hitch", "bind", "hitchIgnore", "bindIgnore","curry"];
16 | var arrayMethods = ["pluck", "invoke"];
17 | var dateMethods = [
18 | ["parse", "parseDate"]
19 | ];
20 | var regexpMethods = [
21 | ["escapeString", "escape"]
22 | ];
23 |
24 | module.exports = function (o) {
25 | comb = comb || (require("../index"));
26 | extend(o, methods, string, null, true);
27 | extend(o, baseMethods, base, null, true);
28 | extend(o, dateMethods, date, null, true);
29 | extend(o, regexpMethods, regexp, null, true);
30 | extend(o, arrayMethods, array, function (name, func) {
31 | return function () {
32 | return comb(func.apply(null, argsToArray(arguments).concat([this.valueOf()])));
33 | };
34 | }, true);
35 | extend(o, functionMethods, base, function (name, func) {
36 | return function (arg1) {
37 | var args = argsToArray(arguments, 1);
38 | return comb(func.apply(null, [arg1, this.valueOf()].concat(args)));
39 | };
40 | });
41 |
42 | return o;
43 | };
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lib/extensions/utils.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define").define,
3 | base = require("../base"),
4 | array = base.array,
5 | isBoolean = base.isBoolean,
6 | argsToArray = base.argsToArray,
7 | comb;
8 |
9 | function proxyFunc(name, func, valueOf, scope) {
10 | return function proxy() {
11 | comb || (comb = require("../index"));
12 | var ret = func.apply(scope, [valueOf ? this.valueOf() : this].concat(argsToArray(arguments)));
13 | if (ret && !base.isBoolean(ret) && ret !== this && !ret["__isExtended__"]) {
14 | ret = comb(ret);
15 | }
16 | return ret;
17 | };
18 | }
19 |
20 |
21 | function extend(obj, methods, base, creator, valueOf) {
22 | valueOf = isBoolean(valueOf) ? valueOf : false;
23 | array.forEach(methods, function (method) {
24 | var newFunc, func, m, name;
25 | if (Array.isArray(method) && method.length === 2) {
26 | m = method[0];
27 | name = method[1];
28 | } else {
29 | m = name = method;
30 | }
31 | Object.defineProperty(obj, name, {
32 | value: (creator || proxyFunc)(name, base[m], valueOf, base),
33 | writable: false,
34 | enumerable: false,
35 | configurable: true
36 | });
37 |
38 | });
39 | return obj;
40 | }
41 |
42 |
43 | module.exports = {
44 | proxyFunc: proxyFunc,
45 | extend: extend
46 | };
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var base = require("./base"),
3 | extension = require("./extensions"),
4 | createExtension = extension.createExtension;
5 |
6 | /**
7 | * @projectName comb
8 | *
9 | * @github https://github.com/C2FO/comb
10 | *
11 | * @includeDoc [Getting Started] ../docs-md/introduction.md
12 | * @includeDoc [OO] ../docs-md/define.md
13 | * @includeDoc [Promises] ../docs-md/promise.md
14 | * @includeDoc [Logging] ../docs-md/logging.md
15 | * @includeDoc [Utilities] ../docs-md/utilities.md
16 | * @includeDoc [Change Log] ../History.md
17 | *
18 | * @header
19 | * [](http://travis-ci.org/C2FO/comb)
20 | * #Comb
21 | *
22 | * ##Overview
23 | *
24 | * Framework for node that provides a one stop shop for frequently needed utilities, including:
25 | *
26 | * * [OO utilties](./define.html)
27 | * * Collections
28 | * * [Logging](./logging.html)
29 | * * [String & date formatting](./utilities)
30 | * * [Flow control](./promise.html)
31 | *
32 | *
33 | * ##Installation
34 | *
35 | * `npm install comb`
36 | *
37 | * ###[Getting Started](./introduction.html)
38 | *
39 | * ##Highlights
40 | *
41 | * * 100% test coverage!
42 | * * comb([define](./comb.html#.define)|[singleton](./comb.html#.singleton))
43 | * * The backbone of comb.
44 | * * Options for classical inheritance models as well as mixins(pseudo multi-inheritance)
45 | * * You can call this._super from any method. Including statically defined ones!
46 | * * Access to your class level properties within an instance
47 | * * Logging
48 | * * Logger inheritance through name spaces
49 | * * Predefined [level](./comb_logging_Level.html) level definition along with the ability to define your own.
50 | * * Multiple appenders including
51 | * * [FileAppender](./comb_logging_appenders_FileAppender.html) - log it to a file
52 | * * [RollingFileAppender](./comb_logging_appenders_RollingFileAppender.html) - log it to a file up to a customizable size then create a new one.
53 | * * [JSONAppender](./comb_logging_appenders_JSONAppender.html) - write it out as JSON to a file.
54 | * * [ConsoleAppender](./comb_logging_appenders_ConsoleAppender.html)- log it to the console
55 | * * Configurable with [files OR programatically](./comb_logger.html#.configure)
56 | * * Collections
57 | * * [RedBlackTree](./comb_collections_RedBlackTree.html)
58 | * * [AVLTree](./comb_collections_AVLTree.html)
59 | * * [AnderssonTree](./comb_collections_AnderssonTree.html)
60 | * * [BinaryTree](./comb_collections_BinaryTree.html)
61 | * * [HashTable](./comb_collections_HashTable.html)
62 | * * [MaxHeap](./comb_collections_MaxHeap.html)
63 | * * [MinHeap](./comb_collections_MinHeap.html)
64 | * * [Pool](./comb_collections_Pool.html)
65 | * * [PriorityQueue](./comb_collections_PriorityQueue.html)
66 | * * [Queue](./comb_collections_Queue.html)
67 | * * [Stack](./comb_collections_Stack.html)
68 | *
69 | * * [Flow control](./promise.html)
70 | * * [Promises](./comb_Promise.html)
71 | * * [PromiseList](./comb_PromiseList.html)
72 | * * [comb.when](./comb.html#.when)
73 | * * [comb.serial](./comb.html#.serial)
74 | *
75 | * @footer
76 | * ##License
77 | *
78 | * MIT
79 | *
80 | * ##Meta
81 | * * Code: `git clone git://github.com/C2FO/comb.git`
82 | * * Website:
83 | * * Twitter: [http://twitter.com/c2fo](http://twitter.com/c2fo) - 877.465.4045
84 | */
85 |
86 | /**
87 | * Utilities for javascript, optimized for the server environment.
88 | *
89 | *
90 | * @namespace
91 | * @ignoreCode
92 | */
93 | var comb = createExtension;
94 | base.merge(comb, base, require("./define"), require("./promise"), require("./async"), require("./plugins"), require("./collections"), require("./logging"));
95 |
96 |
97 | comb.definePlugin = function (obj) {
98 | if (comb.isHash(obj)) {
99 | comb.deepMerge(comb, obj);
100 | }
101 | return comb;
102 | };
103 |
104 | module.exports = comb;
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/lib/logging/appenders/consoleAppender.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../../define.js").define,
3 | base = require("../../base"),
4 | string = base.string,
5 | style = string.style,
6 | format = string.format,
7 | Appender = require("./appender"),
8 | Level = require("../level");
9 |
10 | /**
11 | * @class Appends messages to the console.
12 | *
13 | * @name ConsoleAppender
14 | * @augments comb.logging.appenders.Appender
15 | * @memberOf comb.logging.appenders
16 | */
17 |
18 | Appender.extend({
19 | instance: {
20 |
21 | constructor: function (options) {
22 | options = options || {};
23 | !options.name && (options.name = "consoleAppender");
24 | this.__wrapStyle = options.wrapStyle;
25 | if (!("wrapStyle" in options)) {
26 | this.__wrapStyle = true;
27 | }
28 | this._super(arguments, [options]);
29 | },
30 |
31 | getLevelColor: function (level) {
32 | if (Level.ERROR.equals(level) || Level.FATAL.equals(level)) {
33 | return "red";
34 | } else if (Level.WARN.equals(level)) {
35 | return "yellow";
36 | } else if (Level.DEBUG.equals(level)) {
37 | return "cyan";
38 | } else if (Level.TRACE.equals(level)) {
39 | return "magenta";
40 | } else if (Level.INFO.equals(level)) {
41 | return "blue";
42 | }
43 | return null;
44 | },
45 |
46 | extraEventData: function (event) {
47 | var level = event.level,
48 | color = this.getLevelColor(level);
49 | return base.merge({
50 | levelNameColored: color ? style(level.name, color) : level,
51 | }, event);
52 | },
53 |
54 | append: function (event) {
55 | if (this._canAppend(event)) {
56 | var level = event.level,
57 | message = format(this.__pattern, this.extraEventData(event));
58 | if (this.__wrapStyle) {
59 | console.log(style(message, this.getLevelColor(level)));
60 | } else {
61 | console.log(message);
62 | }
63 | }
64 | }
65 | }
66 | }).registerType("ConsoleAppender").as(module);
--------------------------------------------------------------------------------
/lib/logging/appenders/fileAppender.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../../define.js").define,
3 | base = require("../../base"),
4 | promise = require("../../promise"),
5 | string = base.string,
6 | Promise = promise.Promise,
7 | PromiseList = promise.PromiseList,
8 | style = string.style,
9 | format = string.format,
10 | Appender = require("./appender"),
11 | Level = require("../level"),
12 | fs = require("fs");
13 |
14 |
15 | /**
16 | * @class Appends messages to a file.
17 | *
18 | * @example
19 | * var fileAppender = new comb.logging.appenders.FileAppender({
20 | * file : "/var/log/myLog.log"
21 | * });
22 | *
23 | *
24 | * @name FileAppender
25 | * @augments comb.logging.appenders.Appender
26 | * @memberOf comb.logging.appenders
27 | *
28 | * @param {Object} [options] options to assign to this Appender
29 | * @param {String} [options.name="appender"] the name of this Appender. If you want two of the same type of appender
30 | * on a logger it must have a different name.
31 | * @param {String} [options.pattern="[{[yyyy-MM-ddTHH:mm:ss:SSS (z)]timeStamp}] {[- 5]levelName} {[-20]name} - {message}"]
32 | * Available Options for formatting see {@link comb.string.format} for formatting options
33 | *
34 | * - timeStamp - the timestamp of the event being logged
35 | * - level - the {@link comb.logging.Level} of the event
36 | * - levelName - the name of the level being logged
37 | * - name - the name of the logger logging the event
38 | * - message - the message being logged
39 | *
40 | * @param {comb.logging.Level|String} [options.level=comb.logging.Level.INFO] the logging level of this appender
41 | * Note: the level can be different from the logger in the case that you want a particular logger
42 | * to only log particular event of a level. For example an appender that only logs errors. BEWARE that if the
43 | * appenders level is lower than the logger is will not recieve any messages.
44 | *
45 | * @param {String} [options.file="./log.log"] the file to log events to.
46 | * @param {String} [options.encoding="utf8"] the encoding of the file.
47 | * @param {Boolean} [options.overwrite=false] if true the log file is overwritten otherwise it is appended to.
48 | * @ignoreCode
49 | */
50 | Appender.extend({
51 | instance: {
52 |
53 | constructor: function (options) {
54 | options = options || {};
55 | !options.name && (options.name = "fileAppender");
56 | this.__file = options.file || "./log.log";
57 | this.__encoding = options.encoding || "utf8";
58 | this.__overwrite = options.overwrite || false;
59 | this.__writeStream = options.writeStream || fs.createWriteStream(this.__file, {
60 | flags: this.__overwrite ? "w" : 'a',
61 | encoding: this.__encoding
62 | });
63 | this._super([options]);
64 | this.__pattern += "\n";
65 | base.listenForExit(base.hitch(this, "__onExit"));
66 | },
67 |
68 |
69 | __onExit: function () {
70 | var ret = new Promise();
71 | var ws = this.__writeStream;
72 | this.__writeStream = null;
73 | ws.on("close", base.hitch(ret, "callback"));
74 | ws.destroySoon();
75 | return ret.promise();
76 | },
77 |
78 | append: function (event) {
79 | var ws = this.__writeStream;
80 | if (this._canAppend(event) && ws && ws.writable) {
81 | var message = format(this.__pattern, event);
82 | var level = event.level;
83 | ws.write(message);
84 | }
85 | }
86 | }
87 | }).registerType("FileAppender").as(module);
--------------------------------------------------------------------------------
/lib/logging/appenders/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**@ignore*/
3 | exports.Appender = require("./appender");
4 | /**@ignore*/
5 | exports.ConsoleAppender = require("./consoleAppender");
6 | /**@ignore*/
7 | exports.FileAppender = require("./fileAppender");
8 | /**@ignore*/
9 | exports.JSONAppender = require("./jsonAppender");
10 | /**@ignore*/
11 | exports.RollingFileAppender = require("./rollingFileAppender");
12 |
13 |
--------------------------------------------------------------------------------
/lib/logging/appenders/jsonAppender.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../../define.js").define,
3 | base = require("../../base"),
4 | string = base.string,
5 | escape = base.regexp.escapeString,
6 | FileAppender = require("./fileAppender"),
7 | format = string.format,
8 | Level = require("../level"),
9 | fs = require("fs");
10 |
11 |
12 | /**
13 | * @class Appends messages to a file in JSON format. The messages are logged to an array in a JSON file
14 | * The file is always overwritten
15 | *
16 | * @example
17 | * //example log.json
18 | * [
19 | * {
20 | * "timestamp" : "Wed Jun 08 2011 11:16:20 GMT-0500 (CDT)",
21 | * "level" : "INFO",
22 | * "name" : "comb",
23 | * "message" : "INFO MESSAGE!!!!"
24 | * }
25 | * ]
26 | *
27 | *
28 | * @name JSONAppender
29 | * @augments comb.logging.appenders.FileAppender
30 | * @memberOf comb.logging.appenders
31 | *
32 | * @param {Object} [options] options to assign to this Appender
33 | * @param {String} [options.name="appender"] the name of this Appender. If you want two of the same type of appender
34 | * on a logger it must have a different name.
35 | * @param {String} [options.pattern="{"timestamp" : "{timeStamp}", "level" : "{levelName}", "name" : "{name}", "message" : "{message}"}"]
36 | * Available Options for formatting see {@link comb.string.format} for formatting options
37 | *
38 | * - timeStamp - the timestamp of the event being logged
39 | * - level - the {@link comb.logging.Level} of the event
40 | * - levelName - the name of the level being logged
41 | * - name - the name of the logger logging the event
42 | * - message - the message being logged
43 | *
44 | * @param {comb.logging.Level|String} [options.level=comb.logging.Level.INFO] the logging level of this appender
45 | * Note: the level can be different from the logger in the case that you want a particular logger
46 | * to only log particular event of a level. For example an appender that only logs errors. BEWARE that if the
47 | * appenders level is lower than the logger is will not recieve any messages.
48 | *
49 | * @param {String} [options.file="./log.json"] the file to log events to.
50 | * @param {String} [options.encoding="utf8"] the encoding of the file.
51 | *
52 | * @ignoreCode
53 | */
54 | FileAppender.extend({
55 | instance:{
56 |
57 | constructor:function (options) {
58 | options = options || {};
59 | this.name = options.name || "JSONAppender";
60 | this.__count = 0;
61 | this.__file = options.file || "./log.json";
62 | this.__encoding = options.encoding || "utf8";
63 | this.__writeStream = options.writeStream || fs.createWriteStream(this.__file, { flags:"w", encoding:this.__encoding});
64 | this.__writeStream.write("[\n");
65 | this.level = options.level;
66 | //explicit overwrite of patter
67 | this.__pattern = '{"timestamp" : "{timeStamp}", "level" : "{levelName}", "name" : "{name}", "message" : "{message}"}';
68 | base.listenForExit(base.hitch(this, "__onExit"));
69 | },
70 |
71 | append:function (event) {
72 | if (this._canAppend(event)) {
73 | event.message = event.message.replace(/\n+/g, "\\n");
74 | var message = (this.__count ? ",\n" : "\n") + format(this.__pattern, event);
75 | this.__writeStream.write(message);
76 | this.__count++;
77 | }
78 | },
79 |
80 |
81 | __onExit:function () {
82 | this.__writeStream.write("]");
83 | this._super(arguments);
84 | }
85 | }
86 | }).registerType("JSONAppender").as(module);
--------------------------------------------------------------------------------
/lib/logging/level.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var define = require("../define.js").define, base = require("../base");
3 |
4 | var LEVELS = {
5 | ALL: -100000,
6 | DEBUG: 1,
7 | TRACE: 2,
8 | INFO: 3,
9 | WARN: 4,
10 | ERROR: 5,
11 | FATAL: 6,
12 | OFF: 100000
13 | };
14 |
15 | var LEVELS_REVERSE = {
16 | "-100000": "ALL",
17 | "1": "DEBUG",
18 | "2": "TRACE",
19 | "3": "INFO",
20 | "4": "WARN",
21 | "5": "ERROR",
22 | "6": "FATAL",
23 | "100000": "OFF"
24 | };
25 |
26 | /**
27 | * @class Level class used to describe logging levels. The levels determine what types of events are logged to the appenders
28 | * for example the if Level.ALL is used then all event will be logged, however if Level.INFO was used then ONLY
29 | * INFO, WARN, ERROR, and FATAL events will be logged. To turn off logging for a logger use Level.OFF.
30 | *
31 | * Not typically instantiated directly, but through staticly defined levels
32 | * @example
33 | * //Levels in ascending order
34 | * comb.logging.Level.ALL
35 | * comb.logging.Level.DEBUG
36 | * comb.logging.Level.TRACE
37 | * comb.logging.Level.INFO
38 | * comb.logging.Level.WARN
39 | * comb.logging.Level.ERROR
40 | * comb.logging.Level.FATAL
41 | * comb.logging.Level.OFF
42 | *
43 | * //or
44 | * Level.getLevel("INFO");
45 | *
46 | * @name Level
47 | * @memberOf comb.logging
48 | *
49 | * @property {Number} level the numerical representation of this level.
50 | * @property {String} name the name of level.
51 | * @ignoreCode
52 | */
53 | var Level = (exports = module.exports = define(null, {
54 | instance: {
55 | /**@lends comb.logging.Level.prototype*/
56 |
57 | constructor: function (level, name) {
58 | this.level = level;
59 | this.name = name;
60 | },
61 |
62 | /**
63 | * Determing if this level is >= another level
64 | * @param {comb.logging.Level} level the level to test against
65 | *
66 | * @returns {Boolean} true if this is >= false otherwise.
67 | */
68 | isGreaterOrEqualToo: function (level) {
69 | var ret = false;
70 | if (level && base.isNumber(level.level)) {
71 | if (this.level >= level.level) {
72 | ret = true;
73 | }
74 | }
75 | return ret;
76 | },
77 |
78 | /**
79 | * Determing if this level is equal to another level based off of the numerical rank.
80 | *
81 | * @param {comb.logging.Level} level the level to compare
82 | *
83 | * @returns {Boolean} true if this is equal to that false otherwise.
84 | */
85 | equals: function (level) {
86 | return level.level === this.level;
87 | }
88 | },
89 | static: {
90 | /**@lends comb.logging.Level*/
91 |
92 | /**
93 | * Converts a numerical or string representation of a level, if a default level is provided,
94 | * then if a level cannot be determined then the default level is used.
95 | *
96 | * @param {Number|String|comb.logging.Level} level the level to try to convert
97 | * @param {comb.logging.Level} [defaultLevel] default level to use if one cannot be determined,
98 | *
99 | * @returns {comb.logging.Level|null} returns a level if one can be determined null otherwise.
100 | */
101 | toLevel: function (level, defaultLevel) {
102 | var ret = null;
103 | var args = base.argsToArray(arguments);
104 | if (args.length === 1) {
105 | level = args[0];
106 | if (base.isNumber(level)) {
107 | var strLevel = LEVELS_REVERSE[level];
108 | ret = Level[strLevel];
109 | } else if (base.isString(level)) {
110 | ret = Level[level.toUpperCase()];
111 | } else {
112 | ret = level;
113 | }
114 | } else {
115 | ret = (Level.toLevel(args[0]) || args[1]);
116 | }
117 | return ret;
118 | },
119 |
120 | /**
121 | * Adds a new level to the Level object.
122 | *
123 | * @example
124 | *
125 | * logger = Logger.getLogger("my.logger");
126 | *
127 | * //create the custom level
128 | * Level.addLevel("custom_Level", 20);
129 | *
130 | * //now set the level on a logger
131 | * logger.level = Level.CUSTOM_LEVEL;
132 | *
133 | * @param {string} label the label of the level, Note: the label will be coverted to uppercase.
134 | * @param {number} level the level of the level
135 | *
136 | * @return {undefined|comb.logging.Level} the level that was created.
137 | *
138 | */
139 | addLevel: function (label, level) {
140 | var ret;
141 | if (base.isString(label) && base.isNumber(level)) {
142 | label = label.toUpperCase();
143 | LEVELS_REVERSE[level] = label;
144 | LEVELS[label] = level;
145 | ret = (this[label] = new Level(level, label));
146 | }
147 | return ret;
148 | },
149 |
150 | /**
151 | * Level to allow logging of all events.
152 | */
153 | ALL: null,
154 | /**
155 | * Logs only events debug or greater.
156 | */
157 | DEBUG: null,
158 | /**
159 | * Like debug but provides a finer level of detail
160 | */
161 | TRACE: null,
162 | /**
163 | * Only info, or error related events
164 | */
165 | INFO: null,
166 | /**
167 | * Only warn or error related events
168 | */
169 | WARN: null,
170 | /**
171 | * Error or fatal events
172 | */
173 | ERROR: null,
174 | /**
175 | * Only fatal events
176 | */
177 | FATAL: null,
178 | /**
179 | * No events will be logged.
180 | */
181 | OFF: null
182 |
183 | }
184 | }));
185 |
186 | for (var i in LEVELS_REVERSE) {
187 | Level[LEVELS_REVERSE[i]] = new Level(parseInt(i, 10), LEVELS_REVERSE[i]);
188 | }
--------------------------------------------------------------------------------
/lib/plugins/Broadcaster.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var func = require("../base/functions"),
3 | define = require("../define").define;
4 |
5 |
6 | var Broadcaster = define(null, {
7 | instance: {
8 | /** @lends comb.plugins.Broadcaster.prototype */
9 | /**
10 | * Plugin to allow a class to easily broadcast events
11 | *
12 | * @example
13 | *
14 | * var Mammal = define(comb.plugins.Broadcaster, {
15 | * instance : {
16 | *
17 | * constructor: function(options) {
18 | * options = options || {};
19 | * this._super(arguments);
20 | * this._type = options.type || "mammal";
21 | * },
22 | *
23 | * speak : function() {
24 | * var str = "A mammal of type " + this._type + " sounds like";
25 | * this.broadcast("speak", str);
26 | * this.onSpeak(str);
27 | * return str;
28 | * },
29 | *
30 | * onSpeak : function(){}
31 | * }
32 | * });
33 | *
34 | *
35 | * var m = new Mammal({color : "gold"});
36 | * m.listen("speak", function(str){
37 | * //called back from the broadcast event
38 | * console.log(str);
39 | * });
40 | * m.speak();
41 | *
42 | * @constructs
43 | */
44 | constructor: function () {
45 | this.__listeners = {};
46 | },
47 |
48 | /**
49 | * Broadcasts an event from an object
50 | *
51 | * @param name the name of the event to broadcast
52 | * @param {Object|String|Function|Date|Number} [args] variable number of arguments to pass to listeners, can be anything
53 | */
54 | broadcast: function (topic, args) {
55 | args = Array.prototype.slice.call(arguments, 0);
56 | topic = args.shift();
57 | if (topic && topic in this.__listeners) {
58 | var list = this.__listeners[topic], i = list.length - 1;
59 | while (i >= 0) {
60 | list[i--].cb.apply(this, args);
61 | }
62 | }
63 | },
64 |
65 | /**
66 | * Listens to a broadcasted event
67 | * Simimlar to {@link comb.listen}
68 | *
69 | * @param {String} topic the topic to listen to
70 | * @param {Function} callback the function to callback on event publish
71 | *
72 | * @returns {Array} handle to disconnect a topic
73 | */
74 | listen: function (topic, callback) {
75 | if (!func.isFunction(callback)) {
76 | throw new Error("callback must be a function");
77 | }
78 | var handle = {
79 | topic: topic,
80 | cb: callback
81 | };
82 | var list = this.__listeners[topic];
83 | if (!list) {
84 | list = (this.__listeners[topic] = [handle]);
85 | handle.pos = 0;
86 | } else {
87 | handle.pos = list.push(handle);
88 | }
89 | return handle;
90 | },
91 |
92 | /**
93 | * Disconnects a listener
94 | * Similar to {@link comb.unListen}
95 | *
96 | * @param handle disconnect a handle returned from Broadcaster.listen
97 | */
98 | unListen: function (handle) {
99 | if (handle) {
100 | var topic = handle.topic;
101 | if (topic in this.__listeners) {
102 | var listeners = this.__listeners, list = listeners[topic];
103 | if (list) {
104 | for (var i = list.length - 1; i >= 0; i--) {
105 | if (list[i] === handle) {
106 | list.splice(i, 1);
107 | break;
108 | }
109 | }
110 | }
111 | }
112 | }
113 | }
114 | }
115 | });
116 |
117 | exports = module.exports = Broadcaster;
--------------------------------------------------------------------------------
/lib/plugins/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var comb = exports;
3 | /**@namespace plugins for classes using {@link comb.define}*/
4 | comb.plugins = {
5 | Broadcaster : require("./Broadcaster"),
6 | Middleware : require("./Middleware")
7 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "comb",
3 | "description": "A framework for node",
4 | "version": "2.0.0",
5 | "keywords": [
6 | "OO",
7 | "Object Oriented",
8 | "Collections",
9 | "Tree",
10 | "HashTable",
11 | "Pool",
12 | "Logging",
13 | "Promise",
14 | "Promises",
15 | "Proxy"
16 | ],
17 | "repository": {
18 | "type": "git",
19 | "url": "git@github.com:C2FO/comb.git"
20 | },
21 | "homepage": "http://c2fo.github.com/comb/",
22 | "author": "C2FO (http://c2fo.github.com)",
23 | "main": "index.js",
24 | "directories": {
25 | "lib": "lib"
26 | },
27 | "devDependencies": {
28 | "coveralls": "^2.11.4",
29 | "grunt": "^0.4.5",
30 | "grunt-contrib-jshint": "^0.11.3",
31 | "grunt-exec": "^0.4.6",
32 | "grunt-it": "^1.0.0",
33 | "istanbul": "^0.4.1",
34 | "it": "^1.1.0",
35 | "jit-grunt": "^0.9.1",
36 | "time-grunt": "^1.2.2"
37 | },
38 | "scripts": {
39 | "test": "grunt test"
40 | },
41 | "engines": {
42 | "node": ">= 10.0.0"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/test/base.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require("it"),
3 | assert = require("assert"),
4 | comb = require("../index");
5 |
6 | it.describe("comb", function(it){
7 | it.should("define a plugin", function(){
8 | comb.definePlugin({a : true});
9 | assert.isTrue(comb.a);
10 | });
11 | }).as(module);
--------------------------------------------------------------------------------
/test/base/broadcast.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | define = comb.define,
6 | hitch = comb.hitch,
7 | Broadcaster = comb;
8 |
9 |
10 | it.describe("comb/base/broadcast.js", function (it) {
11 |
12 | //Super of other classes
13 | var Mammal = define(null, {
14 | instance: {
15 |
16 | constructor: function (options) {
17 | options = options || {};
18 | this._super(arguments);
19 | this._type = options.type || "mammal";
20 | },
21 |
22 | speak: function () {
23 | var str = "A mammal of type " + this._type + " sounds like";
24 | comb.broadcast("speak", str);
25 | this.onSpeak(str);
26 | return str;
27 | },
28 |
29 | onSpeak: function () {
30 |
31 | }
32 | }
33 | });
34 |
35 |
36 | it.should("#listen", function (next) {
37 | var m = new Mammal({color: "gold"}), h;
38 | h = comb.listen("speak", hitch(this, function (str) {
39 | assert.equal(str, "A mammal of type mammal sounds like");
40 | comb.unListen(h);
41 | next();
42 | }));
43 | m.speak();
44 | });
45 |
46 | it.should("#unlisten", function (next) {
47 | var m = new Mammal({color: "gold"});
48 | var han = comb.listen("speak", next);
49 | comb.unListen(han);
50 | comb.listen("speak", hitch(this, function () {
51 | next();
52 | }));
53 | m.speak();
54 | });
55 |
56 | it.should("#connect", function (next) {
57 | var m = new Mammal({color: "gold"}), h;
58 | h = comb.connect(m, "speak", hitch(this, function (str) {
59 | comb.disconnect(h);
60 | next();
61 | }));
62 | m.speak();
63 | });
64 |
65 | it.should("#disconnect", function (next) {
66 | var m = new Mammal({color: "gold"});
67 | var han = comb.connect(m, "speak", next);
68 | comb.disconnect(han);
69 | comb.connect(m, "speak", hitch(this, function () {
70 | next();
71 | }));
72 | m.speak();
73 | });
74 |
75 | it.should("throw an error on #connect if the function does not exist", function () {
76 | var m = new Mammal({color: "gold"});
77 | assert.throws(function () {
78 | comb.connect(m, "someMethod", function () {
79 | });
80 | });
81 | });
82 |
83 | it.should("throw an error on #disconnect if an invalid handler is passed in", function () {
84 | assert.throws(function () {
85 | comb.disconnect();
86 | });
87 |
88 | assert.throws(function () {
89 | comb.disconnect([comb, "someMethod", function () {
90 | }]);
91 | });
92 | });
93 |
94 | }).as(module);
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/test/base/inflections.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index");
5 |
6 | it.describe("comb/base/inflections.js", function (it) {
7 | var INFLECTIONS = {
8 | test: "tests",
9 | ax: "axes",
10 | testis: "testes",
11 | octopus: "octopuses",
12 | virus: "viruses",
13 | alias: "aliases",
14 | status: "statuses",
15 | bus: "buses",
16 | buffalo: "buffaloes",
17 | tomato: "tomatoes",
18 | datum: "data",
19 | bacterium: "bacteria",
20 | analysis: "analyses",
21 | basis: "bases",
22 | diagnosis: "diagnoses",
23 | parenthesis: "parentheses",
24 | prognosis: "prognoses",
25 | synopsis: "synopses",
26 | thesis: "theses",
27 | wife: "wives",
28 | giraffe: "giraffes",
29 | self: "selves",
30 | dwarf: "dwarves",
31 | hive: "hives",
32 | fly: "flies",
33 | buy: "buys",
34 | soliloquy: "soliloquies",
35 | day: "days",
36 | attorney: "attorneys",
37 | boy: "boys",
38 | hoax: "hoaxes",
39 | lunch: "lunches",
40 | princess: "princesses",
41 | matrix: "matrices",
42 | vertex: "vertices",
43 | index: "indices",
44 | mouse: "mice",
45 | louse: "lice",
46 | quiz: "quizzes",
47 | motive: "motives",
48 | movie: "movies",
49 | series: "series",
50 | crisis: "crises",
51 | person: "people",
52 | man: "men",
53 | woman: "women",
54 | child: "children",
55 | sex: "sexes",
56 | move: "moves"
57 | };
58 | //Super of other classes
59 |
60 | it.should("camelize correctly", function () {
61 | assert.isNull(comb.camelize(null));
62 | assert.isUndefined(comb.camelize());
63 | assert.equal(comb.camelize("hello_world"), "helloWorld");
64 | assert.equal(comb.camelize("column_name"), "columnName");
65 | assert.equal(comb.camelize("columnName"), "columnName");
66 |
67 | assert.equal(comb("hello_world").camelize(), "helloWorld");
68 | assert.equal(comb("column_name").camelize(), "columnName");
69 | assert.equal(comb("columnName").camelize(), "columnName");
70 | });
71 |
72 |
73 | it.should("underscore correctly", function () {
74 | assert.isNull(comb.underscore(null));
75 | assert.isUndefined(comb.underscore());
76 | assert.equal(comb.underscore("helloWorld"), "hello_world");
77 | assert.equal(comb.underscore("helloWorld1"), "hello_world_1");
78 | assert.equal(comb.underscore("1HelloWorld"), "1_hello_world");
79 | assert.equal(comb.underscore("column_name"), "column_name");
80 | assert.equal(comb.underscore("columnName"), "column_name");
81 |
82 | assert.equal(comb("helloWorld").underscore(), "hello_world");
83 | assert.equal(comb("helloWorld1").underscore(), "hello_world_1");
84 | assert.equal(comb("1HelloWorld").underscore(), "1_hello_world");
85 | assert.equal(comb("column_name").underscore(), "column_name");
86 | assert.equal(comb("columnName").underscore(), "column_name");
87 | });
88 |
89 | it.should("classify correctly", function () {
90 | assert.isNull(comb.classify(null));
91 | assert.isUndefined(comb.classify());
92 | assert.equal(comb.classify('egg_and_hams'), "eggAndHam");
93 | assert.equal(comb.classify('post'), "post");
94 | assert.equal(comb.classify('schema.post'), "post");
95 |
96 | assert.equal(comb('egg_and_hams').classify(), "eggAndHam");
97 | assert.equal(comb('post').classify(), "post");
98 | assert.equal(comb('schema.post').classify(), "post");
99 | });
100 |
101 |
102 | it.should("singularize correctly", function () {
103 | assert.isNull(comb.singularize(null));
104 | assert.isUndefined(comb.singularize());
105 | for (var i in INFLECTIONS) {
106 | assert.equal(comb.singularize(INFLECTIONS[i]), i);
107 | assert.equal(comb(INFLECTIONS[i]).singularize(), i);
108 | }
109 | });
110 |
111 | it.should("pluralize correctly", function () {
112 | assert.isNull(comb.pluralize(null));
113 | assert.isUndefined(comb.pluralize());
114 | for (var i in INFLECTIONS) {
115 | assert.equal(comb.pluralize(i), INFLECTIONS[i]);
116 | assert.equal(comb(i).pluralize(), INFLECTIONS[i]);
117 | }
118 | });
119 |
120 |
121 | }).as(module);
122 |
123 |
--------------------------------------------------------------------------------
/test/base/misc.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index");
5 |
6 | it.describe("comb/base/misc.js", function (it) {
7 | //Super of other classes
8 | it.should("#isBoolean", function () {
9 | //This is true because they inherit from eachother!
10 | assert.isTrue(comb.isBoolean(true));
11 | assert.isTrue(comb(true).isBoolean());
12 | assert.isFalse(comb.isBoolean(function () {
13 | }));
14 |
15 | assert.isFalse(comb(function () {
16 | }).isBoolean());
17 |
18 | assert.isFalse(comb.isBoolean("hello"));
19 | assert.isFalse(comb("hello").isBoolean());
20 | assert.isFalse(comb.isBoolean({}));
21 | assert.isFalse(comb({}).isBoolean());
22 | assert.isFalse(comb(new Date()).isBoolean());
23 | assert.isFalse(comb(1).isBoolean());
24 | });
25 |
26 | it.should("#isArguments", function () {
27 | assert.isTrue(comb.isArguments(arguments));
28 | assert.isTrue(comb(arguments).isArguments());
29 | assert.isFalse(comb.isArguments(function () {
30 | }));
31 |
32 | assert.isFalse(comb(function () {
33 | }).isArguments());
34 | assert.isFalse(comb.isArguments("hello"));
35 | assert.isFalse(comb("hello").isArguments());
36 | assert.isFalse(comb({}).isArguments());
37 | assert.isFalse(comb(new Date()).isArguments());
38 | assert.isFalse(comb(1).isArguments());
39 | });
40 |
41 | it.should("#isUndefined", function () {
42 | assert.isTrue(comb.isUndefined(undefined));
43 | assert.isFalse(comb.isUndefined(null));
44 | assert.isFalse(comb.isUndefined(true));
45 | assert.isFalse(comb(true).isUndefined());
46 | assert.isFalse(comb.isUndefined(function () {
47 | }));
48 | assert.isFalse(comb(function () {
49 | }).isUndefined());
50 | assert.isFalse(comb("hello").isUndefined());
51 | assert.isFalse(comb({}).isUndefined());
52 | assert.isFalse(comb(new Date()).isUndefined());
53 | assert.isFalse(comb(1).isUndefined());
54 | });
55 |
56 | it.should("#isNull", function () {
57 | //This is true because they inherit from eachother!
58 | assert.isTrue(comb.isNull(null));
59 | assert.isFalse(comb.isNull(undefined));
60 | assert.isFalse(comb.isNull(true));
61 | assert.isFalse(comb(true).isNull());
62 | assert.isFalse(comb.isNull(function () {
63 | }));
64 | assert.isFalse(comb(function () {
65 | }).isNull());
66 | assert.isFalse(comb("hello").isNull());
67 | assert.isFalse(comb({}).isNull());
68 | assert.isFalse(comb(new Date()).isNull());
69 | assert.isFalse(comb(1).isNull());
70 | });
71 |
72 | it.should("#isDefined", function () {
73 | //This is true because they inherit from eachother!
74 | assert.isTrue(comb.isDefined(null));
75 | assert.isFalse(comb.isDefined(undefined));
76 | assert.isTrue(comb.isDefined(true));
77 | assert.isTrue(comb(true).isDefined());
78 | assert.isTrue(comb.isDefined(function () {
79 | }));
80 | assert.isTrue(comb(function () {
81 | }).isDefined());
82 | assert.isTrue(comb("hello").isDefined());
83 | assert.isTrue(comb({}).isDefined());
84 | assert.isTrue(comb(new Date()).isDefined());
85 | assert.isTrue(comb(1).isDefined());
86 | });
87 |
88 | it.should("#isInstanceOf", function () {
89 | /*jshint -W053 */
90 | //This is true because they inherit from eachother!
91 | assert.isTrue(comb.isInstanceOf(new Date(), Date));
92 | assert.isTrue(comb(new Date()).isInstanceOf(Date));
93 | assert.isTrue(comb(new Number(1)).isInstanceOf(Number));
94 | assert.isTrue(comb(new String(1)).isInstanceOf(String));
95 | assert.isFalse(comb.isInstanceOf(undefined, String));
96 | assert.isFalse(comb.isInstanceOf(undefined, 1));
97 | });
98 |
99 | it.should("convert arumgents to array", function () {
100 |
101 | (function () {
102 | assert.deepEqual(comb.argsToArray(arguments), [1, 2, 3]);
103 | assert.deepEqual(comb(arguments).toArray(), [1, 2, 3]);
104 | assert.deepEqual(comb.argsToArray(arguments, 1), [2, 3]);
105 | assert.deepEqual(comb(arguments).toArray(1), [2, 3]);
106 | })(1, 2, 3);
107 |
108 | });
109 | }).as(module);
110 |
111 |
--------------------------------------------------------------------------------
/test/base/regexp.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index");
5 |
6 |
7 | it.describe("comb/base/regexp.js", function (it) {
8 | //Super of other classes
9 |
10 | it.should("escape it properly", function () {
11 | var chars = [".", "$", "?", "*", "|", "{", "}", "(", ")", "[", "]", "\\", "/", "+", "^"];
12 | chars.forEach(function (c) {
13 | assert.equal(comb.regexp.escapeString(c), "\\" + c);
14 | assert.equal(comb(c).escape(), "\\" + c);
15 | });
16 | chars.forEach(function (c) {
17 | assert.equal(comb(c).escape([c]), c);
18 | });
19 | });
20 |
21 |
22 | it.should("determine if something is a RegExp", function () {
23 | assert.isTrue(comb.isRexExp(/a/));
24 | assert.isTrue(comb.isRexExp(new RegExp("a")));
25 | assert.isFalse(comb.isRexExp());
26 | assert.isFalse(comb.isRexExp(""));
27 | assert.isFalse(comb.isRexExp(1));
28 | assert.isFalse(comb.isRexExp(false));
29 | assert.isFalse(comb.isRexExp(true));
30 |
31 | assert.isTrue(comb(/a/).isRegExp());
32 | assert.isTrue(comb(new RegExp("a")).isRegExp());
33 | assert.isFalse(comb("").isRegExp());
34 | assert.isFalse(comb(1).isRegExp());
35 | assert.isFalse(comb(false).isRegExp());
36 | assert.isFalse(comb(true).isRegExp());
37 | });
38 |
39 |
40 | }).as(module);
--------------------------------------------------------------------------------
/test/collections/AVLTree.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | helper = require("./treeTest.helper.js"),
6 | Mammal = helper.Mammal,
7 | AVLTree = comb.collections.AVLTree;
8 |
9 |
10 | it.describe("comb.collections.AVLTree", function (it) {
11 |
12 | var words = ["c", "ca", "b", "ba", "bb", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
13 | var wordsInOrder = ['a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'];
14 | var wordsPreOrder = ['ba', 'aa', 'a', 'ajk', 'ab', 'b', 'h', 'd', 'c', 'bb', 'ca', 'f', 'ee', 'ff', 'i', 'hi', 'z', 'j'];
15 | var wordsPostOrder = ['a', 'ab', 'b', 'ajk', 'aa', 'bb', 'ca', 'c', 'ee', 'ff', 'f', 'd', 'hi', 'j', 'z', 'i', 'h', 'ba'];
16 |
17 |
18 | var mammals = [
19 | new Mammal({type: "bird"}),
20 | new Mammal({type: "dog"}),
21 | new Mammal({type: "rat"}),
22 | new Mammal({type: "zebra"}),
23 | new Mammal({type: "mouse"}),
24 | new Mammal({type: "horse"}),
25 | new Mammal({type: "squirrel"}),
26 | new Mammal({type: "groundhog"})
27 | ],
28 |
29 | mammalsInOrder = [
30 | new Mammal({type: "bird"}),
31 | new Mammal({type: "dog"}),
32 | new Mammal({type: "groundhog"}),
33 | new Mammal({type: "horse"}),
34 | new Mammal({type: "mouse"}),
35 | new Mammal({type: "rat"}),
36 | new Mammal({type: "squirrel"}),
37 | new Mammal({type: "zebra"})
38 | ],
39 |
40 | mammalsPreOrder = [
41 | new Mammal({type: "mouse"}),
42 | new Mammal({type: "dog"}),
43 | new Mammal({type: "bird"}),
44 | new Mammal({type: "horse"}),
45 | new Mammal({type: "groundhog"}),
46 | new Mammal({type: "squirrel"}),
47 | new Mammal({type: "rat"}),
48 | new Mammal({type: "zebra"})
49 |
50 | ],
51 |
52 | mammalsPostOrder = [
53 | new Mammal({type: "bird"}),
54 | new Mammal({type: "groundhog"}),
55 | new Mammal({type: "horse"}),
56 | new Mammal({type: "dog"}),
57 | new Mammal({type: "rat"}),
58 | new Mammal({type: "zebra"}),
59 | new Mammal({type: "squirrel"}),
60 | new Mammal({type: "mouse"})
61 |
62 | ];
63 | var orderedMammals = [
64 | [AVLTree.IN_ORDER, mammalsInOrder],
65 | [AVLTree.PRE_ORDER, mammalsPreOrder],
66 | [AVLTree.POST_ORDER, mammalsPostOrder]
67 | ];
68 |
69 |
70 | var expectedOutput = "\t\t\t\t~\n\t\t\tz:-1\n\n\t\t\t\t\t~\n\t\t\t\tj:0\n\n\t\t\t\t\t~\n\t\ti:1\n\n\t\t\t\t~\n\t\t\t" +
71 | "hi:0\n\n\t\t\t\t~\n\th:0\n\n\t\t\t\t\t~\n\t\t\t\tff:0\n\n\t\t\t\t\t~\n\t\t\tf:0\n\n\t\t\t\t\t~\n\t\t\t\t" +
72 | "ee:0\n\n\t\t\t\t\t~\n\t\td:0\n\n\t\t\t\t\t~\n\t\t\t\tca:0\n\n\t\t\t\t\t~\n\t\t\tc:0\n\n\t\t\t\t\t~\n\t\t\t\t" +
73 | "bb:0\n\n\t\t\t\t\t~\nba:1\n\n\t\t\t\t~\n\t\t\tb:0\n\n\t\t\t\t~\n\t\tajk:0\n\n\t\t\t\t~\n\t\t\tab:0\n\n\t\t\t\t~\n\t" +
74 | "aa:1\n\n\t\t\t~\n\t\ta:0\n\n\t\t\t~";
75 |
76 | var orderedWords = [
77 | [AVLTree.IN_ORDER, wordsInOrder],
78 | [AVLTree.PRE_ORDER, wordsPreOrder],
79 | [AVLTree.POST_ORDER, wordsPostOrder]
80 | ];
81 |
82 |
83 | helper.setup(
84 | it,
85 | AVLTree,
86 | words,
87 | orderedWords,
88 | mammals,
89 | orderedMammals,
90 | expectedOutput);
91 |
92 | }).as(module);
--------------------------------------------------------------------------------
/test/collections/AnderssonTree.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | helper = require("./treeTest.helper.js"),
6 | Mammal = helper.Mammal,
7 | AnderssonTree = comb.collections.AnderssonTree;
8 |
9 |
10 | it.describe("comb.collections.AnderssonTree", function (it) {
11 | var words = ["c", "ca", "b", "ba", "bb", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
12 | var wordsInOrder = ['a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'];
13 | var wordsPreOrder = ['d', 'ba', 'aa', 'a', 'ajk', 'ab', 'b', 'c', 'bb', 'ca', 'h', 'f', 'ee', 'ff', 'i', 'hi', 'j', 'z'];
14 | var wordsPostOrder = ['a', 'ab', 'b', 'ajk', 'aa', 'bb', 'ca', 'c', 'ba', 'ee', 'ff', 'f', 'hi', 'z', 'j', 'i', 'h', 'd'];
15 |
16 |
17 | var mammals = [
18 | new Mammal({type: "bird"}),
19 | new Mammal({type: "dog"}),
20 | new Mammal({type: "rat"}),
21 | new Mammal({type: "zebra"}),
22 | new Mammal({type: "mouse"}),
23 | new Mammal({type: "horse"}),
24 | new Mammal({type: "squirrel"}),
25 | new Mammal({type: "groundhog"})
26 | ],
27 |
28 | mammalsInOrder = [
29 | new Mammal({type: "bird"}),
30 | new Mammal({type: "dog"}),
31 | new Mammal({type: "groundhog"}),
32 | new Mammal({type: "horse"}),
33 | new Mammal({type: "mouse"}),
34 | new Mammal({type: "rat"}),
35 | new Mammal({type: "squirrel"}),
36 | new Mammal({type: "zebra"})
37 | ],
38 |
39 | mammalsPreOrder = [
40 | new Mammal({type: "horse"}),
41 | new Mammal({type: "dog"}),
42 | new Mammal({type: "bird"}),
43 | new Mammal({type: "groundhog"}),
44 | new Mammal({type: "rat"}),
45 | new Mammal({type: "mouse"}),
46 | new Mammal({type: "squirrel"}),
47 | new Mammal({type: "zebra"})
48 |
49 | ],
50 |
51 | mammalsPostOrder = [
52 | new Mammal({type: "bird"}),
53 | new Mammal({type: "groundhog"}),
54 | new Mammal({type: "dog"}),
55 | new Mammal({type: "mouse"}),
56 | new Mammal({type: "zebra"}),
57 | new Mammal({type: "squirrel"}),
58 | new Mammal({type: "rat"}),
59 | new Mammal({type: "horse"})
60 | ];
61 | var orderedMammals = [
62 | [AnderssonTree.IN_ORDER, mammalsInOrder],
63 | [AnderssonTree.PRE_ORDER, mammalsPreOrder],
64 | [AnderssonTree.POST_ORDER, mammalsPostOrder]
65 | ];
66 |
67 |
68 | var orderedWords = [
69 | [AnderssonTree.IN_ORDER, wordsInOrder],
70 | [AnderssonTree.PRE_ORDER, wordsPreOrder],
71 | [AnderssonTree.POST_ORDER, wordsPostOrder]
72 | ];
73 | helper.setup(
74 | it,
75 | AnderssonTree,
76 | words,
77 | orderedWords,
78 | mammals,
79 | orderedMammals,
80 | "\t\t\t\t\t~\n\t\t\t\tz:1\n\n\t\t\t\t\t~\n\t\t\tj:1\n\n\t\t\t\t~\n\t\ti:2\n\n\t\t\t\t~\n\t\t\thi:1\n\n\t\t\t\t" +
81 | "~\n\th:3\n\n\t\t\t\t~\n\t\t\tff:1\n\n\t\t\t\t~\n\t\tf:2\n\n\t\t\t\t~\n\t\t\tee:1\n\n\t\t\t\t" +
82 | "~\nd:4\n\n\t\t\t\t~\n\t\t\tca:1\n\n\t\t\t\t~\n\t\tc:2\n\n\t\t\t\t~\n\t\t\tbb:1\n\n\t\t\t\t" +
83 | "~\n\tba:3\n\n\t\t\t\t\t~\n\t\t\t\tb:1\n\n\t\t\t\t\t~\n\t\t\tajk:2\n\n\t\t\t\t\t~\n\t\t\t\t" +
84 | "ab:1\n\n\t\t\t\t\t~\n\t\taa:2\n\n\t\t\t\t~\n\t\t\ta:1\n\n\t\t\t\t~");
85 | }).as(module);
86 |
--------------------------------------------------------------------------------
/test/collections/BinaryTree.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | helper = require("./treeTest.helper.js"),
6 | Mammal = helper.Mammal,
7 | BinaryTree = comb.collections.BinaryTree;
8 |
9 |
10 | it.describe("comb.collections.BinaryTree", function (it) {
11 |
12 | var words = ["c", "ca", "b", "ba", "bb", "a", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
13 | var wordsInOrder = ['a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'];
14 | var wordsPreOrder = ["c", "b", "a", "aa", "ab", "ajk", "ba", "bb", "ca", "z", "d", "f", "ee", "h", "ff", "i", "hi", "j"];
15 | var wordsPostOrder = ["ajk", "ab", "aa", "a", "bb", "ba", "b", "ee", "ff", "hi", "j", "i", "h", "f", "d", "z", "ca", "c"];
16 |
17 | var mammals = [
18 | new Mammal({type: "bird"}),
19 | new Mammal({type: "dog"}),
20 | new Mammal({type: "rat"}),
21 | new Mammal({type: "mouse"}),
22 | new Mammal({type: "zebra"}),
23 | new Mammal({type: "horse"}),
24 | new Mammal({type: "squirrel"}),
25 | new Mammal({type: "groundhog"})
26 | ],
27 |
28 | mammalsInOrder = [
29 | new Mammal({type: "bird"}),
30 | new Mammal({type: "dog"}),
31 | new Mammal({type: "groundhog"}),
32 | new Mammal({type: "horse"}),
33 | new Mammal({type: "mouse"}),
34 | new Mammal({type: "rat"}),
35 | new Mammal({type: "squirrel"}),
36 | new Mammal({type: "zebra"})
37 | ],
38 |
39 | mammalsPreOrder = [
40 | new Mammal({type: "bird"}),
41 | new Mammal({type: "dog"}),
42 | new Mammal({type: "rat"}),
43 | new Mammal({type: "mouse"}),
44 | new Mammal({type: "horse"}),
45 | new Mammal({type: "groundhog"}),
46 | new Mammal({type: "zebra"}),
47 | new Mammal({type: "squirrel"})
48 | ],
49 |
50 | mammalsPostOrder = [
51 | new Mammal({type: "groundhog"}),
52 | new Mammal({type: "horse"}),
53 | new Mammal({type: "mouse"}),
54 | new Mammal({type: "squirrel"}),
55 | new Mammal({type: "zebra"}),
56 | new Mammal({type: "rat"}),
57 | new Mammal({type: "dog"}),
58 | new Mammal({type: "bird"})
59 | ];
60 |
61 | var expectedOutput = "\t\t\t~\n\t\tz\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\t\t\tj\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\t\t" +
62 | "i\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\t\t\thi\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\th\n\n\t\t\t\t\t\t\t~\n\t\t\t\t\t\t" +
63 | "ff\n\n\t\t\t\t\t\t\t~\n\t\t\t\tf\n\n\t\t\t\t\t\t~\n\t\t\t\t\tee\n\n\t\t\t\t\t\t~\n\t\t\td\n\n\t\t\t\t~\n\t" +
64 | "ca\n\n\t\t~\nc\n\n\t\t\t\t~\n\t\t\tbb\n\n\t\t\t\t~\n\t\tba\n\n\t\t\t~\n\tb\n\n\t\t\t\t\t\t~\n\t\t\t\t\t" +
65 | "ajk\n\n\t\t\t\t\t\t~\n\t\t\t\tab\n\n\t\t\t\t\t~\n\t\t\taa\n\n\t\t\t\t~\n\t\ta\n\n\t\t\t~";
66 | var orderedWords = [
67 | [BinaryTree.IN_ORDER, wordsInOrder],
68 | [BinaryTree.PRE_ORDER, wordsPreOrder],
69 | [BinaryTree.POST_ORDER, wordsPostOrder]
70 | ];
71 | var orderedMammals = [
72 | [BinaryTree.IN_ORDER, mammalsInOrder],
73 | [BinaryTree.PRE_ORDER, mammalsPreOrder],
74 | [BinaryTree.POST_ORDER, mammalsPostOrder]
75 | ];
76 |
77 |
78 | helper.setup(
79 | it,
80 | BinaryTree,
81 | words,
82 | orderedWords,
83 | mammals,
84 | orderedMammals,
85 | expectedOutput);
86 |
87 |
88 | }).as(module);
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/test/collections/Collection.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | Collection = comb.collections.Collection;
6 |
7 |
8 | it.describe("comb.collections.Collection", function (it) {
9 |
10 |
11 | var collection = new Collection();
12 | ["concat", "join", "slice", "toString", "indexOf", "lastIndexOf"].forEach(function (m) {
13 | it.describe("#" + m, function (it) {
14 | it.should("be a method", function () {
15 | assert.isFunction(collection[m]);
16 | });
17 |
18 | it.should("throw an error if invoked", function () {
19 | assert.throws(function () {
20 | collection[m]();
21 | });
22 | });
23 | });
24 | });
25 |
26 | }).as(module);
27 |
--------------------------------------------------------------------------------
/test/collections/Heap.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | Heap = comb.collections.Heap;
6 |
7 |
8 | it.describe("comb.collections.Heap", function (it) {
9 | var heap = new Heap();
10 |
11 | it.should("throw an error when calling insert and remove methods", function () {
12 | assert.throws(function () {
13 | heap.insert(1, "hello");
14 | });
15 | assert.throws(function () {
16 | heap.__downHeap();
17 | });
18 | });
19 |
20 | it.should("throw an error when using an invalid key", function () {
21 | assert.throws(function () {
22 | heap.insert("1", 2);
23 | });
24 | });
25 |
26 |
27 | }).as(module);
28 |
29 |
--------------------------------------------------------------------------------
/test/collections/Iterable.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | Iterable = comb.collections.Iterable;
6 |
7 |
8 | it.describe("comb.collections.Iterable", function (it) {
9 |
10 | var iter = new Iterable();
11 | ["filter", "forEach", "every", "map", "some", "reduce", "reduceRight"].forEach(function (m) {
12 | it.describe("#" + m, function (it) {
13 |
14 | it.should("be a function", function () {
15 | assert.isFunction(iter[m]);
16 | });
17 |
18 | it.should("throw an error if invoked", function () {
19 | assert.throws(function () {
20 | iter[m]();
21 | });
22 | });
23 |
24 | });
25 | });
26 |
27 | }).as(module);
28 |
--------------------------------------------------------------------------------
/test/collections/MaxHeap.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | MaxHeap = comb.collections.MaxHeap;
6 |
7 | it.describe("comb.collections.MaxHeap", function (it) {
8 |
9 | it.should("know its count", function () {
10 | var h = new MaxHeap();
11 | h.insert(0, 'a');
12 | h.insert(1, 'b');
13 | h.insert(2, 'c');
14 | h.insert(3, 'd');
15 | assert.equal(h.count, 4);
16 | h.remove();
17 | assert.equal(h.count, 3);
18 | h.remove();
19 | h.remove();
20 | h.remove();
21 | assert.equal(h.count, 0);
22 | });
23 |
24 | it.should("know its keys", function () {
25 | var h = new MaxHeap();
26 | h.insert(0, 'a');
27 | h.insert(1, 'b');
28 | h.insert(2, 'c');
29 | h.insert(3, 'd');
30 | var keys = h.keys;
31 | for (var i = 0; i < 4; i++) {
32 | assert.isTrue(keys.indexOf(i) !== -1);
33 | }
34 | for (i = 0; i < 4; i++) {
35 | assert.isTrue(h.containsKey(i));
36 | }
37 | assert.isFalse(h.containsKey(4));
38 | });
39 |
40 | it.should("know its values", function () {
41 | var h = new MaxHeap();
42 | h.insert(0, 'a');
43 | h.insert(1, 'b');
44 | h.insert(2, 'c');
45 | h.insert(3, 'd');
46 | var vals = h.values;
47 | assert.isTrue(vals.indexOf("a") !== -1);
48 | assert.isTrue(vals.indexOf("b") !== -1);
49 | assert.isTrue(vals.indexOf("c") !== -1);
50 | assert.isTrue(vals.indexOf("d") !== -1);
51 | assert.isTrue(h.containsValue("a"));
52 | assert.isTrue(h.containsValue("b"));
53 | assert.isTrue(h.containsValue("c"));
54 | assert.isTrue(h.containsValue("d"));
55 | assert.isFalse(h.containsValue("e"));
56 | });
57 |
58 | it.should("remove items ", function () {
59 | var h = new MaxHeap();
60 | h.insert(0, 'a');
61 | h.insert(1, 'b');
62 | h.insert(2, 'c');
63 | h.insert(3, 'd');
64 | assert.isFalse(h.isEmpty);
65 | h.remove();
66 | assert.isFalse(h.isEmpty);
67 | h.remove();
68 | assert.isFalse(h.isEmpty);
69 | h.remove();
70 | assert.isFalse(h.isEmpty);
71 | h.remove();
72 | assert.isTrue(h.isEmpty);
73 | });
74 |
75 | it.should("clear all values", function () {
76 | var h = new MaxHeap();
77 | h.insert(0, 'a');
78 | h.insert(1, 'b');
79 | h.insert(2, 'c');
80 | h.insert(3, 'd');
81 | h.clear();
82 | assert.isTrue(h.isEmpty);
83 | assert.equal(h.count, 0, 'count, should be 4');
84 | });
85 |
86 | it.should("peek in order ", function () {
87 | var h = new MaxHeap();
88 | h.insert(0, 'a');
89 | h.insert(1, 'b');
90 | h.insert(2, 'c');
91 | h.insert(3, 'd');
92 | assert.equal(h.peekKey(), 3);
93 | assert.equal(h.peek(), "d");
94 | h.clear();
95 | assert.isUndefined(h.peek());
96 | assert.isUndefined(h.peekKey());
97 | h = new MaxHeap();
98 | h.insert(1, 'b');
99 | h.insert(3, 'd');
100 | h.insert(0, 'a');
101 | h.insert(2, 'c');
102 | assert.equal(h.peekKey(), 3);
103 | assert.equal(h.peek(), "d");
104 |
105 | });
106 |
107 | it.should("remove elements in order", function () {
108 | var h = new MaxHeap();
109 | h.insert(0, 'a');
110 | h.insert(1, 'b');
111 | h.insert(2, 'c');
112 | h.insert(3, 'd');
113 | assert.equal(h.remove(), "d");
114 | assert.equal(h.remove(), "c");
115 | assert.equal(h.remove(), "b");
116 | assert.equal(h.remove(), "a");
117 | h = new MaxHeap();
118 | h.insert(1, 'b');
119 | h.insert(3, 'd');
120 | h.insert(0, 'a');
121 | h.insert(2, 'c');
122 | assert.equal(h.remove(), "d");
123 | assert.equal(h.remove(), "c");
124 | assert.equal(h.remove(), "b");
125 | assert.equal(h.remove(), "a");
126 |
127 | });
128 |
129 |
130 | it.should("peek as items are inserted ", function () {
131 | var h = new MaxHeap();
132 | h.insert(3, 'c');
133 | assert.equal(h.peek(), 'c');
134 | h.insert(2, 'b');
135 | assert.equal(h.peek(), 'c');
136 | h.insert(1, 'd');
137 | assert.equal(h.peek(), 'c');
138 | h.insert(0, 'a');
139 | assert.equal(h.peek(), 'c');
140 | h.clear();
141 | h.insert(1, 'a');
142 | assert.equal(h.peek(), 'a');
143 | h.insert(3, 'b');
144 | assert.equal(h.peek(), 'b');
145 | h.insert(0, 'c');
146 | assert.equal(h.peek(), 'b');
147 | h.insert(2, 'd');
148 | assert.equal(h.peek(), 'b');
149 | });
150 |
151 | it.should("print", function () {
152 | var h = new MaxHeap();
153 | h.insert(1, 'b');
154 | h.insert(3, 'd');
155 | h.insert(0, 'a');
156 | h.insert(2, 'c');
157 | var res = [];
158 | var orig = console.log;
159 | console.log = function (str) {
160 | res.push(str);
161 | };
162 | h.print();
163 | console.log = orig;
164 | res = res.join("\n");
165 |
166 | var expected = "\t\t~\n\t0 : a\n\n\t\t~\n3 : d\n\n\t\t~\n\t2 : c\n\n\t\t\t~\n\t\t1 : b\n\n\t\t\t~";
167 | assert.equal(res, expected);
168 | });
169 |
170 |
171 | }).as(module);
172 |
173 |
174 |
--------------------------------------------------------------------------------
/test/collections/MinHeap.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | MinHeap = comb.collections.MinHeap;
6 |
7 | it.describe("comb.collections.MinHeap", function (it) {
8 |
9 | it.should("know its count", function () {
10 | var h = new MinHeap();
11 | h.insert(0, 'a');
12 | h.insert(1, 'b');
13 | h.insert(2, 'c');
14 | h.insert(3, 'd');
15 | assert.equal(h.count, 4);
16 | h.remove();
17 | assert.equal(h.count, 3);
18 | h.remove();
19 | h.remove();
20 | h.remove();
21 | assert.equal(h.count, 0);
22 | });
23 |
24 | it.should("know its keys", function () {
25 | var h = new MinHeap();
26 | h.insert(0, 'a');
27 | h.insert(1, 'b');
28 | h.insert(2, 'c');
29 | h.insert(3, 'd');
30 | var keys = h.keys;
31 | for (var i = 0; i < 4; i++) {
32 | assert.isTrue(keys.indexOf(i) !== -1);
33 | }
34 | for (i = 0; i < 4; i++) {
35 | assert.isTrue(h.containsKey(i));
36 | }
37 | assert.isFalse(h.containsKey(4));
38 | });
39 |
40 | it.should("know its values", function () {
41 | var h = new MinHeap();
42 | h.insert(0, 'a');
43 | h.insert(1, 'b');
44 | h.insert(2, 'c');
45 | h.insert(3, 'd');
46 | var vals = h.values;
47 | assert.isTrue(vals.indexOf("a") !== -1);
48 | assert.isTrue(vals.indexOf("b") !== -1);
49 | assert.isTrue(vals.indexOf("c") !== -1);
50 | assert.isTrue(vals.indexOf("d") !== -1);
51 | assert.isTrue(h.containsValue("a"));
52 | assert.isTrue(h.containsValue("b"));
53 | assert.isTrue(h.containsValue("c"));
54 | assert.isTrue(h.containsValue("d"));
55 | assert.isFalse(h.containsValue("e"));
56 | });
57 |
58 | it.should("remove items ", function () {
59 | var h = new MinHeap();
60 | h.insert(0, 'a');
61 | h.insert(1, 'b');
62 | h.insert(2, 'c');
63 | h.insert(3, 'd');
64 | assert.isFalse(h.isEmpty);
65 | h.remove();
66 | assert.isFalse(h.isEmpty);
67 | h.remove();
68 | assert.isFalse(h.isEmpty);
69 | h.remove();
70 | assert.isFalse(h.isEmpty);
71 | h.remove();
72 | assert.isTrue(h.isEmpty);
73 | });
74 |
75 | it.should("clear all values", function () {
76 | var h = new MinHeap();
77 | h.insert(0, 'a');
78 | h.insert(1, 'b');
79 | h.insert(2, 'c');
80 | h.insert(3, 'd');
81 | h.clear();
82 | assert.isTrue(h.isEmpty);
83 | assert.equal(h.count, 0, 'count, should be 4');
84 | });
85 |
86 | it.should("peek in order ", function () {
87 | var h = new MinHeap();
88 | h.insert(0, 'a');
89 | h.insert(1, 'b');
90 | h.insert(2, 'c');
91 | h.insert(3, 'd');
92 | assert.equal(h.peekKey(), 0);
93 | assert.equal(h.peek(), "a");
94 | h.clear();
95 | assert.isUndefined(h.peek());
96 | assert.isUndefined(h.peekKey());
97 | h = new MinHeap();
98 | h.insert(1, 'b');
99 | h.insert(3, 'd');
100 | h.insert(0, 'a');
101 | h.insert(2, 'c');
102 | assert.equal(h.peekKey(), 0);
103 | assert.equal(h.peek(), "a");
104 |
105 | });
106 |
107 | it.should("remove elements in order", function () {
108 | var h = new MinHeap();
109 | h.insert(0, 'a');
110 | h.insert(1, 'b');
111 | h.insert(2, 'c');
112 | h.insert(3, 'd');
113 | assert.equal(h.remove(), "a");
114 | assert.equal(h.remove(), "b");
115 | assert.equal(h.remove(), "c");
116 | assert.equal(h.remove(), "d");
117 | h = new MinHeap();
118 | h.insert(1, 'b');
119 | h.insert(3, 'd');
120 | h.insert(0, 'a');
121 | h.insert(2, 'c');
122 | assert.equal(h.remove(), "a");
123 | assert.equal(h.remove(), "b");
124 | assert.equal(h.remove(), "c");
125 | assert.equal(h.remove(), "d");
126 | });
127 |
128 |
129 | it.should("peek as items are inserted ", function () {
130 | var h = new MinHeap();
131 | h.insert(3, 'd');
132 | assert.equal(h.peek(), 'd');
133 | h.insert(2, 'c');
134 | assert.equal(h.peek(), 'c');
135 | h.insert(1, 'b');
136 | assert.equal(h.peek(), 'b');
137 | h.insert(0, 'a');
138 | assert.equal(h.peek(), 'a');
139 | h.clear();
140 | h.insert(1, 'b');
141 | assert.equal(h.peek(), 'b');
142 | h.insert(3, 'd');
143 | assert.equal(h.peek(), 'b');
144 | h.insert(0, 'a');
145 | assert.equal(h.peek(), 'a');
146 | h.insert(2, 'c');
147 | assert.equal(h.peek(), 'a');
148 | });
149 |
150 |
151 | }).as(module);
152 |
153 |
--------------------------------------------------------------------------------
/test/collections/Pool.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | Pool = comb.collections.Pool;
6 |
7 | it.describe("comb.collections.Pool", function (it) {
8 |
9 | var p = new Pool();
10 |
11 | it.should("know its minObjects count ", function () {
12 | assert.equal(p.minObjects, 0);
13 | });
14 |
15 | it.should("know its free count", function () {
16 | assert.equal(p.freeCount, 0);
17 | });
18 |
19 | it.should("know its in use count", function () {
20 | assert.equal(p.inUseCount, 0);
21 | });
22 |
23 | it.should("know its total count", function () {
24 | assert.equal(p.count, 0);
25 | });
26 |
27 | it.should("only return 1 object", function () {
28 | var o = p.getObject();
29 | assert.isObject(o);
30 | assert.isUndefined(p.getObject());
31 | p.returnObject(o);
32 | });
33 |
34 | it.should("update the maxObjects ", function () {
35 | p.maxObjects = 3;
36 | var o = p.getObject(), o1 = p.getObject(), o2 = p.getObject();
37 | assert.isObject(o);
38 | assert.isUndefined(p.getObject());
39 | p.maxObjects = 1;
40 | p.returnObject(o2);
41 | p.returnObject(o1);
42 | p.returnObject(o);
43 | assert.equal(p.getObject(), o);
44 | p.returnObject(o);
45 | assert.throws(function () {
46 | p.maxObjects = -1;
47 | });
48 | p.maxObjects = 5;
49 | });
50 |
51 | it.should("update the minObjects ", function () {
52 | p.minObjects = 5;
53 | assert.equal(p.inUseCount, 0);
54 | assert.equal(p.count, 5);
55 | assert.equal(p.freeCount, 5);
56 | assert.equal(p.minObjects, 5);
57 | });
58 |
59 | it.should("throw an error when creating a with maxObjects less than minObject", function () {
60 | assert.throws(function () {
61 | new Pool({maxObject:1, minObjects:3});
62 | });
63 | });
64 |
65 | it.should("return objects properly", function () {
66 | var p = new Pool({maxObjects:3});
67 |
68 | var o1 = p.getObject();
69 | assert.isObject(o1);
70 | assert.equal(p.freeCount, 0);
71 | assert.equal(p.inUseCount, 1);
72 | assert.equal(p.count, 1);
73 | var o2 = p.getObject();
74 | assert.isObject(o2);
75 | assert.equal(p.freeCount, 0);
76 | assert.equal(p.inUseCount, 2);
77 | assert.equal(p.count, 2);
78 | var o3 = p.getObject();
79 | assert.isObject(o3);
80 | assert.equal(p.freeCount, 0);
81 | assert.equal(p.inUseCount, 3);
82 | assert.equal(p.count, 3);
83 | assert.isUndefined(p.getObject());
84 | assert.equal(p.freeCount, 0);
85 | assert.equal(p.inUseCount, 3);
86 | assert.equal(p.count, 3);
87 | p.returnObject(o1);
88 | assert.equal(p.freeCount, 1);
89 | assert.equal(p.inUseCount, 2);
90 | assert.equal(p.count, 3);
91 | p.returnObject(o2);
92 | assert.equal(p.freeCount, 2);
93 | assert.equal(p.inUseCount, 1);
94 | assert.equal(p.count, 3);
95 | p.returnObject(o3);
96 | assert.equal(p.freeCount, 3);
97 | assert.equal(p.inUseCount, 0);
98 | assert.equal(p.count, 3);
99 |
100 | });
101 |
102 | it.should("allow adjusting maxObjects", function () {
103 | var p = new Pool();
104 |
105 | assert.equal(p.freeCount, 0);
106 | assert.equal(p.inUseCount, 0);
107 | assert.equal(p.count, 0);
108 | assert.isObject(p.getObject());
109 | assert.isUndefined(p.getObject());
110 | p.maxObjects = 3;
111 | assert.equal(p.freeCount, 0);
112 | assert.equal(p.inUseCount, 1);
113 | assert.equal(p.count, 1);
114 | assert.isObject(p.getObject());
115 | assert.equal(p.freeCount, 0);
116 | assert.equal(p.inUseCount, 2);
117 | assert.equal(p.count, 2);
118 | assert.isObject(p.getObject());
119 | assert.equal(p.freeCount, 0);
120 | assert.equal(p.inUseCount, 3);
121 | assert.equal(p.count, 3);
122 |
123 | });
124 |
125 | it.describe("creating a new pool maxObjects", function (it) {
126 | var p = new Pool({maxObjects:3});
127 |
128 | it.should("know its maxObjects count ", function () {
129 | assert.equal(p.maxObjects, 3);
130 | });
131 |
132 | it.should("only return 3 object", function () {
133 | assert.isObject(p.getObject());
134 | assert.isObject(p.getObject());
135 | assert.isObject(p.getObject());
136 | assert.isUndefined(p.getObject());
137 | });
138 |
139 | it.should("know its free count", function () {
140 | assert.equal(p.freeCount, 0);
141 | });
142 |
143 | it.should("know its in use count", function () {
144 | assert.equal(p.inUseCount, 3);
145 | });
146 |
147 | it.should("know its total count", function () {
148 | assert.equal(p.count, 3);
149 | });
150 | });
151 | }).as(module);
152 |
--------------------------------------------------------------------------------
/test/collections/PriorityQueue.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | PriorityQueue = comb.collections.PriorityQueue;
6 |
7 | it.describe("comb.collections.PriorityQueue", function (it) {
8 |
9 | it.should("know its count", function () {
10 | var q = new PriorityQueue();
11 | q.enqueue(0, 'a');
12 | q.enqueue(1, 'b');
13 | q.enqueue(2, 'c');
14 | q.enqueue(3, 'd');
15 | assert.equal(q.count, 4);
16 | q.dequeue();
17 | assert.equal(q.count, 3);
18 | q.dequeue();
19 | q.dequeue();
20 | q.dequeue();
21 | assert.equal(q.count, 0);
22 | });
23 |
24 | it.should("know its keys", function () {
25 | var q = new PriorityQueue();
26 | q.enqueue(0, 'a');
27 | q.enqueue(1, 'b');
28 | q.enqueue(2, 'c');
29 | q.enqueue(3, 'd');
30 |
31 | var keys = q.keys;
32 | for (var i = 0; i < 4; i++) {
33 | assert.isTrue(keys.indexOf(i) !== -1);
34 | }
35 | for (i = 0; i < 4; i++) {
36 | assert.isTrue(q.containsKey(i));
37 | }
38 | assert.isFalse(q.containsKey(4));
39 |
40 | });
41 |
42 | it.should("know its values", function () {
43 | var q = new PriorityQueue();
44 | q.enqueue(0, 'a');
45 | q.enqueue(1, 'b');
46 | q.enqueue(2, 'c');
47 | q.enqueue(3, 'd');
48 | var vals = q.values;
49 | assert.isTrue(vals.indexOf("a") !== -1);
50 | assert.isTrue(vals.indexOf("b") !== -1);
51 | assert.isTrue(vals.indexOf("c") !== -1);
52 | assert.isTrue(vals.indexOf("d") !== -1);
53 | assert.isTrue(q.containsValue("a"));
54 | assert.isTrue(q.containsValue("b"));
55 | assert.isTrue(q.containsValue("c"));
56 | assert.isTrue(q.containsValue("d"));
57 | assert.isFalse(q.containsValue("e"));
58 | });
59 |
60 | it.should("dequeue items ", function () {
61 | var q = new PriorityQueue();
62 | q.enqueue(0, 'a');
63 | q.enqueue(1, 'b');
64 | q.enqueue(2, 'c');
65 | q.enqueue(3, 'd');
66 | assert.isFalse(q.isEmpty);
67 | q.dequeue();
68 | assert.isFalse(q.isEmpty);
69 | q.dequeue();
70 | assert.isFalse(q.isEmpty);
71 | q.dequeue();
72 | assert.isFalse(q.isEmpty);
73 | q.dequeue();
74 | assert.isTrue(q.isEmpty);
75 | });
76 |
77 | it.should("clear its items", function () {
78 |
79 | var q = new PriorityQueue();
80 | q.enqueue(0, 'a');
81 | q.enqueue(1, 'b');
82 | q.enqueue(2, 'c');
83 | q.enqueue(3, 'd');
84 | q.clear();
85 | assert.isTrue(q.isEmpty);
86 | assert.equal(q.count, 0, 'count, should be 4');
87 | });
88 |
89 | it.should("peek items in order ", function () {
90 | var q = new PriorityQueue();
91 | q.enqueue(0, 'a');
92 | q.enqueue(1, 'b');
93 | q.enqueue(2, 'c');
94 | q.enqueue(3, 'd');
95 | assert.equal(q.peek(), "a");
96 | q.clear();
97 | assert.isUndefined(q.peek());
98 | q = new PriorityQueue();
99 | q.enqueue(1, 'b');
100 | q.enqueue(3, 'd');
101 | q.enqueue(0, 'a');
102 | q.enqueue(2, 'c');
103 | assert.equal(q.peek(), "a");
104 | });
105 |
106 | it.should("dequeue in order", function () {
107 | var q = new PriorityQueue();
108 | q.enqueue(0, 'a');
109 | q.enqueue(1, 'b');
110 | q.enqueue(2, 'c');
111 | q.enqueue(3, 'd');
112 | assert.equal(q.dequeue(), "a");
113 | assert.equal(q.dequeue(), "b");
114 | assert.equal(q.dequeue(), "c");
115 | assert.equal(q.dequeue(), "d");
116 | q = new PriorityQueue();
117 | q.enqueue(1, 'b');
118 | q.enqueue(3, 'd');
119 | q.enqueue(0, 'a');
120 | q.enqueue(2, 'c');
121 | assert.equal(q.dequeue(), "a");
122 | assert.equal(q.dequeue(), "b");
123 | assert.equal(q.dequeue(), "c");
124 | assert.equal(q.dequeue(), "d");
125 | });
126 |
127 | it.should("peek as enqueued properly", function () {
128 | var q = new PriorityQueue();
129 | q.enqueue(3, 'd');
130 | assert.equal(q.peek(), 'd');
131 | q.enqueue(2, 'c');
132 | assert.equal(q.peek(), 'c');
133 | q.enqueue(1, 'b');
134 | assert.equal(q.peek(), 'b');
135 | q.enqueue(0, 'a');
136 | assert.equal(q.peek(), 'a');
137 | q.clear();
138 | q.enqueue(1, 'b');
139 | assert.equal(q.peek(), 'b');
140 | q.enqueue(3, 'd');
141 | assert.equal(q.peek(), 'b');
142 | q.enqueue(0, 'a');
143 | assert.equal(q.peek(), 'a');
144 | q.enqueue(2, 'c');
145 | assert.equal(q.peek(), 'a');
146 | });
147 |
148 | }).as(module);
149 |
150 |
151 |
--------------------------------------------------------------------------------
/test/collections/Queue.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | Queue = comb.collections.Queue;
6 |
7 |
8 | it.describe("comb.collections.Queue", function (it) {
9 | var queue = new Queue();
10 |
11 | it.should("enqueue", function () {
12 | queue.enqueue("test");
13 | assert.isTrue(queue.contains("test"));
14 | assert.equal("test", queue.toString());
15 | });
16 | it.should("dequeue", function () {
17 | assert.equal(queue.dequeue(), "test");
18 | assert.isFalse(queue.contains("test"));
19 | });
20 | it.should("peek", function () {
21 | queue.enqueue("test");
22 | assert.equal(queue.peek(), "test");
23 | assert.isTrue(queue.contains("test"));
24 | });
25 | it.should("know if it is empty", function () {
26 | assert.isFalse(queue.isEmpty);
27 | queue.dequeue();
28 | assert.isTrue(queue.isEmpty);
29 | });
30 | it.should("know its element count", function () {
31 | queue.enqueue("test");
32 | queue.enqueue("test1");
33 | queue.enqueue("test2");
34 | queue.enqueue("test3");
35 | queue.enqueue("test4");
36 | queue.enqueue("test5");
37 | queue.enqueue("test6");
38 | assert.equal(queue.count, 7);
39 | assert.equal(",,test,test1,test2,test3,test4,test5,test6", queue.toString());
40 | });
41 | it.should("return all values", function () {
42 | var vals = ["test", "test1", "test2", "test3", "test4", "test5", "test6"];
43 | assert.isTrue(queue.values.every(function (v, i) {
44 | return v === vals[i];
45 | }));
46 | });
47 |
48 | it.should("remove values", function () {
49 | queue.remove("test6");
50 | queue.remove("test5");
51 | queue.remove("test4");
52 | queue.remove("test3");
53 | queue.remove("test2");
54 | queue.remove("test1");
55 | queue.remove("test");
56 | assert.isTrue(queue.isEmpty);
57 | });
58 |
59 | it.should("clear all elements", function () {
60 | queue.enqueue("test");
61 | queue.enqueue("test1");
62 | queue.enqueue("test2");
63 | queue.enqueue("test3");
64 | queue.enqueue("test4");
65 | queue.enqueue("test5");
66 | queue.enqueue("test6");
67 | assert.isFalse(queue.isEmpty);
68 | assert.equal(",,,test,test1,test2,test3,test4,test5,test6", queue.toString());
69 | queue.clear();
70 | assert.isTrue(queue.isEmpty);
71 | assert.equal(queue.count, 0);
72 | });
73 | it.should("return undefined if empty and dequeue is called", function () {
74 | assert.isUndefined(queue.dequeue());
75 | });
76 |
77 |
78 | }).as(module);
79 |
--------------------------------------------------------------------------------
/test/collections/RedBlackTree.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | helper = require("./treeTest.helper.js"),
6 | Mammal = helper.Mammal,
7 | RedBlackTree = comb.collections.RedBlackTree;
8 |
9 |
10 | it.describe("comb.collections.RedBlackTree", function (it) {
11 |
12 | var words = ["c", "ca", "b", "ba", "bb", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
13 | var wordsInOrder = [ 'a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z' ];
14 | var wordsPreOrder = ['d', 'ba', 'aa', 'a', 'ajk', 'ab', 'b', 'c', 'bb', 'ca', 'h', 'f', 'ee', 'ff', 'i', 'hi', 'z', 'j'];
15 | var wordsPostOrder = [ 'a', 'ab', 'b', 'ajk', 'aa', 'bb', 'ca', 'c', 'ba', 'ee', 'ff', 'f', 'hi', 'j', 'z', 'i', 'h', 'd'];
16 |
17 |
18 |
19 | var mammals = [
20 | new Mammal({type:"bird"}),
21 | new Mammal({type:"dog"}),
22 | new Mammal({type:"rat"}),
23 | new Mammal({type:"zebra"}),
24 | new Mammal({type:"mouse"}),
25 | new Mammal({type:"horse"}),
26 | new Mammal({type:"squirrel"}),
27 | new Mammal({type:"groundhog"})
28 | ],
29 |
30 | mammalsInOrder = [
31 | new Mammal({type:"bird"}),
32 | new Mammal({type:"dog"}),
33 | new Mammal({type:"groundhog"}),
34 | new Mammal({type:"horse"}),
35 | new Mammal({type:"mouse"}),
36 | new Mammal({type:"rat"}),
37 | new Mammal({type:"squirrel"}),
38 | new Mammal({type:"zebra"})
39 | ],
40 |
41 | mammalsPreOrder = [
42 | new Mammal({type:"dog"}),
43 | new Mammal({type:"bird"}),
44 | new Mammal({type:"rat"}),
45 | new Mammal({type:"horse"}),
46 | new Mammal({type:"groundhog"}),
47 | new Mammal({type:"mouse"}),
48 | new Mammal({type:"zebra"}),
49 | new Mammal({type:"squirrel"})
50 | ],
51 |
52 | mammalsPostOrder = [
53 | new Mammal({type:"bird"}),
54 | new Mammal({type:"groundhog"}),
55 | new Mammal({type:"mouse"}),
56 | new Mammal({type:"horse"}),
57 | new Mammal({type:"squirrel"}),
58 | new Mammal({type:"zebra"}),
59 | new Mammal({type:"rat"}),
60 | new Mammal({type:"dog"})
61 | ];
62 |
63 | var orderedMammals = [
64 | [RedBlackTree.IN_ORDER, mammalsInOrder],
65 | [RedBlackTree.PRE_ORDER, mammalsPreOrder],
66 | [RedBlackTree.POST_ORDER, mammalsPostOrder]
67 | ];
68 |
69 | var expectedOutput = "\t\t\t\t~\n\t\t\tBLACK:z\n\n\t\t\t\t\t~\n\t\t\t\tRED:j\n\n\t\t\t\t\t~\n\t\tBLACK:i" +
70 | "\n\n\t\t\t\t~\n\t\t\tBLACK:hi\n\n\t\t\t\t~\n\tBLACK:h\n\n\t\t\t\t~\n\t\t\tBLACK:ff\n\n\t\t\t\t~" +
71 | "\n\t\tBLACK:f\n\n\t\t\t\t~\n\t\t\tBLACK:ee\n\n\t\t\t\t~\nBLACK:d\n\n\t\t\t\t~\n\t\t\tBLACK:ca" +
72 | "\n\n\t\t\t\t~\n\t\tBLACK:c\n\n\t\t\t\t~\n\t\t\tBLACK:bb\n\n\t\t\t\t~\n\tBLACK:ba" +
73 | "\n\n\t\t\t\t\t~\n\t\t\t\tRED:b\n\n\t\t\t\t\t~\n\t\t\tBLACK:ajk\n\n\t\t\t\t\t~\n\t\t\t\t" +
74 | "RED:ab\n\n\t\t\t\t\t~\n\t\tBLACK:aa\n\n\t\t\t\t~\n\t\t\tBLACK:a\n\n\t\t\t\t~";
75 | var orderedWords = [
76 | [RedBlackTree.IN_ORDER, wordsInOrder],
77 | [RedBlackTree.PRE_ORDER, wordsPreOrder],
78 | [RedBlackTree.POST_ORDER, wordsPostOrder]
79 | ];
80 |
81 | helper.setup(
82 | it,
83 | RedBlackTree,
84 | words,
85 | orderedWords,
86 | mammals,
87 | orderedMammals,
88 | expectedOutput);
89 |
90 | }).as(module);
--------------------------------------------------------------------------------
/test/collections/Stack.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | Stack = comb.collections.Stack;
6 |
7 | it.describe("comb.collections.Stack", function (it) {
8 | var stack = new Stack();
9 |
10 | it.should("push", function () {
11 | stack.push("test");
12 | assert.isTrue(stack.contains("test"));
13 | assert.equal("test", stack.toString());
14 | });
15 |
16 | it.should("pop", function () {
17 | assert.equal(stack.pop(), "test");
18 | assert.isFalse(stack.contains("test"));
19 | });
20 |
21 | it.should("peek", function () {
22 | stack.push("test");
23 | assert.equal(stack.peek(), "test");
24 | assert.isTrue(stack.contains("test"));
25 | });
26 |
27 | it.should("know if it is empty", function () {
28 | assert.isFalse(stack.isEmpty);
29 | stack.pop();
30 | assert.isTrue(stack.isEmpty);
31 | });
32 |
33 | it.should("know its element count", function () {
34 | stack.push("test");
35 | stack.push("test1");
36 | stack.push("test2");
37 | stack.push("test3");
38 | stack.push("test4");
39 | stack.push("test5");
40 | stack.push("test6");
41 | assert.equal(stack.count, 7);
42 | assert.equal("test,test1,test2,test3,test4,test5,test6", stack.toString());
43 | });
44 |
45 | it.should("pop values", function () {
46 | assert.equal(stack.pop(), "test6");
47 | assert.equal(stack.pop(), "test5");
48 | assert.equal(stack.pop(), "test4");
49 | assert.equal(stack.pop(), "test3");
50 | assert.equal(stack.pop(), "test2");
51 | assert.equal(stack.pop(), "test1");
52 | assert.equal(stack.pop(), "test");
53 | assert.equal(stack.count, 0);
54 | });
55 |
56 | it.should("return all values", function () {
57 | stack.push("test");
58 | stack.push("test1");
59 | stack.push("test2");
60 | stack.push("test3");
61 | stack.push("test4");
62 | stack.push("test5");
63 | stack.push("test6");
64 | var vals = ["test", "test1", "test2", "test3", "test4", "test5", "test6"].reverse();
65 | assert.isTrue(stack.values.every(function (v, i) {
66 | return v === vals[i];
67 | }));
68 | assert.equal("test,test1,test2,test3,test4,test5,test6", stack.toString());
69 | });
70 |
71 | it.should("remove values", function () {
72 | stack.remove("test");
73 | stack.remove("test1");
74 | stack.remove("test2");
75 | stack.remove("test3");
76 | stack.remove("test4");
77 | stack.remove("test5");
78 | stack.remove("test6");
79 | assert.isTrue(stack.isEmpty);
80 | });
81 |
82 | it.should("clear all elements", function () {
83 | stack.push("test");
84 | stack.push("test1");
85 | stack.push("test2");
86 | stack.push("test3");
87 | stack.push("test4");
88 | stack.push("test5");
89 | stack.push("test6");
90 | assert.isFalse(stack.isEmpty);
91 | stack.clear();
92 | assert.isTrue(stack.isEmpty);
93 | assert.equal(stack.count, 0);
94 | });
95 |
96 | it.should("return undefined if empty and dequeue is called", function () {
97 | assert.isUndefined(stack.pop());
98 | });
99 |
100 | }).as(module);
101 |
--------------------------------------------------------------------------------
/test/collections/Tree.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | Tree = comb.collections.Tree;
6 |
7 |
8 | it.describe("A Tree interface", function (it) {
9 | var methods = ["insert", "remove"];
10 |
11 | var tree = new Tree();
12 | methods.forEach(function (m) {
13 | it.describe("#" + m, function (it) {
14 | it.should("be abstract", function () {
15 | assert.throws(function () {
16 | tree[m]();
17 | });
18 | });
19 | });
20 | });
21 |
22 | }).as(module);
23 |
24 |
--------------------------------------------------------------------------------
/test/extensions/is.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var comb = require("../../index"),
3 | assert = require("assert"),
4 | it = require("it");
5 |
6 | it.describe("is extension",function (it) {
7 |
8 | it.should("expose equality methods", function () {
9 | assert.isTrue(comb(1).eq(1));
10 | assert.isFalse(comb(1).eq(2));
11 | assert.isTrue(comb("hello").eq("hello"));
12 | assert.isFalse(comb("hello").eq("world"));
13 | assert.isFalse(comb(new Date(2001, 1, 1, 1, 1, 1, 111)).eq(new Date(2001, 1, 1, 1, 1, 1, 111)));
14 | assert.isFalse(comb({}).eq({}));
15 | });
16 |
17 | it.should("expose neq methods", function () {
18 | assert.isFalse(comb(1).neq(1));
19 | assert.isTrue(comb(1).neq(2));
20 | assert.isFalse(comb("hello").neq("hello"));
21 | assert.isTrue(comb("hello").neq("world"));
22 | assert.isTrue(comb(new Date(2001, 1, 1, 1, 1, 1, 111)).neq(new Date(2001, 1, 1, 1, 1, 1, 111)));
23 | assert.isTrue(comb({}).neq({}));
24 | });
25 |
26 | it.should("expose value of properly", function () {
27 | var date = new Date(2001, 1, 1, 1, 1, 1, 111),
28 | date2 = new Date(2001, 1, 1, 1, 1, 1, 111);
29 | assert.deepEqual(comb(date).valueOf(), date.valueOf());
30 | assert.strictEqual(comb("hello").valueOf(), "hello");
31 | assert.strictEqual(comb(true).valueOf(), true);
32 | assert.deepEqual(comb({}).valueOf(), {});
33 | });
34 |
35 | it.should("print properly", function () {
36 | var orig = console.log, val;
37 | console.log = function (arg) {
38 | val = arg;
39 | };
40 | comb("hello").print();
41 | assert.strictEqual(val, "hello");
42 |
43 | comb(1).print();
44 | assert.strictEqual(val, 1);
45 |
46 | comb(true).print();
47 | assert.strictEqual(val, true);
48 | console.log = orig;
49 | });
50 |
51 | }).as(module);
--------------------------------------------------------------------------------
/test/logging/appenders/appender.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../../index"),
5 | logging = comb.logging,
6 | Appender = logging.appenders.Appender;
7 |
8 | it.describe("comb.logging.appenders.Appender", function (it) {
9 |
10 | var MyAppender = comb.define(Appender, {
11 | instance: {
12 | append: function (event) {
13 | if (this._canAppend(event)) {
14 | this.onAppend(comb.string.format(this.__pattern, event));
15 | }
16 | },
17 |
18 | onAppend: function () {
19 |
20 | }
21 | }
22 | }).registerType("MyAppender");
23 |
24 |
25 | var logger1 = logging.Logger.getLogger("AppenderTest"),
26 | logger2 = logging.Logger.getLogger("AppenderTest.one"),
27 | logger3 = logging.Logger.getLogger("AppenderTest.one.two");
28 | it.describe("adding appender to loggers", function (it) {
29 | var appender;
30 | it.beforeAll(function () {
31 | appender = new Appender({name: "myAppender1"});
32 | logger1.addAppender(appender);
33 | });
34 |
35 | it.should("be added to all subloggers", function () {
36 | assert.isTrue(logger1.isAppenderAttached(appender.name));
37 | assert.isTrue(logger2.isAppenderAttached(appender.name));
38 | assert.isTrue(logger3.isAppenderAttached(appender.name));
39 | });
40 |
41 | it.should("have it level defaulted to all", function () {
42 | assert.equal(appender.level, logging.Level.ALL);
43 | });
44 |
45 | it.should("allow its level to be set", function () {
46 | appender.level = "info";
47 | assert.equal(appender.level, logging.Level.INFO);
48 | });
49 |
50 | it.should("allow its pattern to be set", function () {
51 | appender.pattern = "{message}";
52 | assert.equal(appender.pattern, "{message}");
53 | });
54 |
55 | it.should("be removed from loggers if removeAllAppenders is called", function () {
56 | logger1.removeAppender(appender.name);
57 | assert.isFalse(logger1.isAppenderAttached(appender.name));
58 | assert.isFalse(logger2.isAppenderAttached(appender.name));
59 | assert.isFalse(logger3.isAppenderAttached(appender.name));
60 | logger2.addAppenders([appender]);
61 | assert.isFalse(logger1.isAppenderAttached(appender.name));
62 | assert.isTrue(logger2.isAppenderAttached(appender.name));
63 | assert.isTrue(logger3.isAppenderAttached(appender.name));
64 | logger2.removeAppenders([appender.name]);
65 | assert.isFalse(logger1.isAppenderAttached(appender.name));
66 | assert.isFalse(logger2.isAppenderAttached(appender.name));
67 | assert.isFalse(logger3.isAppenderAttached(appender.name));
68 | logger3.addAppender(appender);
69 | assert.isFalse(logger1.isAppenderAttached(appender.name));
70 | assert.isFalse(logger2.isAppenderAttached(appender.name));
71 | assert.isTrue(logger3.isAppenderAttached(appender.name));
72 | logger3.removeAllAppenders();
73 | assert.isFalse(logger1.isAppenderAttached(appender.name));
74 | assert.isFalse(logger2.isAppenderAttached(appender.name));
75 | assert.isFalse(logger3.isAppenderAttached(appender.name));
76 | });
77 |
78 | it.should("throw an error if append is called", function () {
79 | assert.throws(function () {
80 | appender.append();
81 | });
82 | });
83 | });
84 |
85 | it.describe("adding an appender and setting the level ", function (it) {
86 | var topic;
87 | it.beforeAll(function () {
88 | topic = new MyAppender({level: 6});
89 | });
90 |
91 | it.should("have its level set to FATAL", function () {
92 | assert.equal(topic.level, logging.Level.FATAL);
93 | });
94 |
95 | it.should("only log fatal messages ", function () {
96 | logger1.addAppender(topic);
97 | topic.level = 6;
98 | var levels = ["debug", "trace", "info", "warn", "error", "fatal"];
99 | var count = 0;
100 | comb.connect(topic, "onAppend", function () {
101 | count++;
102 | });
103 | levels.forEach(function (l) {
104 | logger1[l](l);
105 | logger2[l](l);
106 | logger3[l](l);
107 | });
108 | assert.equal(count, 3);
109 |
110 | });
111 |
112 | });
113 |
114 | it.describe(".createAppender", function (it) {
115 | it.should("create an appender from a type", function () {
116 | var appender = Appender.createAppender("MyAppender");
117 | assert.instanceOf(appender, MyAppender);
118 | });
119 |
120 | it.should("throw an error if an appender is not registered", function () {
121 | assert.throws(function () {
122 | Appender.createAppender("nonexistentappender");
123 | });
124 | });
125 | });
126 |
127 | }).as(module);
128 |
--------------------------------------------------------------------------------
/test/logging/appenders/consoleAppender.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../../index"),
5 | logging = comb.logging,
6 | ConsoleAppender = logging.appenders.ConsoleAppender;
7 |
8 |
9 | it.describe("comb.logging.appenders.ConsoleAppender", function (it) {
10 |
11 | var logger = comb.logger("ConsoleLoggerTest"), appender;
12 | it.beforeAll(function () {
13 | appender = new ConsoleAppender();
14 | logger.addAppender(appender);
15 | });
16 |
17 | it.should("be added to the logger", function () {
18 | assert.isTrue(logger.isAppenderAttached("consoleAppender"));
19 | assert.deepEqual(logger.appenders, [appender]);
20 | });
21 |
22 |
23 | it.should("have then logged to the appender ", function () {
24 | var orig = console.log;
25 | try {
26 | var count = 0;
27 | var levels = ["debug", "trace", "info", "warn", "error", "fatal"];
28 | console.log = function (str) {
29 | assert.isTrue(str.match(levels[count]) != null);
30 | count++;
31 | };
32 | levels.forEach(function (l) {
33 | logger[l](l);
34 | });
35 | assert.equal(count, 6);
36 | } catch (e) {
37 | throw e;
38 | } finally {
39 | console.log = orig;
40 | }
41 |
42 | });
43 |
44 | it.should("the logger should log no events to the appender ", function () {
45 |
46 | var orig = console.log;
47 | try {
48 | logger.level = logging.Level.OFF;
49 | var count = 0;
50 | var levels = ["debug", "trace", "info", "warn", "error", "fatal"];
51 | console.log = function (str) {
52 | assert.isTrue(str.match(levels[count]) != null);
53 | count++;
54 | };
55 | levels.forEach(function (l) {
56 | logger[l](l);
57 | });
58 | assert.equal(count, 0);
59 | } catch (e) {
60 | throw e;
61 | } finally {
62 | console.log = orig;
63 | }
64 | });
65 |
66 | it.should("have an wrapStyle option to turn off style", function () {
67 | var styleLogger = comb.logger("ConsoleLoggerIncludeStyleTest"),
68 | styleAppender = new ConsoleAppender({
69 | wrapStyle: false,
70 | pattern: "{message}"
71 | }),
72 | orig = console.log;
73 | styleLogger.addAppender(styleAppender);
74 | try {
75 | var count = 0;
76 | var levels = ["debug", "info", "warn", "error", "fatal"];
77 | console.log = function (str) {
78 | assert.equal(str, levels[count]);
79 | count++;
80 | };
81 | levels.forEach(function (l) {
82 | styleLogger[l](l);
83 | });
84 | assert.equal(count, 5);
85 |
86 | console.log = function (str) {
87 | assert.isTrue(str.match(/Trace: message/) != null);
88 | count++;
89 | };
90 | styleLogger.trace("message");
91 | } catch (e) {
92 | throw e;
93 | } finally {
94 | console.log = orig;
95 | }
96 | });
97 |
98 | it.should("supports levelNameColored property", function () {
99 | var styleLogger = comb.logger("ConsoleLoggerIncludeStyleTest2"),
100 | styleAppender = new ConsoleAppender({
101 | wrapStyle: false,
102 | pattern: "{levelNameColored} {message}"
103 | }),
104 | orig = console.log;
105 | styleLogger.addAppender(styleAppender);
106 | try {
107 | var count = 0;
108 | console.log = function (str) {
109 | assert.equal(str, "\x1B[31mERROR\x1B[0m message");
110 | count++;
111 | };
112 | styleLogger.error("message");
113 | assert.equal(count, 1);
114 | } catch (e) {
115 | throw e;
116 | } finally {
117 | console.log = orig;
118 | }
119 | });
120 |
121 | }).as(module);
122 |
--------------------------------------------------------------------------------
/test/logging/appenders/fileAppender.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../../index"),
5 | logging = comb.logging,
6 | FileAppender = logging.appenders.FileAppender;
7 |
8 |
9 | it.describe("comb.logging.appenders.FileAppender", function (it) {
10 |
11 | var MockWriteStream = {
12 | writable: true,
13 | on: function () {
14 | },
15 | destroySoon: function () {
16 | },
17 | write: function (str) {
18 | return str;
19 | }
20 | };
21 |
22 | var logger = logging.Logger.getLogger("FilerAppenderTest"),
23 | appender = new FileAppender({writeStream: MockWriteStream});
24 | logger.addAppender(appender);
25 |
26 | it.should("be added to the logger", function () {
27 | assert.isTrue(logger.isAppenderAttached("fileAppender"));
28 | assert.deepEqual(logger.appenders, [appender]);
29 | });
30 |
31 | it.should("have events logged to it by the logger according to level", function () {
32 |
33 | var count = 0;
34 | var levels = ["debug", "trace", "info", "warn", "error", "fatal"];
35 | var conn = comb.connect(MockWriteStream, "write", function (str) {
36 | assert.isTrue(str.match(levels[count]) != null);
37 | count++;
38 | });
39 | levels.forEach(function (l) {
40 | logger[l](l);
41 | });
42 | assert.equal(count, 6);
43 | comb.disconnect(conn);
44 |
45 |
46 | logger.level = logging.Level.OFF;
47 | count = 0;
48 | conn = comb.connect(MockWriteStream, "write", function (str) {
49 | assert.isTrue(str.match(levels[count]) != null);
50 | count++;
51 | });
52 | levels.forEach(function (l) {
53 | logger[l](l);
54 | });
55 | assert.equal(count, 0);
56 | comb.disconnect(conn);
57 |
58 |
59 | });
60 |
61 |
62 | }).as(module);
63 |
--------------------------------------------------------------------------------
/test/logging/appenders/jsonAppender.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../../index"),
5 | logging = comb.logging,
6 | JSONAppender = logging.appenders.JSONAppender;
7 |
8 |
9 | it.describe("comb.logging.appenders.JSONAppender", function (it) {
10 |
11 | var MockWriteStream = {
12 | writable: true,
13 | on: function () {
14 | },
15 | destroySoon: function () {
16 | },
17 | write: function (str) {
18 | return str;
19 | }
20 | };
21 |
22 | var logger = logging.Logger.getLogger("JSONAppenderTest"),
23 | appender = new JSONAppender({writeStream: MockWriteStream});
24 | logger.addAppender(appender);
25 |
26 | it.should("be added to the logger", function () {
27 | assert.isTrue(logger.isAppenderAttached("JSONAppender"));
28 | assert.deepEqual(logger.appenders, [appender]);
29 | });
30 |
31 | it.should("have events logged to it by the logger according to level", function () {
32 |
33 | var count = 0;
34 | var levels = ["debug", "trace", "info", "warn", "error", "fatal"];
35 | var conn = comb.connect(MockWriteStream, "write", function (str) {
36 | if (!str.match(/^\[|\]$/)) {
37 | str = str.replace(/^,/, "");
38 | var obj = JSON.parse(str);
39 | assert.isTrue(obj.message.match(levels[count]) != null);
40 | count++;
41 | }
42 | });
43 | levels.forEach(function (l) {
44 | logger[l](l);
45 | });
46 | assert.equal(count, 6);
47 | comb.disconnect(conn);
48 | logger.level = logging.Level.OFF;
49 | count = 0;
50 | conn = comb.connect(MockWriteStream, "write", function (str) {
51 | count++;
52 | });
53 | levels.forEach(function (l) {
54 | logger[l](l);
55 | });
56 | assert.equal(count, 0);
57 | comb.disconnect(conn);
58 | });
59 |
60 | }).as(module);
61 |
62 |
63 |
--------------------------------------------------------------------------------
/test/logging/appenders/rollingFileAppender.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../../index"),
5 | logging = comb.logging,
6 | RollingFileAppender = logging.appenders.RollingFileAppender,
7 | fs = require("fs");
8 |
9 |
10 | it.describe("comb.logging.appenders.RollingFileAppender", function (it) {
11 | var origWatch = fs.watchFile;
12 | var origStat = fs.stat;
13 | var origCreateWriteStream = fs.createWriteStream;
14 | var origReadDir = fs.readdir;
15 | var origUnlink = fs.unlink;
16 | var origRename = fs.rename;
17 |
18 | var size = 0, callwatch;
19 | var setUpFS = function () {
20 | fs.watchFile = function (name, cb) {
21 | //do nothing
22 | };
23 |
24 | fs.stat = function (name, cb) {
25 | setTimeout(comb.partial(cb, null, {size: size++ % 2 ? 1024 : 0}), 10);
26 | };
27 |
28 | fs.createWriteStream = function () {
29 | return MockWriteStream;
30 | };
31 |
32 | fs.readdir = function (dir, cb) {
33 | var ret = ["log.log.3", "noMatch.log.3", "log.log", "log.log.1", "log.log.2"];
34 | setTimeout(comb.partial(cb, null, ret), 10);
35 | };
36 |
37 | fs.unlink = function (str, cb) {
38 | setTimeout(cb, 10);
39 | };
40 |
41 | fs.rename = function (str, str2, cb) {
42 | setTimeout(cb, 10);
43 | };
44 | };
45 |
46 | var resetFs = function () {
47 | fs.watchFile = origWatch;
48 | fs.stat = origStat;
49 | fs.createWriteStream = origCreateWriteStream;
50 | fs.readdir = origReadDir;
51 | fs.unlink = origUnlink;
52 | fs.rename = origRename;
53 | };
54 |
55 | var MockWriteStream = {
56 | writable: true,
57 | on: function (str, cb) {
58 | cb();
59 | },
60 | destroySoon: function () {
61 | },
62 | write: function (str) {
63 | return str;
64 | }
65 | };
66 | var appender, logger;
67 | it.beforeAll(function () {
68 | logger = logging.Logger.getLogger("RollingFileAppenderTest");
69 | setUpFS();
70 | appender = new RollingFileAppender({writeStream: MockWriteStream, maxSize: "1KB", maxBackupIndex: 3});
71 | logger.addAppender(appender);
72 | });
73 |
74 |
75 | it.should("be added to the logger", function () {
76 | assert.isTrue(logger.isAppenderAttached("rollingFileAppender"));
77 | assert.deepEqual(logger.appenders, [appender]);
78 | });
79 |
80 | it.should("have events logged to it", function () {
81 | var count = 0;
82 | var levels = ["debug", "trace", "info", "warn", "error", "fatal"];
83 | var conn = comb.connect(MockWriteStream, "write", function (str) {
84 | assert.isTrue(str.match(levels[count]) != null);
85 | count++;
86 | });
87 | levels.forEach(function (l) {
88 | logger[l](l);
89 | });
90 | assert.equal(count, 6);
91 | comb.disconnect(conn);
92 |
93 | logger.level = logging.Level.OFF;
94 | count = 0;
95 | conn = comb.connect(MockWriteStream, "write", function (str) {
96 | count++;
97 | });
98 | levels.forEach(function (l) {
99 | logger[l](l);
100 | });
101 | assert.equal(count, 0);
102 | comb.disconnect(conn);
103 |
104 | });
105 |
106 |
107 | it.should("rollover files ", function (next) {
108 |
109 | logger.level = logging.Level.INFO;
110 | var renameLogs = [
111 | {name: "./log.log.2", newName: "./log.log.3"},
112 | {name: "./log.log.1", newName: "./log.log.2"},
113 | {name: "./log.log", newName: "./log.log.1"}
114 | ];
115 | var unlinkCount = 0, renameCount = 0, logCount = 0;
116 | var unlinkConn = comb.connect(fs, "unlink", comb.hitch(this, function (name) {
117 | assert.isTrue(name === "./log.log.3");
118 | unlinkCount++;
119 | }));
120 | var conn = comb.connect(MockWriteStream, "write", function (str) {
121 | logCount++;
122 | });
123 | var renameConn = comb.connect(fs, "rename", comb.hitch(this, function (name, newName) {
124 | var o = renameLogs[renameCount];
125 | assert.isTrue(name === o.name);
126 | assert.isTrue(newName === o.newName);
127 | renameCount++;
128 | }));
129 | var called = false;
130 | //max sure that the callback is called right away
131 | appender.__checkFile({size: 1023})
132 | .chain(function () {
133 | called = true;
134 | })
135 | .chain(function () {
136 |
137 | assert.isTrue(called);
138 | //set the next state
139 | called = false;
140 | appender.__inRollover = true;
141 | return appender.__checkFile({size: 1025}).chain(comb.hitch(this, function () {
142 | called = true;
143 | }));
144 |
145 | })
146 | .chain(function () {
147 | assert.isTrue(called);
148 | appender.__inRollover = false;
149 | called = false;
150 | //now make sure it just creates a new write stream;
151 | appender.maxBackupIndex = 0;
152 | appender.__checkFile({size: 1025}).then(comb.hitch(this, function () {
153 | called = true;
154 | })).chain(function () {
155 |
156 | assert.isTrue(called);
157 | appender.maxBackupIndex = 3;
158 | called = false;
159 | //now make sure it acutally rolls over
160 | appender.__checkFile({size: 1025}).then(comb.hitch(this, function () {
161 | called = true;
162 | assert.equal(unlinkCount, 1);
163 | assert.equal(renameCount, 3);
164 | assert.equal(logCount, 3);
165 | next();
166 | }));
167 |
168 | assert.isFalse(called);
169 | logger.info("hello");
170 | logger.info("hello2");
171 | logger.info("hello3");
172 |
173 | });
174 | });
175 | });
176 |
177 |
178 | it.afterAll(resetFs);
179 |
180 |
181 | }).as(module);
182 |
183 |
--------------------------------------------------------------------------------
/test/plugins/Broadcaster.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | define = comb.define,
6 | hitch = comb.hitch;
7 |
8 |
9 | it.describe("comb.plugins.Broadcaster", function (it) {
10 | //Super of other classes
11 | var Mammal = define(comb.plugins.Broadcaster, {
12 | instance: {
13 |
14 | constructor: function (options) {
15 | options = options || {};
16 | this._super(arguments);
17 | this._type = options.type || "mammal";
18 | },
19 |
20 | speak: function () {
21 | var str = "A mammal of type " + this._type + " sounds like";
22 | this.broadcast("speak", str);
23 | this.onSpeak(str);
24 | return str;
25 | },
26 |
27 | onSpeak: function () {
28 |
29 | }
30 | }
31 | });
32 |
33 | it.should("broadcast a speak event", function (next) {
34 | var m = new Mammal({color: "gold"});
35 | m.listen("speak", function (str) {
36 | assert.equal(str, "A mammal of type mammal sounds like");
37 | next();
38 | });
39 | m.speak();
40 | });
41 |
42 | it.should("should unListen a listener", function (next) {
43 | var m = new Mammal({color: "gold"});
44 | var han = m.listen("speak", function () {
45 | next("Should not have called");
46 | });
47 | m.unListen(han);
48 | m.listen("speak", hitch(this, function (str) {
49 | assert.equal(str, "A mammal of type mammal sounds like");
50 | next();
51 | }));
52 | m.speak();
53 | });
54 |
55 |
56 | }).as(module);
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/test/plugins/Middleware.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../../index"),
5 | define = comb.define,
6 | hitch = comb.hitch;
7 |
8 |
9 | it.describe("comb.plugins.Middleware",function (it) {
10 | //Super of other classes
11 | function valWrapper(val) {
12 | return function () {
13 | return val;
14 | };
15 | }
16 |
17 | var Mammal = define(comb.plugins.Middleware, {
18 | instance:{
19 |
20 | constructor:function (options) {
21 | options = options || {};
22 | this._super(arguments);
23 | this._type = options.type || "mammal";
24 | },
25 |
26 | speak:function () {
27 | return this._hook("pre", "speak")
28 | .chain(comb.hitch(this, "_hook", "post", "speak"))
29 | .chain(valWrapper("speak")).promise();
30 | },
31 |
32 | speakAgain:function () {
33 | return this._hook("pre", "speakAgain")
34 | .chain(comb.hitch(this, "_hook", "post", "speakAgain"))
35 | .chain(valWrapper("speakAgain")).promise();
36 |
37 | },
38 |
39 | eat:function () {
40 | return this._hook("pre", "eat")
41 | .chain(comb.hitch(this, "_hook", "post", "eat"))
42 | .chain(valWrapper("eat")).promise();
43 | }
44 | }
45 | });
46 |
47 | it.should("call pre middleware", function (next) {
48 | Mammal.pre('speak', function (n) {
49 | assert.isTrue(comb.isFunction(n));
50 | n();
51 | next();
52 | });
53 | var m = new Mammal({color:"gold"});
54 | m.speak();
55 | });
56 |
57 | it.should("call pre middleware on an instance of middleware", function (next) {
58 | var m = new Mammal({color:"gold"});
59 | m.pre('speakAgain', function (n) {
60 | assert.isTrue(comb.isFunction(n));
61 | n();
62 | next();
63 | });
64 | m.speakAgain();
65 | });
66 |
67 | it.should("call post middleware", function (next) {
68 | Mammal.post('speak', function (n) {
69 | assert.isTrue(comb.isFunction(n));
70 | n();
71 | next();
72 | });
73 | var m = new Mammal({color:"gold"});
74 | m.speak();
75 | });
76 |
77 | it.should("call post middleware on an instance of middleware", function (next) {
78 | var m = new Mammal({color:"gold"});
79 | m.post('speakAgain', function (n) {
80 | assert.isTrue(comb.isFunction(n));
81 | n();
82 | next();
83 | });
84 | m.speakAgain();
85 | });
86 |
87 | it.should("callback right away if there is no middleware", function (next) {
88 | var m = new Mammal({color:"gold"});
89 | m.eat().then(comb.hitch(this, function (str) {
90 | assert.equal(str, "eat");
91 | next();
92 | }));
93 | });
94 |
95 | it.should("errback if the first argument to next is not null/undefined", function (next) {
96 | Mammal.pre('speak', function (n) {
97 | assert.isTrue(comb.isFunction(n));
98 | n("error");
99 | });
100 | var m = new Mammal({color:"gold"});
101 | m.speak().then(next, function (err) {
102 | assert.equal(err, "error");
103 | next();
104 | });
105 | });
106 |
107 | }).as(module);
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/test/promiseList.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var it = require('it'),
3 | assert = require('assert'),
4 | comb = require("../index"),
5 | Promise = comb.Promise,
6 | PromiseList = comb.PromiseList;
7 |
8 | it.describe("comb.PromiseList", function (it) {
9 |
10 |
11 | it.should("should callback after all have fired ", function (next) {
12 |
13 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
14 | setTimeout(comb.hitch(promise, "callback", "hello"), 100);
15 | setTimeout(comb.hitch(promise2, "callback", "world"), 150);
16 | setTimeout(comb.hitch(promise3, "callback", "!"), 200);
17 | new PromiseList([promise, promise2, promise3]).then(function (res) {
18 | var expected = ["hello", "world", "!"];
19 | res.forEach(function (r, i) {
20 | assert.equal(r[1], expected[i]);
21 | });
22 | next();
23 | }, next);
24 | });
25 |
26 | it.should("callback immediately if no promises are provided", function (next) {
27 | new PromiseList().then(function (res) {
28 | assert.deepEqual(res, []);
29 | next();
30 | }, next);
31 | });
32 |
33 | it.should("callback immediately if and empty array is provided", function (next) {
34 | new PromiseList([]).then(function (res) {
35 | assert.deepEqual(res, []);
36 | next();
37 | }, next);
38 | });
39 |
40 | it.should("callback if provided promises that have already fired", function (next) {
41 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
42 | promise.callback("hello");
43 | promise2.callback("world");
44 | promise3.callback("!");
45 | new PromiseList([promise, promise2, promise3]).then(function (res) {
46 | var expected = ["hello", "world", "!"];
47 | res.forEach(function (r, i) {
48 | assert.equal(r[1], expected[i]);
49 | });
50 | next();
51 | }, next);
52 | });
53 |
54 | it.should("errback if provided promises that have already fired and one errored back", function (next) {
55 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
56 | promise.callback("hello");
57 | promise2.callback("world");
58 | promise3.errback("error");
59 | var pl = new PromiseList([promise, promise2, promise3]);
60 | process.nextTick(function () {
61 | pl.then(next, function (res) {
62 | res.forEach(function (res) {
63 | assert.equal(res[1], "error");
64 | });
65 | next();
66 | });
67 | });
68 | });
69 |
70 | it.should("throw an error if callback is called after firing", function (next) {
71 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
72 | promise.callback("hello");
73 | promise2.callback("world");
74 | promise3.callback("!");
75 | var pl = new PromiseList([promise, promise2, promise3]);
76 | pl.addCallback(function () {
77 | assert.throws(function () {
78 | pl.callback();
79 | });
80 | });
81 | return pl;
82 | });
83 |
84 | it.should("throw an error if errback is called after firing", function (next) {
85 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
86 | promise.callback("hello");
87 | promise2.callback("world");
88 | promise3.callback("!");
89 | var pl = new PromiseList([promise, promise2, promise3]);
90 | pl.addCallback(function () {
91 | assert.throws(function () {
92 | pl.errback();
93 | });
94 | });
95 | return pl;
96 | });
97 |
98 | it.should("handle the ordering of results if resolved out of order", function (next) {
99 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
100 | setTimeout(comb.hitch(promise, "callback", "hello"), 200);
101 | setTimeout(comb.hitch(promise2, "callback", "world"), 150);
102 | setTimeout(comb.hitch(promise3, "callback", "!"), 100);
103 | new PromiseList([promise, promise2, promise3]).then(function (res) {
104 | var expected = ["hello", "world", "!"];
105 | res.forEach(function (res, i) {
106 | assert.equal(res[1], expected[i]);
107 | });
108 | next();
109 | }, next);
110 | });
111 |
112 | it.should("normalize results", function (next) {
113 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
114 | setTimeout(comb.hitch(promise, "callback", "hello"), 200);
115 | setTimeout(comb.hitch(promise2, "callback", "world"), 150);
116 | setTimeout(comb.hitch(promise3, "callback", "!"), 100);
117 | new PromiseList([promise, promise2, promise3], true).then(function (res) {
118 | assert.deepEqual(res, ["hello", "world", "!"]);
119 | next();
120 | }, next);
121 | });
122 |
123 | it.should("accept a promise as a callback", function (next) {
124 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
125 | process.nextTick(comb.hitch(promise, "callback", "hello"));
126 | process.nextTick(comb.hitch(promise2, "callback", "world"));
127 | process.nextTick(comb.hitch(promise3, "callback", "!"));
128 | var p2 = new Promise();
129 | p2.then(function (res) {
130 | assert.deepEqual(res, ["hello", "world", "!"]);
131 | next();
132 | });
133 | new PromiseList([promise, promise2, promise3], true).addCallback(p2).addErrback(next);
134 | });
135 |
136 | it.should("accept a promise as a errback", function (next) {
137 | var promise = new Promise(), promise2 = new Promise(), promise3 = new Promise();
138 | process.nextTick(comb.hitch(promise, "callback", "hello"));
139 | process.nextTick(comb.hitch(promise2, "callback", "world"));
140 | process.nextTick(comb.hitch(promise3, "errback", "error"));
141 | var p2 = new Promise();
142 | p2.then(next, function (res) {
143 | assert.equal(res[2], "error");
144 | next();
145 | });
146 | new PromiseList([promise, promise2, promise3], true).addCallback(next).addErrback(p2);
147 | });
148 |
149 | }).as(module);
150 |
--------------------------------------------------------------------------------