├── .gitignore
├── .jshintrc
├── .npmignore
├── Gruntfile.coffee
├── LICENSE.md
├── README.md
├── demo
└── index.html
├── dist
├── css-to-matrix.js
├── css-to-matrix.min.js
├── css-to-matrix.standalone.js
└── css-to-matrix.standalone.min.js
├── grunt-umd-template.hbs
├── package.json
├── src
└── css-to-matrix.js
└── test
├── .DS_Store
├── chai.js
├── index.html
├── mocha.css
├── mocha.js
├── test.coffee.md
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | Gruntfile.js
3 | .DS_Store
4 | npm-debug.log
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "eqnull": true,
3 | "esnext": true,
4 | "laxbreak": true,
5 | "laxcomma": true,
6 | "asi": true,
7 | "smarttabs": true
8 | }
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | demo/
2 | test/
3 | grunt-umd-template.hbs
4 | Gruntfile.coffee
--------------------------------------------------------------------------------
/Gruntfile.coffee:
--------------------------------------------------------------------------------
1 | changeCase = require 'change-case'
2 |
3 | module.exports = (grunt) ->
4 |
5 | nameParts = __dirname.split '/'
6 | name = nameParts[nameParts.length - 1]
7 | pkg = grunt.file.readJSON 'package.json'
8 | deps = grunt.util._.keys pkg.dependencies
9 |
10 | build = ['concat', 'regex-replace', 'umd', 'uglify']
11 | test = ['coffee:test']
12 |
13 | grunt.config.init
14 |
15 | pkg: pkg
16 |
17 | coffee:
18 |
19 | test:
20 | files:
21 | 'test/test.js': 'test/test.coffee.md'
22 |
23 | uglify:
24 |
25 | options:
26 | mangle:
27 | toplevel: true
28 | compress:
29 | dead_code: true
30 | unused: true
31 | join_vars: true
32 | comments: false
33 |
34 | standalone:
35 | files:
36 | 'dist/<%= pkg.name %>.standalone.min.js': [
37 | 'dist/<%= pkg.name %>.standalone.js'
38 | ]
39 | 'dist/<%= pkg.name %>.min.js': [
40 | 'src/<%= pkg.name %>.js'
41 | ]
42 |
43 | concat:
44 |
45 | standard:
46 | src: 'src/<%= pkg.name %>.js'
47 | dest: 'dist/<%= pkg.name %>.js'
48 |
49 | standalone:
50 | src: [
51 | 'node_modules/matrix-utilities/matrix-utilities.js'
52 | 'node_modules/transform-to-matrix/transform-to-matrix.js'
53 | 'node_modules/umodel/umodel.js'
54 | 'src/<%= pkg.name %>.js'
55 | ]
56 | dest: 'dist/<%= pkg.name %>.standalone.js'
57 |
58 | 'regex-replace':
59 |
60 | min:
61 | src: ['dist/<%= pkg.name %>.min.js', 'dist/<%= pkg.name %>.standalone.min.js'],
62 | actions: [
63 | {
64 | name: 'remove debug checks'
65 | search: '////DEV(.+)////END DEV'
66 | replace: ''
67 | flags: 'gim'
68 | }
69 | ]
70 |
71 | watch:
72 |
73 | test:
74 | files: './test/*'
75 | tasks: test
76 | options:
77 | interrupt: true
78 | spawn: false
79 |
80 | umd:
81 | all:
82 | src: './dist/' + name + '.js'
83 | objectToExport: changeCase.pascalCase name
84 | amdModuleId: name
85 | globalAlias: name
86 | deps:
87 | default: deps
88 | template: 'grunt-umd-template.hbs'
89 |
90 |
91 | [
92 | 'grunt-contrib-coffee'
93 | 'grunt-contrib-concat'
94 | 'grunt-contrib-watch'
95 | 'grunt-contrib-uglify'
96 | 'grunt-regex-replace'
97 | 'grunt-umd'
98 | ].forEach grunt.loadNpmTasks
99 |
100 | grunt.registerTask 'default', build
101 | grunt.registerTask 'test', test
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright © 2013 Boris Cherny
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # css-to-matrix
2 |
3 | A little library for converting compound CSS transforms into their matrix equivalents.
4 |
5 | ## usage
6 |
7 | ```coffee
8 |
9 | # using the default matrix
10 | new CssToMatrix
11 |
12 | # or using a custom 4x4 matrix (meaning some transformations are already applied)
13 | matrix = [
14 | [1, 2, 3, 4]
15 | [5, 6, 7, 8]
16 | [9, 0, 1, 2]
17 | [3, 4, 5, 6]
18 | ]
19 | new CssToMatrix matrix
20 |
21 | ```
22 |
23 | ## example
24 |
25 | ```coffee
26 | cssToMatrix = new CssToMatrix
27 |
28 | cssToMatrix
29 |
30 | # set some transforms
31 | .rotate '90deg'
32 | .translate3d 50, 100, 200
33 |
34 | # get a matrix back
35 | .getMatrix()
36 |
37 |
38 | #=> [
39 | # [9.870993963020204, 0.7, 0, 0],
40 | # [-0.5, 0, 0, 0],
41 | # [0, 0, 1, 0],
42 | # [443.54969815101026, 35, 200, 1]
43 | # ]
44 |
45 | # .. or as a CSS property
46 | cssToMatrix.getMatrixCSS()
47 |
48 | #=> "matrix3d(9.870993963020204, 0.7, 0, 0, -0.5, 0, 0, 0, 0, 0, 1, 0, 443.54969815101026, 35, 200, 1)"
49 |
50 | # set a new base matrix (on the basis of which transforms are applied)
51 | cssToMatrix.matrix [
52 | [3, 1, 4, 1]
53 | [5, 9, 2, 6]
54 | [5, 3, 5, 8]
55 | [9, 7, 9, 3]
56 | ]
57 |
58 | ```
59 |
60 | ## supported transforms
61 |
62 | - perspective
63 | - rotate
64 | - rotateX
65 | - rotateY
66 | - rotateZ
67 | - rotate3d
68 | - scale
69 | - scaleX
70 | - scaleY
71 | - scaleZ
72 | - scale3d
73 | - skew
74 | - skewX
75 | - skewY
76 | - translate
77 | - translateX
78 | - translateY
79 | - translateZ
80 | - translate3d
81 |
82 | ## why not use actual matricies?
83 |
84 | If you're performing caculations dozens of times per second (in the case of animations. 60 times per second), performance is essential. Not only do we need to be able to perform calculations for complex compound 3D transforms at 60FPS, but we need to leave head room for any precursor computations, as well as compositing and painting. Performing the calculations ourselves (instead of leaving it to the CSS engine) gives us finer control over where (CPU vs. GPU, this thread vs. a WebWorker, sync vs. async) and when (precomputed, partially applied, realtime) computation occurs.
85 |
86 | ## see also
87 |
88 | - http://www.w3.org/TR/css3-transforms/#transform-functions
89 | - http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined
90 | - http://dev.opera.com/articles/view/understanding-the-css-transforms-matrix/
91 | - http://dev.opera.com/articles/view/understanding-3d-transforms/
92 | - http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/
93 | - http://stackoverflow.com/a/15208858/435124
94 | - http://desandro.github.io/3dtransforms/docs/perspective.html
95 |
96 | ## todo
97 |
98 | - accept alternative units for scalars (%, em, pt, etc.)
99 |
100 | ## running the tests
101 |
102 | ```bash
103 | npm i
104 | grunt test
105 | ```
106 |
107 | then, open test/index.html in a browser
108 |
109 | ## license
110 |
111 | MIT
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
61 |
62 |
--------------------------------------------------------------------------------
/dist/css-to-matrix.js:
--------------------------------------------------------------------------------
1 | (function(root, factory) {
2 | if(typeof exports === 'object') {
3 | module.exports = factory(require('transform-to-matrix'), require('matrix-utilities'), require('umodel'));
4 | }
5 | else if(typeof define === 'function' && define.amd) {
6 | define('css-to-matrix', ['transform-to-matrix', 'matrix-utilities', 'umodel'], factory);
7 | }
8 | else {
9 | root['css-to-matrix'] = factory(root['transform-to-matrix'], root['matrix-utilities'], root.umodel);
10 | }
11 | }(this, function(transformToMatrix, matrixUtilities, umodel) {
12 | var _ = {
13 |
14 | // convert strings like "55deg" or ".75rad" to floats (in radians)
15 | rad: function (string) {
16 |
17 | if (typeof string === 'string') {
18 |
19 | var angle = parseFloat(string, 10),
20 | isDegrees = string.indexOf('deg') > -1
21 |
22 | // convert deg -> rad?
23 | if (isDegrees) angle *= Math.PI / 180
24 |
25 | return angle
26 |
27 | }
28 |
29 | return string
30 |
31 | },
32 |
33 | // shallow object extend
34 | extend: function (a, b) {
35 |
36 | for (var key in b) {
37 | a[key] = b[key]
38 | }
39 |
40 | return a
41 |
42 | },
43 |
44 | // make functions return `this`, for easy chaining
45 | fluent: function (fn) {
46 |
47 | return function() {
48 | fn.apply(this, arguments)
49 | return this
50 | }
51 |
52 | },
53 |
54 | isNumber: function (a) {
55 | return typeof a === 'number'
56 | }
57 |
58 | };
59 |
60 | function CssToMatrix (data) {
61 |
62 | // default options
63 | this.model = new umodel({
64 | matrix: new matrixUtilities.Identity(),
65 | transformations: {
66 | perspective: new matrixUtilities.Identity(),
67 | rotate: new matrixUtilities.Identity(),
68 | scale: new matrixUtilities.Identity(),
69 | skew: new matrixUtilities.Identity(),
70 | translate: new matrixUtilities.Identity()
71 | }
72 | })
73 |
74 | // set data?
75 | if (data) {
76 | this.matrix(data)
77 | }
78 |
79 | }
80 |
81 | _.extend(CssToMatrix.prototype, {
82 |
83 | // set matrix in model
84 | matrix: function (data) {
85 |
86 | ////DEV
87 | if (data.length == null)
88 | throw new TypeError('expected parameter `data` to be an Array, but was given a ' + typeof data)
89 |
90 | var rows = data.length,
91 | columns = rows > 0 ? rows : 0
92 |
93 | if (rows !== 4 || columns !== 4)
94 | throw new Error('expected parameter `data` to be a 4x4 matrix of arrays, but was given a ' + rows + 'x' + columns + ' matrix')
95 | ////END DEV
96 |
97 | this.model.set('matrix', data)
98 |
99 | },
100 |
101 | // apply transformations as defined in the model, and get back get calculated matrix
102 | getMatrix: function() {
103 |
104 | var matrix = this.model.get('matrix'),
105 | t = this.model.get('transformations')
106 |
107 | // perspective
108 | matrix = matrixUtilities.multiply(matrix, t.perspective)
109 |
110 | // translate
111 | matrix = matrixUtilities.multiply(matrix, t.translate)
112 |
113 | // rotate
114 | matrix = matrixUtilities.multiply(matrix, t.rotate)
115 |
116 | // skew
117 | matrix = matrixUtilities.multiply(matrix, t.skew)
118 |
119 | // scale
120 | matrix = matrixUtilities.multiply(matrix, t.scale)
121 |
122 | return matrixUtilities.flip(matrix)
123 |
124 | },
125 |
126 | // get matrix formatted as a string that can be plugged right into CSS's `transform` function
127 | getMatrixCSS: function() {
128 |
129 | return 'matrix3d('
130 | + this
131 | .getMatrix()
132 | .reduce(function (flat, row) {
133 | flat.push.apply(flat, row)
134 | return flat
135 | }, [])
136 | .join(',')
137 | + ')'
138 |
139 | },
140 |
141 | // transform functions
142 | // 1-to-1 with their CSS equivalents
143 | rotate: function (a) { return this.rotateZ(a) },
144 | rotateX: function (a) { return this.rotate3d(1, 0, 0, a) },
145 | rotateY: function (a) { return this.rotate3d(0, 1, 0, a) },
146 | rotateZ: function (a) { return this.rotate3d(0, 0, 1, a) },
147 | scale: function (x, y) { return this.scale3d(x, y) },
148 | scaleX: function (x) { return this.scale3d(x) },
149 | scaleY: function (y) { return this.scale3d(null, y) },
150 | scaleZ: function (z) { return this.scale3d(null, null, z) },
151 | skewX: function (x) { return this.skew(x) },
152 | skewY: function (y) { return this.skew(null, y) },
153 | translate: function (x, y) { return this.translate3d(x, y) },
154 | translateX: function (x) { return this.translate3d(x) },
155 | translateY: function (y) { return this.translate3d(null, y) },
156 | translateZ: function (z) { return this.translate3d(null, null, z) },
157 |
158 | perspective: _.fluent(function (x) {
159 |
160 | if (x == null) { x = 0 }
161 |
162 | ////DEV
163 | if (!_.isNumber(x))
164 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
165 | ////END DEV
166 |
167 | this.model.set('transformations/perspective', transformToMatrix.perspective(x))
168 |
169 | }),
170 |
171 | rotate3d: _.fluent(function (x, y, z, a) {
172 |
173 | if (x == null) { x = 0 }
174 | if (y == null) { y = 0 }
175 | if (z == null) { z = 0 }
176 | if (a == null) { a = 0 }
177 |
178 | ////DEV
179 | if (!_.isNumber(x))
180 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
181 | if (!_.isNumber(y))
182 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
183 | if (!_.isNumber(z))
184 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
185 | ////END DEV
186 |
187 | // if angle was passed as a string, convert it to a float first
188 | this.model.set('transformations/rotate', transformToMatrix.rotate3d(x, y, z, _.rad(a)))
189 |
190 | }),
191 |
192 | scale3d: _.fluent(function (x, y, z) {
193 |
194 | if (x == null) { x = 1 }
195 | if (y == null) { y = 1 }
196 | if (z == null) { z = 1 }
197 |
198 | ////DEV
199 | if (!_.isNumber(x))
200 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
201 | if (!_.isNumber(y))
202 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
203 | if (!_.isNumber(z))
204 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
205 | ////END DEV
206 |
207 | this.model.set('transformations/scale', transformToMatrix.scale3d(x, y, z))
208 |
209 | }),
210 |
211 | skew: _.fluent(function (x, y) {
212 |
213 | if (x == null) { x = 0 }
214 | if (y == null) { y = 0 }
215 |
216 | this.model.set('transformations/skew', matrixUtilities.to3d(transformToMatrix.skew(_.rad(x), _.rad(y))))
217 |
218 | }),
219 |
220 | translate3d: _.fluent(function(x, y, z) {
221 |
222 | if (x == null) { x = 0 }
223 | if (y == null) { y = 0 }
224 | if (z == null) { z = 0 }
225 |
226 | ////DEV
227 | if (!_.isNumber(x))
228 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
229 | if (!_.isNumber(y))
230 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
231 | if (!_.isNumber(z))
232 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
233 | ////END DEV
234 |
235 | this.model.set('transformations/translate', transformToMatrix.translate3d(x, y, z))
236 |
237 | })
238 |
239 | })
240 | return CssToMatrix;
241 | }));
--------------------------------------------------------------------------------
/dist/css-to-matrix.min.js:
--------------------------------------------------------------------------------
1 | function a(a){this.model=new umodel({matrix:new matrixUtilities.Identity,transformations:{perspective:new matrixUtilities.Identity,rotate:new matrixUtilities.Identity,scale:new matrixUtilities.Identity,skew:new matrixUtilities.Identity,translate:new matrixUtilities.Identity}}),a&&this.matrix(a)}var b={rad:function(a){if("string"==typeof a){var b=parseFloat(a,10),c=a.indexOf("deg")>-1;return c&&(b*=Math.PI/180),b}return a},extend:function(a,b){for(var c in b)a[c]=b[c];return a},fluent:function(a){return function(){return a.apply(this,arguments),this}},isNumber:function(a){return"number"==typeof a}};b.extend(a.prototype,{matrix:function(a){if(null==a.length)throw new TypeError("expected parameter `data` to be an Array, but was given a "+typeof a);var b=a.length,c=b>0?b:0;if(4!==b||4!==c)throw new Error("expected parameter `data` to be a 4x4 matrix of arrays, but was given a "+b+"x"+c+" matrix");this.model.set("matrix",a)},getMatrix:function(){var a=this.model.get("matrix"),b=this.model.get("transformations");return a=matrixUtilities.multiply(a,b.perspective),a=matrixUtilities.multiply(a,b.translate),a=matrixUtilities.multiply(a,b.rotate),a=matrixUtilities.multiply(a,b.skew),a=matrixUtilities.multiply(a,b.scale),matrixUtilities.flip(a)},getMatrixCSS:function(){return"matrix3d("+this.getMatrix().reduce(function(a,b){return a.push.apply(a,b),a},[]).join(",")+")"},rotate:function(a){return this.rotateZ(a)},rotateX:function(a){return this.rotate3d(1,0,0,a)},rotateY:function(a){return this.rotate3d(0,1,0,a)},rotateZ:function(a){return this.rotate3d(0,0,1,a)},scale:function(a,b){return this.scale3d(a,b)},scaleX:function(a){return this.scale3d(a)},scaleY:function(a){return this.scale3d(null,a)},scaleZ:function(a){return this.scale3d(null,null,a)},skewX:function(a){return this.skew(a)},skewY:function(a){return this.skew(null,a)},translate:function(a,b){return this.translate3d(a,b)},translateX:function(a){return this.translate3d(a)},translateY:function(a){return this.translate3d(null,a)},translateZ:function(a){return this.translate3d(null,null,a)},perspective:b.fluent(function(a){if(null==a&&(a=0),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);this.model.set("transformations/perspective",transformToMatrix.perspective(a))}),rotate3d:b.fluent(function(a,c,d,e){if(null==a&&(a=0),null==c&&(c=0),null==d&&(d=0),null==e&&(e=0),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);if(!b.isNumber(c))throw new TypeError("expected parameter `y` to be a Number, but was given a "+typeof c);if(!b.isNumber(d))throw new TypeError("expected parameter `z` to be a Number, but was given a "+typeof d);this.model.set("transformations/rotate",transformToMatrix.rotate3d(a,c,d,b.rad(e)))}),scale3d:b.fluent(function(a,c,d){if(null==a&&(a=1),null==c&&(c=1),null==d&&(d=1),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);if(!b.isNumber(c))throw new TypeError("expected parameter `y` to be a Number, but was given a "+typeof c);if(!b.isNumber(d))throw new TypeError("expected parameter `z` to be a Number, but was given a "+typeof d);this.model.set("transformations/scale",transformToMatrix.scale3d(a,c,d))}),skew:b.fluent(function(a,c){null==a&&(a=0),null==c&&(c=0),this.model.set("transformations/skew",matrixUtilities.to3d(transformToMatrix.skew(b.rad(a),b.rad(c))))}),translate3d:b.fluent(function(a,c,d){if(null==a&&(a=0),null==c&&(c=0),null==d&&(d=0),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);if(!b.isNumber(c))throw new TypeError("expected parameter `y` to be a Number, but was given a "+typeof c);if(!b.isNumber(d))throw new TypeError("expected parameter `z` to be a Number, but was given a "+typeof d);this.model.set("transformations/translate",transformToMatrix.translate3d(a,c,d))})});
--------------------------------------------------------------------------------
/dist/css-to-matrix.standalone.js:
--------------------------------------------------------------------------------
1 | (function(root, factory) {
2 | if(typeof exports === 'object') {
3 | module.exports = factory();
4 | }
5 | else if(typeof define === 'function' && define.amd) {
6 | define('matrix-utilities', [], factory);
7 | }
8 | else {
9 | root['matrix-utilities'] = factory();
10 | }
11 | }(this, function() {
12 | var matrixutilities;
13 |
14 | matrixutilities = (function() {
15 | var util;
16 | return util = {
17 | add: function(one, two) {
18 | var i, j, result, row, value, _i, _j, _len, _len1;
19 | if (one.length !== two.length) {
20 | throw new Error('Matrix y dimensions do not match');
21 | }
22 | result = [];
23 | for (i = _i = 0, _len = one.length; _i < _len; i = ++_i) {
24 | row = one[i];
25 | if (row.length !== two[i].length) {
26 | throw new Error("Matrix x dimensions do not match on row " + (i + 1));
27 | }
28 | result[i] = [];
29 | for (j = _j = 0, _len1 = row.length; _j < _len1; j = ++_j) {
30 | value = row[j];
31 | result[i][j] = value + two[i][j];
32 | }
33 | }
34 | return result;
35 | },
36 | multiply: function(one, two) {
37 | var j, k, l, result, row, size, sum, value, _i, _j, _len, _len1;
38 | if (one[0].length !== two.length) {
39 | throw new Error('Matrix 1\'s row count should equal matrix 2\'s column count');
40 | }
41 | size = one[0].length;
42 | result = [];
43 | for (j = _i = 0, _len = two.length; _i < _len; j = ++_i) {
44 | row = two[j];
45 | result[j] = [];
46 | for (k = _j = 0, _len1 = row.length; _j < _len1; k = ++_j) {
47 | value = row[k];
48 | l = size;
49 | sum = 0;
50 | while (l--) {
51 | sum += one[j][l] * two[l][k];
52 | }
53 | result[j][k] = sum;
54 | }
55 | }
56 | return result;
57 | },
58 | flip: function(matrix) {
59 | var j, k, result, row, value, _i, _j, _len, _len1;
60 | result = [];
61 | for (j = _i = 0, _len = matrix.length; _i < _len; j = ++_i) {
62 | row = matrix[j];
63 | for (k = _j = 0, _len1 = row.length; _j < _len1; k = ++_j) {
64 | value = row[k];
65 | (result[k] || (result[k] = []))[j] = value;
66 | }
67 | }
68 | return result;
69 | },
70 | to2d: function(matrix) {
71 | return [[matrix[0][0] || 1, matrix[0][1] || 0, matrix[0][3] || 0], [matrix[1][0] || 0, matrix[1][1] || 1, matrix[1][3] || 0]];
72 | },
73 | to3d: function(matrix) {
74 | return [[matrix[0][0] || 1, matrix[0][1] || 0, 0, matrix[0][2] || 0], [matrix[1][0] || 0, matrix[1][1] || 1, 0, matrix[1][2] || 0], [0, 0, 1, 0], [0, 0, 0, 1]];
75 | },
76 | Identity: function() {
77 | return [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]];
78 | }
79 | };
80 | })();
81 |
82 | return matrixutilities;
83 | }));
84 | (function() {
85 | var fns, umd;
86 |
87 | umd = function(factory) {
88 | if (typeof exports === 'object') {
89 | return module.exports = factory;
90 | } else if (typeof define === 'function' && define.amd) {
91 | return define([], factory);
92 | } else {
93 | return this['transform-to-matrix'] = factory;
94 | }
95 | };
96 |
97 | fns = {
98 | perspective: function(d) {
99 | return [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, -1 / d, 1]];
100 | },
101 | rotate: function(a) {
102 | return fns.rotateZ(a);
103 | },
104 | rotateX: function(a) {
105 | return fns.rotate3d(1, 0, 0, a);
106 | },
107 | rotateY: function(a) {
108 | return fns.rotate3d(0, 1, 0, a);
109 | },
110 | rotateZ: function(a) {
111 | var c, n;
112 | c = Math.cos(a);
113 | n = Math.sin(a);
114 | return [[c, -n, 0], [n, c, 0]];
115 | },
116 | rotate3d: function(x, y, z, a) {
117 | var c, i, n, rs, s;
118 | s = x * x + y * y + z * z;
119 | c = Math.cos(a);
120 | n = Math.sin(a);
121 | i = 1 - c;
122 | rs = Math.sqrt(s) * n;
123 | return [[(x * x + (y * y + z * z) * c) / s, (x * y * i - z * rs) / s, (x * z * i + y * rs) / s, 0], [(x * y * i + z * rs) / s, (y * y + (x * x + z * z) * c) / s, (y * z * i - x * rs) / s, 0], [(x * z * i - y * rs) / s, (y * z * i + x * rs) / s, (z * z + (x * x + y * y) * c) / s, 0], [0, 0, 0, 1]];
124 | },
125 | scale: function(x, y) {
126 | return [[x, 0, 0], [0, y, 0]];
127 | },
128 | scaleX: function(x) {
129 | return fns.scale(x, 1);
130 | },
131 | scaleY: function(y) {
132 | return fns.scale(1, y);
133 | },
134 | scaleZ: function(z) {
135 | return fns.scale3d(1, 1, z);
136 | },
137 | scale3d: function(x, y, z) {
138 | return [[x, 0, 0, 0], [0, y, 0, 0], [0, 0, z, 0], [0, 0, 0, 1]];
139 | },
140 | skew: function(x, y) {
141 | return [[1, Math.tan(x), 0], [Math.tan(y), 1, 0]];
142 | },
143 | skewX: function(x) {
144 | return [[1, Math.tan(x), 0], [0, 1, 0]];
145 | },
146 | skewY: function(y) {
147 | return [[1, 0, 0], [Math.tan(y), 1, 0]];
148 | },
149 | translate: function(x, y) {
150 | return [[1, 0, x], [0, 1, y]];
151 | },
152 | translateX: function(x) {
153 | return fns.translate(x, 0);
154 | },
155 | translateY: function(y) {
156 | return fns.translate(0, y);
157 | },
158 | translateZ: function(z) {
159 | return fns.translate3d(0, 0, z);
160 | },
161 | translate3d: function(x, y, z) {
162 | return [[1, 0, 0, x], [0, 1, 0, y], [0, 0, 1, z], [0, 0, 0, 1]];
163 | }
164 | };
165 |
166 | umd(fns);
167 |
168 | }).call(this);
169 |
170 | (function(root, factory) {
171 | if(typeof exports === 'object') {
172 | module.exports = factory();
173 | }
174 | else if(typeof define === 'function' && define.amd) {
175 | define('umodel', [], factory);
176 | }
177 | else {
178 | root.umodel = factory();
179 | }
180 | }(this, function() {
181 | var umodel, _,
182 | __hasProp = {}.hasOwnProperty;
183 |
184 | _ = {
185 | extend: function(a, b) {
186 | var key;
187 | for (key in b) {
188 | if (!__hasProp.call(b, key)) continue;
189 | a[key] = b[key];
190 | }
191 | return a;
192 | },
193 | trim: (function() {
194 | var head, tail;
195 | if (''.trim) {
196 | return function(string) {
197 | return string.trim();
198 | };
199 | } else {
200 | head = /^\s\s*/;
201 | tail = /\s\s*$/;
202 | return function(string) {
203 | return string.replace(head, '').replace(tail, '');
204 | };
205 | }
206 | })()
207 | };
208 |
209 | umodel = (function() {
210 | function umodel(_data, options) {
211 | this._data = _data != null ? _data : {};
212 | this.options = {
213 | separator: '/'
214 | };
215 | if (options) {
216 | _.extend(this.options, options);
217 | }
218 | this.events = {};
219 | }
220 |
221 | umodel.prototype.get = function(key) {
222 | this.trigger('get', key);
223 | return this._get(this._split(key), this._data);
224 | };
225 |
226 | umodel.prototype.set = function(key, value) {
227 | var old;
228 | old = this._get(this._split(key), this._data);
229 | this._set(this._split(key), value, false, this._data);
230 | return this.trigger('set', key, value, old);
231 | };
232 |
233 | umodel.prototype.setnx = function(key, value) {
234 | var old;
235 | old = this._get(this._split(key), this._data);
236 | this._set(this._split(key), value, true, this._data);
237 | return this.trigger('setnx', key, value, old);
238 | };
239 |
240 | umodel.prototype.on = function(eventAndProperty, fn) {
241 | var e, _results;
242 | if (fn) {
243 | return this._on(eventAndProperty, fn);
244 | } else {
245 | _results = [];
246 | for (e in eventAndProperty) {
247 | fn = eventAndProperty[e];
248 | _results.push(this._on(e, fn));
249 | }
250 | return _results;
251 | }
252 | };
253 |
254 | umodel.prototype.trigger = function(event, path, value, oldValue) {
255 | var e, fn, fns, _ref, _results;
256 | if (path == null) {
257 | path = '*';
258 | }
259 | path = this._normalize(path);
260 | if (event in this.events) {
261 | _ref = this.events[event];
262 | _results = [];
263 | for (e in _ref) {
264 | fns = _ref[e];
265 | if (e === '*' || (path + '/').indexOf(e + '/') === 0) {
266 | _results.push((function() {
267 | var _i, _len, _results1;
268 | _results1 = [];
269 | for (_i = 0, _len = fns.length; _i < _len; _i++) {
270 | fn = fns[_i];
271 | if (oldValue != null) {
272 | _results1.push(fn.call(this, path, value, oldValue));
273 | } else {
274 | _results1.push(fn.call(this, path, value));
275 | }
276 | }
277 | return _results1;
278 | }).call(this));
279 | } else {
280 | _results.push(void 0);
281 | }
282 | }
283 | return _results;
284 | }
285 | };
286 |
287 | umodel.prototype._get = function(key, parent, accumulator) {
288 | var head;
289 | if (accumulator == null) {
290 | accumulator = [];
291 | }
292 | head = key.shift();
293 | if (head) {
294 | if (!(head in parent)) {
295 | return void 0;
296 | }
297 | accumulator.push(head);
298 | return this._get(key, parent[head], accumulator);
299 | }
300 | return parent;
301 | };
302 |
303 | umodel.prototype._set = function(key, value, nx, parent, accumulator) {
304 | var head;
305 | if (nx == null) {
306 | nx = false;
307 | }
308 | if (accumulator == null) {
309 | accumulator = [];
310 | }
311 | head = key.shift();
312 | if (key.length) {
313 | if (!(head in parent)) {
314 | parent[head] = {};
315 | }
316 | accumulator.push(head);
317 | return this._set(key, value, nx, parent[head], accumulator);
318 | }
319 | if (!(nx && head in parent)) {
320 | return parent[head] = value;
321 | }
322 | };
323 |
324 | umodel.prototype._on = function(eventAndProperty, fn) {
325 | var event, events, parts, property, _i, _len, _results;
326 | parts = eventAndProperty.split(':');
327 | events = parts[0].split(' ');
328 | property = this._normalize(parts[1] || '*');
329 | _results = [];
330 | for (_i = 0, _len = events.length; _i < _len; _i++) {
331 | event = events[_i];
332 | event = _.trim(event);
333 | if (!(event in this.events)) {
334 | this.events[event] = {};
335 | }
336 | if (!(property in this.events[event])) {
337 | this.events[event][property] = [];
338 | }
339 | _results.push(this.events[event][property].push(fn));
340 | }
341 | return _results;
342 | };
343 |
344 | umodel.prototype._normalize = function(key) {
345 | var separator;
346 | separator = this.options.separator;
347 | key = _.trim(key);
348 | if (key.charAt(0) === separator) {
349 | key = key.slice(1);
350 | }
351 | if (key.charAt(key.length - 1) === separator) {
352 | key = key.slice(0, -1);
353 | }
354 | return key;
355 | };
356 |
357 | umodel.prototype._split = function(key) {
358 | return (this._normalize(key)).split(this.options.separator);
359 | };
360 |
361 | return umodel;
362 |
363 | })();
364 |
365 | return umodel;
366 | }));
367 |
368 | var _ = {
369 |
370 | // convert strings like "55deg" or ".75rad" to floats (in radians)
371 | rad: function (string) {
372 |
373 | if (typeof string === 'string') {
374 |
375 | var angle = parseFloat(string, 10),
376 | isDegrees = string.indexOf('deg') > -1
377 |
378 | // convert deg -> rad?
379 | if (isDegrees) angle *= Math.PI / 180
380 |
381 | return angle
382 |
383 | }
384 |
385 | return string
386 |
387 | },
388 |
389 | // shallow object extend
390 | extend: function (a, b) {
391 |
392 | for (var key in b) {
393 | a[key] = b[key]
394 | }
395 |
396 | return a
397 |
398 | },
399 |
400 | // make functions return `this`, for easy chaining
401 | fluent: function (fn) {
402 |
403 | return function() {
404 | fn.apply(this, arguments)
405 | return this
406 | }
407 |
408 | },
409 |
410 | isNumber: function (a) {
411 | return typeof a === 'number'
412 | }
413 |
414 | };
415 |
416 | function CssToMatrix (data) {
417 |
418 | // default options
419 | this.model = new umodel({
420 | matrix: new matrixUtilities.Identity(),
421 | transformations: {
422 | perspective: new matrixUtilities.Identity(),
423 | rotate: new matrixUtilities.Identity(),
424 | scale: new matrixUtilities.Identity(),
425 | skew: new matrixUtilities.Identity(),
426 | translate: new matrixUtilities.Identity()
427 | }
428 | })
429 |
430 | // set data?
431 | if (data) {
432 | this.matrix(data)
433 | }
434 |
435 | }
436 |
437 | _.extend(CssToMatrix.prototype, {
438 |
439 | // set matrix in model
440 | matrix: function (data) {
441 |
442 | ////DEV
443 | if (data.length == null)
444 | throw new TypeError('expected parameter `data` to be an Array, but was given a ' + typeof data)
445 |
446 | var rows = data.length,
447 | columns = rows > 0 ? rows : 0
448 |
449 | if (rows !== 4 || columns !== 4)
450 | throw new Error('expected parameter `data` to be a 4x4 matrix of arrays, but was given a ' + rows + 'x' + columns + ' matrix')
451 | ////END DEV
452 |
453 | this.model.set('matrix', data)
454 |
455 | },
456 |
457 | // apply transformations as defined in the model, and get back get calculated matrix
458 | getMatrix: function() {
459 |
460 | var matrix = this.model.get('matrix'),
461 | t = this.model.get('transformations')
462 |
463 | // perspective
464 | matrix = matrixUtilities.multiply(matrix, t.perspective)
465 |
466 | // translate
467 | matrix = matrixUtilities.multiply(matrix, t.translate)
468 |
469 | // rotate
470 | matrix = matrixUtilities.multiply(matrix, t.rotate)
471 |
472 | // skew
473 | matrix = matrixUtilities.multiply(matrix, t.skew)
474 |
475 | // scale
476 | matrix = matrixUtilities.multiply(matrix, t.scale)
477 |
478 | return matrixUtilities.flip(matrix)
479 |
480 | },
481 |
482 | // get matrix formatted as a string that can be plugged right into CSS's `transform` function
483 | getMatrixCSS: function() {
484 |
485 | return 'matrix3d('
486 | + this
487 | .getMatrix()
488 | .reduce(function (flat, row) {
489 | flat.push.apply(flat, row)
490 | return flat
491 | }, [])
492 | .join(',')
493 | + ')'
494 |
495 | },
496 |
497 | // transform functions
498 | // 1-to-1 with their CSS equivalents
499 | rotate: function (a) { return this.rotateZ(a) },
500 | rotateX: function (a) { return this.rotate3d(1, 0, 0, a) },
501 | rotateY: function (a) { return this.rotate3d(0, 1, 0, a) },
502 | rotateZ: function (a) { return this.rotate3d(0, 0, 1, a) },
503 | scale: function (x, y) { return this.scale3d(x, y) },
504 | scaleX: function (x) { return this.scale3d(x) },
505 | scaleY: function (y) { return this.scale3d(null, y) },
506 | scaleZ: function (z) { return this.scale3d(null, null, z) },
507 | skewX: function (x) { return this.skew(x) },
508 | skewY: function (y) { return this.skew(null, y) },
509 | translate: function (x, y) { return this.translate3d(x, y) },
510 | translateX: function (x) { return this.translate3d(x) },
511 | translateY: function (y) { return this.translate3d(null, y) },
512 | translateZ: function (z) { return this.translate3d(null, null, z) },
513 |
514 | perspective: _.fluent(function (x) {
515 |
516 | if (x == null) { x = 0 }
517 |
518 | ////DEV
519 | if (!_.isNumber(x))
520 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
521 | ////END DEV
522 |
523 | this.model.set('transformations/perspective', transformToMatrix.perspective(x))
524 |
525 | }),
526 |
527 | rotate3d: _.fluent(function (x, y, z, a) {
528 |
529 | if (x == null) { x = 0 }
530 | if (y == null) { y = 0 }
531 | if (z == null) { z = 0 }
532 | if (a == null) { a = 0 }
533 |
534 | ////DEV
535 | if (!_.isNumber(x))
536 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
537 | if (!_.isNumber(y))
538 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
539 | if (!_.isNumber(z))
540 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
541 | ////END DEV
542 |
543 | // if angle was passed as a string, convert it to a float first
544 | this.model.set('transformations/rotate', transformToMatrix.rotate3d(x, y, z, _.rad(a)))
545 |
546 | }),
547 |
548 | scale3d: _.fluent(function (x, y, z) {
549 |
550 | if (x == null) { x = 1 }
551 | if (y == null) { y = 1 }
552 | if (z == null) { z = 1 }
553 |
554 | ////DEV
555 | if (!_.isNumber(x))
556 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
557 | if (!_.isNumber(y))
558 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
559 | if (!_.isNumber(z))
560 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
561 | ////END DEV
562 |
563 | this.model.set('transformations/scale', transformToMatrix.scale3d(x, y, z))
564 |
565 | }),
566 |
567 | skew: _.fluent(function (x, y) {
568 |
569 | if (x == null) { x = 0 }
570 | if (y == null) { y = 0 }
571 |
572 | this.model.set('transformations/skew', matrixUtilities.to3d(transformToMatrix.skew(_.rad(x), _.rad(y))))
573 |
574 | }),
575 |
576 | translate3d: _.fluent(function(x, y, z) {
577 |
578 | if (x == null) { x = 0 }
579 | if (y == null) { y = 0 }
580 | if (z == null) { z = 0 }
581 |
582 | ////DEV
583 | if (!_.isNumber(x))
584 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
585 | if (!_.isNumber(y))
586 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
587 | if (!_.isNumber(z))
588 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
589 | ////END DEV
590 |
591 | this.model.set('transformations/translate', transformToMatrix.translate3d(x, y, z))
592 |
593 | })
594 |
595 | })
--------------------------------------------------------------------------------
/dist/css-to-matrix.standalone.min.js:
--------------------------------------------------------------------------------
1 | function a(a){this.model=new umodel({matrix:new matrixUtilities.Identity,transformations:{perspective:new matrixUtilities.Identity,rotate:new matrixUtilities.Identity,scale:new matrixUtilities.Identity,skew:new matrixUtilities.Identity,translate:new matrixUtilities.Identity}}),a&&this.matrix(a)}!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define("matrix-utilities",[],b):a["matrix-utilities"]=b()}(this,function(){var a;return a=function(){var a;return a={add:function(a,b){var c,d,e,f,g,h,i,j,k;if(a.length!==b.length)throw new Error("Matrix y dimensions do not match");for(e=[],c=h=0,j=a.length;j>h;c=++h){if(f=a[c],f.length!==b[c].length)throw new Error("Matrix x dimensions do not match on row "+(c+1));for(e[c]=[],d=i=0,k=f.length;k>i;d=++i)g=f[d],e[c][d]=g+b[c][d]}return e},multiply:function(a,b){var c,d,e,f,g,h,i,j,k,l,m,n;if(a[0].length!==b.length)throw new Error("Matrix 1's row count should equal matrix 2's column count");for(h=a[0].length,f=[],c=k=0,m=b.length;m>k;c=++k)for(g=b[c],f[c]=[],d=l=0,n=g.length;n>l;d=++l){for(j=g[d],e=h,i=0;e--;)i+=a[c][e]*b[e][d];f[c][d]=i}return f},flip:function(a){var b,c,d,e,f,g,h,i,j;for(d=[],b=g=0,i=a.length;i>g;b=++g)for(e=a[b],c=h=0,j=e.length;j>h;c=++h)f=e[c],(d[c]||(d[c]=[]))[b]=f;return d},to2d:function(a){return[[a[0][0]||1,a[0][1]||0,a[0][3]||0],[a[1][0]||0,a[1][1]||1,a[1][3]||0]]},to3d:function(a){return[[a[0][0]||1,a[0][1]||0,0,a[0][2]||0],[a[1][0]||0,a[1][1]||1,0,a[1][2]||0],[0,0,1,0],[0,0,0,1]]},Identity:function(){return[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]}}}()}),function(){var a,b;b=function(a){return"object"==typeof exports?module.exports=a:"function"==typeof define&&define.amd?define([],a):this["transform-to-matrix"]=a},a={perspective:function(a){return[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,-1/a,1]]},rotate:function(b){return a.rotateZ(b)},rotateX:function(b){return a.rotate3d(1,0,0,b)},rotateY:function(b){return a.rotate3d(0,1,0,b)},rotateZ:function(a){var b,c;return b=Math.cos(a),c=Math.sin(a),[[b,-c,0],[c,b,0]]},rotate3d:function(a,b,c,d){var e,f,g,h,i;return i=a*a+b*b+c*c,e=Math.cos(d),g=Math.sin(d),f=1-e,h=Math.sqrt(i)*g,[[(a*a+(b*b+c*c)*e)/i,(a*b*f-c*h)/i,(a*c*f+b*h)/i,0],[(a*b*f+c*h)/i,(b*b+(a*a+c*c)*e)/i,(b*c*f-a*h)/i,0],[(a*c*f-b*h)/i,(b*c*f+a*h)/i,(c*c+(a*a+b*b)*e)/i,0],[0,0,0,1]]},scale:function(a,b){return[[a,0,0],[0,b,0]]},scaleX:function(b){return a.scale(b,1)},scaleY:function(b){return a.scale(1,b)},scaleZ:function(b){return a.scale3d(1,1,b)},scale3d:function(a,b,c){return[[a,0,0,0],[0,b,0,0],[0,0,c,0],[0,0,0,1]]},skew:function(a,b){return[[1,Math.tan(a),0],[Math.tan(b),1,0]]},skewX:function(a){return[[1,Math.tan(a),0],[0,1,0]]},skewY:function(a){return[[1,0,0],[Math.tan(a),1,0]]},translate:function(a,b){return[[1,0,a],[0,1,b]]},translateX:function(b){return a.translate(b,0)},translateY:function(b){return a.translate(0,b)},translateZ:function(b){return a.translate3d(0,0,b)},translate3d:function(a,b,c){return[[1,0,0,a],[0,1,0,b],[0,0,1,c],[0,0,0,1]]}},b(a)}.call(this),function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define("umodel",[],b):a.umodel=b()}(this,function(){var a,b,c={}.hasOwnProperty;return b={extend:function(a,b){var d;for(d in b)c.call(b,d)&&(a[d]=b[d]);return a},trim:function(){var a,b;return"".trim?function(a){return a.trim()}:(a=/^\s\s*/,b=/\s\s*$/,function(c){return c.replace(a,"").replace(b,"")})}()},a=function(){function a(a,c){this._data=null!=a?a:{},this.options={separator:"/"},c&&b.extend(this.options,c),this.events={}}return a.prototype.get=function(a){return this.trigger("get",a),this._get(this._split(a),this._data)},a.prototype.set=function(a,b){var c;return c=this._get(this._split(a),this._data),this._set(this._split(a),b,!1,this._data),this.trigger("set",a,b,c)},a.prototype.setnx=function(a,b){var c;return c=this._get(this._split(a),this._data),this._set(this._split(a),b,!0,this._data),this.trigger("setnx",a,b,c)},a.prototype.on=function(a,b){var c,d;if(b)return this._on(a,b);d=[];for(c in a)b=a[c],d.push(this._on(c,b));return d},a.prototype.trigger=function(a,b,c,d){var e,f,g,h,i;if(null==b&&(b="*"),b=this._normalize(b),a in this.events){h=this.events[a],i=[];for(e in h)g=h[e],i.push("*"===e||0===(b+"/").indexOf(e+"/")?function(){var a,e,h;for(h=[],a=0,e=g.length;e>a;a++)f=g[a],h.push(null!=d?f.call(this,b,c,d):f.call(this,b,c));return h}.call(this):void 0);return i}},a.prototype._get=function(a,b,c){var d;return null==c&&(c=[]),d=a.shift(),d?d in b?(c.push(d),this._get(a,b[d],c)):void 0:b},a.prototype._set=function(a,b,c,d,e){var f;return null==c&&(c=!1),null==e&&(e=[]),f=a.shift(),a.length?(f in d||(d[f]={}),e.push(f),this._set(a,b,c,d[f],e)):c&&f in d?void 0:d[f]=b},a.prototype._on=function(a,c){var d,e,f,g,h,i,j;for(f=a.split(":"),e=f[0].split(" "),g=this._normalize(f[1]||"*"),j=[],h=0,i=e.length;i>h;h++)d=e[h],d=b.trim(d),d in this.events||(this.events[d]={}),g in this.events[d]||(this.events[d][g]=[]),j.push(this.events[d][g].push(c));return j},a.prototype._normalize=function(a){var c;return c=this.options.separator,a=b.trim(a),a.charAt(0)===c&&(a=a.slice(1)),a.charAt(a.length-1)===c&&(a=a.slice(0,-1)),a},a.prototype._split=function(a){return this._normalize(a).split(this.options.separator)},a}()});var b={rad:function(a){if("string"==typeof a){var b=parseFloat(a,10),c=a.indexOf("deg")>-1;return c&&(b*=Math.PI/180),b}return a},extend:function(a,b){for(var c in b)a[c]=b[c];return a},fluent:function(a){return function(){return a.apply(this,arguments),this}},isNumber:function(a){return"number"==typeof a}};b.extend(a.prototype,{matrix:function(a){if(null==a.length)throw new TypeError("expected parameter `data` to be an Array, but was given a "+typeof a);var b=a.length,c=b>0?b:0;if(4!==b||4!==c)throw new Error("expected parameter `data` to be a 4x4 matrix of arrays, but was given a "+b+"x"+c+" matrix");this.model.set("matrix",a)},getMatrix:function(){var a=this.model.get("matrix"),b=this.model.get("transformations");return a=matrixUtilities.multiply(a,b.perspective),a=matrixUtilities.multiply(a,b.translate),a=matrixUtilities.multiply(a,b.rotate),a=matrixUtilities.multiply(a,b.skew),a=matrixUtilities.multiply(a,b.scale),matrixUtilities.flip(a)},getMatrixCSS:function(){return"matrix3d("+this.getMatrix().reduce(function(a,b){return a.push.apply(a,b),a},[]).join(",")+")"},rotate:function(a){return this.rotateZ(a)},rotateX:function(a){return this.rotate3d(1,0,0,a)},rotateY:function(a){return this.rotate3d(0,1,0,a)},rotateZ:function(a){return this.rotate3d(0,0,1,a)},scale:function(a,b){return this.scale3d(a,b)},scaleX:function(a){return this.scale3d(a)},scaleY:function(a){return this.scale3d(null,a)},scaleZ:function(a){return this.scale3d(null,null,a)},skewX:function(a){return this.skew(a)},skewY:function(a){return this.skew(null,a)},translate:function(a,b){return this.translate3d(a,b)},translateX:function(a){return this.translate3d(a)},translateY:function(a){return this.translate3d(null,a)},translateZ:function(a){return this.translate3d(null,null,a)},perspective:b.fluent(function(a){if(null==a&&(a=0),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);this.model.set("transformations/perspective",transformToMatrix.perspective(a))}),rotate3d:b.fluent(function(a,c,d,e){if(null==a&&(a=0),null==c&&(c=0),null==d&&(d=0),null==e&&(e=0),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);if(!b.isNumber(c))throw new TypeError("expected parameter `y` to be a Number, but was given a "+typeof c);if(!b.isNumber(d))throw new TypeError("expected parameter `z` to be a Number, but was given a "+typeof d);this.model.set("transformations/rotate",transformToMatrix.rotate3d(a,c,d,b.rad(e)))}),scale3d:b.fluent(function(a,c,d){if(null==a&&(a=1),null==c&&(c=1),null==d&&(d=1),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);if(!b.isNumber(c))throw new TypeError("expected parameter `y` to be a Number, but was given a "+typeof c);if(!b.isNumber(d))throw new TypeError("expected parameter `z` to be a Number, but was given a "+typeof d);this.model.set("transformations/scale",transformToMatrix.scale3d(a,c,d))}),skew:b.fluent(function(a,c){null==a&&(a=0),null==c&&(c=0),this.model.set("transformations/skew",matrixUtilities.to3d(transformToMatrix.skew(b.rad(a),b.rad(c))))}),translate3d:b.fluent(function(a,c,d){if(null==a&&(a=0),null==c&&(c=0),null==d&&(d=0),!b.isNumber(a))throw new TypeError("expected parameter `x` to be a Number, but was given a "+typeof a);if(!b.isNumber(c))throw new TypeError("expected parameter `y` to be a Number, but was given a "+typeof c);if(!b.isNumber(d))throw new TypeError("expected parameter `z` to be a Number, but was given a "+typeof d);this.model.set("transformations/translate",transformToMatrix.translate3d(a,c,d))})});
--------------------------------------------------------------------------------
/grunt-umd-template.hbs:
--------------------------------------------------------------------------------
1 | (function(root, factory) {
2 | if(typeof exports === 'object') {
3 | module.exports = factory(require('transform-to-matrix'), require('matrix-utilities'), require('umodel'));
4 | }
5 | else if(typeof define === 'function' && define.amd) {
6 | define('css-to-matrix', ['transform-to-matrix', 'matrix-utilities', 'umodel'], factory);
7 | }
8 | else {
9 | root['css-to-matrix'] = factory(root['transform-to-matrix'], root['matrix-utilities'], root.umodel);
10 | }
11 | }(this, function(transformToMatrix, matrixUtilities, umodel) {
12 | {{{code}}}
13 | return {{objectToExport}};
14 | }));
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "css-to-matrix",
3 | "version": "1.0.0",
4 | "description": "A little library for converting compound CSS transforms into their matrix equivalents",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/eighttrackmind/css-to-matrix.git"
8 | },
9 | "author": "Boris Cherny ",
10 | "contributors": [
11 | {
12 | "name": "Boris Cherny",
13 | "email": "boris@performancejs.com"
14 | }
15 | ],
16 | "devDependencies": {
17 | "annie": "~0.1.3",
18 | "change-case": "^2.1.1",
19 | "grunt": "~0.4.1",
20 | "grunt-contrib-coffee": "~0.7.0",
21 | "grunt-contrib-concat": "^0.4.0",
22 | "grunt-contrib-uglify": "~0.2.4",
23 | "grunt-contrib-watch": "^0.6.1",
24 | "grunt-regex-replace": "~0.2.5",
25 | "grunt-umd": "^1.7.4"
26 | },
27 | "license": "MIT",
28 | "readmeFilename": "README.md",
29 | "dependencies": {
30 | "transform-to-matrix": "~0",
31 | "matrix-utilities": "^1.2",
32 | "umodel": "~0"
33 | },
34 | "scripts": {
35 | "test": "grunt test"
36 | },
37 | "keywords": [
38 | "transform",
39 | "3d",
40 | "css",
41 | "matrix",
42 | "identity",
43 | "multiply",
44 | "css3"
45 | ],
46 | "main": "dist/css-to-matrix.js",
47 | "testling": {
48 | "files": "test/test.js",
49 | "browsers": {
50 | "ie": [
51 | 6,
52 | 7,
53 | 8,
54 | 9
55 | ],
56 | "firefox": [
57 | "nightly",
58 | 24,
59 | 23,
60 | 22,
61 | 21,
62 | 20
63 | ],
64 | "chrome": [
65 | "canary",
66 | 30,
67 | 25,
68 | 20,
69 | 15,
70 | 10
71 | ],
72 | "safari": [
73 | 6,
74 | 5,
75 | 4,
76 | 3
77 | ],
78 | "opera": [
79 | "next",
80 | 16,
81 | 15,
82 | 14,
83 | 13,
84 | 12
85 | ],
86 | "iphone": [
87 | 6
88 | ],
89 | "ipad": [
90 | 6
91 | ],
92 | "android": [
93 | 4
94 | ]
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/css-to-matrix.js:
--------------------------------------------------------------------------------
1 | var _ = {
2 |
3 | // convert strings like "55deg" or ".75rad" to floats (in radians)
4 | rad: function (string) {
5 |
6 | if (typeof string === 'string') {
7 |
8 | var angle = parseFloat(string, 10),
9 | isDegrees = string.indexOf('deg') > -1
10 |
11 | // convert deg -> rad?
12 | if (isDegrees) angle *= Math.PI / 180
13 |
14 | return angle
15 |
16 | }
17 |
18 | return string
19 |
20 | },
21 |
22 | // shallow object extend
23 | extend: function (a, b) {
24 |
25 | for (var key in b) {
26 | a[key] = b[key]
27 | }
28 |
29 | return a
30 |
31 | },
32 |
33 | // make functions return `this`, for easy chaining
34 | fluent: function (fn) {
35 |
36 | return function() {
37 | fn.apply(this, arguments)
38 | return this
39 | }
40 |
41 | },
42 |
43 | isNumber: function (a) {
44 | return typeof a === 'number'
45 | }
46 |
47 | };
48 |
49 | function CssToMatrix (data) {
50 |
51 | // default options
52 | this.model = new umodel({
53 | matrix: new matrixUtilities.Identity(),
54 | transformations: {
55 | perspective: new matrixUtilities.Identity(),
56 | rotate: new matrixUtilities.Identity(),
57 | scale: new matrixUtilities.Identity(),
58 | skew: new matrixUtilities.Identity(),
59 | translate: new matrixUtilities.Identity()
60 | }
61 | })
62 |
63 | // set data?
64 | if (data) {
65 | this.matrix(data)
66 | }
67 |
68 | }
69 |
70 | _.extend(CssToMatrix.prototype, {
71 |
72 | // set matrix in model
73 | matrix: function (data) {
74 |
75 | ////DEV
76 | if (data.length == null)
77 | throw new TypeError('expected parameter `data` to be an Array, but was given a ' + typeof data)
78 |
79 | var rows = data.length,
80 | columns = rows > 0 ? rows : 0
81 |
82 | if (rows !== 4 || columns !== 4)
83 | throw new Error('expected parameter `data` to be a 4x4 matrix of arrays, but was given a ' + rows + 'x' + columns + ' matrix')
84 | ////END DEV
85 |
86 | this.model.set('matrix', data)
87 |
88 | },
89 |
90 | // apply transformations as defined in the model, and get back get calculated matrix
91 | getMatrix: function() {
92 |
93 | var matrix = this.model.get('matrix'),
94 | t = this.model.get('transformations')
95 |
96 | // perspective
97 | matrix = matrixUtilities.multiply(matrix, t.perspective)
98 |
99 | // translate
100 | matrix = matrixUtilities.multiply(matrix, t.translate)
101 |
102 | // rotate
103 | matrix = matrixUtilities.multiply(matrix, t.rotate)
104 |
105 | // skew
106 | matrix = matrixUtilities.multiply(matrix, t.skew)
107 |
108 | // scale
109 | matrix = matrixUtilities.multiply(matrix, t.scale)
110 |
111 | return matrixUtilities.flip(matrix)
112 |
113 | },
114 |
115 | // get matrix formatted as a string that can be plugged right into CSS's `transform` function
116 | getMatrixCSS: function() {
117 |
118 | return 'matrix3d('
119 | + this
120 | .getMatrix()
121 | .reduce(function (flat, row) {
122 | flat.push.apply(flat, row)
123 | return flat
124 | }, [])
125 | .join(',')
126 | + ')'
127 |
128 | },
129 |
130 | // transform functions
131 | // 1-to-1 with their CSS equivalents
132 | rotate: function (a) { return this.rotateZ(a) },
133 | rotateX: function (a) { return this.rotate3d(1, 0, 0, a) },
134 | rotateY: function (a) { return this.rotate3d(0, 1, 0, a) },
135 | rotateZ: function (a) { return this.rotate3d(0, 0, 1, a) },
136 | scale: function (x, y) { return this.scale3d(x, y) },
137 | scaleX: function (x) { return this.scale3d(x) },
138 | scaleY: function (y) { return this.scale3d(null, y) },
139 | scaleZ: function (z) { return this.scale3d(null, null, z) },
140 | skewX: function (x) { return this.skew(x) },
141 | skewY: function (y) { return this.skew(null, y) },
142 | translate: function (x, y) { return this.translate3d(x, y) },
143 | translateX: function (x) { return this.translate3d(x) },
144 | translateY: function (y) { return this.translate3d(null, y) },
145 | translateZ: function (z) { return this.translate3d(null, null, z) },
146 |
147 | perspective: _.fluent(function (x) {
148 |
149 | if (x == null) { x = 0 }
150 |
151 | ////DEV
152 | if (!_.isNumber(x))
153 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
154 | ////END DEV
155 |
156 | this.model.set('transformations/perspective', transformToMatrix.perspective(x))
157 |
158 | }),
159 |
160 | rotate3d: _.fluent(function (x, y, z, a) {
161 |
162 | if (x == null) { x = 0 }
163 | if (y == null) { y = 0 }
164 | if (z == null) { z = 0 }
165 | if (a == null) { a = 0 }
166 |
167 | ////DEV
168 | if (!_.isNumber(x))
169 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
170 | if (!_.isNumber(y))
171 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
172 | if (!_.isNumber(z))
173 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
174 | ////END DEV
175 |
176 | // if angle was passed as a string, convert it to a float first
177 | this.model.set('transformations/rotate', transformToMatrix.rotate3d(x, y, z, _.rad(a)))
178 |
179 | }),
180 |
181 | scale3d: _.fluent(function (x, y, z) {
182 |
183 | if (x == null) { x = 1 }
184 | if (y == null) { y = 1 }
185 | if (z == null) { z = 1 }
186 |
187 | ////DEV
188 | if (!_.isNumber(x))
189 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
190 | if (!_.isNumber(y))
191 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
192 | if (!_.isNumber(z))
193 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
194 | ////END DEV
195 |
196 | this.model.set('transformations/scale', transformToMatrix.scale3d(x, y, z))
197 |
198 | }),
199 |
200 | skew: _.fluent(function (x, y) {
201 |
202 | if (x == null) { x = 0 }
203 | if (y == null) { y = 0 }
204 |
205 | this.model.set('transformations/skew', matrixUtilities.to3d(transformToMatrix.skew(_.rad(x), _.rad(y))))
206 |
207 | }),
208 |
209 | translate3d: _.fluent(function(x, y, z) {
210 |
211 | if (x == null) { x = 0 }
212 | if (y == null) { y = 0 }
213 | if (z == null) { z = 0 }
214 |
215 | ////DEV
216 | if (!_.isNumber(x))
217 | throw new TypeError('expected parameter `x` to be a Number, but was given a ' + typeof x)
218 | if (!_.isNumber(y))
219 | throw new TypeError('expected parameter `y` to be a Number, but was given a ' + typeof y)
220 | if (!_.isNumber(z))
221 | throw new TypeError('expected parameter `z` to be a Number, but was given a ' + typeof z)
222 | ////END DEV
223 |
224 | this.model.set('transformations/translate', transformToMatrix.translate3d(x, y, z))
225 |
226 | })
227 |
228 | })
--------------------------------------------------------------------------------
/test/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcherny/css-to-matrix/c7f4ca861624e30067ce885d8b4513eb9a5802cc/test/.DS_Store
--------------------------------------------------------------------------------
/test/chai.js:
--------------------------------------------------------------------------------
1 | ;(function(){
2 |
3 | /**
4 | * Require the given path.
5 | *
6 | * @param {String} path
7 | * @return {Object} exports
8 | * @api public
9 | */
10 |
11 | function require(path, parent, orig) {
12 | var resolved = require.resolve(path);
13 |
14 | // lookup failed
15 | if (null == resolved) {
16 | orig = orig || path;
17 | parent = parent || 'root';
18 | var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
19 | err.path = orig;
20 | err.parent = parent;
21 | err.require = true;
22 | throw err;
23 | }
24 |
25 | var module = require.modules[resolved];
26 |
27 | // perform real require()
28 | // by invoking the module's
29 | // registered function
30 | if (!module._resolving && !module.exports) {
31 | var mod = {};
32 | mod.exports = {};
33 | mod.client = mod.component = true;
34 | module._resolving = true;
35 | module.call(this, mod.exports, require.relative(resolved), mod);
36 | delete module._resolving;
37 | module.exports = mod.exports;
38 | }
39 |
40 | return module.exports;
41 | }
42 |
43 | /**
44 | * Registered modules.
45 | */
46 |
47 | require.modules = {};
48 |
49 | /**
50 | * Registered aliases.
51 | */
52 |
53 | require.aliases = {};
54 |
55 | /**
56 | * Resolve `path`.
57 | *
58 | * Lookup:
59 | *
60 | * - PATH/index.js
61 | * - PATH.js
62 | * - PATH
63 | *
64 | * @param {String} path
65 | * @return {String} path or null
66 | * @api private
67 | */
68 |
69 | require.resolve = function(path) {
70 | if (path.charAt(0) === '/') path = path.slice(1);
71 |
72 | var paths = [
73 | path,
74 | path + '.js',
75 | path + '.json',
76 | path + '/index.js',
77 | path + '/index.json'
78 | ];
79 |
80 | for (var i = 0; i < paths.length; i++) {
81 | var path = paths[i];
82 | if (require.modules.hasOwnProperty(path)) return path;
83 | if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
84 | }
85 | };
86 |
87 | /**
88 | * Normalize `path` relative to the current path.
89 | *
90 | * @param {String} curr
91 | * @param {String} path
92 | * @return {String}
93 | * @api private
94 | */
95 |
96 | require.normalize = function(curr, path) {
97 | var segs = [];
98 |
99 | if ('.' != path.charAt(0)) return path;
100 |
101 | curr = curr.split('/');
102 | path = path.split('/');
103 |
104 | for (var i = 0; i < path.length; ++i) {
105 | if ('..' == path[i]) {
106 | curr.pop();
107 | } else if ('.' != path[i] && '' != path[i]) {
108 | segs.push(path[i]);
109 | }
110 | }
111 |
112 | return curr.concat(segs).join('/');
113 | };
114 |
115 | /**
116 | * Register module at `path` with callback `definition`.
117 | *
118 | * @param {String} path
119 | * @param {Function} definition
120 | * @api private
121 | */
122 |
123 | require.register = function(path, definition) {
124 | require.modules[path] = definition;
125 | };
126 |
127 | /**
128 | * Alias a module definition.
129 | *
130 | * @param {String} from
131 | * @param {String} to
132 | * @api private
133 | */
134 |
135 | require.alias = function(from, to) {
136 | if (!require.modules.hasOwnProperty(from)) {
137 | throw new Error('Failed to alias "' + from + '", it does not exist');
138 | }
139 | require.aliases[to] = from;
140 | };
141 |
142 | /**
143 | * Return a require function relative to the `parent` path.
144 | *
145 | * @param {String} parent
146 | * @return {Function}
147 | * @api private
148 | */
149 |
150 | require.relative = function(parent) {
151 | var p = require.normalize(parent, '..');
152 |
153 | /**
154 | * lastIndexOf helper.
155 | */
156 |
157 | function lastIndexOf(arr, obj) {
158 | var i = arr.length;
159 | while (i--) {
160 | if (arr[i] === obj) return i;
161 | }
162 | return -1;
163 | }
164 |
165 | /**
166 | * The relative require() itself.
167 | */
168 |
169 | function localRequire(path) {
170 | var resolved = localRequire.resolve(path);
171 | return require(resolved, parent, path);
172 | }
173 |
174 | /**
175 | * Resolve relative to the parent.
176 | */
177 |
178 | localRequire.resolve = function(path) {
179 | var c = path.charAt(0);
180 | if ('/' == c) return path.slice(1);
181 | if ('.' == c) return require.normalize(p, path);
182 |
183 | // resolve deps by returning
184 | // the dep in the nearest "deps"
185 | // directory
186 | var segs = parent.split('/');
187 | var i = lastIndexOf(segs, 'deps') + 1;
188 | if (!i) i = 0;
189 | path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
190 | return path;
191 | };
192 |
193 | /**
194 | * Check if module is defined at `path`.
195 | */
196 |
197 | localRequire.exists = function(path) {
198 | return require.modules.hasOwnProperty(localRequire.resolve(path));
199 | };
200 |
201 | return localRequire;
202 | };
203 | require.register("chaijs-assertion-error/index.js", function(exports, require, module){
204 | /*!
205 | * assertion-error
206 | * Copyright(c) 2013 Jake Luer
207 | * MIT Licensed
208 | */
209 |
210 | /*!
211 | * Return a function that will copy properties from
212 | * one object to another excluding any originally
213 | * listed. Returned function will create a new `{}`.
214 | *
215 | * @param {String} excluded properties ...
216 | * @return {Function}
217 | */
218 |
219 | function exclude () {
220 | var excludes = [].slice.call(arguments);
221 |
222 | function excludeProps (res, obj) {
223 | Object.keys(obj).forEach(function (key) {
224 | if (!~excludes.indexOf(key)) res[key] = obj[key];
225 | });
226 | }
227 |
228 | return function extendExclude () {
229 | var args = [].slice.call(arguments)
230 | , i = 0
231 | , res = {};
232 |
233 | for (; i < args.length; i++) {
234 | excludeProps(res, args[i]);
235 | }
236 |
237 | return res;
238 | };
239 | };
240 |
241 | /*!
242 | * Primary Exports
243 | */
244 |
245 | module.exports = AssertionError;
246 |
247 | /**
248 | * ### AssertionError
249 | *
250 | * An extension of the JavaScript `Error` constructor for
251 | * assertion and validation scenarios.
252 | *
253 | * @param {String} message
254 | * @param {Object} properties to include (optional)
255 | * @param {callee} start stack function (optional)
256 | */
257 |
258 | function AssertionError (message, _props, ssf) {
259 | var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON')
260 | , props = extend(_props || {});
261 |
262 | // default values
263 | this.message = message || 'Unspecified AssertionError';
264 | this.showDiff = false;
265 |
266 | // copy from properties
267 | for (var key in props) {
268 | this[key] = props[key];
269 | }
270 |
271 | // capture stack trace
272 | ssf = ssf || arguments.callee;
273 | if (ssf && Error.captureStackTrace) {
274 | Error.captureStackTrace(this, ssf);
275 | }
276 | }
277 |
278 | /*!
279 | * Inherit from Error.prototype
280 | */
281 |
282 | AssertionError.prototype = Object.create(Error.prototype);
283 |
284 | /*!
285 | * Statically set name
286 | */
287 |
288 | AssertionError.prototype.name = 'AssertionError';
289 |
290 | /*!
291 | * Ensure correct constructor
292 | */
293 |
294 | AssertionError.prototype.constructor = AssertionError;
295 |
296 | /**
297 | * Allow errors to be converted to JSON for static transfer.
298 | *
299 | * @param {Boolean} include stack (default: `true`)
300 | * @return {Object} object that can be `JSON.stringify`
301 | */
302 |
303 | AssertionError.prototype.toJSON = function (stack) {
304 | var extend = exclude('constructor', 'toJSON', 'stack')
305 | , props = extend({ name: this.name }, this);
306 |
307 | // include stack if exists and not turned off
308 | if (false !== stack && this.stack) {
309 | props.stack = this.stack;
310 | }
311 |
312 | return props;
313 | };
314 |
315 | });
316 | require.register("chaijs-type-detect/lib/type.js", function(exports, require, module){
317 | /*!
318 | * type-detect
319 | * Copyright(c) 2013 jake luer
320 | * MIT Licensed
321 | */
322 |
323 | /*!
324 | * Primary Exports
325 | */
326 |
327 | var exports = module.exports = getType;
328 |
329 | /*!
330 | * Detectable javascript natives
331 | */
332 |
333 | var natives = {
334 | '[object Array]': 'array'
335 | , '[object RegExp]': 'regexp'
336 | , '[object Function]': 'function'
337 | , '[object Arguments]': 'arguments'
338 | , '[object Date]': 'date'
339 | };
340 |
341 | /**
342 | * ### typeOf (obj)
343 | *
344 | * Use several different techniques to determine
345 | * the type of object being tested.
346 | *
347 | *
348 | * @param {Mixed} object
349 | * @return {String} object type
350 | * @api public
351 | */
352 |
353 | function getType (obj) {
354 | var str = Object.prototype.toString.call(obj);
355 | if (natives[str]) return natives[str];
356 | if (obj === null) return 'null';
357 | if (obj === undefined) return 'undefined';
358 | if (obj === Object(obj)) return 'object';
359 | return typeof obj;
360 | }
361 |
362 | exports.Library = Library;
363 |
364 | /**
365 | * ### Library
366 | *
367 | * Create a repository for custom type detection.
368 | *
369 | * ```js
370 | * var lib = new type.Library;
371 | * ```
372 | *
373 | */
374 |
375 | function Library () {
376 | this.tests = {};
377 | }
378 |
379 | /**
380 | * #### .of (obj)
381 | *
382 | * Expose replacement `typeof` detection to the library.
383 | *
384 | * ```js
385 | * if ('string' === lib.of('hello world')) {
386 | * // ...
387 | * }
388 | * ```
389 | *
390 | * @param {Mixed} object to test
391 | * @return {String} type
392 | */
393 |
394 | Library.prototype.of = getType;
395 |
396 | /**
397 | * #### .define (type, test)
398 | *
399 | * Add a test to for the `.test()` assertion.
400 | *
401 | * Can be defined as a regular expression:
402 | *
403 | * ```js
404 | * lib.define('int', /^[0-9]+$/);
405 | * ```
406 | *
407 | * ... or as a function:
408 | *
409 | * ```js
410 | * lib.define('bln', function (obj) {
411 | * if ('boolean' === lib.of(obj)) return true;
412 | * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ];
413 | * if ('string' === lib.of(obj)) obj = obj.toLowerCase();
414 | * return !! ~blns.indexOf(obj);
415 | * });
416 | * ```
417 | *
418 | * @param {String} type
419 | * @param {RegExp|Function} test
420 | * @api public
421 | */
422 |
423 | Library.prototype.define = function (type, test) {
424 | if (arguments.length === 1) return this.tests[type];
425 | this.tests[type] = test;
426 | return this;
427 | };
428 |
429 | /**
430 | * #### .test (obj, test)
431 | *
432 | * Assert that an object is of type. Will first
433 | * check natives, and if that does not pass it will
434 | * use the user defined custom tests.
435 | *
436 | * ```js
437 | * assert(lib.test('1', 'int'));
438 | * assert(lib.test('yes', 'bln'));
439 | * ```
440 | *
441 | * @param {Mixed} object
442 | * @param {String} type
443 | * @return {Boolean} result
444 | * @api public
445 | */
446 |
447 | Library.prototype.test = function (obj, type) {
448 | if (type === getType(obj)) return true;
449 | var test = this.tests[type];
450 |
451 | if (test && 'regexp' === getType(test)) {
452 | return test.test(obj);
453 | } else if (test && 'function' === getType(test)) {
454 | return test(obj);
455 | } else {
456 | throw new ReferenceError('Type test "' + type + '" not defined or invalid.');
457 | }
458 | };
459 |
460 | });
461 | require.register("chaijs-deep-eql/lib/eql.js", function(exports, require, module){
462 | /*!
463 | * deep-eql
464 | * Copyright(c) 2013 Jake Luer
465 | * MIT Licensed
466 | */
467 |
468 | /*!
469 | * Module dependencies
470 | */
471 |
472 | var type = require('type-detect');
473 |
474 | /*!
475 | * Buffer.isBuffer browser shim
476 | */
477 |
478 | var Buffer;
479 | try { Buffer = require('buffer').Buffer; }
480 | catch(ex) {
481 | Buffer = {};
482 | Buffer.isBuffer = function() { return false; }
483 | }
484 |
485 | /*!
486 | * Primary Export
487 | */
488 |
489 | module.exports = deepEqual;
490 |
491 | /**
492 | * Assert super-strict (egal) equality between
493 | * two objects of any type.
494 | *
495 | * @param {Mixed} a
496 | * @param {Mixed} b
497 | * @param {Array} memoised (optional)
498 | * @return {Boolean} equal match
499 | */
500 |
501 | function deepEqual(a, b, m) {
502 | if (sameValue(a, b)) {
503 | return true;
504 | } else if ('date' === type(a)) {
505 | return dateEqual(a, b);
506 | } else if ('regexp' === type(a)) {
507 | return regexpEqual(a, b);
508 | } else if (Buffer.isBuffer(a)) {
509 | return bufferEqual(a, b);
510 | } else if ('arguments' === type(a)) {
511 | return argumentsEqual(a, b, m);
512 | } else if (!typeEqual(a, b)) {
513 | return false;
514 | } else if (('object' !== type(a) && 'object' !== type(b))
515 | && ('array' !== type(a) && 'array' !== type(b))) {
516 | return sameValue(a, b);
517 | } else {
518 | return objectEqual(a, b, m);
519 | }
520 | }
521 |
522 | /*!
523 | * Strict (egal) equality test. Ensures that NaN always
524 | * equals NaN and `-0` does not equal `+0`.
525 | *
526 | * @param {Mixed} a
527 | * @param {Mixed} b
528 | * @return {Boolean} equal match
529 | */
530 |
531 | function sameValue(a, b) {
532 | if (a === b) return a !== 0 || 1 / a === 1 / b;
533 | return a !== a && b !== b;
534 | }
535 |
536 | /*!
537 | * Compare the types of two given objects and
538 | * return if they are equal. Note that an Array
539 | * has a type of `array` (not `object`) and arguments
540 | * have a type of `arguments` (not `array`/`object`).
541 | *
542 | * @param {Mixed} a
543 | * @param {Mixed} b
544 | * @return {Boolean} result
545 | */
546 |
547 | function typeEqual(a, b) {
548 | return type(a) === type(b);
549 | }
550 |
551 | /*!
552 | * Compare two Date objects by asserting that
553 | * the time values are equal using `saveValue`.
554 | *
555 | * @param {Date} a
556 | * @param {Date} b
557 | * @return {Boolean} result
558 | */
559 |
560 | function dateEqual(a, b) {
561 | if ('date' !== type(b)) return false;
562 | return sameValue(a.getTime(), b.getTime());
563 | }
564 |
565 | /*!
566 | * Compare two regular expressions by converting them
567 | * to string and checking for `sameValue`.
568 | *
569 | * @param {RegExp} a
570 | * @param {RegExp} b
571 | * @return {Boolean} result
572 | */
573 |
574 | function regexpEqual(a, b) {
575 | if ('regexp' !== type(b)) return false;
576 | return sameValue(a.toString(), b.toString());
577 | }
578 |
579 | /*!
580 | * Assert deep equality of two `arguments` objects.
581 | * Unfortunately, these must be sliced to arrays
582 | * prior to test to ensure no bad behavior.
583 | *
584 | * @param {Arguments} a
585 | * @param {Arguments} b
586 | * @param {Array} memoize (optional)
587 | * @return {Boolean} result
588 | */
589 |
590 | function argumentsEqual(a, b, m) {
591 | if ('arguments' !== type(b)) return false;
592 | a = [].slice.call(a);
593 | b = [].slice.call(b);
594 | return deepEqual(a, b, m);
595 | }
596 |
597 | /*!
598 | * Get enumerable properties of a given object.
599 | *
600 | * @param {Object} a
601 | * @return {Array} property names
602 | */
603 |
604 | function enumerable(a) {
605 | var res = [];
606 | for (var key in a) res.push(key);
607 | return res;
608 | }
609 |
610 | /*!
611 | * Simple equality for flat iterable objects
612 | * such as Arrays or Node.js buffers.
613 | *
614 | * @param {Iterable} a
615 | * @param {Iterable} b
616 | * @return {Boolean} result
617 | */
618 |
619 | function iterableEqual(a, b) {
620 | if (a.length !== b.length) return false;
621 |
622 | var i = 0;
623 | var match = true;
624 |
625 | for (; i < a.length; i++) {
626 | if (a[i] !== b[i]) {
627 | match = false;
628 | break;
629 | }
630 | }
631 |
632 | return match;
633 | }
634 |
635 | /*!
636 | * Extension to `iterableEqual` specifically
637 | * for Node.js Buffers.
638 | *
639 | * @param {Buffer} a
640 | * @param {Mixed} b
641 | * @return {Boolean} result
642 | */
643 |
644 | function bufferEqual(a, b) {
645 | if (!Buffer.isBuffer(b)) return false;
646 | return iterableEqual(a, b);
647 | }
648 |
649 | /*!
650 | * Block for `objectEqual` ensuring non-existing
651 | * values don't get in.
652 | *
653 | * @param {Mixed} object
654 | * @return {Boolean} result
655 | */
656 |
657 | function isValue(a) {
658 | return a !== null && a !== undefined;
659 | }
660 |
661 | /*!
662 | * Recursively check the equality of two objects.
663 | * Once basic sameness has been established it will
664 | * defer to `deepEqual` for each enumerable key
665 | * in the object.
666 | *
667 | * @param {Mixed} a
668 | * @param {Mixed} b
669 | * @return {Boolean} result
670 | */
671 |
672 | function objectEqual(a, b, m) {
673 | if (!isValue(a) || !isValue(b)) {
674 | return false;
675 | }
676 |
677 | if (a.prototype !== b.prototype) {
678 | return false;
679 | }
680 |
681 | var i;
682 | if (m) {
683 | for (i = 0; i < m.length; i++) {
684 | if ((m[i][0] === a && m[i][1] === b)
685 | || (m[i][0] === b && m[i][1] === a)) {
686 | return true;
687 | }
688 | }
689 | } else {
690 | m = [];
691 | }
692 |
693 | try {
694 | var ka = enumerable(a);
695 | var kb = enumerable(b);
696 | } catch (ex) {
697 | return false;
698 | }
699 |
700 | ka.sort();
701 | kb.sort();
702 |
703 | if (!iterableEqual(ka, kb)) {
704 | return false;
705 | }
706 |
707 | m.push([ a, b ]);
708 |
709 | var key;
710 | for (i = ka.length - 1; i >= 0; i--) {
711 | key = ka[i];
712 | if (!deepEqual(a[key], b[key], m)) {
713 | return false;
714 | }
715 | }
716 |
717 | return true;
718 | }
719 |
720 | });
721 | require.register("chai/index.js", function(exports, require, module){
722 | module.exports = require('./lib/chai');
723 |
724 | });
725 | require.register("chai/lib/chai.js", function(exports, require, module){
726 | /*!
727 | * chai
728 | * Copyright(c) 2011-2013 Jake Luer
729 | * MIT Licensed
730 | */
731 |
732 | var used = []
733 | , exports = module.exports = {};
734 |
735 | /*!
736 | * Chai version
737 | */
738 |
739 | exports.version = '1.8.0';
740 |
741 | /*!
742 | * Assertion Error
743 | */
744 |
745 | exports.AssertionError = require('assertion-error');
746 |
747 | /*!
748 | * Utils for plugins (not exported)
749 | */
750 |
751 | var util = require('./chai/utils');
752 |
753 | /**
754 | * # .use(function)
755 | *
756 | * Provides a way to extend the internals of Chai
757 | *
758 | * @param {Function}
759 | * @returns {this} for chaining
760 | * @api public
761 | */
762 |
763 | exports.use = function (fn) {
764 | if (!~used.indexOf(fn)) {
765 | fn(this, util);
766 | used.push(fn);
767 | }
768 |
769 | return this;
770 | };
771 |
772 | /*!
773 | * Primary `Assertion` prototype
774 | */
775 |
776 | var assertion = require('./chai/assertion');
777 | exports.use(assertion);
778 |
779 | /*!
780 | * Core Assertions
781 | */
782 |
783 | var core = require('./chai/core/assertions');
784 | exports.use(core);
785 |
786 | /*!
787 | * Expect interface
788 | */
789 |
790 | var expect = require('./chai/interface/expect');
791 | exports.use(expect);
792 |
793 | /*!
794 | * Should interface
795 | */
796 |
797 | var should = require('./chai/interface/should');
798 | exports.use(should);
799 |
800 | /*!
801 | * Assert interface
802 | */
803 |
804 | var assert = require('./chai/interface/assert');
805 | exports.use(assert);
806 |
807 | });
808 | require.register("chai/lib/chai/assertion.js", function(exports, require, module){
809 | /*!
810 | * chai
811 | * http://chaijs.com
812 | * Copyright(c) 2011-2013 Jake Luer
813 | * MIT Licensed
814 | */
815 |
816 | module.exports = function (_chai, util) {
817 | /*!
818 | * Module dependencies.
819 | */
820 |
821 | var AssertionError = _chai.AssertionError
822 | , flag = util.flag;
823 |
824 | /*!
825 | * Module export.
826 | */
827 |
828 | _chai.Assertion = Assertion;
829 |
830 | /*!
831 | * Assertion Constructor
832 | *
833 | * Creates object for chaining.
834 | *
835 | * @api private
836 | */
837 |
838 | function Assertion (obj, msg, stack) {
839 | flag(this, 'ssfi', stack || arguments.callee);
840 | flag(this, 'object', obj);
841 | flag(this, 'message', msg);
842 | }
843 |
844 | /*!
845 | * ### Assertion.includeStack
846 | *
847 | * User configurable property, influences whether stack trace
848 | * is included in Assertion error message. Default of false
849 | * suppresses stack trace in the error message
850 | *
851 | * Assertion.includeStack = true; // enable stack on error
852 | *
853 | * @api public
854 | */
855 |
856 | Assertion.includeStack = false;
857 |
858 | /*!
859 | * ### Assertion.showDiff
860 | *
861 | * User configurable property, influences whether or not
862 | * the `showDiff` flag should be included in the thrown
863 | * AssertionErrors. `false` will always be `false`; `true`
864 | * will be true when the assertion has requested a diff
865 | * be shown.
866 | *
867 | * @api public
868 | */
869 |
870 | Assertion.showDiff = true;
871 |
872 | Assertion.addProperty = function (name, fn) {
873 | util.addProperty(this.prototype, name, fn);
874 | };
875 |
876 | Assertion.addMethod = function (name, fn) {
877 | util.addMethod(this.prototype, name, fn);
878 | };
879 |
880 | Assertion.addChainableMethod = function (name, fn, chainingBehavior) {
881 | util.addChainableMethod(this.prototype, name, fn, chainingBehavior);
882 | };
883 |
884 | Assertion.overwriteProperty = function (name, fn) {
885 | util.overwriteProperty(this.prototype, name, fn);
886 | };
887 |
888 | Assertion.overwriteMethod = function (name, fn) {
889 | util.overwriteMethod(this.prototype, name, fn);
890 | };
891 |
892 | /*!
893 | * ### .assert(expression, message, negateMessage, expected, actual)
894 | *
895 | * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass.
896 | *
897 | * @name assert
898 | * @param {Philosophical} expression to be tested
899 | * @param {String} message to display if fails
900 | * @param {String} negatedMessage to display if negated expression fails
901 | * @param {Mixed} expected value (remember to check for negation)
902 | * @param {Mixed} actual (optional) will default to `this.obj`
903 | * @api private
904 | */
905 |
906 | Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) {
907 | var ok = util.test(this, arguments);
908 | if (true !== showDiff) showDiff = false;
909 | if (true !== Assertion.showDiff) showDiff = false;
910 |
911 | if (!ok) {
912 | var msg = util.getMessage(this, arguments)
913 | , actual = util.getActual(this, arguments);
914 | throw new AssertionError(msg, {
915 | actual: actual
916 | , expected: expected
917 | , showDiff: showDiff
918 | }, (Assertion.includeStack) ? this.assert : flag(this, 'ssfi'));
919 | }
920 | };
921 |
922 | /*!
923 | * ### ._obj
924 | *
925 | * Quick reference to stored `actual` value for plugin developers.
926 | *
927 | * @api private
928 | */
929 |
930 | Object.defineProperty(Assertion.prototype, '_obj',
931 | { get: function () {
932 | return flag(this, 'object');
933 | }
934 | , set: function (val) {
935 | flag(this, 'object', val);
936 | }
937 | });
938 | };
939 |
940 | });
941 | require.register("chai/lib/chai/core/assertions.js", function(exports, require, module){
942 | /*!
943 | * chai
944 | * http://chaijs.com
945 | * Copyright(c) 2011-2013 Jake Luer
946 | * MIT Licensed
947 | */
948 |
949 | module.exports = function (chai, _) {
950 | var Assertion = chai.Assertion
951 | , toString = Object.prototype.toString
952 | , flag = _.flag;
953 |
954 | /**
955 | * ### Language Chains
956 | *
957 | * The following are provide as chainable getters to
958 | * improve the readability of your assertions. They
959 | * do not provide an testing capability unless they
960 | * have been overwritten by a plugin.
961 | *
962 | * **Chains**
963 | *
964 | * - to
965 | * - be
966 | * - been
967 | * - is
968 | * - that
969 | * - and
970 | * - have
971 | * - with
972 | * - at
973 | * - of
974 | * - same
975 | *
976 | * @name language chains
977 | * @api public
978 | */
979 |
980 | [ 'to', 'be', 'been'
981 | , 'is', 'and', 'have'
982 | , 'with', 'that', 'at'
983 | , 'of', 'same' ].forEach(function (chain) {
984 | Assertion.addProperty(chain, function () {
985 | return this;
986 | });
987 | });
988 |
989 | /**
990 | * ### .not
991 | *
992 | * Negates any of assertions following in the chain.
993 | *
994 | * expect(foo).to.not.equal('bar');
995 | * expect(goodFn).to.not.throw(Error);
996 | * expect({ foo: 'baz' }).to.have.property('foo')
997 | * .and.not.equal('bar');
998 | *
999 | * @name not
1000 | * @api public
1001 | */
1002 |
1003 | Assertion.addProperty('not', function () {
1004 | flag(this, 'negate', true);
1005 | });
1006 |
1007 | /**
1008 | * ### .deep
1009 | *
1010 | * Sets the `deep` flag, later used by the `equal` and
1011 | * `property` assertions.
1012 | *
1013 | * expect(foo).to.deep.equal({ bar: 'baz' });
1014 | * expect({ foo: { bar: { baz: 'quux' } } })
1015 | * .to.have.deep.property('foo.bar.baz', 'quux');
1016 | *
1017 | * @name deep
1018 | * @api public
1019 | */
1020 |
1021 | Assertion.addProperty('deep', function () {
1022 | flag(this, 'deep', true);
1023 | });
1024 |
1025 | /**
1026 | * ### .a(type)
1027 | *
1028 | * The `a` and `an` assertions are aliases that can be
1029 | * used either as language chains or to assert a value's
1030 | * type.
1031 | *
1032 | * // typeof
1033 | * expect('test').to.be.a('string');
1034 | * expect({ foo: 'bar' }).to.be.an('object');
1035 | * expect(null).to.be.a('null');
1036 | * expect(undefined).to.be.an('undefined');
1037 | *
1038 | * // language chain
1039 | * expect(foo).to.be.an.instanceof(Foo);
1040 | *
1041 | * @name a
1042 | * @alias an
1043 | * @param {String} type
1044 | * @param {String} message _optional_
1045 | * @api public
1046 | */
1047 |
1048 | function an (type, msg) {
1049 | if (msg) flag(this, 'message', msg);
1050 | type = type.toLowerCase();
1051 | var obj = flag(this, 'object')
1052 | , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';
1053 |
1054 | this.assert(
1055 | type === _.type(obj)
1056 | , 'expected #{this} to be ' + article + type
1057 | , 'expected #{this} not to be ' + article + type
1058 | );
1059 | }
1060 |
1061 | Assertion.addChainableMethod('an', an);
1062 | Assertion.addChainableMethod('a', an);
1063 |
1064 | /**
1065 | * ### .include(value)
1066 | *
1067 | * The `include` and `contain` assertions can be used as either property
1068 | * based language chains or as methods to assert the inclusion of an object
1069 | * in an array or a substring in a string. When used as language chains,
1070 | * they toggle the `contain` flag for the `keys` assertion.
1071 | *
1072 | * expect([1,2,3]).to.include(2);
1073 | * expect('foobar').to.contain('foo');
1074 | * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
1075 | *
1076 | * @name include
1077 | * @alias contain
1078 | * @param {Object|String|Number} obj
1079 | * @param {String} message _optional_
1080 | * @api public
1081 | */
1082 |
1083 | function includeChainingBehavior () {
1084 | flag(this, 'contains', true);
1085 | }
1086 |
1087 | function include (val, msg) {
1088 | if (msg) flag(this, 'message', msg);
1089 | var obj = flag(this, 'object')
1090 | this.assert(
1091 | ~obj.indexOf(val)
1092 | , 'expected #{this} to include ' + _.inspect(val)
1093 | , 'expected #{this} to not include ' + _.inspect(val));
1094 | }
1095 |
1096 | Assertion.addChainableMethod('include', include, includeChainingBehavior);
1097 | Assertion.addChainableMethod('contain', include, includeChainingBehavior);
1098 |
1099 | /**
1100 | * ### .ok
1101 | *
1102 | * Asserts that the target is truthy.
1103 | *
1104 | * expect('everthing').to.be.ok;
1105 | * expect(1).to.be.ok;
1106 | * expect(false).to.not.be.ok;
1107 | * expect(undefined).to.not.be.ok;
1108 | * expect(null).to.not.be.ok;
1109 | *
1110 | * @name ok
1111 | * @api public
1112 | */
1113 |
1114 | Assertion.addProperty('ok', function () {
1115 | this.assert(
1116 | flag(this, 'object')
1117 | , 'expected #{this} to be truthy'
1118 | , 'expected #{this} to be falsy');
1119 | });
1120 |
1121 | /**
1122 | * ### .true
1123 | *
1124 | * Asserts that the target is `true`.
1125 | *
1126 | * expect(true).to.be.true;
1127 | * expect(1).to.not.be.true;
1128 | *
1129 | * @name true
1130 | * @api public
1131 | */
1132 |
1133 | Assertion.addProperty('true', function () {
1134 | this.assert(
1135 | true === flag(this, 'object')
1136 | , 'expected #{this} to be true'
1137 | , 'expected #{this} to be false'
1138 | , this.negate ? false : true
1139 | );
1140 | });
1141 |
1142 | /**
1143 | * ### .false
1144 | *
1145 | * Asserts that the target is `false`.
1146 | *
1147 | * expect(false).to.be.false;
1148 | * expect(0).to.not.be.false;
1149 | *
1150 | * @name false
1151 | * @api public
1152 | */
1153 |
1154 | Assertion.addProperty('false', function () {
1155 | this.assert(
1156 | false === flag(this, 'object')
1157 | , 'expected #{this} to be false'
1158 | , 'expected #{this} to be true'
1159 | , this.negate ? true : false
1160 | );
1161 | });
1162 |
1163 | /**
1164 | * ### .null
1165 | *
1166 | * Asserts that the target is `null`.
1167 | *
1168 | * expect(null).to.be.null;
1169 | * expect(undefined).not.to.be.null;
1170 | *
1171 | * @name null
1172 | * @api public
1173 | */
1174 |
1175 | Assertion.addProperty('null', function () {
1176 | this.assert(
1177 | null === flag(this, 'object')
1178 | , 'expected #{this} to be null'
1179 | , 'expected #{this} not to be null'
1180 | );
1181 | });
1182 |
1183 | /**
1184 | * ### .undefined
1185 | *
1186 | * Asserts that the target is `undefined`.
1187 | *
1188 | * expect(undefined).to.be.undefined;
1189 | * expect(null).to.not.be.undefined;
1190 | *
1191 | * @name undefined
1192 | * @api public
1193 | */
1194 |
1195 | Assertion.addProperty('undefined', function () {
1196 | this.assert(
1197 | undefined === flag(this, 'object')
1198 | , 'expected #{this} to be undefined'
1199 | , 'expected #{this} not to be undefined'
1200 | );
1201 | });
1202 |
1203 | /**
1204 | * ### .exist
1205 | *
1206 | * Asserts that the target is neither `null` nor `undefined`.
1207 | *
1208 | * var foo = 'hi'
1209 | * , bar = null
1210 | * , baz;
1211 | *
1212 | * expect(foo).to.exist;
1213 | * expect(bar).to.not.exist;
1214 | * expect(baz).to.not.exist;
1215 | *
1216 | * @name exist
1217 | * @api public
1218 | */
1219 |
1220 | Assertion.addProperty('exist', function () {
1221 | this.assert(
1222 | null != flag(this, 'object')
1223 | , 'expected #{this} to exist'
1224 | , 'expected #{this} to not exist'
1225 | );
1226 | });
1227 |
1228 |
1229 | /**
1230 | * ### .empty
1231 | *
1232 | * Asserts that the target's length is `0`. For arrays, it checks
1233 | * the `length` property. For objects, it gets the count of
1234 | * enumerable keys.
1235 | *
1236 | * expect([]).to.be.empty;
1237 | * expect('').to.be.empty;
1238 | * expect({}).to.be.empty;
1239 | *
1240 | * @name empty
1241 | * @api public
1242 | */
1243 |
1244 | Assertion.addProperty('empty', function () {
1245 | var obj = flag(this, 'object')
1246 | , expected = obj;
1247 |
1248 | if (Array.isArray(obj) || 'string' === typeof object) {
1249 | expected = obj.length;
1250 | } else if (typeof obj === 'object') {
1251 | expected = Object.keys(obj).length;
1252 | }
1253 |
1254 | this.assert(
1255 | !expected
1256 | , 'expected #{this} to be empty'
1257 | , 'expected #{this} not to be empty'
1258 | );
1259 | });
1260 |
1261 | /**
1262 | * ### .arguments
1263 | *
1264 | * Asserts that the target is an arguments object.
1265 | *
1266 | * function test () {
1267 | * expect(arguments).to.be.arguments;
1268 | * }
1269 | *
1270 | * @name arguments
1271 | * @alias Arguments
1272 | * @api public
1273 | */
1274 |
1275 | function checkArguments () {
1276 | var obj = flag(this, 'object')
1277 | , type = Object.prototype.toString.call(obj);
1278 | this.assert(
1279 | '[object Arguments]' === type
1280 | , 'expected #{this} to be arguments but got ' + type
1281 | , 'expected #{this} to not be arguments'
1282 | );
1283 | }
1284 |
1285 | Assertion.addProperty('arguments', checkArguments);
1286 | Assertion.addProperty('Arguments', checkArguments);
1287 |
1288 | /**
1289 | * ### .equal(value)
1290 | *
1291 | * Asserts that the target is strictly equal (`===`) to `value`.
1292 | * Alternately, if the `deep` flag is set, asserts that
1293 | * the target is deeply equal to `value`.
1294 | *
1295 | * expect('hello').to.equal('hello');
1296 | * expect(42).to.equal(42);
1297 | * expect(1).to.not.equal(true);
1298 | * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
1299 | * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
1300 | *
1301 | * @name equal
1302 | * @alias equals
1303 | * @alias eq
1304 | * @alias deep.equal
1305 | * @param {Mixed} value
1306 | * @param {String} message _optional_
1307 | * @api public
1308 | */
1309 |
1310 | function assertEqual (val, msg) {
1311 | if (msg) flag(this, 'message', msg);
1312 | var obj = flag(this, 'object');
1313 | if (flag(this, 'deep')) {
1314 | return this.eql(val);
1315 | } else {
1316 | this.assert(
1317 | val === obj
1318 | , 'expected #{this} to equal #{exp}'
1319 | , 'expected #{this} to not equal #{exp}'
1320 | , val
1321 | , this._obj
1322 | , true
1323 | );
1324 | }
1325 | }
1326 |
1327 | Assertion.addMethod('equal', assertEqual);
1328 | Assertion.addMethod('equals', assertEqual);
1329 | Assertion.addMethod('eq', assertEqual);
1330 |
1331 | /**
1332 | * ### .eql(value)
1333 | *
1334 | * Asserts that the target is deeply equal to `value`.
1335 | *
1336 | * expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
1337 | * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
1338 | *
1339 | * @name eql
1340 | * @alias eqls
1341 | * @param {Mixed} value
1342 | * @param {String} message _optional_
1343 | * @api public
1344 | */
1345 |
1346 | function assertEql(obj, msg) {
1347 | if (msg) flag(this, 'message', msg);
1348 | this.assert(
1349 | _.eql(obj, flag(this, 'object'))
1350 | , 'expected #{this} to deeply equal #{exp}'
1351 | , 'expected #{this} to not deeply equal #{exp}'
1352 | , obj
1353 | , this._obj
1354 | , true
1355 | );
1356 | }
1357 |
1358 | Assertion.addMethod('eql', assertEql);
1359 | Assertion.addMethod('eqls', assertEql);
1360 |
1361 | /**
1362 | * ### .above(value)
1363 | *
1364 | * Asserts that the target is greater than `value`.
1365 | *
1366 | * expect(10).to.be.above(5);
1367 | *
1368 | * Can also be used in conjunction with `length` to
1369 | * assert a minimum length. The benefit being a
1370 | * more informative error message than if the length
1371 | * was supplied directly.
1372 | *
1373 | * expect('foo').to.have.length.above(2);
1374 | * expect([ 1, 2, 3 ]).to.have.length.above(2);
1375 | *
1376 | * @name above
1377 | * @alias gt
1378 | * @alias greaterThan
1379 | * @param {Number} value
1380 | * @param {String} message _optional_
1381 | * @api public
1382 | */
1383 |
1384 | function assertAbove (n, msg) {
1385 | if (msg) flag(this, 'message', msg);
1386 | var obj = flag(this, 'object');
1387 | if (flag(this, 'doLength')) {
1388 | new Assertion(obj, msg).to.have.property('length');
1389 | var len = obj.length;
1390 | this.assert(
1391 | len > n
1392 | , 'expected #{this} to have a length above #{exp} but got #{act}'
1393 | , 'expected #{this} to not have a length above #{exp}'
1394 | , n
1395 | , len
1396 | );
1397 | } else {
1398 | this.assert(
1399 | obj > n
1400 | , 'expected #{this} to be above ' + n
1401 | , 'expected #{this} to be at most ' + n
1402 | );
1403 | }
1404 | }
1405 |
1406 | Assertion.addMethod('above', assertAbove);
1407 | Assertion.addMethod('gt', assertAbove);
1408 | Assertion.addMethod('greaterThan', assertAbove);
1409 |
1410 | /**
1411 | * ### .least(value)
1412 | *
1413 | * Asserts that the target is greater than or equal to `value`.
1414 | *
1415 | * expect(10).to.be.at.least(10);
1416 | *
1417 | * Can also be used in conjunction with `length` to
1418 | * assert a minimum length. The benefit being a
1419 | * more informative error message than if the length
1420 | * was supplied directly.
1421 | *
1422 | * expect('foo').to.have.length.of.at.least(2);
1423 | * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);
1424 | *
1425 | * @name least
1426 | * @alias gte
1427 | * @param {Number} value
1428 | * @param {String} message _optional_
1429 | * @api public
1430 | */
1431 |
1432 | function assertLeast (n, msg) {
1433 | if (msg) flag(this, 'message', msg);
1434 | var obj = flag(this, 'object');
1435 | if (flag(this, 'doLength')) {
1436 | new Assertion(obj, msg).to.have.property('length');
1437 | var len = obj.length;
1438 | this.assert(
1439 | len >= n
1440 | , 'expected #{this} to have a length at least #{exp} but got #{act}'
1441 | , 'expected #{this} to have a length below #{exp}'
1442 | , n
1443 | , len
1444 | );
1445 | } else {
1446 | this.assert(
1447 | obj >= n
1448 | , 'expected #{this} to be at least ' + n
1449 | , 'expected #{this} to be below ' + n
1450 | );
1451 | }
1452 | }
1453 |
1454 | Assertion.addMethod('least', assertLeast);
1455 | Assertion.addMethod('gte', assertLeast);
1456 |
1457 | /**
1458 | * ### .below(value)
1459 | *
1460 | * Asserts that the target is less than `value`.
1461 | *
1462 | * expect(5).to.be.below(10);
1463 | *
1464 | * Can also be used in conjunction with `length` to
1465 | * assert a maximum length. The benefit being a
1466 | * more informative error message than if the length
1467 | * was supplied directly.
1468 | *
1469 | * expect('foo').to.have.length.below(4);
1470 | * expect([ 1, 2, 3 ]).to.have.length.below(4);
1471 | *
1472 | * @name below
1473 | * @alias lt
1474 | * @alias lessThan
1475 | * @param {Number} value
1476 | * @param {String} message _optional_
1477 | * @api public
1478 | */
1479 |
1480 | function assertBelow (n, msg) {
1481 | if (msg) flag(this, 'message', msg);
1482 | var obj = flag(this, 'object');
1483 | if (flag(this, 'doLength')) {
1484 | new Assertion(obj, msg).to.have.property('length');
1485 | var len = obj.length;
1486 | this.assert(
1487 | len < n
1488 | , 'expected #{this} to have a length below #{exp} but got #{act}'
1489 | , 'expected #{this} to not have a length below #{exp}'
1490 | , n
1491 | , len
1492 | );
1493 | } else {
1494 | this.assert(
1495 | obj < n
1496 | , 'expected #{this} to be below ' + n
1497 | , 'expected #{this} to be at least ' + n
1498 | );
1499 | }
1500 | }
1501 |
1502 | Assertion.addMethod('below', assertBelow);
1503 | Assertion.addMethod('lt', assertBelow);
1504 | Assertion.addMethod('lessThan', assertBelow);
1505 |
1506 | /**
1507 | * ### .most(value)
1508 | *
1509 | * Asserts that the target is less than or equal to `value`.
1510 | *
1511 | * expect(5).to.be.at.most(5);
1512 | *
1513 | * Can also be used in conjunction with `length` to
1514 | * assert a maximum length. The benefit being a
1515 | * more informative error message than if the length
1516 | * was supplied directly.
1517 | *
1518 | * expect('foo').to.have.length.of.at.most(4);
1519 | * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);
1520 | *
1521 | * @name most
1522 | * @alias lte
1523 | * @param {Number} value
1524 | * @param {String} message _optional_
1525 | * @api public
1526 | */
1527 |
1528 | function assertMost (n, msg) {
1529 | if (msg) flag(this, 'message', msg);
1530 | var obj = flag(this, 'object');
1531 | if (flag(this, 'doLength')) {
1532 | new Assertion(obj, msg).to.have.property('length');
1533 | var len = obj.length;
1534 | this.assert(
1535 | len <= n
1536 | , 'expected #{this} to have a length at most #{exp} but got #{act}'
1537 | , 'expected #{this} to have a length above #{exp}'
1538 | , n
1539 | , len
1540 | );
1541 | } else {
1542 | this.assert(
1543 | obj <= n
1544 | , 'expected #{this} to be at most ' + n
1545 | , 'expected #{this} to be above ' + n
1546 | );
1547 | }
1548 | }
1549 |
1550 | Assertion.addMethod('most', assertMost);
1551 | Assertion.addMethod('lte', assertMost);
1552 |
1553 | /**
1554 | * ### .within(start, finish)
1555 | *
1556 | * Asserts that the target is within a range.
1557 | *
1558 | * expect(7).to.be.within(5,10);
1559 | *
1560 | * Can also be used in conjunction with `length` to
1561 | * assert a length range. The benefit being a
1562 | * more informative error message than if the length
1563 | * was supplied directly.
1564 | *
1565 | * expect('foo').to.have.length.within(2,4);
1566 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
1567 | *
1568 | * @name within
1569 | * @param {Number} start lowerbound inclusive
1570 | * @param {Number} finish upperbound inclusive
1571 | * @param {String} message _optional_
1572 | * @api public
1573 | */
1574 |
1575 | Assertion.addMethod('within', function (start, finish, msg) {
1576 | if (msg) flag(this, 'message', msg);
1577 | var obj = flag(this, 'object')
1578 | , range = start + '..' + finish;
1579 | if (flag(this, 'doLength')) {
1580 | new Assertion(obj, msg).to.have.property('length');
1581 | var len = obj.length;
1582 | this.assert(
1583 | len >= start && len <= finish
1584 | , 'expected #{this} to have a length within ' + range
1585 | , 'expected #{this} to not have a length within ' + range
1586 | );
1587 | } else {
1588 | this.assert(
1589 | obj >= start && obj <= finish
1590 | , 'expected #{this} to be within ' + range
1591 | , 'expected #{this} to not be within ' + range
1592 | );
1593 | }
1594 | });
1595 |
1596 | /**
1597 | * ### .instanceof(constructor)
1598 | *
1599 | * Asserts that the target is an instance of `constructor`.
1600 | *
1601 | * var Tea = function (name) { this.name = name; }
1602 | * , Chai = new Tea('chai');
1603 | *
1604 | * expect(Chai).to.be.an.instanceof(Tea);
1605 | * expect([ 1, 2, 3 ]).to.be.instanceof(Array);
1606 | *
1607 | * @name instanceof
1608 | * @param {Constructor} constructor
1609 | * @param {String} message _optional_
1610 | * @alias instanceOf
1611 | * @api public
1612 | */
1613 |
1614 | function assertInstanceOf (constructor, msg) {
1615 | if (msg) flag(this, 'message', msg);
1616 | var name = _.getName(constructor);
1617 | this.assert(
1618 | flag(this, 'object') instanceof constructor
1619 | , 'expected #{this} to be an instance of ' + name
1620 | , 'expected #{this} to not be an instance of ' + name
1621 | );
1622 | };
1623 |
1624 | Assertion.addMethod('instanceof', assertInstanceOf);
1625 | Assertion.addMethod('instanceOf', assertInstanceOf);
1626 |
1627 | /**
1628 | * ### .property(name, [value])
1629 | *
1630 | * Asserts that the target has a property `name`, optionally asserting that
1631 | * the value of that property is strictly equal to `value`.
1632 | * If the `deep` flag is set, you can use dot- and bracket-notation for deep
1633 | * references into objects and arrays.
1634 | *
1635 | * // simple referencing
1636 | * var obj = { foo: 'bar' };
1637 | * expect(obj).to.have.property('foo');
1638 | * expect(obj).to.have.property('foo', 'bar');
1639 | *
1640 | * // deep referencing
1641 | * var deepObj = {
1642 | * green: { tea: 'matcha' }
1643 | * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
1644 | * };
1645 |
1646 | * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
1647 | * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
1648 | * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
1649 | *
1650 | * You can also use an array as the starting point of a `deep.property`
1651 | * assertion, or traverse nested arrays.
1652 | *
1653 | * var arr = [
1654 | * [ 'chai', 'matcha', 'konacha' ]
1655 | * , [ { tea: 'chai' }
1656 | * , { tea: 'matcha' }
1657 | * , { tea: 'konacha' } ]
1658 | * ];
1659 | *
1660 | * expect(arr).to.have.deep.property('[0][1]', 'matcha');
1661 | * expect(arr).to.have.deep.property('[1][2].tea', 'konacha');
1662 | *
1663 | * Furthermore, `property` changes the subject of the assertion
1664 | * to be the value of that property from the original object. This
1665 | * permits for further chainable assertions on that property.
1666 | *
1667 | * expect(obj).to.have.property('foo')
1668 | * .that.is.a('string');
1669 | * expect(deepObj).to.have.property('green')
1670 | * .that.is.an('object')
1671 | * .that.deep.equals({ tea: 'matcha' });
1672 | * expect(deepObj).to.have.property('teas')
1673 | * .that.is.an('array')
1674 | * .with.deep.property('[2]')
1675 | * .that.deep.equals({ tea: 'konacha' });
1676 | *
1677 | * @name property
1678 | * @alias deep.property
1679 | * @param {String} name
1680 | * @param {Mixed} value (optional)
1681 | * @param {String} message _optional_
1682 | * @returns value of property for chaining
1683 | * @api public
1684 | */
1685 |
1686 | Assertion.addMethod('property', function (name, val, msg) {
1687 | if (msg) flag(this, 'message', msg);
1688 |
1689 | var descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
1690 | , negate = flag(this, 'negate')
1691 | , obj = flag(this, 'object')
1692 | , value = flag(this, 'deep')
1693 | ? _.getPathValue(name, obj)
1694 | : obj[name];
1695 |
1696 | if (negate && undefined !== val) {
1697 | if (undefined === value) {
1698 | msg = (msg != null) ? msg + ': ' : '';
1699 | throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name));
1700 | }
1701 | } else {
1702 | this.assert(
1703 | undefined !== value
1704 | , 'expected #{this} to have a ' + descriptor + _.inspect(name)
1705 | , 'expected #{this} to not have ' + descriptor + _.inspect(name));
1706 | }
1707 |
1708 | if (undefined !== val) {
1709 | this.assert(
1710 | val === value
1711 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
1712 | , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'
1713 | , val
1714 | , value
1715 | );
1716 | }
1717 |
1718 | flag(this, 'object', value);
1719 | });
1720 |
1721 |
1722 | /**
1723 | * ### .ownProperty(name)
1724 | *
1725 | * Asserts that the target has an own property `name`.
1726 | *
1727 | * expect('test').to.have.ownProperty('length');
1728 | *
1729 | * @name ownProperty
1730 | * @alias haveOwnProperty
1731 | * @param {String} name
1732 | * @param {String} message _optional_
1733 | * @api public
1734 | */
1735 |
1736 | function assertOwnProperty (name, msg) {
1737 | if (msg) flag(this, 'message', msg);
1738 | var obj = flag(this, 'object');
1739 | this.assert(
1740 | obj.hasOwnProperty(name)
1741 | , 'expected #{this} to have own property ' + _.inspect(name)
1742 | , 'expected #{this} to not have own property ' + _.inspect(name)
1743 | );
1744 | }
1745 |
1746 | Assertion.addMethod('ownProperty', assertOwnProperty);
1747 | Assertion.addMethod('haveOwnProperty', assertOwnProperty);
1748 |
1749 | /**
1750 | * ### .length(value)
1751 | *
1752 | * Asserts that the target's `length` property has
1753 | * the expected value.
1754 | *
1755 | * expect([ 1, 2, 3]).to.have.length(3);
1756 | * expect('foobar').to.have.length(6);
1757 | *
1758 | * Can also be used as a chain precursor to a value
1759 | * comparison for the length property.
1760 | *
1761 | * expect('foo').to.have.length.above(2);
1762 | * expect([ 1, 2, 3 ]).to.have.length.above(2);
1763 | * expect('foo').to.have.length.below(4);
1764 | * expect([ 1, 2, 3 ]).to.have.length.below(4);
1765 | * expect('foo').to.have.length.within(2,4);
1766 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
1767 | *
1768 | * @name length
1769 | * @alias lengthOf
1770 | * @param {Number} length
1771 | * @param {String} message _optional_
1772 | * @api public
1773 | */
1774 |
1775 | function assertLengthChain () {
1776 | flag(this, 'doLength', true);
1777 | }
1778 |
1779 | function assertLength (n, msg) {
1780 | if (msg) flag(this, 'message', msg);
1781 | var obj = flag(this, 'object');
1782 | new Assertion(obj, msg).to.have.property('length');
1783 | var len = obj.length;
1784 |
1785 | this.assert(
1786 | len == n
1787 | , 'expected #{this} to have a length of #{exp} but got #{act}'
1788 | , 'expected #{this} to not have a length of #{act}'
1789 | , n
1790 | , len
1791 | );
1792 | }
1793 |
1794 | Assertion.addChainableMethod('length', assertLength, assertLengthChain);
1795 | Assertion.addMethod('lengthOf', assertLength, assertLengthChain);
1796 |
1797 | /**
1798 | * ### .match(regexp)
1799 | *
1800 | * Asserts that the target matches a regular expression.
1801 | *
1802 | * expect('foobar').to.match(/^foo/);
1803 | *
1804 | * @name match
1805 | * @param {RegExp} RegularExpression
1806 | * @param {String} message _optional_
1807 | * @api public
1808 | */
1809 |
1810 | Assertion.addMethod('match', function (re, msg) {
1811 | if (msg) flag(this, 'message', msg);
1812 | var obj = flag(this, 'object');
1813 | this.assert(
1814 | re.exec(obj)
1815 | , 'expected #{this} to match ' + re
1816 | , 'expected #{this} not to match ' + re
1817 | );
1818 | });
1819 |
1820 | /**
1821 | * ### .string(string)
1822 | *
1823 | * Asserts that the string target contains another string.
1824 | *
1825 | * expect('foobar').to.have.string('bar');
1826 | *
1827 | * @name string
1828 | * @param {String} string
1829 | * @param {String} message _optional_
1830 | * @api public
1831 | */
1832 |
1833 | Assertion.addMethod('string', function (str, msg) {
1834 | if (msg) flag(this, 'message', msg);
1835 | var obj = flag(this, 'object');
1836 | new Assertion(obj, msg).is.a('string');
1837 |
1838 | this.assert(
1839 | ~obj.indexOf(str)
1840 | , 'expected #{this} to contain ' + _.inspect(str)
1841 | , 'expected #{this} to not contain ' + _.inspect(str)
1842 | );
1843 | });
1844 |
1845 |
1846 | /**
1847 | * ### .keys(key1, [key2], [...])
1848 | *
1849 | * Asserts that the target has exactly the given keys, or
1850 | * asserts the inclusion of some keys when using the
1851 | * `include` or `contain` modifiers.
1852 | *
1853 | * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
1854 | * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
1855 | *
1856 | * @name keys
1857 | * @alias key
1858 | * @param {String...|Array} keys
1859 | * @api public
1860 | */
1861 |
1862 | function assertKeys (keys) {
1863 | var obj = flag(this, 'object')
1864 | , str
1865 | , ok = true;
1866 |
1867 | keys = keys instanceof Array
1868 | ? keys
1869 | : Array.prototype.slice.call(arguments);
1870 |
1871 | if (!keys.length) throw new Error('keys required');
1872 |
1873 | var actual = Object.keys(obj)
1874 | , len = keys.length;
1875 |
1876 | // Inclusion
1877 | ok = keys.every(function(key){
1878 | return ~actual.indexOf(key);
1879 | });
1880 |
1881 | // Strict
1882 | if (!flag(this, 'negate') && !flag(this, 'contains')) {
1883 | ok = ok && keys.length == actual.length;
1884 | }
1885 |
1886 | // Key string
1887 | if (len > 1) {
1888 | keys = keys.map(function(key){
1889 | return _.inspect(key);
1890 | });
1891 | var last = keys.pop();
1892 | str = keys.join(', ') + ', and ' + last;
1893 | } else {
1894 | str = _.inspect(keys[0]);
1895 | }
1896 |
1897 | // Form
1898 | str = (len > 1 ? 'keys ' : 'key ') + str;
1899 |
1900 | // Have / include
1901 | str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
1902 |
1903 | // Assertion
1904 | this.assert(
1905 | ok
1906 | , 'expected #{this} to ' + str
1907 | , 'expected #{this} to not ' + str
1908 | );
1909 | }
1910 |
1911 | Assertion.addMethod('keys', assertKeys);
1912 | Assertion.addMethod('key', assertKeys);
1913 |
1914 | /**
1915 | * ### .throw(constructor)
1916 | *
1917 | * Asserts that the function target will throw a specific error, or specific type of error
1918 | * (as determined using `instanceof`), optionally with a RegExp or string inclusion test
1919 | * for the error's message.
1920 | *
1921 | * var err = new ReferenceError('This is a bad function.');
1922 | * var fn = function () { throw err; }
1923 | * expect(fn).to.throw(ReferenceError);
1924 | * expect(fn).to.throw(Error);
1925 | * expect(fn).to.throw(/bad function/);
1926 | * expect(fn).to.not.throw('good function');
1927 | * expect(fn).to.throw(ReferenceError, /bad function/);
1928 | * expect(fn).to.throw(err);
1929 | * expect(fn).to.not.throw(new RangeError('Out of range.'));
1930 | *
1931 | * Please note that when a throw expectation is negated, it will check each
1932 | * parameter independently, starting with error constructor type. The appropriate way
1933 | * to check for the existence of a type of error but for a message that does not match
1934 | * is to use `and`.
1935 | *
1936 | * expect(fn).to.throw(ReferenceError)
1937 | * .and.not.throw(/good function/);
1938 | *
1939 | * @name throw
1940 | * @alias throws
1941 | * @alias Throw
1942 | * @param {ErrorConstructor} constructor
1943 | * @param {String|RegExp} expected error message
1944 | * @param {String} message _optional_
1945 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
1946 | * @api public
1947 | */
1948 |
1949 | function assertThrows (constructor, errMsg, msg) {
1950 | if (msg) flag(this, 'message', msg);
1951 | var obj = flag(this, 'object');
1952 | new Assertion(obj, msg).is.a('function');
1953 |
1954 | var thrown = false
1955 | , desiredError = null
1956 | , name = null
1957 | , thrownError = null;
1958 |
1959 | if (arguments.length === 0) {
1960 | errMsg = null;
1961 | constructor = null;
1962 | } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
1963 | errMsg = constructor;
1964 | constructor = null;
1965 | } else if (constructor && constructor instanceof Error) {
1966 | desiredError = constructor;
1967 | constructor = null;
1968 | errMsg = null;
1969 | } else if (typeof constructor === 'function') {
1970 | name = (new constructor()).name;
1971 | } else {
1972 | constructor = null;
1973 | }
1974 |
1975 | try {
1976 | obj();
1977 | } catch (err) {
1978 | // first, check desired error
1979 | if (desiredError) {
1980 | this.assert(
1981 | err === desiredError
1982 | , 'expected #{this} to throw #{exp} but #{act} was thrown'
1983 | , 'expected #{this} to not throw #{exp}'
1984 | , desiredError
1985 | , err
1986 | );
1987 |
1988 | return this;
1989 | }
1990 | // next, check constructor
1991 | if (constructor) {
1992 | this.assert(
1993 | err instanceof constructor
1994 | , 'expected #{this} to throw #{exp} but #{act} was thrown'
1995 | , 'expected #{this} to not throw #{exp} but #{act} was thrown'
1996 | , name
1997 | , err
1998 | );
1999 |
2000 | if (!errMsg) return this;
2001 | }
2002 | // next, check message
2003 | var message = 'object' === _.type(err) && "message" in err
2004 | ? err.message
2005 | : '' + err;
2006 |
2007 | if ((message != null) && errMsg && errMsg instanceof RegExp) {
2008 | this.assert(
2009 | errMsg.exec(message)
2010 | , 'expected #{this} to throw error matching #{exp} but got #{act}'
2011 | , 'expected #{this} to throw error not matching #{exp}'
2012 | , errMsg
2013 | , message
2014 | );
2015 |
2016 | return this;
2017 | } else if ((message != null) && errMsg && 'string' === typeof errMsg) {
2018 | this.assert(
2019 | ~message.indexOf(errMsg)
2020 | , 'expected #{this} to throw error including #{exp} but got #{act}'
2021 | , 'expected #{this} to throw error not including #{act}'
2022 | , errMsg
2023 | , message
2024 | );
2025 |
2026 | return this;
2027 | } else {
2028 | thrown = true;
2029 | thrownError = err;
2030 | }
2031 | }
2032 |
2033 | var actuallyGot = ''
2034 | , expectedThrown = name !== null
2035 | ? name
2036 | : desiredError
2037 | ? '#{exp}' //_.inspect(desiredError)
2038 | : 'an error';
2039 |
2040 | if (thrown) {
2041 | actuallyGot = ' but #{act} was thrown'
2042 | }
2043 |
2044 | this.assert(
2045 | thrown === true
2046 | , 'expected #{this} to throw ' + expectedThrown + actuallyGot
2047 | , 'expected #{this} to not throw ' + expectedThrown + actuallyGot
2048 | , desiredError
2049 | , thrownError
2050 | );
2051 | };
2052 |
2053 | Assertion.addMethod('throw', assertThrows);
2054 | Assertion.addMethod('throws', assertThrows);
2055 | Assertion.addMethod('Throw', assertThrows);
2056 |
2057 | /**
2058 | * ### .respondTo(method)
2059 | *
2060 | * Asserts that the object or class target will respond to a method.
2061 | *
2062 | * Klass.prototype.bar = function(){};
2063 | * expect(Klass).to.respondTo('bar');
2064 | * expect(obj).to.respondTo('bar');
2065 | *
2066 | * To check if a constructor will respond to a static function,
2067 | * set the `itself` flag.
2068 | *
2069 | * Klass.baz = function(){};
2070 | * expect(Klass).itself.to.respondTo('baz');
2071 | *
2072 | * @name respondTo
2073 | * @param {String} method
2074 | * @param {String} message _optional_
2075 | * @api public
2076 | */
2077 |
2078 | Assertion.addMethod('respondTo', function (method, msg) {
2079 | if (msg) flag(this, 'message', msg);
2080 | var obj = flag(this, 'object')
2081 | , itself = flag(this, 'itself')
2082 | , context = ('function' === _.type(obj) && !itself)
2083 | ? obj.prototype[method]
2084 | : obj[method];
2085 |
2086 | this.assert(
2087 | 'function' === typeof context
2088 | , 'expected #{this} to respond to ' + _.inspect(method)
2089 | , 'expected #{this} to not respond to ' + _.inspect(method)
2090 | );
2091 | });
2092 |
2093 | /**
2094 | * ### .itself
2095 | *
2096 | * Sets the `itself` flag, later used by the `respondTo` assertion.
2097 | *
2098 | * function Foo() {}
2099 | * Foo.bar = function() {}
2100 | * Foo.prototype.baz = function() {}
2101 | *
2102 | * expect(Foo).itself.to.respondTo('bar');
2103 | * expect(Foo).itself.not.to.respondTo('baz');
2104 | *
2105 | * @name itself
2106 | * @api public
2107 | */
2108 |
2109 | Assertion.addProperty('itself', function () {
2110 | flag(this, 'itself', true);
2111 | });
2112 |
2113 | /**
2114 | * ### .satisfy(method)
2115 | *
2116 | * Asserts that the target passes a given truth test.
2117 | *
2118 | * expect(1).to.satisfy(function(num) { return num > 0; });
2119 | *
2120 | * @name satisfy
2121 | * @param {Function} matcher
2122 | * @param {String} message _optional_
2123 | * @api public
2124 | */
2125 |
2126 | Assertion.addMethod('satisfy', function (matcher, msg) {
2127 | if (msg) flag(this, 'message', msg);
2128 | var obj = flag(this, 'object');
2129 | this.assert(
2130 | matcher(obj)
2131 | , 'expected #{this} to satisfy ' + _.objDisplay(matcher)
2132 | , 'expected #{this} to not satisfy' + _.objDisplay(matcher)
2133 | , this.negate ? false : true
2134 | , matcher(obj)
2135 | );
2136 | });
2137 |
2138 | /**
2139 | * ### .closeTo(expected, delta)
2140 | *
2141 | * Asserts that the target is equal `expected`, to within a +/- `delta` range.
2142 | *
2143 | * expect(1.5).to.be.closeTo(1, 0.5);
2144 | *
2145 | * @name closeTo
2146 | * @param {Number} expected
2147 | * @param {Number} delta
2148 | * @param {String} message _optional_
2149 | * @api public
2150 | */
2151 |
2152 | Assertion.addMethod('closeTo', function (expected, delta, msg) {
2153 | if (msg) flag(this, 'message', msg);
2154 | var obj = flag(this, 'object');
2155 | this.assert(
2156 | Math.abs(obj - expected) <= delta
2157 | , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
2158 | , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
2159 | );
2160 | });
2161 |
2162 | function isSubsetOf(subset, superset) {
2163 | return subset.every(function(elem) {
2164 | return superset.indexOf(elem) !== -1;
2165 | })
2166 | }
2167 |
2168 | /**
2169 | * ### .members(set)
2170 | *
2171 | * Asserts that the target is a superset of `set`,
2172 | * or that the target and `set` have the same members.
2173 | *
2174 | * expect([1, 2, 3]).to.include.members([3, 2]);
2175 | * expect([1, 2, 3]).to.not.include.members([3, 2, 8]);
2176 | *
2177 | * expect([4, 2]).to.have.members([2, 4]);
2178 | * expect([5, 2]).to.not.have.members([5, 2, 1]);
2179 | *
2180 | * @name members
2181 | * @param {Array} set
2182 | * @param {String} message _optional_
2183 | * @api public
2184 | */
2185 |
2186 | Assertion.addMethod('members', function (subset, msg) {
2187 | if (msg) flag(this, 'message', msg);
2188 | var obj = flag(this, 'object');
2189 |
2190 | new Assertion(obj).to.be.an('array');
2191 | new Assertion(subset).to.be.an('array');
2192 |
2193 | if (flag(this, 'contains')) {
2194 | return this.assert(
2195 | isSubsetOf(subset, obj)
2196 | , 'expected #{this} to be a superset of #{act}'
2197 | , 'expected #{this} to not be a superset of #{act}'
2198 | , obj
2199 | , subset
2200 | );
2201 | }
2202 |
2203 | this.assert(
2204 | isSubsetOf(obj, subset) && isSubsetOf(subset, obj)
2205 | , 'expected #{this} to have the same members as #{act}'
2206 | , 'expected #{this} to not have the same members as #{act}'
2207 | , obj
2208 | , subset
2209 | );
2210 | });
2211 | };
2212 |
2213 | });
2214 | require.register("chai/lib/chai/interface/assert.js", function(exports, require, module){
2215 | /*!
2216 | * chai
2217 | * Copyright(c) 2011-2013 Jake Luer
2218 | * MIT Licensed
2219 | */
2220 |
2221 |
2222 | module.exports = function (chai, util) {
2223 |
2224 | /*!
2225 | * Chai dependencies.
2226 | */
2227 |
2228 | var Assertion = chai.Assertion
2229 | , flag = util.flag;
2230 |
2231 | /*!
2232 | * Module export.
2233 | */
2234 |
2235 | /**
2236 | * ### assert(expression, message)
2237 | *
2238 | * Write your own test expressions.
2239 | *
2240 | * assert('foo' !== 'bar', 'foo is not bar');
2241 | * assert(Array.isArray([]), 'empty arrays are arrays');
2242 | *
2243 | * @param {Mixed} expression to test for truthiness
2244 | * @param {String} message to display on error
2245 | * @name assert
2246 | * @api public
2247 | */
2248 |
2249 | var assert = chai.assert = function (express, errmsg) {
2250 | var test = new Assertion(null);
2251 | test.assert(
2252 | express
2253 | , errmsg
2254 | , '[ negation message unavailable ]'
2255 | );
2256 | };
2257 |
2258 | /**
2259 | * ### .fail(actual, expected, [message], [operator])
2260 | *
2261 | * Throw a failure. Node.js `assert` module-compatible.
2262 | *
2263 | * @name fail
2264 | * @param {Mixed} actual
2265 | * @param {Mixed} expected
2266 | * @param {String} message
2267 | * @param {String} operator
2268 | * @api public
2269 | */
2270 |
2271 | assert.fail = function (actual, expected, message, operator) {
2272 | throw new chai.AssertionError({
2273 | actual: actual
2274 | , expected: expected
2275 | , message: message
2276 | , operator: operator
2277 | , stackStartFunction: assert.fail
2278 | });
2279 | };
2280 |
2281 | /**
2282 | * ### .ok(object, [message])
2283 | *
2284 | * Asserts that `object` is truthy.
2285 | *
2286 | * assert.ok('everything', 'everything is ok');
2287 | * assert.ok(false, 'this will fail');
2288 | *
2289 | * @name ok
2290 | * @param {Mixed} object to test
2291 | * @param {String} message
2292 | * @api public
2293 | */
2294 |
2295 | assert.ok = function (val, msg) {
2296 | new Assertion(val, msg).is.ok;
2297 | };
2298 |
2299 | /**
2300 | * ### .notOk(object, [message])
2301 | *
2302 | * Asserts that `object` is falsy.
2303 | *
2304 | * assert.notOk('everything', 'this will fail');
2305 | * assert.notOk(false, 'this will pass');
2306 | *
2307 | * @name notOk
2308 | * @param {Mixed} object to test
2309 | * @param {String} message
2310 | * @api public
2311 | */
2312 |
2313 | assert.notOk = function (val, msg) {
2314 | new Assertion(val, msg).is.not.ok;
2315 | };
2316 |
2317 | /**
2318 | * ### .equal(actual, expected, [message])
2319 | *
2320 | * Asserts non-strict equality (`==`) of `actual` and `expected`.
2321 | *
2322 | * assert.equal(3, '3', '== coerces values to strings');
2323 | *
2324 | * @name equal
2325 | * @param {Mixed} actual
2326 | * @param {Mixed} expected
2327 | * @param {String} message
2328 | * @api public
2329 | */
2330 |
2331 | assert.equal = function (act, exp, msg) {
2332 | var test = new Assertion(act, msg);
2333 |
2334 | test.assert(
2335 | exp == flag(test, 'object')
2336 | , 'expected #{this} to equal #{exp}'
2337 | , 'expected #{this} to not equal #{act}'
2338 | , exp
2339 | , act
2340 | );
2341 | };
2342 |
2343 | /**
2344 | * ### .notEqual(actual, expected, [message])
2345 | *
2346 | * Asserts non-strict inequality (`!=`) of `actual` and `expected`.
2347 | *
2348 | * assert.notEqual(3, 4, 'these numbers are not equal');
2349 | *
2350 | * @name notEqual
2351 | * @param {Mixed} actual
2352 | * @param {Mixed} expected
2353 | * @param {String} message
2354 | * @api public
2355 | */
2356 |
2357 | assert.notEqual = function (act, exp, msg) {
2358 | var test = new Assertion(act, msg);
2359 |
2360 | test.assert(
2361 | exp != flag(test, 'object')
2362 | , 'expected #{this} to not equal #{exp}'
2363 | , 'expected #{this} to equal #{act}'
2364 | , exp
2365 | , act
2366 | );
2367 | };
2368 |
2369 | /**
2370 | * ### .strictEqual(actual, expected, [message])
2371 | *
2372 | * Asserts strict equality (`===`) of `actual` and `expected`.
2373 | *
2374 | * assert.strictEqual(true, true, 'these booleans are strictly equal');
2375 | *
2376 | * @name strictEqual
2377 | * @param {Mixed} actual
2378 | * @param {Mixed} expected
2379 | * @param {String} message
2380 | * @api public
2381 | */
2382 |
2383 | assert.strictEqual = function (act, exp, msg) {
2384 | new Assertion(act, msg).to.equal(exp);
2385 | };
2386 |
2387 | /**
2388 | * ### .notStrictEqual(actual, expected, [message])
2389 | *
2390 | * Asserts strict inequality (`!==`) of `actual` and `expected`.
2391 | *
2392 | * assert.notStrictEqual(3, '3', 'no coercion for strict equality');
2393 | *
2394 | * @name notStrictEqual
2395 | * @param {Mixed} actual
2396 | * @param {Mixed} expected
2397 | * @param {String} message
2398 | * @api public
2399 | */
2400 |
2401 | assert.notStrictEqual = function (act, exp, msg) {
2402 | new Assertion(act, msg).to.not.equal(exp);
2403 | };
2404 |
2405 | /**
2406 | * ### .deepEqual(actual, expected, [message])
2407 | *
2408 | * Asserts that `actual` is deeply equal to `expected`.
2409 | *
2410 | * assert.deepEqual({ tea: 'green' }, { tea: 'green' });
2411 | *
2412 | * @name deepEqual
2413 | * @param {Mixed} actual
2414 | * @param {Mixed} expected
2415 | * @param {String} message
2416 | * @api public
2417 | */
2418 |
2419 | assert.deepEqual = function (act, exp, msg) {
2420 | new Assertion(act, msg).to.eql(exp);
2421 | };
2422 |
2423 | /**
2424 | * ### .notDeepEqual(actual, expected, [message])
2425 | *
2426 | * Assert that `actual` is not deeply equal to `expected`.
2427 | *
2428 | * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' });
2429 | *
2430 | * @name notDeepEqual
2431 | * @param {Mixed} actual
2432 | * @param {Mixed} expected
2433 | * @param {String} message
2434 | * @api public
2435 | */
2436 |
2437 | assert.notDeepEqual = function (act, exp, msg) {
2438 | new Assertion(act, msg).to.not.eql(exp);
2439 | };
2440 |
2441 | /**
2442 | * ### .isTrue(value, [message])
2443 | *
2444 | * Asserts that `value` is true.
2445 | *
2446 | * var teaServed = true;
2447 | * assert.isTrue(teaServed, 'the tea has been served');
2448 | *
2449 | * @name isTrue
2450 | * @param {Mixed} value
2451 | * @param {String} message
2452 | * @api public
2453 | */
2454 |
2455 | assert.isTrue = function (val, msg) {
2456 | new Assertion(val, msg).is['true'];
2457 | };
2458 |
2459 | /**
2460 | * ### .isFalse(value, [message])
2461 | *
2462 | * Asserts that `value` is false.
2463 | *
2464 | * var teaServed = false;
2465 | * assert.isFalse(teaServed, 'no tea yet? hmm...');
2466 | *
2467 | * @name isFalse
2468 | * @param {Mixed} value
2469 | * @param {String} message
2470 | * @api public
2471 | */
2472 |
2473 | assert.isFalse = function (val, msg) {
2474 | new Assertion(val, msg).is['false'];
2475 | };
2476 |
2477 | /**
2478 | * ### .isNull(value, [message])
2479 | *
2480 | * Asserts that `value` is null.
2481 | *
2482 | * assert.isNull(err, 'there was no error');
2483 | *
2484 | * @name isNull
2485 | * @param {Mixed} value
2486 | * @param {String} message
2487 | * @api public
2488 | */
2489 |
2490 | assert.isNull = function (val, msg) {
2491 | new Assertion(val, msg).to.equal(null);
2492 | };
2493 |
2494 | /**
2495 | * ### .isNotNull(value, [message])
2496 | *
2497 | * Asserts that `value` is not null.
2498 | *
2499 | * var tea = 'tasty chai';
2500 | * assert.isNotNull(tea, 'great, time for tea!');
2501 | *
2502 | * @name isNotNull
2503 | * @param {Mixed} value
2504 | * @param {String} message
2505 | * @api public
2506 | */
2507 |
2508 | assert.isNotNull = function (val, msg) {
2509 | new Assertion(val, msg).to.not.equal(null);
2510 | };
2511 |
2512 | /**
2513 | * ### .isUndefined(value, [message])
2514 | *
2515 | * Asserts that `value` is `undefined`.
2516 | *
2517 | * var tea;
2518 | * assert.isUndefined(tea, 'no tea defined');
2519 | *
2520 | * @name isUndefined
2521 | * @param {Mixed} value
2522 | * @param {String} message
2523 | * @api public
2524 | */
2525 |
2526 | assert.isUndefined = function (val, msg) {
2527 | new Assertion(val, msg).to.equal(undefined);
2528 | };
2529 |
2530 | /**
2531 | * ### .isDefined(value, [message])
2532 | *
2533 | * Asserts that `value` is not `undefined`.
2534 | *
2535 | * var tea = 'cup of chai';
2536 | * assert.isDefined(tea, 'tea has been defined');
2537 | *
2538 | * @name isDefined
2539 | * @param {Mixed} value
2540 | * @param {String} message
2541 | * @api public
2542 | */
2543 |
2544 | assert.isDefined = function (val, msg) {
2545 | new Assertion(val, msg).to.not.equal(undefined);
2546 | };
2547 |
2548 | /**
2549 | * ### .isFunction(value, [message])
2550 | *
2551 | * Asserts that `value` is a function.
2552 | *
2553 | * function serveTea() { return 'cup of tea'; };
2554 | * assert.isFunction(serveTea, 'great, we can have tea now');
2555 | *
2556 | * @name isFunction
2557 | * @param {Mixed} value
2558 | * @param {String} message
2559 | * @api public
2560 | */
2561 |
2562 | assert.isFunction = function (val, msg) {
2563 | new Assertion(val, msg).to.be.a('function');
2564 | };
2565 |
2566 | /**
2567 | * ### .isNotFunction(value, [message])
2568 | *
2569 | * Asserts that `value` is _not_ a function.
2570 | *
2571 | * var serveTea = [ 'heat', 'pour', 'sip' ];
2572 | * assert.isNotFunction(serveTea, 'great, we have listed the steps');
2573 | *
2574 | * @name isNotFunction
2575 | * @param {Mixed} value
2576 | * @param {String} message
2577 | * @api public
2578 | */
2579 |
2580 | assert.isNotFunction = function (val, msg) {
2581 | new Assertion(val, msg).to.not.be.a('function');
2582 | };
2583 |
2584 | /**
2585 | * ### .isObject(value, [message])
2586 | *
2587 | * Asserts that `value` is an object (as revealed by
2588 | * `Object.prototype.toString`).
2589 | *
2590 | * var selection = { name: 'Chai', serve: 'with spices' };
2591 | * assert.isObject(selection, 'tea selection is an object');
2592 | *
2593 | * @name isObject
2594 | * @param {Mixed} value
2595 | * @param {String} message
2596 | * @api public
2597 | */
2598 |
2599 | assert.isObject = function (val, msg) {
2600 | new Assertion(val, msg).to.be.a('object');
2601 | };
2602 |
2603 | /**
2604 | * ### .isNotObject(value, [message])
2605 | *
2606 | * Asserts that `value` is _not_ an object.
2607 | *
2608 | * var selection = 'chai'
2609 | * assert.isObject(selection, 'tea selection is not an object');
2610 | * assert.isObject(null, 'null is not an object');
2611 | *
2612 | * @name isNotObject
2613 | * @param {Mixed} value
2614 | * @param {String} message
2615 | * @api public
2616 | */
2617 |
2618 | assert.isNotObject = function (val, msg) {
2619 | new Assertion(val, msg).to.not.be.a('object');
2620 | };
2621 |
2622 | /**
2623 | * ### .isArray(value, [message])
2624 | *
2625 | * Asserts that `value` is an array.
2626 | *
2627 | * var menu = [ 'green', 'chai', 'oolong' ];
2628 | * assert.isArray(menu, 'what kind of tea do we want?');
2629 | *
2630 | * @name isArray
2631 | * @param {Mixed} value
2632 | * @param {String} message
2633 | * @api public
2634 | */
2635 |
2636 | assert.isArray = function (val, msg) {
2637 | new Assertion(val, msg).to.be.an('array');
2638 | };
2639 |
2640 | /**
2641 | * ### .isNotArray(value, [message])
2642 | *
2643 | * Asserts that `value` is _not_ an array.
2644 | *
2645 | * var menu = 'green|chai|oolong';
2646 | * assert.isNotArray(menu, 'what kind of tea do we want?');
2647 | *
2648 | * @name isNotArray
2649 | * @param {Mixed} value
2650 | * @param {String} message
2651 | * @api public
2652 | */
2653 |
2654 | assert.isNotArray = function (val, msg) {
2655 | new Assertion(val, msg).to.not.be.an('array');
2656 | };
2657 |
2658 | /**
2659 | * ### .isString(value, [message])
2660 | *
2661 | * Asserts that `value` is a string.
2662 | *
2663 | * var teaOrder = 'chai';
2664 | * assert.isString(teaOrder, 'order placed');
2665 | *
2666 | * @name isString
2667 | * @param {Mixed} value
2668 | * @param {String} message
2669 | * @api public
2670 | */
2671 |
2672 | assert.isString = function (val, msg) {
2673 | new Assertion(val, msg).to.be.a('string');
2674 | };
2675 |
2676 | /**
2677 | * ### .isNotString(value, [message])
2678 | *
2679 | * Asserts that `value` is _not_ a string.
2680 | *
2681 | * var teaOrder = 4;
2682 | * assert.isNotString(teaOrder, 'order placed');
2683 | *
2684 | * @name isNotString
2685 | * @param {Mixed} value
2686 | * @param {String} message
2687 | * @api public
2688 | */
2689 |
2690 | assert.isNotString = function (val, msg) {
2691 | new Assertion(val, msg).to.not.be.a('string');
2692 | };
2693 |
2694 | /**
2695 | * ### .isNumber(value, [message])
2696 | *
2697 | * Asserts that `value` is a number.
2698 | *
2699 | * var cups = 2;
2700 | * assert.isNumber(cups, 'how many cups');
2701 | *
2702 | * @name isNumber
2703 | * @param {Number} value
2704 | * @param {String} message
2705 | * @api public
2706 | */
2707 |
2708 | assert.isNumber = function (val, msg) {
2709 | new Assertion(val, msg).to.be.a('number');
2710 | };
2711 |
2712 | /**
2713 | * ### .isNotNumber(value, [message])
2714 | *
2715 | * Asserts that `value` is _not_ a number.
2716 | *
2717 | * var cups = '2 cups please';
2718 | * assert.isNotNumber(cups, 'how many cups');
2719 | *
2720 | * @name isNotNumber
2721 | * @param {Mixed} value
2722 | * @param {String} message
2723 | * @api public
2724 | */
2725 |
2726 | assert.isNotNumber = function (val, msg) {
2727 | new Assertion(val, msg).to.not.be.a('number');
2728 | };
2729 |
2730 | /**
2731 | * ### .isBoolean(value, [message])
2732 | *
2733 | * Asserts that `value` is a boolean.
2734 | *
2735 | * var teaReady = true
2736 | * , teaServed = false;
2737 | *
2738 | * assert.isBoolean(teaReady, 'is the tea ready');
2739 | * assert.isBoolean(teaServed, 'has tea been served');
2740 | *
2741 | * @name isBoolean
2742 | * @param {Mixed} value
2743 | * @param {String} message
2744 | * @api public
2745 | */
2746 |
2747 | assert.isBoolean = function (val, msg) {
2748 | new Assertion(val, msg).to.be.a('boolean');
2749 | };
2750 |
2751 | /**
2752 | * ### .isNotBoolean(value, [message])
2753 | *
2754 | * Asserts that `value` is _not_ a boolean.
2755 | *
2756 | * var teaReady = 'yep'
2757 | * , teaServed = 'nope';
2758 | *
2759 | * assert.isNotBoolean(teaReady, 'is the tea ready');
2760 | * assert.isNotBoolean(teaServed, 'has tea been served');
2761 | *
2762 | * @name isNotBoolean
2763 | * @param {Mixed} value
2764 | * @param {String} message
2765 | * @api public
2766 | */
2767 |
2768 | assert.isNotBoolean = function (val, msg) {
2769 | new Assertion(val, msg).to.not.be.a('boolean');
2770 | };
2771 |
2772 | /**
2773 | * ### .typeOf(value, name, [message])
2774 | *
2775 | * Asserts that `value`'s type is `name`, as determined by
2776 | * `Object.prototype.toString`.
2777 | *
2778 | * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object');
2779 | * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array');
2780 | * assert.typeOf('tea', 'string', 'we have a string');
2781 | * assert.typeOf(/tea/, 'regexp', 'we have a regular expression');
2782 | * assert.typeOf(null, 'null', 'we have a null');
2783 | * assert.typeOf(undefined, 'undefined', 'we have an undefined');
2784 | *
2785 | * @name typeOf
2786 | * @param {Mixed} value
2787 | * @param {String} name
2788 | * @param {String} message
2789 | * @api public
2790 | */
2791 |
2792 | assert.typeOf = function (val, type, msg) {
2793 | new Assertion(val, msg).to.be.a(type);
2794 | };
2795 |
2796 | /**
2797 | * ### .notTypeOf(value, name, [message])
2798 | *
2799 | * Asserts that `value`'s type is _not_ `name`, as determined by
2800 | * `Object.prototype.toString`.
2801 | *
2802 | * assert.notTypeOf('tea', 'number', 'strings are not numbers');
2803 | *
2804 | * @name notTypeOf
2805 | * @param {Mixed} value
2806 | * @param {String} typeof name
2807 | * @param {String} message
2808 | * @api public
2809 | */
2810 |
2811 | assert.notTypeOf = function (val, type, msg) {
2812 | new Assertion(val, msg).to.not.be.a(type);
2813 | };
2814 |
2815 | /**
2816 | * ### .instanceOf(object, constructor, [message])
2817 | *
2818 | * Asserts that `value` is an instance of `constructor`.
2819 | *
2820 | * var Tea = function (name) { this.name = name; }
2821 | * , chai = new Tea('chai');
2822 | *
2823 | * assert.instanceOf(chai, Tea, 'chai is an instance of tea');
2824 | *
2825 | * @name instanceOf
2826 | * @param {Object} object
2827 | * @param {Constructor} constructor
2828 | * @param {String} message
2829 | * @api public
2830 | */
2831 |
2832 | assert.instanceOf = function (val, type, msg) {
2833 | new Assertion(val, msg).to.be.instanceOf(type);
2834 | };
2835 |
2836 | /**
2837 | * ### .notInstanceOf(object, constructor, [message])
2838 | *
2839 | * Asserts `value` is not an instance of `constructor`.
2840 | *
2841 | * var Tea = function (name) { this.name = name; }
2842 | * , chai = new String('chai');
2843 | *
2844 | * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea');
2845 | *
2846 | * @name notInstanceOf
2847 | * @param {Object} object
2848 | * @param {Constructor} constructor
2849 | * @param {String} message
2850 | * @api public
2851 | */
2852 |
2853 | assert.notInstanceOf = function (val, type, msg) {
2854 | new Assertion(val, msg).to.not.be.instanceOf(type);
2855 | };
2856 |
2857 | /**
2858 | * ### .include(haystack, needle, [message])
2859 | *
2860 | * Asserts that `haystack` includes `needle`. Works
2861 | * for strings and arrays.
2862 | *
2863 | * assert.include('foobar', 'bar', 'foobar contains string "bar"');
2864 | * assert.include([ 1, 2, 3 ], 3, 'array contains value');
2865 | *
2866 | * @name include
2867 | * @param {Array|String} haystack
2868 | * @param {Mixed} needle
2869 | * @param {String} message
2870 | * @api public
2871 | */
2872 |
2873 | assert.include = function (exp, inc, msg) {
2874 | var obj = new Assertion(exp, msg);
2875 |
2876 | if (Array.isArray(exp)) {
2877 | obj.to.include(inc);
2878 | } else if ('string' === typeof exp) {
2879 | obj.to.contain.string(inc);
2880 | } else {
2881 | throw new chai.AssertionError(
2882 | 'expected an array or string'
2883 | , null
2884 | , assert.include
2885 | );
2886 | }
2887 | };
2888 |
2889 | /**
2890 | * ### .notInclude(haystack, needle, [message])
2891 | *
2892 | * Asserts that `haystack` does not include `needle`. Works
2893 | * for strings and arrays.
2894 | *i
2895 | * assert.notInclude('foobar', 'baz', 'string not include substring');
2896 | * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value');
2897 | *
2898 | * @name notInclude
2899 | * @param {Array|String} haystack
2900 | * @param {Mixed} needle
2901 | * @param {String} message
2902 | * @api public
2903 | */
2904 |
2905 | assert.notInclude = function (exp, inc, msg) {
2906 | var obj = new Assertion(exp, msg);
2907 |
2908 | if (Array.isArray(exp)) {
2909 | obj.to.not.include(inc);
2910 | } else if ('string' === typeof exp) {
2911 | obj.to.not.contain.string(inc);
2912 | } else {
2913 | throw new chai.AssertionError(
2914 | 'expected an array or string'
2915 | , null
2916 | , assert.notInclude
2917 | );
2918 | }
2919 | };
2920 |
2921 | /**
2922 | * ### .match(value, regexp, [message])
2923 | *
2924 | * Asserts that `value` matches the regular expression `regexp`.
2925 | *
2926 | * assert.match('foobar', /^foo/, 'regexp matches');
2927 | *
2928 | * @name match
2929 | * @param {Mixed} value
2930 | * @param {RegExp} regexp
2931 | * @param {String} message
2932 | * @api public
2933 | */
2934 |
2935 | assert.match = function (exp, re, msg) {
2936 | new Assertion(exp, msg).to.match(re);
2937 | };
2938 |
2939 | /**
2940 | * ### .notMatch(value, regexp, [message])
2941 | *
2942 | * Asserts that `value` does not match the regular expression `regexp`.
2943 | *
2944 | * assert.notMatch('foobar', /^foo/, 'regexp does not match');
2945 | *
2946 | * @name notMatch
2947 | * @param {Mixed} value
2948 | * @param {RegExp} regexp
2949 | * @param {String} message
2950 | * @api public
2951 | */
2952 |
2953 | assert.notMatch = function (exp, re, msg) {
2954 | new Assertion(exp, msg).to.not.match(re);
2955 | };
2956 |
2957 | /**
2958 | * ### .property(object, property, [message])
2959 | *
2960 | * Asserts that `object` has a property named by `property`.
2961 | *
2962 | * assert.property({ tea: { green: 'matcha' }}, 'tea');
2963 | *
2964 | * @name property
2965 | * @param {Object} object
2966 | * @param {String} property
2967 | * @param {String} message
2968 | * @api public
2969 | */
2970 |
2971 | assert.property = function (obj, prop, msg) {
2972 | new Assertion(obj, msg).to.have.property(prop);
2973 | };
2974 |
2975 | /**
2976 | * ### .notProperty(object, property, [message])
2977 | *
2978 | * Asserts that `object` does _not_ have a property named by `property`.
2979 | *
2980 | * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee');
2981 | *
2982 | * @name notProperty
2983 | * @param {Object} object
2984 | * @param {String} property
2985 | * @param {String} message
2986 | * @api public
2987 | */
2988 |
2989 | assert.notProperty = function (obj, prop, msg) {
2990 | new Assertion(obj, msg).to.not.have.property(prop);
2991 | };
2992 |
2993 | /**
2994 | * ### .deepProperty(object, property, [message])
2995 | *
2996 | * Asserts that `object` has a property named by `property`, which can be a
2997 | * string using dot- and bracket-notation for deep reference.
2998 | *
2999 | * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green');
3000 | *
3001 | * @name deepProperty
3002 | * @param {Object} object
3003 | * @param {String} property
3004 | * @param {String} message
3005 | * @api public
3006 | */
3007 |
3008 | assert.deepProperty = function (obj, prop, msg) {
3009 | new Assertion(obj, msg).to.have.deep.property(prop);
3010 | };
3011 |
3012 | /**
3013 | * ### .notDeepProperty(object, property, [message])
3014 | *
3015 | * Asserts that `object` does _not_ have a property named by `property`, which
3016 | * can be a string using dot- and bracket-notation for deep reference.
3017 | *
3018 | * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong');
3019 | *
3020 | * @name notDeepProperty
3021 | * @param {Object} object
3022 | * @param {String} property
3023 | * @param {String} message
3024 | * @api public
3025 | */
3026 |
3027 | assert.notDeepProperty = function (obj, prop, msg) {
3028 | new Assertion(obj, msg).to.not.have.deep.property(prop);
3029 | };
3030 |
3031 | /**
3032 | * ### .propertyVal(object, property, value, [message])
3033 | *
3034 | * Asserts that `object` has a property named by `property` with value given
3035 | * by `value`.
3036 | *
3037 | * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good');
3038 | *
3039 | * @name propertyVal
3040 | * @param {Object} object
3041 | * @param {String} property
3042 | * @param {Mixed} value
3043 | * @param {String} message
3044 | * @api public
3045 | */
3046 |
3047 | assert.propertyVal = function (obj, prop, val, msg) {
3048 | new Assertion(obj, msg).to.have.property(prop, val);
3049 | };
3050 |
3051 | /**
3052 | * ### .propertyNotVal(object, property, value, [message])
3053 | *
3054 | * Asserts that `object` has a property named by `property`, but with a value
3055 | * different from that given by `value`.
3056 | *
3057 | * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad');
3058 | *
3059 | * @name propertyNotVal
3060 | * @param {Object} object
3061 | * @param {String} property
3062 | * @param {Mixed} value
3063 | * @param {String} message
3064 | * @api public
3065 | */
3066 |
3067 | assert.propertyNotVal = function (obj, prop, val, msg) {
3068 | new Assertion(obj, msg).to.not.have.property(prop, val);
3069 | };
3070 |
3071 | /**
3072 | * ### .deepPropertyVal(object, property, value, [message])
3073 | *
3074 | * Asserts that `object` has a property named by `property` with value given
3075 | * by `value`. `property` can use dot- and bracket-notation for deep
3076 | * reference.
3077 | *
3078 | * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha');
3079 | *
3080 | * @name deepPropertyVal
3081 | * @param {Object} object
3082 | * @param {String} property
3083 | * @param {Mixed} value
3084 | * @param {String} message
3085 | * @api public
3086 | */
3087 |
3088 | assert.deepPropertyVal = function (obj, prop, val, msg) {
3089 | new Assertion(obj, msg).to.have.deep.property(prop, val);
3090 | };
3091 |
3092 | /**
3093 | * ### .deepPropertyNotVal(object, property, value, [message])
3094 | *
3095 | * Asserts that `object` has a property named by `property`, but with a value
3096 | * different from that given by `value`. `property` can use dot- and
3097 | * bracket-notation for deep reference.
3098 | *
3099 | * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');
3100 | *
3101 | * @name deepPropertyNotVal
3102 | * @param {Object} object
3103 | * @param {String} property
3104 | * @param {Mixed} value
3105 | * @param {String} message
3106 | * @api public
3107 | */
3108 |
3109 | assert.deepPropertyNotVal = function (obj, prop, val, msg) {
3110 | new Assertion(obj, msg).to.not.have.deep.property(prop, val);
3111 | };
3112 |
3113 | /**
3114 | * ### .lengthOf(object, length, [message])
3115 | *
3116 | * Asserts that `object` has a `length` property with the expected value.
3117 | *
3118 | * assert.lengthOf([1,2,3], 3, 'array has length of 3');
3119 | * assert.lengthOf('foobar', 5, 'string has length of 6');
3120 | *
3121 | * @name lengthOf
3122 | * @param {Mixed} object
3123 | * @param {Number} length
3124 | * @param {String} message
3125 | * @api public
3126 | */
3127 |
3128 | assert.lengthOf = function (exp, len, msg) {
3129 | new Assertion(exp, msg).to.have.length(len);
3130 | };
3131 |
3132 | /**
3133 | * ### .throws(function, [constructor/string/regexp], [string/regexp], [message])
3134 | *
3135 | * Asserts that `function` will throw an error that is an instance of
3136 | * `constructor`, or alternately that it will throw an error with message
3137 | * matching `regexp`.
3138 | *
3139 | * assert.throw(fn, 'function throws a reference error');
3140 | * assert.throw(fn, /function throws a reference error/);
3141 | * assert.throw(fn, ReferenceError);
3142 | * assert.throw(fn, ReferenceError, 'function throws a reference error');
3143 | * assert.throw(fn, ReferenceError, /function throws a reference error/);
3144 | *
3145 | * @name throws
3146 | * @alias throw
3147 | * @alias Throw
3148 | * @param {Function} function
3149 | * @param {ErrorConstructor} constructor
3150 | * @param {RegExp} regexp
3151 | * @param {String} message
3152 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
3153 | * @api public
3154 | */
3155 |
3156 | assert.Throw = function (fn, errt, errs, msg) {
3157 | if ('string' === typeof errt || errt instanceof RegExp) {
3158 | errs = errt;
3159 | errt = null;
3160 | }
3161 |
3162 | new Assertion(fn, msg).to.Throw(errt, errs);
3163 | };
3164 |
3165 | /**
3166 | * ### .doesNotThrow(function, [constructor/regexp], [message])
3167 | *
3168 | * Asserts that `function` will _not_ throw an error that is an instance of
3169 | * `constructor`, or alternately that it will not throw an error with message
3170 | * matching `regexp`.
3171 | *
3172 | * assert.doesNotThrow(fn, Error, 'function does not throw');
3173 | *
3174 | * @name doesNotThrow
3175 | * @param {Function} function
3176 | * @param {ErrorConstructor} constructor
3177 | * @param {RegExp} regexp
3178 | * @param {String} message
3179 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
3180 | * @api public
3181 | */
3182 |
3183 | assert.doesNotThrow = function (fn, type, msg) {
3184 | if ('string' === typeof type) {
3185 | msg = type;
3186 | type = null;
3187 | }
3188 |
3189 | new Assertion(fn, msg).to.not.Throw(type);
3190 | };
3191 |
3192 | /**
3193 | * ### .operator(val1, operator, val2, [message])
3194 | *
3195 | * Compares two values using `operator`.
3196 | *
3197 | * assert.operator(1, '<', 2, 'everything is ok');
3198 | * assert.operator(1, '>', 2, 'this will fail');
3199 | *
3200 | * @name operator
3201 | * @param {Mixed} val1
3202 | * @param {String} operator
3203 | * @param {Mixed} val2
3204 | * @param {String} message
3205 | * @api public
3206 | */
3207 |
3208 | assert.operator = function (val, operator, val2, msg) {
3209 | if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) {
3210 | throw new Error('Invalid operator "' + operator + '"');
3211 | }
3212 | var test = new Assertion(eval(val + operator + val2), msg);
3213 | test.assert(
3214 | true === flag(test, 'object')
3215 | , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2)
3216 | , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) );
3217 | };
3218 |
3219 | /**
3220 | * ### .closeTo(actual, expected, delta, [message])
3221 | *
3222 | * Asserts that the target is equal `expected`, to within a +/- `delta` range.
3223 | *
3224 | * assert.closeTo(1.5, 1, 0.5, 'numbers are close');
3225 | *
3226 | * @name closeTo
3227 | * @param {Number} actual
3228 | * @param {Number} expected
3229 | * @param {Number} delta
3230 | * @param {String} message
3231 | * @api public
3232 | */
3233 |
3234 | assert.closeTo = function (act, exp, delta, msg) {
3235 | new Assertion(act, msg).to.be.closeTo(exp, delta);
3236 | };
3237 |
3238 | /**
3239 | * ### .sameMembers(set1, set2, [message])
3240 | *
3241 | * Asserts that `set1` and `set2` have the same members.
3242 | * Order is not taken into account.
3243 | *
3244 | * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members');
3245 | *
3246 | * @name sameMembers
3247 | * @param {Array} superset
3248 | * @param {Array} subset
3249 | * @param {String} message
3250 | * @api public
3251 | */
3252 |
3253 | assert.sameMembers = function (set1, set2, msg) {
3254 | new Assertion(set1, msg).to.have.same.members(set2);
3255 | }
3256 |
3257 | /**
3258 | * ### .includeMembers(superset, subset, [message])
3259 | *
3260 | * Asserts that `subset` is included in `superset`.
3261 | * Order is not taken into account.
3262 | *
3263 | * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members');
3264 | *
3265 | * @name includeMembers
3266 | * @param {Array} superset
3267 | * @param {Array} subset
3268 | * @param {String} message
3269 | * @api public
3270 | */
3271 |
3272 | assert.includeMembers = function (superset, subset, msg) {
3273 | new Assertion(superset, msg).to.include.members(subset);
3274 | }
3275 |
3276 | /*!
3277 | * Undocumented / untested
3278 | */
3279 |
3280 | assert.ifError = function (val, msg) {
3281 | new Assertion(val, msg).to.not.be.ok;
3282 | };
3283 |
3284 | /*!
3285 | * Aliases.
3286 | */
3287 |
3288 | (function alias(name, as){
3289 | assert[as] = assert[name];
3290 | return alias;
3291 | })
3292 | ('Throw', 'throw')
3293 | ('Throw', 'throws');
3294 | };
3295 |
3296 | });
3297 | require.register("chai/lib/chai/interface/expect.js", function(exports, require, module){
3298 | /*!
3299 | * chai
3300 | * Copyright(c) 2011-2013 Jake Luer
3301 | * MIT Licensed
3302 | */
3303 |
3304 | module.exports = function (chai, util) {
3305 | chai.expect = function (val, message) {
3306 | return new chai.Assertion(val, message);
3307 | };
3308 | };
3309 |
3310 |
3311 | });
3312 | require.register("chai/lib/chai/interface/should.js", function(exports, require, module){
3313 | /*!
3314 | * chai
3315 | * Copyright(c) 2011-2013 Jake Luer
3316 | * MIT Licensed
3317 | */
3318 |
3319 | module.exports = function (chai, util) {
3320 | var Assertion = chai.Assertion;
3321 |
3322 | function loadShould () {
3323 | // modify Object.prototype to have `should`
3324 | Object.defineProperty(Object.prototype, 'should',
3325 | {
3326 | set: function (value) {
3327 | // See https://github.com/chaijs/chai/issues/86: this makes
3328 | // `whatever.should = someValue` actually set `someValue`, which is
3329 | // especially useful for `global.should = require('chai').should()`.
3330 | //
3331 | // Note that we have to use [[DefineProperty]] instead of [[Put]]
3332 | // since otherwise we would trigger this very setter!
3333 | Object.defineProperty(this, 'should', {
3334 | value: value,
3335 | enumerable: true,
3336 | configurable: true,
3337 | writable: true
3338 | });
3339 | }
3340 | , get: function(){
3341 | if (this instanceof String || this instanceof Number) {
3342 | return new Assertion(this.constructor(this));
3343 | } else if (this instanceof Boolean) {
3344 | return new Assertion(this == true);
3345 | }
3346 | return new Assertion(this);
3347 | }
3348 | , configurable: true
3349 | });
3350 |
3351 | var should = {};
3352 |
3353 | should.equal = function (val1, val2, msg) {
3354 | new Assertion(val1, msg).to.equal(val2);
3355 | };
3356 |
3357 | should.Throw = function (fn, errt, errs, msg) {
3358 | new Assertion(fn, msg).to.Throw(errt, errs);
3359 | };
3360 |
3361 | should.exist = function (val, msg) {
3362 | new Assertion(val, msg).to.exist;
3363 | }
3364 |
3365 | // negation
3366 | should.not = {}
3367 |
3368 | should.not.equal = function (val1, val2, msg) {
3369 | new Assertion(val1, msg).to.not.equal(val2);
3370 | };
3371 |
3372 | should.not.Throw = function (fn, errt, errs, msg) {
3373 | new Assertion(fn, msg).to.not.Throw(errt, errs);
3374 | };
3375 |
3376 | should.not.exist = function (val, msg) {
3377 | new Assertion(val, msg).to.not.exist;
3378 | }
3379 |
3380 | should['throw'] = should['Throw'];
3381 | should.not['throw'] = should.not['Throw'];
3382 |
3383 | return should;
3384 | };
3385 |
3386 | chai.should = loadShould;
3387 | chai.Should = loadShould;
3388 | };
3389 |
3390 | });
3391 | require.register("chai/lib/chai/utils/addChainableMethod.js", function(exports, require, module){
3392 | /*!
3393 | * Chai - addChainingMethod utility
3394 | * Copyright(c) 2012-2013 Jake Luer
3395 | * MIT Licensed
3396 | */
3397 |
3398 | /*!
3399 | * Module dependencies
3400 | */
3401 |
3402 | var transferFlags = require('./transferFlags');
3403 |
3404 | /*!
3405 | * Module variables
3406 | */
3407 |
3408 | // Check whether `__proto__` is supported
3409 | var hasProtoSupport = '__proto__' in Object;
3410 |
3411 | // Without `__proto__` support, this module will need to add properties to a function.
3412 | // However, some Function.prototype methods cannot be overwritten,
3413 | // and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69).
3414 | var excludeNames = /^(?:length|name|arguments|caller)$/;
3415 |
3416 | // Cache `Function` properties
3417 | var call = Function.prototype.call,
3418 | apply = Function.prototype.apply;
3419 |
3420 | /**
3421 | * ### addChainableMethod (ctx, name, method, chainingBehavior)
3422 | *
3423 | * Adds a method to an object, such that the method can also be chained.
3424 | *
3425 | * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) {
3426 | * var obj = utils.flag(this, 'object');
3427 | * new chai.Assertion(obj).to.be.equal(str);
3428 | * });
3429 | *
3430 | * Can also be accessed directly from `chai.Assertion`.
3431 | *
3432 | * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior);
3433 | *
3434 | * The result can then be used as both a method assertion, executing both `method` and
3435 | * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`.
3436 | *
3437 | * expect(fooStr).to.be.foo('bar');
3438 | * expect(fooStr).to.be.foo.equal('foo');
3439 | *
3440 | * @param {Object} ctx object to which the method is added
3441 | * @param {String} name of method to add
3442 | * @param {Function} method function to be used for `name`, when called
3443 | * @param {Function} chainingBehavior function to be called every time the property is accessed
3444 | * @name addChainableMethod
3445 | * @api public
3446 | */
3447 |
3448 | module.exports = function (ctx, name, method, chainingBehavior) {
3449 | if (typeof chainingBehavior !== 'function')
3450 | chainingBehavior = function () { };
3451 |
3452 | Object.defineProperty(ctx, name,
3453 | { get: function () {
3454 | chainingBehavior.call(this);
3455 |
3456 | var assert = function () {
3457 | var result = method.apply(this, arguments);
3458 | return result === undefined ? this : result;
3459 | };
3460 |
3461 | // Use `__proto__` if available
3462 | if (hasProtoSupport) {
3463 | // Inherit all properties from the object by replacing the `Function` prototype
3464 | var prototype = assert.__proto__ = Object.create(this);
3465 | // Restore the `call` and `apply` methods from `Function`
3466 | prototype.call = call;
3467 | prototype.apply = apply;
3468 | }
3469 | // Otherwise, redefine all properties (slow!)
3470 | else {
3471 | var asserterNames = Object.getOwnPropertyNames(ctx);
3472 | asserterNames.forEach(function (asserterName) {
3473 | if (!excludeNames.test(asserterName)) {
3474 | var pd = Object.getOwnPropertyDescriptor(ctx, asserterName);
3475 | Object.defineProperty(assert, asserterName, pd);
3476 | }
3477 | });
3478 | }
3479 |
3480 | transferFlags(this, assert);
3481 | return assert;
3482 | }
3483 | , configurable: true
3484 | });
3485 | };
3486 |
3487 | });
3488 | require.register("chai/lib/chai/utils/addMethod.js", function(exports, require, module){
3489 | /*!
3490 | * Chai - addMethod utility
3491 | * Copyright(c) 2012-2013 Jake Luer
3492 | * MIT Licensed
3493 | */
3494 |
3495 | /**
3496 | * ### .addMethod (ctx, name, method)
3497 | *
3498 | * Adds a method to the prototype of an object.
3499 | *
3500 | * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) {
3501 | * var obj = utils.flag(this, 'object');
3502 | * new chai.Assertion(obj).to.be.equal(str);
3503 | * });
3504 | *
3505 | * Can also be accessed directly from `chai.Assertion`.
3506 | *
3507 | * chai.Assertion.addMethod('foo', fn);
3508 | *
3509 | * Then can be used as any other assertion.
3510 | *
3511 | * expect(fooStr).to.be.foo('bar');
3512 | *
3513 | * @param {Object} ctx object to which the method is added
3514 | * @param {String} name of method to add
3515 | * @param {Function} method function to be used for name
3516 | * @name addMethod
3517 | * @api public
3518 | */
3519 |
3520 | module.exports = function (ctx, name, method) {
3521 | ctx[name] = function () {
3522 | var result = method.apply(this, arguments);
3523 | return result === undefined ? this : result;
3524 | };
3525 | };
3526 |
3527 | });
3528 | require.register("chai/lib/chai/utils/addProperty.js", function(exports, require, module){
3529 | /*!
3530 | * Chai - addProperty utility
3531 | * Copyright(c) 2012-2013 Jake Luer
3532 | * MIT Licensed
3533 | */
3534 |
3535 | /**
3536 | * ### addProperty (ctx, name, getter)
3537 | *
3538 | * Adds a property to the prototype of an object.
3539 | *
3540 | * utils.addProperty(chai.Assertion.prototype, 'foo', function () {
3541 | * var obj = utils.flag(this, 'object');
3542 | * new chai.Assertion(obj).to.be.instanceof(Foo);
3543 | * });
3544 | *
3545 | * Can also be accessed directly from `chai.Assertion`.
3546 | *
3547 | * chai.Assertion.addProperty('foo', fn);
3548 | *
3549 | * Then can be used as any other assertion.
3550 | *
3551 | * expect(myFoo).to.be.foo;
3552 | *
3553 | * @param {Object} ctx object to which the property is added
3554 | * @param {String} name of property to add
3555 | * @param {Function} getter function to be used for name
3556 | * @name addProperty
3557 | * @api public
3558 | */
3559 |
3560 | module.exports = function (ctx, name, getter) {
3561 | Object.defineProperty(ctx, name,
3562 | { get: function () {
3563 | var result = getter.call(this);
3564 | return result === undefined ? this : result;
3565 | }
3566 | , configurable: true
3567 | });
3568 | };
3569 |
3570 | });
3571 | require.register("chai/lib/chai/utils/flag.js", function(exports, require, module){
3572 | /*!
3573 | * Chai - flag utility
3574 | * Copyright(c) 2012-2013 Jake Luer
3575 | * MIT Licensed
3576 | */
3577 |
3578 | /**
3579 | * ### flag(object ,key, [value])
3580 | *
3581 | * Get or set a flag value on an object. If a
3582 | * value is provided it will be set, else it will
3583 | * return the currently set value or `undefined` if
3584 | * the value is not set.
3585 | *
3586 | * utils.flag(this, 'foo', 'bar'); // setter
3587 | * utils.flag(this, 'foo'); // getter, returns `bar`
3588 | *
3589 | * @param {Object} object (constructed Assertion
3590 | * @param {String} key
3591 | * @param {Mixed} value (optional)
3592 | * @name flag
3593 | * @api private
3594 | */
3595 |
3596 | module.exports = function (obj, key, value) {
3597 | var flags = obj.__flags || (obj.__flags = Object.create(null));
3598 | if (arguments.length === 3) {
3599 | flags[key] = value;
3600 | } else {
3601 | return flags[key];
3602 | }
3603 | };
3604 |
3605 | });
3606 | require.register("chai/lib/chai/utils/getActual.js", function(exports, require, module){
3607 | /*!
3608 | * Chai - getActual utility
3609 | * Copyright(c) 2012-2013 Jake Luer
3610 | * MIT Licensed
3611 | */
3612 |
3613 | /**
3614 | * # getActual(object, [actual])
3615 | *
3616 | * Returns the `actual` value for an Assertion
3617 | *
3618 | * @param {Object} object (constructed Assertion)
3619 | * @param {Arguments} chai.Assertion.prototype.assert arguments
3620 | */
3621 |
3622 | module.exports = function (obj, args) {
3623 | var actual = args[4];
3624 | return 'undefined' !== typeof actual ? actual : obj._obj;
3625 | };
3626 |
3627 | });
3628 | require.register("chai/lib/chai/utils/getEnumerableProperties.js", function(exports, require, module){
3629 | /*!
3630 | * Chai - getEnumerableProperties utility
3631 | * Copyright(c) 2012-2013 Jake Luer
3632 | * MIT Licensed
3633 | */
3634 |
3635 | /**
3636 | * ### .getEnumerableProperties(object)
3637 | *
3638 | * This allows the retrieval of enumerable property names of an object,
3639 | * inherited or not.
3640 | *
3641 | * @param {Object} object
3642 | * @returns {Array}
3643 | * @name getEnumerableProperties
3644 | * @api public
3645 | */
3646 |
3647 | module.exports = function getEnumerableProperties(object) {
3648 | var result = [];
3649 | for (var name in object) {
3650 | result.push(name);
3651 | }
3652 | return result;
3653 | };
3654 |
3655 | });
3656 | require.register("chai/lib/chai/utils/getMessage.js", function(exports, require, module){
3657 | /*!
3658 | * Chai - message composition utility
3659 | * Copyright(c) 2012-2013 Jake Luer
3660 | * MIT Licensed
3661 | */
3662 |
3663 | /*!
3664 | * Module dependancies
3665 | */
3666 |
3667 | var flag = require('./flag')
3668 | , getActual = require('./getActual')
3669 | , inspect = require('./inspect')
3670 | , objDisplay = require('./objDisplay');
3671 |
3672 | /**
3673 | * ### .getMessage(object, message, negateMessage)
3674 | *
3675 | * Construct the error message based on flags
3676 | * and template tags. Template tags will return
3677 | * a stringified inspection of the object referenced.
3678 | *
3679 | * Message template tags:
3680 | * - `#{this}` current asserted object
3681 | * - `#{act}` actual value
3682 | * - `#{exp}` expected value
3683 | *
3684 | * @param {Object} object (constructed Assertion)
3685 | * @param {Arguments} chai.Assertion.prototype.assert arguments
3686 | * @name getMessage
3687 | * @api public
3688 | */
3689 |
3690 | module.exports = function (obj, args) {
3691 | var negate = flag(obj, 'negate')
3692 | , val = flag(obj, 'object')
3693 | , expected = args[3]
3694 | , actual = getActual(obj, args)
3695 | , msg = negate ? args[2] : args[1]
3696 | , flagMsg = flag(obj, 'message');
3697 |
3698 | msg = msg || '';
3699 | msg = msg
3700 | .replace(/#{this}/g, objDisplay(val))
3701 | .replace(/#{act}/g, objDisplay(actual))
3702 | .replace(/#{exp}/g, objDisplay(expected));
3703 |
3704 | return flagMsg ? flagMsg + ': ' + msg : msg;
3705 | };
3706 |
3707 | });
3708 | require.register("chai/lib/chai/utils/getName.js", function(exports, require, module){
3709 | /*!
3710 | * Chai - getName utility
3711 | * Copyright(c) 2012-2013 Jake Luer
3712 | * MIT Licensed
3713 | */
3714 |
3715 | /**
3716 | * # getName(func)
3717 | *
3718 | * Gets the name of a function, in a cross-browser way.
3719 | *
3720 | * @param {Function} a function (usually a constructor)
3721 | */
3722 |
3723 | module.exports = function (func) {
3724 | if (func.name) return func.name;
3725 |
3726 | var match = /^\s?function ([^(]*)\(/.exec(func);
3727 | return match && match[1] ? match[1] : "";
3728 | };
3729 |
3730 | });
3731 | require.register("chai/lib/chai/utils/getPathValue.js", function(exports, require, module){
3732 | /*!
3733 | * Chai - getPathValue utility
3734 | * Copyright(c) 2012-2013 Jake Luer
3735 | * @see https://github.com/logicalparadox/filtr
3736 | * MIT Licensed
3737 | */
3738 |
3739 | /**
3740 | * ### .getPathValue(path, object)
3741 | *
3742 | * This allows the retrieval of values in an
3743 | * object given a string path.
3744 | *
3745 | * var obj = {
3746 | * prop1: {
3747 | * arr: ['a', 'b', 'c']
3748 | * , str: 'Hello'
3749 | * }
3750 | * , prop2: {
3751 | * arr: [ { nested: 'Universe' } ]
3752 | * , str: 'Hello again!'
3753 | * }
3754 | * }
3755 | *
3756 | * The following would be the results.
3757 | *
3758 | * getPathValue('prop1.str', obj); // Hello
3759 | * getPathValue('prop1.att[2]', obj); // b
3760 | * getPathValue('prop2.arr[0].nested', obj); // Universe
3761 | *
3762 | * @param {String} path
3763 | * @param {Object} object
3764 | * @returns {Object} value or `undefined`
3765 | * @name getPathValue
3766 | * @api public
3767 | */
3768 |
3769 | var getPathValue = module.exports = function (path, obj) {
3770 | var parsed = parsePath(path);
3771 | return _getPathValue(parsed, obj);
3772 | };
3773 |
3774 | /*!
3775 | * ## parsePath(path)
3776 | *
3777 | * Helper function used to parse string object
3778 | * paths. Use in conjunction with `_getPathValue`.
3779 | *
3780 | * var parsed = parsePath('myobject.property.subprop');
3781 | *
3782 | * ### Paths:
3783 | *
3784 | * * Can be as near infinitely deep and nested
3785 | * * Arrays are also valid using the formal `myobject.document[3].property`.
3786 | *
3787 | * @param {String} path
3788 | * @returns {Object} parsed
3789 | * @api private
3790 | */
3791 |
3792 | function parsePath (path) {
3793 | var str = path.replace(/\[/g, '.[')
3794 | , parts = str.match(/(\\\.|[^.]+?)+/g);
3795 | return parts.map(function (value) {
3796 | var re = /\[(\d+)\]$/
3797 | , mArr = re.exec(value)
3798 | if (mArr) return { i: parseFloat(mArr[1]) };
3799 | else return { p: value };
3800 | });
3801 | };
3802 |
3803 | /*!
3804 | * ## _getPathValue(parsed, obj)
3805 | *
3806 | * Helper companion function for `.parsePath` that returns
3807 | * the value located at the parsed address.
3808 | *
3809 | * var value = getPathValue(parsed, obj);
3810 | *
3811 | * @param {Object} parsed definition from `parsePath`.
3812 | * @param {Object} object to search against
3813 | * @returns {Object|Undefined} value
3814 | * @api private
3815 | */
3816 |
3817 | function _getPathValue (parsed, obj) {
3818 | var tmp = obj
3819 | , res;
3820 | for (var i = 0, l = parsed.length; i < l; i++) {
3821 | var part = parsed[i];
3822 | if (tmp) {
3823 | if ('undefined' !== typeof part.p)
3824 | tmp = tmp[part.p];
3825 | else if ('undefined' !== typeof part.i)
3826 | tmp = tmp[part.i];
3827 | if (i == (l - 1)) res = tmp;
3828 | } else {
3829 | res = undefined;
3830 | }
3831 | }
3832 | return res;
3833 | };
3834 |
3835 | });
3836 | require.register("chai/lib/chai/utils/getProperties.js", function(exports, require, module){
3837 | /*!
3838 | * Chai - getProperties utility
3839 | * Copyright(c) 2012-2013 Jake Luer
3840 | * MIT Licensed
3841 | */
3842 |
3843 | /**
3844 | * ### .getProperties(object)
3845 | *
3846 | * This allows the retrieval of property names of an object, enumerable or not,
3847 | * inherited or not.
3848 | *
3849 | * @param {Object} object
3850 | * @returns {Array}
3851 | * @name getProperties
3852 | * @api public
3853 | */
3854 |
3855 | module.exports = function getProperties(object) {
3856 | var result = Object.getOwnPropertyNames(subject);
3857 |
3858 | function addProperty(property) {
3859 | if (result.indexOf(property) === -1) {
3860 | result.push(property);
3861 | }
3862 | }
3863 |
3864 | var proto = Object.getPrototypeOf(subject);
3865 | while (proto !== null) {
3866 | Object.getOwnPropertyNames(proto).forEach(addProperty);
3867 | proto = Object.getPrototypeOf(proto);
3868 | }
3869 |
3870 | return result;
3871 | };
3872 |
3873 | });
3874 | require.register("chai/lib/chai/utils/index.js", function(exports, require, module){
3875 | /*!
3876 | * chai
3877 | * Copyright(c) 2011 Jake Luer
3878 | * MIT Licensed
3879 | */
3880 |
3881 | /*!
3882 | * Main exports
3883 | */
3884 |
3885 | var exports = module.exports = {};
3886 |
3887 | /*!
3888 | * test utility
3889 | */
3890 |
3891 | exports.test = require('./test');
3892 |
3893 | /*!
3894 | * type utility
3895 | */
3896 |
3897 | exports.type = require('./type');
3898 |
3899 | /*!
3900 | * message utility
3901 | */
3902 |
3903 | exports.getMessage = require('./getMessage');
3904 |
3905 | /*!
3906 | * actual utility
3907 | */
3908 |
3909 | exports.getActual = require('./getActual');
3910 |
3911 | /*!
3912 | * Inspect util
3913 | */
3914 |
3915 | exports.inspect = require('./inspect');
3916 |
3917 | /*!
3918 | * Object Display util
3919 | */
3920 |
3921 | exports.objDisplay = require('./objDisplay');
3922 |
3923 | /*!
3924 | * Flag utility
3925 | */
3926 |
3927 | exports.flag = require('./flag');
3928 |
3929 | /*!
3930 | * Flag transferring utility
3931 | */
3932 |
3933 | exports.transferFlags = require('./transferFlags');
3934 |
3935 | /*!
3936 | * Deep equal utility
3937 | */
3938 |
3939 | exports.eql = require('deep-eql');
3940 |
3941 | /*!
3942 | * Deep path value
3943 | */
3944 |
3945 | exports.getPathValue = require('./getPathValue');
3946 |
3947 | /*!
3948 | * Function name
3949 | */
3950 |
3951 | exports.getName = require('./getName');
3952 |
3953 | /*!
3954 | * add Property
3955 | */
3956 |
3957 | exports.addProperty = require('./addProperty');
3958 |
3959 | /*!
3960 | * add Method
3961 | */
3962 |
3963 | exports.addMethod = require('./addMethod');
3964 |
3965 | /*!
3966 | * overwrite Property
3967 | */
3968 |
3969 | exports.overwriteProperty = require('./overwriteProperty');
3970 |
3971 | /*!
3972 | * overwrite Method
3973 | */
3974 |
3975 | exports.overwriteMethod = require('./overwriteMethod');
3976 |
3977 | /*!
3978 | * Add a chainable method
3979 | */
3980 |
3981 | exports.addChainableMethod = require('./addChainableMethod');
3982 |
3983 |
3984 | });
3985 | require.register("chai/lib/chai/utils/inspect.js", function(exports, require, module){
3986 | // This is (almost) directly from Node.js utils
3987 | // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js
3988 |
3989 | var getName = require('./getName');
3990 | var getProperties = require('./getProperties');
3991 | var getEnumerableProperties = require('./getEnumerableProperties');
3992 |
3993 | module.exports = inspect;
3994 |
3995 | /**
3996 | * Echos the value of a value. Trys to print the value out
3997 | * in the best way possible given the different types.
3998 | *
3999 | * @param {Object} obj The object to print out.
4000 | * @param {Boolean} showHidden Flag that shows hidden (not enumerable)
4001 | * properties of objects.
4002 | * @param {Number} depth Depth in which to descend in object. Default is 2.
4003 | * @param {Boolean} colors Flag to turn on ANSI escape codes to color the
4004 | * output. Default is false (no coloring).
4005 | */
4006 | function inspect(obj, showHidden, depth, colors) {
4007 | var ctx = {
4008 | showHidden: showHidden,
4009 | seen: [],
4010 | stylize: function (str) { return str; }
4011 | };
4012 | return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth));
4013 | }
4014 |
4015 | // https://gist.github.com/1044128/
4016 | var getOuterHTML = function(element) {
4017 | if ('outerHTML' in element) return element.outerHTML;
4018 | var ns = "http://www.w3.org/1999/xhtml";
4019 | var container = document.createElementNS(ns, '_');
4020 | var elemProto = (window.HTMLElement || window.Element).prototype;
4021 | var xmlSerializer = new XMLSerializer();
4022 | var html;
4023 | if (document.xmlVersion) {
4024 | return xmlSerializer.serializeToString(element);
4025 | } else {
4026 | container.appendChild(element.cloneNode(false));
4027 | html = container.innerHTML.replace('><', '>' + element.innerHTML + '<');
4028 | container.innerHTML = '';
4029 | return html;
4030 | }
4031 | };
4032 |
4033 | // Returns true if object is a DOM element.
4034 | var isDOMElement = function (object) {
4035 | if (typeof HTMLElement === 'object') {
4036 | return object instanceof HTMLElement;
4037 | } else {
4038 | return object &&
4039 | typeof object === 'object' &&
4040 | object.nodeType === 1 &&
4041 | typeof object.nodeName === 'string';
4042 | }
4043 | };
4044 |
4045 | function formatValue(ctx, value, recurseTimes) {
4046 | // Provide a hook for user-specified inspect functions.
4047 | // Check that value is an object with an inspect function on it
4048 | if (value && typeof value.inspect === 'function' &&
4049 | // Filter out the util module, it's inspect function is special
4050 | value.inspect !== exports.inspect &&
4051 | // Also filter out any prototype objects using the circular check.
4052 | !(value.constructor && value.constructor.prototype === value)) {
4053 | var ret = value.inspect(recurseTimes);
4054 | if (typeof ret !== 'string') {
4055 | ret = formatValue(ctx, ret, recurseTimes);
4056 | }
4057 | return ret;
4058 | }
4059 |
4060 | // Primitive types cannot have properties
4061 | var primitive = formatPrimitive(ctx, value);
4062 | if (primitive) {
4063 | return primitive;
4064 | }
4065 |
4066 | // If it's DOM elem, get outer HTML.
4067 | if (isDOMElement(value)) {
4068 | return getOuterHTML(value);
4069 | }
4070 |
4071 | // Look up the keys of the object.
4072 | var visibleKeys = getEnumerableProperties(value);
4073 | var keys = ctx.showHidden ? getProperties(value) : visibleKeys;
4074 |
4075 | // Some type of object without properties can be shortcutted.
4076 | // In IE, errors have a single `stack` property, or if they are vanilla `Error`,
4077 | // a `stack` plus `description` property; ignore those for consistency.
4078 | if (keys.length === 0 || (isError(value) && (
4079 | (keys.length === 1 && keys[0] === 'stack') ||
4080 | (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack')
4081 | ))) {
4082 | if (typeof value === 'function') {
4083 | var name = getName(value);
4084 | var nameSuffix = name ? ': ' + name : '';
4085 | return ctx.stylize('[Function' + nameSuffix + ']', 'special');
4086 | }
4087 | if (isRegExp(value)) {
4088 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
4089 | }
4090 | if (isDate(value)) {
4091 | return ctx.stylize(Date.prototype.toUTCString.call(value), 'date');
4092 | }
4093 | if (isError(value)) {
4094 | return formatError(value);
4095 | }
4096 | }
4097 |
4098 | var base = '', array = false, braces = ['{', '}'];
4099 |
4100 | // Make Array say that they are Array
4101 | if (isArray(value)) {
4102 | array = true;
4103 | braces = ['[', ']'];
4104 | }
4105 |
4106 | // Make functions say that they are functions
4107 | if (typeof value === 'function') {
4108 | var name = getName(value);
4109 | var nameSuffix = name ? ': ' + name : '';
4110 | base = ' [Function' + nameSuffix + ']';
4111 | }
4112 |
4113 | // Make RegExps say that they are RegExps
4114 | if (isRegExp(value)) {
4115 | base = ' ' + RegExp.prototype.toString.call(value);
4116 | }
4117 |
4118 | // Make dates with properties first say the date
4119 | if (isDate(value)) {
4120 | base = ' ' + Date.prototype.toUTCString.call(value);
4121 | }
4122 |
4123 | // Make error with message first say the error
4124 | if (isError(value)) {
4125 | return formatError(value);
4126 | }
4127 |
4128 | if (keys.length === 0 && (!array || value.length == 0)) {
4129 | return braces[0] + base + braces[1];
4130 | }
4131 |
4132 | if (recurseTimes < 0) {
4133 | if (isRegExp(value)) {
4134 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
4135 | } else {
4136 | return ctx.stylize('[Object]', 'special');
4137 | }
4138 | }
4139 |
4140 | ctx.seen.push(value);
4141 |
4142 | var output;
4143 | if (array) {
4144 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
4145 | } else {
4146 | output = keys.map(function(key) {
4147 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
4148 | });
4149 | }
4150 |
4151 | ctx.seen.pop();
4152 |
4153 | return reduceToSingleString(output, base, braces);
4154 | }
4155 |
4156 |
4157 | function formatPrimitive(ctx, value) {
4158 | switch (typeof value) {
4159 | case 'undefined':
4160 | return ctx.stylize('undefined', 'undefined');
4161 |
4162 | case 'string':
4163 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
4164 | .replace(/'/g, "\\'")
4165 | .replace(/\\"/g, '"') + '\'';
4166 | return ctx.stylize(simple, 'string');
4167 |
4168 | case 'number':
4169 | return ctx.stylize('' + value, 'number');
4170 |
4171 | case 'boolean':
4172 | return ctx.stylize('' + value, 'boolean');
4173 | }
4174 | // For some reason typeof null is "object", so special case here.
4175 | if (value === null) {
4176 | return ctx.stylize('null', 'null');
4177 | }
4178 | }
4179 |
4180 |
4181 | function formatError(value) {
4182 | return '[' + Error.prototype.toString.call(value) + ']';
4183 | }
4184 |
4185 |
4186 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
4187 | var output = [];
4188 | for (var i = 0, l = value.length; i < l; ++i) {
4189 | if (Object.prototype.hasOwnProperty.call(value, String(i))) {
4190 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
4191 | String(i), true));
4192 | } else {
4193 | output.push('');
4194 | }
4195 | }
4196 | keys.forEach(function(key) {
4197 | if (!key.match(/^\d+$/)) {
4198 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
4199 | key, true));
4200 | }
4201 | });
4202 | return output;
4203 | }
4204 |
4205 |
4206 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
4207 | var name, str;
4208 | if (value.__lookupGetter__) {
4209 | if (value.__lookupGetter__(key)) {
4210 | if (value.__lookupSetter__(key)) {
4211 | str = ctx.stylize('[Getter/Setter]', 'special');
4212 | } else {
4213 | str = ctx.stylize('[Getter]', 'special');
4214 | }
4215 | } else {
4216 | if (value.__lookupSetter__(key)) {
4217 | str = ctx.stylize('[Setter]', 'special');
4218 | }
4219 | }
4220 | }
4221 | if (visibleKeys.indexOf(key) < 0) {
4222 | name = '[' + key + ']';
4223 | }
4224 | if (!str) {
4225 | if (ctx.seen.indexOf(value[key]) < 0) {
4226 | if (recurseTimes === null) {
4227 | str = formatValue(ctx, value[key], null);
4228 | } else {
4229 | str = formatValue(ctx, value[key], recurseTimes - 1);
4230 | }
4231 | if (str.indexOf('\n') > -1) {
4232 | if (array) {
4233 | str = str.split('\n').map(function(line) {
4234 | return ' ' + line;
4235 | }).join('\n').substr(2);
4236 | } else {
4237 | str = '\n' + str.split('\n').map(function(line) {
4238 | return ' ' + line;
4239 | }).join('\n');
4240 | }
4241 | }
4242 | } else {
4243 | str = ctx.stylize('[Circular]', 'special');
4244 | }
4245 | }
4246 | if (typeof name === 'undefined') {
4247 | if (array && key.match(/^\d+$/)) {
4248 | return str;
4249 | }
4250 | name = JSON.stringify('' + key);
4251 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
4252 | name = name.substr(1, name.length - 2);
4253 | name = ctx.stylize(name, 'name');
4254 | } else {
4255 | name = name.replace(/'/g, "\\'")
4256 | .replace(/\\"/g, '"')
4257 | .replace(/(^"|"$)/g, "'");
4258 | name = ctx.stylize(name, 'string');
4259 | }
4260 | }
4261 |
4262 | return name + ': ' + str;
4263 | }
4264 |
4265 |
4266 | function reduceToSingleString(output, base, braces) {
4267 | var numLinesEst = 0;
4268 | var length = output.reduce(function(prev, cur) {
4269 | numLinesEst++;
4270 | if (cur.indexOf('\n') >= 0) numLinesEst++;
4271 | return prev + cur.length + 1;
4272 | }, 0);
4273 |
4274 | if (length > 60) {
4275 | return braces[0] +
4276 | (base === '' ? '' : base + '\n ') +
4277 | ' ' +
4278 | output.join(',\n ') +
4279 | ' ' +
4280 | braces[1];
4281 | }
4282 |
4283 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
4284 | }
4285 |
4286 | function isArray(ar) {
4287 | return Array.isArray(ar) ||
4288 | (typeof ar === 'object' && objectToString(ar) === '[object Array]');
4289 | }
4290 |
4291 | function isRegExp(re) {
4292 | return typeof re === 'object' && objectToString(re) === '[object RegExp]';
4293 | }
4294 |
4295 | function isDate(d) {
4296 | return typeof d === 'object' && objectToString(d) === '[object Date]';
4297 | }
4298 |
4299 | function isError(e) {
4300 | return typeof e === 'object' && objectToString(e) === '[object Error]';
4301 | }
4302 |
4303 | function objectToString(o) {
4304 | return Object.prototype.toString.call(o);
4305 | }
4306 |
4307 | });
4308 | require.register("chai/lib/chai/utils/objDisplay.js", function(exports, require, module){
4309 | /*!
4310 | * Chai - flag utility
4311 | * Copyright(c) 2012-2013 Jake Luer
4312 | * MIT Licensed
4313 | */
4314 |
4315 | /*!
4316 | * Module dependancies
4317 | */
4318 |
4319 | var inspect = require('./inspect');
4320 |
4321 | /**
4322 | * ### .objDisplay (object)
4323 | *
4324 | * Determines if an object or an array matches
4325 | * criteria to be inspected in-line for error
4326 | * messages or should be truncated.
4327 | *
4328 | * @param {Mixed} javascript object to inspect
4329 | * @name objDisplay
4330 | * @api public
4331 | */
4332 |
4333 | module.exports = function (obj) {
4334 | var str = inspect(obj)
4335 | , type = Object.prototype.toString.call(obj);
4336 |
4337 | if (str.length >= 40) {
4338 | if (type === '[object Function]') {
4339 | return !obj.name || obj.name === ''
4340 | ? '[Function]'
4341 | : '[Function: ' + obj.name + ']';
4342 | } else if (type === '[object Array]') {
4343 | return '[ Array(' + obj.length + ') ]';
4344 | } else if (type === '[object Object]') {
4345 | var keys = Object.keys(obj)
4346 | , kstr = keys.length > 2
4347 | ? keys.splice(0, 2).join(', ') + ', ...'
4348 | : keys.join(', ');
4349 | return '{ Object (' + kstr + ') }';
4350 | } else {
4351 | return str;
4352 | }
4353 | } else {
4354 | return str;
4355 | }
4356 | };
4357 |
4358 | });
4359 | require.register("chai/lib/chai/utils/overwriteMethod.js", function(exports, require, module){
4360 | /*!
4361 | * Chai - overwriteMethod utility
4362 | * Copyright(c) 2012-2013 Jake Luer
4363 | * MIT Licensed
4364 | */
4365 |
4366 | /**
4367 | * ### overwriteMethod (ctx, name, fn)
4368 | *
4369 | * Overwites an already existing method and provides
4370 | * access to previous function. Must return function
4371 | * to be used for name.
4372 | *
4373 | * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) {
4374 | * return function (str) {
4375 | * var obj = utils.flag(this, 'object');
4376 | * if (obj instanceof Foo) {
4377 | * new chai.Assertion(obj.value).to.equal(str);
4378 | * } else {
4379 | * _super.apply(this, arguments);
4380 | * }
4381 | * }
4382 | * });
4383 | *
4384 | * Can also be accessed directly from `chai.Assertion`.
4385 | *
4386 | * chai.Assertion.overwriteMethod('foo', fn);
4387 | *
4388 | * Then can be used as any other assertion.
4389 | *
4390 | * expect(myFoo).to.equal('bar');
4391 | *
4392 | * @param {Object} ctx object whose method is to be overwritten
4393 | * @param {String} name of method to overwrite
4394 | * @param {Function} method function that returns a function to be used for name
4395 | * @name overwriteMethod
4396 | * @api public
4397 | */
4398 |
4399 | module.exports = function (ctx, name, method) {
4400 | var _method = ctx[name]
4401 | , _super = function () { return this; };
4402 |
4403 | if (_method && 'function' === typeof _method)
4404 | _super = _method;
4405 |
4406 | ctx[name] = function () {
4407 | var result = method(_super).apply(this, arguments);
4408 | return result === undefined ? this : result;
4409 | }
4410 | };
4411 |
4412 | });
4413 | require.register("chai/lib/chai/utils/overwriteProperty.js", function(exports, require, module){
4414 | /*!
4415 | * Chai - overwriteProperty utility
4416 | * Copyright(c) 2012-2013 Jake Luer
4417 | * MIT Licensed
4418 | */
4419 |
4420 | /**
4421 | * ### overwriteProperty (ctx, name, fn)
4422 | *
4423 | * Overwites an already existing property getter and provides
4424 | * access to previous value. Must return function to use as getter.
4425 | *
4426 | * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) {
4427 | * return function () {
4428 | * var obj = utils.flag(this, 'object');
4429 | * if (obj instanceof Foo) {
4430 | * new chai.Assertion(obj.name).to.equal('bar');
4431 | * } else {
4432 | * _super.call(this);
4433 | * }
4434 | * }
4435 | * });
4436 | *
4437 | *
4438 | * Can also be accessed directly from `chai.Assertion`.
4439 | *
4440 | * chai.Assertion.overwriteProperty('foo', fn);
4441 | *
4442 | * Then can be used as any other assertion.
4443 | *
4444 | * expect(myFoo).to.be.ok;
4445 | *
4446 | * @param {Object} ctx object whose property is to be overwritten
4447 | * @param {String} name of property to overwrite
4448 | * @param {Function} getter function that returns a getter function to be used for name
4449 | * @name overwriteProperty
4450 | * @api public
4451 | */
4452 |
4453 | module.exports = function (ctx, name, getter) {
4454 | var _get = Object.getOwnPropertyDescriptor(ctx, name)
4455 | , _super = function () {};
4456 |
4457 | if (_get && 'function' === typeof _get.get)
4458 | _super = _get.get
4459 |
4460 | Object.defineProperty(ctx, name,
4461 | { get: function () {
4462 | var result = getter(_super).call(this);
4463 | return result === undefined ? this : result;
4464 | }
4465 | , configurable: true
4466 | });
4467 | };
4468 |
4469 | });
4470 | require.register("chai/lib/chai/utils/test.js", function(exports, require, module){
4471 | /*!
4472 | * Chai - test utility
4473 | * Copyright(c) 2012-2013 Jake Luer
4474 | * MIT Licensed
4475 | */
4476 |
4477 | /*!
4478 | * Module dependancies
4479 | */
4480 |
4481 | var flag = require('./flag');
4482 |
4483 | /**
4484 | * # test(object, expression)
4485 | *
4486 | * Test and object for expression.
4487 | *
4488 | * @param {Object} object (constructed Assertion)
4489 | * @param {Arguments} chai.Assertion.prototype.assert arguments
4490 | */
4491 |
4492 | module.exports = function (obj, args) {
4493 | var negate = flag(obj, 'negate')
4494 | , expr = args[0];
4495 | return negate ? !expr : expr;
4496 | };
4497 |
4498 | });
4499 | require.register("chai/lib/chai/utils/transferFlags.js", function(exports, require, module){
4500 | /*!
4501 | * Chai - transferFlags utility
4502 | * Copyright(c) 2012-2013 Jake Luer
4503 | * MIT Licensed
4504 | */
4505 |
4506 | /**
4507 | * ### transferFlags(assertion, object, includeAll = true)
4508 | *
4509 | * Transfer all the flags for `assertion` to `object`. If
4510 | * `includeAll` is set to `false`, then the base Chai
4511 | * assertion flags (namely `object`, `ssfi`, and `message`)
4512 | * will not be transferred.
4513 | *
4514 | *
4515 | * var newAssertion = new Assertion();
4516 | * utils.transferFlags(assertion, newAssertion);
4517 | *
4518 | * var anotherAsseriton = new Assertion(myObj);
4519 | * utils.transferFlags(assertion, anotherAssertion, false);
4520 | *
4521 | * @param {Assertion} assertion the assertion to transfer the flags from
4522 | * @param {Object} object the object to transfer the flags too; usually a new assertion
4523 | * @param {Boolean} includeAll
4524 | * @name getAllFlags
4525 | * @api private
4526 | */
4527 |
4528 | module.exports = function (assertion, object, includeAll) {
4529 | var flags = assertion.__flags || (assertion.__flags = Object.create(null));
4530 |
4531 | if (!object.__flags) {
4532 | object.__flags = Object.create(null);
4533 | }
4534 |
4535 | includeAll = arguments.length === 3 ? includeAll : true;
4536 |
4537 | for (var flag in flags) {
4538 | if (includeAll ||
4539 | (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) {
4540 | object.__flags[flag] = flags[flag];
4541 | }
4542 | }
4543 | };
4544 |
4545 | });
4546 | require.register("chai/lib/chai/utils/type.js", function(exports, require, module){
4547 | /*!
4548 | * Chai - type utility
4549 | * Copyright(c) 2012-2013 Jake Luer
4550 | * MIT Licensed
4551 | */
4552 |
4553 | /*!
4554 | * Detectable javascript natives
4555 | */
4556 |
4557 | var natives = {
4558 | '[object Arguments]': 'arguments'
4559 | , '[object Array]': 'array'
4560 | , '[object Date]': 'date'
4561 | , '[object Function]': 'function'
4562 | , '[object Number]': 'number'
4563 | , '[object RegExp]': 'regexp'
4564 | , '[object String]': 'string'
4565 | };
4566 |
4567 | /**
4568 | * ### type(object)
4569 | *
4570 | * Better implementation of `typeof` detection that can
4571 | * be used cross-browser. Handles the inconsistencies of
4572 | * Array, `null`, and `undefined` detection.
4573 | *
4574 | * utils.type({}) // 'object'
4575 | * utils.type(null) // `null'
4576 | * utils.type(undefined) // `undefined`
4577 | * utils.type([]) // `array`
4578 | *
4579 | * @param {Mixed} object to detect type of
4580 | * @name type
4581 | * @api private
4582 | */
4583 |
4584 | module.exports = function (obj) {
4585 | var str = Object.prototype.toString.call(obj);
4586 | if (natives[str]) return natives[str];
4587 | if (obj === null) return 'null';
4588 | if (obj === undefined) return 'undefined';
4589 | if (obj === Object(obj)) return 'object';
4590 | return typeof obj;
4591 | };
4592 |
4593 | });
4594 |
4595 |
4596 | require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js");
4597 | require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js");
4598 | require.alias("chaijs-assertion-error/index.js", "assertion-error/index.js");
4599 | require.alias("chaijs-assertion-error/index.js", "chaijs-assertion-error/index.js");
4600 | require.alias("chaijs-deep-eql/lib/eql.js", "chai/deps/deep-eql/lib/eql.js");
4601 | require.alias("chaijs-deep-eql/lib/eql.js", "chai/deps/deep-eql/index.js");
4602 | require.alias("chaijs-deep-eql/lib/eql.js", "deep-eql/index.js");
4603 | require.alias("chaijs-type-detect/lib/type.js", "chaijs-deep-eql/deps/type-detect/lib/type.js");
4604 | require.alias("chaijs-type-detect/lib/type.js", "chaijs-deep-eql/deps/type-detect/index.js");
4605 | require.alias("chaijs-type-detect/lib/type.js", "chaijs-type-detect/index.js");
4606 | require.alias("chaijs-deep-eql/lib/eql.js", "chaijs-deep-eql/index.js");
4607 | require.alias("chai/index.js", "chai/index.js");if (typeof exports == "object") {
4608 | module.exports = require("chai");
4609 | } else if (typeof define == "function" && define.amd) {
4610 | define(function(){ return require("chai"); });
4611 | } else {
4612 | this["chai"] = require("chai");
4613 | }})();
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mocha Tests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test/mocha.css:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | body {
4 | margin:0;
5 | }
6 |
7 | #mocha {
8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | margin: 60px 50px;
10 | }
11 |
12 | #mocha ul, #mocha li {
13 | margin: 0;
14 | padding: 0;
15 | }
16 |
17 | #mocha ul {
18 | list-style: none;
19 | }
20 |
21 | #mocha h1, #mocha h2 {
22 | margin: 0;
23 | }
24 |
25 | #mocha h1 {
26 | margin-top: 15px;
27 | font-size: 1em;
28 | font-weight: 200;
29 | }
30 |
31 | #mocha h1 a {
32 | text-decoration: none;
33 | color: inherit;
34 | }
35 |
36 | #mocha h1 a:hover {
37 | text-decoration: underline;
38 | }
39 |
40 | #mocha .suite .suite h1 {
41 | margin-top: 0;
42 | font-size: .8em;
43 | }
44 |
45 | #mocha .hidden {
46 | display: none;
47 | }
48 |
49 | #mocha h2 {
50 | font-size: 12px;
51 | font-weight: normal;
52 | cursor: pointer;
53 | }
54 |
55 | #mocha .suite {
56 | margin-left: 15px;
57 | }
58 |
59 | #mocha .test {
60 | margin-left: 15px;
61 | overflow: hidden;
62 | }
63 |
64 | #mocha .test.pending:hover h2::after {
65 | content: '(pending)';
66 | font-family: arial, sans-serif;
67 | }
68 |
69 | #mocha .test.pass.medium .duration {
70 | background: #C09853;
71 | }
72 |
73 | #mocha .test.pass.slow .duration {
74 | background: #B94A48;
75 | }
76 |
77 | #mocha .test.pass::before {
78 | content: '✓';
79 | font-size: 12px;
80 | display: block;
81 | float: left;
82 | margin-right: 5px;
83 | color: #00d6b2;
84 | }
85 |
86 | #mocha .test.pass .duration {
87 | font-size: 9px;
88 | margin-left: 5px;
89 | padding: 2px 5px;
90 | color: white;
91 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
92 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
93 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
94 | -webkit-border-radius: 5px;
95 | -moz-border-radius: 5px;
96 | -ms-border-radius: 5px;
97 | -o-border-radius: 5px;
98 | border-radius: 5px;
99 | }
100 |
101 | #mocha .test.pass.fast .duration {
102 | display: none;
103 | }
104 |
105 | #mocha .test.pending {
106 | color: #0b97c4;
107 | }
108 |
109 | #mocha .test.pending::before {
110 | content: '◦';
111 | color: #0b97c4;
112 | }
113 |
114 | #mocha .test.fail {
115 | color: #c00;
116 | }
117 |
118 | #mocha .test.fail pre {
119 | color: black;
120 | }
121 |
122 | #mocha .test.fail::before {
123 | content: '✖';
124 | font-size: 12px;
125 | display: block;
126 | float: left;
127 | margin-right: 5px;
128 | color: #c00;
129 | }
130 |
131 | #mocha .test pre.error {
132 | color: #c00;
133 | max-height: 300px;
134 | overflow: auto;
135 | }
136 |
137 | #mocha .test pre {
138 | display: block;
139 | float: left;
140 | clear: left;
141 | font: 12px/1.5 monaco, monospace;
142 | margin: 5px;
143 | padding: 15px;
144 | border: 1px solid #eee;
145 | border-bottom-color: #ddd;
146 | -webkit-border-radius: 3px;
147 | -webkit-box-shadow: 0 1px 3px #eee;
148 | -moz-border-radius: 3px;
149 | -moz-box-shadow: 0 1px 3px #eee;
150 | border-radius: 3px;
151 | }
152 |
153 | #mocha .test h2 {
154 | position: relative;
155 | }
156 |
157 | #mocha .test a.replay {
158 | position: absolute;
159 | top: 3px;
160 | right: 0;
161 | text-decoration: none;
162 | vertical-align: middle;
163 | display: block;
164 | width: 15px;
165 | height: 15px;
166 | line-height: 15px;
167 | text-align: center;
168 | background: #eee;
169 | font-size: 15px;
170 | -moz-border-radius: 15px;
171 | border-radius: 15px;
172 | -webkit-transition: opacity 200ms;
173 | -moz-transition: opacity 200ms;
174 | transition: opacity 200ms;
175 | opacity: 0.3;
176 | color: #888;
177 | }
178 |
179 | #mocha .test:hover a.replay {
180 | opacity: 1;
181 | }
182 |
183 | #mocha-report.pass .test.fail {
184 | display: none;
185 | }
186 |
187 | #mocha-report.fail .test.pass {
188 | display: none;
189 | }
190 |
191 | #mocha-report.pending .test.pass,
192 | #mocha-report.pending .test.fail {
193 | display: none;
194 | }
195 | #mocha-report.pending .test.pass.pending {
196 | display: block;
197 | }
198 |
199 | #mocha-error {
200 | color: #c00;
201 | font-size: 1.5em;
202 | font-weight: 100;
203 | letter-spacing: 1px;
204 | }
205 |
206 | #mocha-stats {
207 | position: fixed;
208 | top: 15px;
209 | right: 10px;
210 | font-size: 12px;
211 | margin: 0;
212 | color: #888;
213 | z-index: 1;
214 | }
215 |
216 | #mocha-stats .progress {
217 | float: right;
218 | padding-top: 0;
219 | }
220 |
221 | #mocha-stats em {
222 | color: black;
223 | }
224 |
225 | #mocha-stats a {
226 | text-decoration: none;
227 | color: inherit;
228 | }
229 |
230 | #mocha-stats a:hover {
231 | border-bottom: 1px solid #eee;
232 | }
233 |
234 | #mocha-stats li {
235 | display: inline-block;
236 | margin: 0 5px;
237 | list-style: none;
238 | padding-top: 11px;
239 | }
240 |
241 | #mocha-stats canvas {
242 | width: 40px;
243 | height: 40px;
244 | }
245 |
246 | #mocha code .comment { color: #ddd }
247 | #mocha code .init { color: #2F6FAD }
248 | #mocha code .string { color: #5890AD }
249 | #mocha code .keyword { color: #8A6343 }
250 | #mocha code .number { color: #2F6FAD }
251 |
252 | @media screen and (max-device-width: 480px) {
253 | #mocha {
254 | margin: 60px 0px;
255 | }
256 |
257 | #mocha #stats {
258 | position: absolute;
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/test/test.coffee.md:
--------------------------------------------------------------------------------
1 | setup
2 |
3 | CssToMatrix = window['css-to-matrix']
4 | expect = chai.expect
5 | div = document.getElementById 'test'
6 | precision = 100000
7 | data = [
8 | [1,2,3,4]
9 | [5,6,7,8]
10 | [9,10,11,12]
11 | [13,14,15,16]
12 | ]
13 |
14 | setup
15 |
16 | mocha.setup 'bdd'
17 |
18 | describe 'constructor', ->
19 |
20 | it 'adds data that is passed when intialized to its model', ->
21 |
22 | cssToMatrix = new CssToMatrix data
23 | actual = cssToMatrix.model.get 'matrix'
24 |
25 | expect(actual).to.deep.equal data
26 |
27 | describe 'matrix', ->
28 |
29 | it 'should add valid data to its instance model', ->
30 |
31 | cssToMatrix = new CssToMatrix
32 | cssToMatrix.matrix data
33 | actual = cssToMatrix.model.get 'matrix'
34 |
35 | expect(actual).to.deep.equal data
36 |
37 | it 'should throw an error when intialized with an invalid array', ->
38 |
39 | fn = -> new CssToMatrix 'bad'
40 |
41 | expect(fn).to.throw Error
42 |
43 | describe 'getMatrix', ->
44 |
45 | it 'should properly apply transformations', ->
46 |
47 | cssToMatrix = new CssToMatrix
48 | cssToMatrix.translate3d 10, 20, 30
49 |
50 | actual = cssToMatrix.getMatrix()
51 | expected = [
52 | [1, 0, 0, 0]
53 | [0, 1, 0, 0]
54 | [0, 0, 1, 0]
55 | [10, 20, 30, 1]
56 | ]
57 |
58 | expect(actual).to.deep.equal expected
59 |
60 | describe 'getMatrixCSS', ->
61 |
62 | it 'should convert matricies to CSS strings', ->
63 |
64 | cssToMatrix = new CssToMatrix data
65 | css = cssToMatrix.getMatrixCSS()
66 |
67 | expect(css).to.equal 'matrix3d(1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16)'
68 |
69 | run
70 |
71 | mocha.run()
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var CssToMatrix, data, div, expect, precision;
3 |
4 | CssToMatrix = window['css-to-matrix'];
5 |
6 | expect = chai.expect;
7 |
8 | div = document.getElementById('test');
9 |
10 | precision = 100000;
11 |
12 | data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
13 |
14 | mocha.setup('bdd');
15 |
16 | describe('constructor', function() {
17 | return it('adds data that is passed when intialized to its model', function() {
18 | var actual, cssToMatrix;
19 | cssToMatrix = new CssToMatrix(data);
20 | actual = cssToMatrix.model.get('matrix');
21 | return expect(actual).to.deep.equal(data);
22 | });
23 | });
24 |
25 | describe('matrix', function() {
26 | it('should add valid data to its instance model', function() {
27 | var actual, cssToMatrix;
28 | cssToMatrix = new CssToMatrix;
29 | cssToMatrix.matrix(data);
30 | actual = cssToMatrix.model.get('matrix');
31 | return expect(actual).to.deep.equal(data);
32 | });
33 | return it('should throw an error when intialized with an invalid array', function() {
34 | var fn;
35 | fn = function() {
36 | return new CssToMatrix('bad');
37 | };
38 | return expect(fn).to["throw"](Error);
39 | });
40 | });
41 |
42 | describe('getMatrix', function() {
43 | return it('should properly apply transformations', function() {
44 | var actual, cssToMatrix, expected;
45 | cssToMatrix = new CssToMatrix;
46 | cssToMatrix.translate3d(10, 20, 30);
47 | actual = cssToMatrix.getMatrix();
48 | expected = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [10, 20, 30, 1]];
49 | return expect(actual).to.deep.equal(expected);
50 | });
51 | });
52 |
53 | describe('getMatrixCSS', function() {
54 | return it('should convert matricies to CSS strings', function() {
55 | var css, cssToMatrix;
56 | cssToMatrix = new CssToMatrix(data);
57 | css = cssToMatrix.getMatrixCSS();
58 | return expect(css).to.equal('matrix3d(1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16)');
59 | });
60 | });
61 |
62 | mocha.run();
63 |
64 | }).call(this);
65 |
--------------------------------------------------------------------------------