ende 0.4.20 → 0.4.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -3
  3. data/build/build.css +111 -0
  4. data/component.json +1 -0
  5. data/lib/assets/javascripts/aura/extensions/models.js.coffee.erb +4 -13
  6. data/lib/assets/javascripts/aura/extensions/platform.js.coffee +2 -8
  7. data/lib/assets/javascripts/aura/extensions/rivets.js.coffee +21 -10
  8. data/lib/assets/javascripts/aura/extensions/states.js.coffee +25 -27
  9. data/lib/assets/javascripts/aura/extensions/widget/eventable.js.coffee +28 -23
  10. data/lib/assets/javascripts/aura/extensions/widget/lifecycleable.js.coffee +21 -34
  11. data/lib/assets/javascripts/aura/extensions/widget/napable.js.coffee +17 -13
  12. data/lib/assets/javascripts/config/load_components.js.coffee +5 -7
  13. data/lib/assets/javascripts/widgets/dialog/main.js.coffee +1 -2
  14. data/lib/assets/javascripts/widgets/list/presenter.js.coffee +5 -4
  15. data/lib/assets/javascripts/widgets/support/adapters/olark.js +1 -1
  16. data/lib/assets/javascripts/widgets/tray/main.js.coffee +16 -22
  17. data/lib/assets/javascripts/widgets/viewer/main.js.coffee +39 -102
  18. data/lib/assets/javascripts/widgets/viewer/plugins/scopable.js.coffee +7 -1
  19. data/lib/ende/version.rb +1 -1
  20. data/vendor/assets/components/ende_build.js +5732 -1047
  21. data/vendor/components/indefinido-indemma/build/development.js +2 -2
  22. data/vendor/components/indefinido-indemma/build/release.js +9 -4
  23. data/vendor/components/indefinido-indemma/build/test.js +115 -21916
  24. data/vendor/components/indefinido-indemma/component.json +0 -1
  25. data/vendor/components/indefinido-indemma/lib/record/restfulable.js +7 -2
  26. data/vendor/components/indefinido-indemma/lib/record/validatable.js +2 -2
  27. data/vendor/components/indefinido-indemma/src/lib/record/persistable.coffee +2 -0
  28. data/vendor/components/indefinido-indemma/src/lib/record/resource.coffee +3 -2
  29. data/vendor/components/indefinido-indemma/src/lib/record/restfulable.coffee +16 -4
  30. data/vendor/components/indefinido-indemma/src/lib/record/validatable.coffee +3 -3
  31. data/vendor/components/indefinido-observable/.gitignore +15 -0
  32. data/vendor/components/indefinido-observable/.ruby-gemset +1 -0
  33. data/vendor/components/indefinido-observable/.ruby-version +1 -0
  34. data/vendor/components/indefinido-observable/Gemfile +13 -0
  35. data/vendor/components/indefinido-observable/Guardfile +39 -0
  36. data/vendor/components/indefinido-observable/History.md +0 -0
  37. data/vendor/components/indefinido-observable/Readme.md +116 -0
  38. data/vendor/components/indefinido-observable/build/build.js +14798 -0
  39. data/vendor/components/indefinido-observable/build/development.js +339 -0
  40. data/vendor/components/indefinido-observable/build/release.js +14937 -0
  41. data/vendor/components/indefinido-observable/build/test.js +339 -0
  42. data/vendor/components/indefinido-observable/component.json +7 -3
  43. data/vendor/components/indefinido-observable/components/chaijs-chai/component.json +46 -0
  44. data/vendor/components/indefinido-observable/components/chaijs-chai/index.js +1 -0
  45. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/assertion.js +132 -0
  46. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/core/assertions.js +1270 -0
  47. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/error.js +60 -0
  48. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/assert.js +1060 -0
  49. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/expect.js +12 -0
  50. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/should.js +76 -0
  51. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addChainableMethod.js +94 -0
  52. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addMethod.js +37 -0
  53. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addProperty.js +40 -0
  54. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/eql.js +124 -0
  55. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/flag.js +32 -0
  56. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getActual.js +19 -0
  57. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getEnumerableProperties.js +25 -0
  58. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getMessage.js +49 -0
  59. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getName.js +20 -0
  60. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getPathValue.js +102 -0
  61. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getProperties.js +35 -0
  62. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/index.js +108 -0
  63. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/inspect.js +316 -0
  64. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/objDisplay.js +48 -0
  65. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/overwriteMethod.js +51 -0
  66. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/overwriteProperty.js +54 -0
  67. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/test.js +26 -0
  68. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/transferFlags.js +44 -0
  69. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/type.js +45 -0
  70. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai.js +79 -0
  71. data/vendor/components/indefinido-observable/components/cjohansen-sinon/sinon.js +4290 -0
  72. data/vendor/components/indefinido-observable/components/component-jquery/component.json +14 -0
  73. data/vendor/components/indefinido-observable/components/component-jquery/index.js +9601 -0
  74. data/vendor/components/indefinido-observable/components/kapit-observe-shim/component.json +11 -0
  75. data/vendor/components/indefinido-observable/components/kapit-observe-utils/component.json +13 -0
  76. data/vendor/components/indefinido-observable/karma.conf.js +92 -0
  77. data/vendor/components/indefinido-observable/lib/observable.js +9 -19
  78. data/vendor/components/indefinido-observable/spec/legacy/observable_spec.js +126 -0
  79. data/vendor/components/indefinido-observable/spec/observable_spec.js +92 -0
  80. data/vendor/components/indefinido-observable/spec/spec_helper.js +8 -0
  81. data/vendor/components/indefinido-observable/spec/vendor/accessors_spec.js +63 -0
  82. data/vendor/components/indefinido-observable/src/lib/adapters/rivets.js.coffee +15 -0
  83. data/vendor/components/indefinido-observable/src/spec/legacy/observable_spec.coffee +132 -0
  84. data/vendor/components/indefinido-observable/src/spec/observable_spec.coffee +85 -0
  85. data/vendor/components/indefinido-observable/src/spec/spec_helper.coffee +5 -0
  86. data/vendor/components/indefinido-observable/src/spec/vendor/accessors_spec.coffee +59 -0
  87. data/vendor/components/indefinido-observable/vendor/spec/boot.js +104 -0
  88. data/vendor/components/indefinido-observable/vendor/spec/jasmine.js +2054 -0
  89. metadata +60 -8
  90. data/lib/assets/javascripts/aura/extensions/domain.js.coffee +0 -55
  91. data/lib/assets/javascripts/aura/extensions/stamps.js.coffee +0 -35
  92. data/lib/assets/javascripts/aura/extensions/widget/composable.js.coffee +0 -135
  93. data/lib/assets/javascripts/aura/extensions/widget/flowable.js.coffee +0 -65
  94. data/lib/assets/javascripts/widgets/attachable/main.js.coffee +0 -77
  95. /data/{lib/assets/javascripts/aura/extensions/stamps → vendor/assets/javascripts/stampit}/stampit.js +0 -0
@@ -0,0 +1,1270 @@
1
+ /*!
2
+ * chai
3
+ * http://chaijs.com
4
+ * Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
5
+ * MIT Licensed
6
+ */
7
+
8
+ module.exports = function (chai, _) {
9
+ var Assertion = chai.Assertion
10
+ , toString = Object.prototype.toString
11
+ , flag = _.flag;
12
+
13
+ /**
14
+ * ### Language Chains
15
+ *
16
+ * The following are provide as chainable getters to
17
+ * improve the readability of your assertions. They
18
+ * do not provide an testing capability unless they
19
+ * have been overwritten by a plugin.
20
+ *
21
+ * **Chains**
22
+ *
23
+ * - to
24
+ * - be
25
+ * - been
26
+ * - is
27
+ * - that
28
+ * - and
29
+ * - have
30
+ * - with
31
+ * - at
32
+ * - of
33
+ * - same
34
+ *
35
+ * @name language chains
36
+ * @api public
37
+ */
38
+
39
+ [ 'to', 'be', 'been'
40
+ , 'is', 'and', 'have'
41
+ , 'with', 'that', 'at'
42
+ , 'of', 'same' ].forEach(function (chain) {
43
+ Assertion.addProperty(chain, function () {
44
+ return this;
45
+ });
46
+ });
47
+
48
+ /**
49
+ * ### .not
50
+ *
51
+ * Negates any of assertions following in the chain.
52
+ *
53
+ * expect(foo).to.not.equal('bar');
54
+ * expect(goodFn).to.not.throw(Error);
55
+ * expect({ foo: 'baz' }).to.have.property('foo')
56
+ * .and.not.equal('bar');
57
+ *
58
+ * @name not
59
+ * @api public
60
+ */
61
+
62
+ Assertion.addProperty('not', function () {
63
+ flag(this, 'negate', true);
64
+ });
65
+
66
+ /**
67
+ * ### .deep
68
+ *
69
+ * Sets the `deep` flag, later used by the `equal` and
70
+ * `property` assertions.
71
+ *
72
+ * expect(foo).to.deep.equal({ bar: 'baz' });
73
+ * expect({ foo: { bar: { baz: 'quux' } } })
74
+ * .to.have.deep.property('foo.bar.baz', 'quux');
75
+ *
76
+ * @name deep
77
+ * @api public
78
+ */
79
+
80
+ Assertion.addProperty('deep', function () {
81
+ flag(this, 'deep', true);
82
+ });
83
+
84
+ /**
85
+ * ### .a(type)
86
+ *
87
+ * The `a` and `an` assertions are aliases that can be
88
+ * used either as language chains or to assert a value's
89
+ * type.
90
+ *
91
+ * // typeof
92
+ * expect('test').to.be.a('string');
93
+ * expect({ foo: 'bar' }).to.be.an('object');
94
+ * expect(null).to.be.a('null');
95
+ * expect(undefined).to.be.an('undefined');
96
+ *
97
+ * // language chain
98
+ * expect(foo).to.be.an.instanceof(Foo);
99
+ *
100
+ * @name a
101
+ * @alias an
102
+ * @param {String} type
103
+ * @param {String} message _optional_
104
+ * @api public
105
+ */
106
+
107
+ function an (type, msg) {
108
+ if (msg) flag(this, 'message', msg);
109
+ type = type.toLowerCase();
110
+ var obj = flag(this, 'object')
111
+ , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';
112
+
113
+ this.assert(
114
+ type === _.type(obj)
115
+ , 'expected #{this} to be ' + article + type
116
+ , 'expected #{this} not to be ' + article + type
117
+ );
118
+ }
119
+
120
+ Assertion.addChainableMethod('an', an);
121
+ Assertion.addChainableMethod('a', an);
122
+
123
+ /**
124
+ * ### .include(value)
125
+ *
126
+ * The `include` and `contain` assertions can be used as either property
127
+ * based language chains or as methods to assert the inclusion of an object
128
+ * in an array or a substring in a string. When used as language chains,
129
+ * they toggle the `contain` flag for the `keys` assertion.
130
+ *
131
+ * expect([1,2,3]).to.include(2);
132
+ * expect('foobar').to.contain('foo');
133
+ * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
134
+ *
135
+ * @name include
136
+ * @alias contain
137
+ * @param {Object|String|Number} obj
138
+ * @param {String} message _optional_
139
+ * @api public
140
+ */
141
+
142
+ function includeChainingBehavior () {
143
+ flag(this, 'contains', true);
144
+ }
145
+
146
+ function include (val, msg) {
147
+ if (msg) flag(this, 'message', msg);
148
+ var obj = flag(this, 'object')
149
+ this.assert(
150
+ ~obj.indexOf(val)
151
+ , 'expected #{this} to include ' + _.inspect(val)
152
+ , 'expected #{this} to not include ' + _.inspect(val));
153
+ }
154
+
155
+ Assertion.addChainableMethod('include', include, includeChainingBehavior);
156
+ Assertion.addChainableMethod('contain', include, includeChainingBehavior);
157
+
158
+ /**
159
+ * ### .ok
160
+ *
161
+ * Asserts that the target is truthy.
162
+ *
163
+ * expect('everthing').to.be.ok;
164
+ * expect(1).to.be.ok;
165
+ * expect(false).to.not.be.ok;
166
+ * expect(undefined).to.not.be.ok;
167
+ * expect(null).to.not.be.ok;
168
+ *
169
+ * @name ok
170
+ * @api public
171
+ */
172
+
173
+ Assertion.addProperty('ok', function () {
174
+ this.assert(
175
+ flag(this, 'object')
176
+ , 'expected #{this} to be truthy'
177
+ , 'expected #{this} to be falsy');
178
+ });
179
+
180
+ /**
181
+ * ### .true
182
+ *
183
+ * Asserts that the target is `true`.
184
+ *
185
+ * expect(true).to.be.true;
186
+ * expect(1).to.not.be.true;
187
+ *
188
+ * @name true
189
+ * @api public
190
+ */
191
+
192
+ Assertion.addProperty('true', function () {
193
+ this.assert(
194
+ true === flag(this, 'object')
195
+ , 'expected #{this} to be true'
196
+ , 'expected #{this} to be false'
197
+ , this.negate ? false : true
198
+ );
199
+ });
200
+
201
+ /**
202
+ * ### .false
203
+ *
204
+ * Asserts that the target is `false`.
205
+ *
206
+ * expect(false).to.be.false;
207
+ * expect(0).to.not.be.false;
208
+ *
209
+ * @name false
210
+ * @api public
211
+ */
212
+
213
+ Assertion.addProperty('false', function () {
214
+ this.assert(
215
+ false === flag(this, 'object')
216
+ , 'expected #{this} to be false'
217
+ , 'expected #{this} to be true'
218
+ , this.negate ? true : false
219
+ );
220
+ });
221
+
222
+ /**
223
+ * ### .null
224
+ *
225
+ * Asserts that the target is `null`.
226
+ *
227
+ * expect(null).to.be.null;
228
+ * expect(undefined).not.to.be.null;
229
+ *
230
+ * @name null
231
+ * @api public
232
+ */
233
+
234
+ Assertion.addProperty('null', function () {
235
+ this.assert(
236
+ null === flag(this, 'object')
237
+ , 'expected #{this} to be null'
238
+ , 'expected #{this} not to be null'
239
+ );
240
+ });
241
+
242
+ /**
243
+ * ### .undefined
244
+ *
245
+ * Asserts that the target is `undefined`.
246
+ *
247
+ * expect(undefined).to.be.undefined;
248
+ * expect(null).to.not.be.undefined;
249
+ *
250
+ * @name undefined
251
+ * @api public
252
+ */
253
+
254
+ Assertion.addProperty('undefined', function () {
255
+ this.assert(
256
+ undefined === flag(this, 'object')
257
+ , 'expected #{this} to be undefined'
258
+ , 'expected #{this} not to be undefined'
259
+ );
260
+ });
261
+
262
+ /**
263
+ * ### .exist
264
+ *
265
+ * Asserts that the target is neither `null` nor `undefined`.
266
+ *
267
+ * var foo = 'hi'
268
+ * , bar = null
269
+ * , baz;
270
+ *
271
+ * expect(foo).to.exist;
272
+ * expect(bar).to.not.exist;
273
+ * expect(baz).to.not.exist;
274
+ *
275
+ * @name exist
276
+ * @api public
277
+ */
278
+
279
+ Assertion.addProperty('exist', function () {
280
+ this.assert(
281
+ null != flag(this, 'object')
282
+ , 'expected #{this} to exist'
283
+ , 'expected #{this} to not exist'
284
+ );
285
+ });
286
+
287
+
288
+ /**
289
+ * ### .empty
290
+ *
291
+ * Asserts that the target's length is `0`. For arrays, it checks
292
+ * the `length` property. For objects, it gets the count of
293
+ * enumerable keys.
294
+ *
295
+ * expect([]).to.be.empty;
296
+ * expect('').to.be.empty;
297
+ * expect({}).to.be.empty;
298
+ *
299
+ * @name empty
300
+ * @api public
301
+ */
302
+
303
+ Assertion.addProperty('empty', function () {
304
+ var obj = flag(this, 'object')
305
+ , expected = obj;
306
+
307
+ if (Array.isArray(obj) || 'string' === typeof object) {
308
+ expected = obj.length;
309
+ } else if (typeof obj === 'object') {
310
+ expected = Object.keys(obj).length;
311
+ }
312
+
313
+ this.assert(
314
+ !expected
315
+ , 'expected #{this} to be empty'
316
+ , 'expected #{this} not to be empty'
317
+ );
318
+ });
319
+
320
+ /**
321
+ * ### .arguments
322
+ *
323
+ * Asserts that the target is an arguments object.
324
+ *
325
+ * function test () {
326
+ * expect(arguments).to.be.arguments;
327
+ * }
328
+ *
329
+ * @name arguments
330
+ * @alias Arguments
331
+ * @api public
332
+ */
333
+
334
+ function checkArguments () {
335
+ var obj = flag(this, 'object')
336
+ , type = Object.prototype.toString.call(obj);
337
+ this.assert(
338
+ '[object Arguments]' === type
339
+ , 'expected #{this} to be arguments but got ' + type
340
+ , 'expected #{this} to not be arguments'
341
+ );
342
+ }
343
+
344
+ Assertion.addProperty('arguments', checkArguments);
345
+ Assertion.addProperty('Arguments', checkArguments);
346
+
347
+ /**
348
+ * ### .equal(value)
349
+ *
350
+ * Asserts that the target is strictly equal (`===`) to `value`.
351
+ * Alternately, if the `deep` flag is set, asserts that
352
+ * the target is deeply equal to `value`.
353
+ *
354
+ * expect('hello').to.equal('hello');
355
+ * expect(42).to.equal(42);
356
+ * expect(1).to.not.equal(true);
357
+ * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
358
+ * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
359
+ *
360
+ * @name equal
361
+ * @alias equals
362
+ * @alias eq
363
+ * @alias deep.equal
364
+ * @param {Mixed} value
365
+ * @param {String} message _optional_
366
+ * @api public
367
+ */
368
+
369
+ function assertEqual (val, msg) {
370
+ if (msg) flag(this, 'message', msg);
371
+ var obj = flag(this, 'object');
372
+ if (flag(this, 'deep')) {
373
+ return this.eql(val);
374
+ } else {
375
+ this.assert(
376
+ val === obj
377
+ , 'expected #{this} to equal #{exp}'
378
+ , 'expected #{this} to not equal #{exp}'
379
+ , val
380
+ , this._obj
381
+ , true
382
+ );
383
+ }
384
+ }
385
+
386
+ Assertion.addMethod('equal', assertEqual);
387
+ Assertion.addMethod('equals', assertEqual);
388
+ Assertion.addMethod('eq', assertEqual);
389
+
390
+ /**
391
+ * ### .eql(value)
392
+ *
393
+ * Asserts that the target is deeply equal to `value`.
394
+ *
395
+ * expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
396
+ * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
397
+ *
398
+ * @name eql
399
+ * @alias eqls
400
+ * @param {Mixed} value
401
+ * @param {String} message _optional_
402
+ * @api public
403
+ */
404
+
405
+ function assertEql(obj, msg) {
406
+ if (msg) flag(this, 'message', msg);
407
+ this.assert(
408
+ _.eql(obj, flag(this, 'object'))
409
+ , 'expected #{this} to deeply equal #{exp}'
410
+ , 'expected #{this} to not deeply equal #{exp}'
411
+ , obj
412
+ , this._obj
413
+ , true
414
+ );
415
+ }
416
+
417
+ Assertion.addMethod('eql', assertEql);
418
+ Assertion.addMethod('eqls', assertEql);
419
+
420
+ /**
421
+ * ### .above(value)
422
+ *
423
+ * Asserts that the target is greater than `value`.
424
+ *
425
+ * expect(10).to.be.above(5);
426
+ *
427
+ * Can also be used in conjunction with `length` to
428
+ * assert a minimum length. The benefit being a
429
+ * more informative error message than if the length
430
+ * was supplied directly.
431
+ *
432
+ * expect('foo').to.have.length.above(2);
433
+ * expect([ 1, 2, 3 ]).to.have.length.above(2);
434
+ *
435
+ * @name above
436
+ * @alias gt
437
+ * @alias greaterThan
438
+ * @param {Number} value
439
+ * @param {String} message _optional_
440
+ * @api public
441
+ */
442
+
443
+ function assertAbove (n, msg) {
444
+ if (msg) flag(this, 'message', msg);
445
+ var obj = flag(this, 'object');
446
+ if (flag(this, 'doLength')) {
447
+ new Assertion(obj, msg).to.have.property('length');
448
+ var len = obj.length;
449
+ this.assert(
450
+ len > n
451
+ , 'expected #{this} to have a length above #{exp} but got #{act}'
452
+ , 'expected #{this} to not have a length above #{exp}'
453
+ , n
454
+ , len
455
+ );
456
+ } else {
457
+ this.assert(
458
+ obj > n
459
+ , 'expected #{this} to be above ' + n
460
+ , 'expected #{this} to be at most ' + n
461
+ );
462
+ }
463
+ }
464
+
465
+ Assertion.addMethod('above', assertAbove);
466
+ Assertion.addMethod('gt', assertAbove);
467
+ Assertion.addMethod('greaterThan', assertAbove);
468
+
469
+ /**
470
+ * ### .least(value)
471
+ *
472
+ * Asserts that the target is greater than or equal to `value`.
473
+ *
474
+ * expect(10).to.be.at.least(10);
475
+ *
476
+ * Can also be used in conjunction with `length` to
477
+ * assert a minimum length. The benefit being a
478
+ * more informative error message than if the length
479
+ * was supplied directly.
480
+ *
481
+ * expect('foo').to.have.length.of.at.least(2);
482
+ * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);
483
+ *
484
+ * @name least
485
+ * @alias gte
486
+ * @param {Number} value
487
+ * @param {String} message _optional_
488
+ * @api public
489
+ */
490
+
491
+ function assertLeast (n, msg) {
492
+ if (msg) flag(this, 'message', msg);
493
+ var obj = flag(this, 'object');
494
+ if (flag(this, 'doLength')) {
495
+ new Assertion(obj, msg).to.have.property('length');
496
+ var len = obj.length;
497
+ this.assert(
498
+ len >= n
499
+ , 'expected #{this} to have a length at least #{exp} but got #{act}'
500
+ , 'expected #{this} to have a length below #{exp}'
501
+ , n
502
+ , len
503
+ );
504
+ } else {
505
+ this.assert(
506
+ obj >= n
507
+ , 'expected #{this} to be at least ' + n
508
+ , 'expected #{this} to be below ' + n
509
+ );
510
+ }
511
+ }
512
+
513
+ Assertion.addMethod('least', assertLeast);
514
+ Assertion.addMethod('gte', assertLeast);
515
+
516
+ /**
517
+ * ### .below(value)
518
+ *
519
+ * Asserts that the target is less than `value`.
520
+ *
521
+ * expect(5).to.be.below(10);
522
+ *
523
+ * Can also be used in conjunction with `length` to
524
+ * assert a maximum length. The benefit being a
525
+ * more informative error message than if the length
526
+ * was supplied directly.
527
+ *
528
+ * expect('foo').to.have.length.below(4);
529
+ * expect([ 1, 2, 3 ]).to.have.length.below(4);
530
+ *
531
+ * @name below
532
+ * @alias lt
533
+ * @alias lessThan
534
+ * @param {Number} value
535
+ * @param {String} message _optional_
536
+ * @api public
537
+ */
538
+
539
+ function assertBelow (n, msg) {
540
+ if (msg) flag(this, 'message', msg);
541
+ var obj = flag(this, 'object');
542
+ if (flag(this, 'doLength')) {
543
+ new Assertion(obj, msg).to.have.property('length');
544
+ var len = obj.length;
545
+ this.assert(
546
+ len < n
547
+ , 'expected #{this} to have a length below #{exp} but got #{act}'
548
+ , 'expected #{this} to not have a length below #{exp}'
549
+ , n
550
+ , len
551
+ );
552
+ } else {
553
+ this.assert(
554
+ obj < n
555
+ , 'expected #{this} to be below ' + n
556
+ , 'expected #{this} to be at least ' + n
557
+ );
558
+ }
559
+ }
560
+
561
+ Assertion.addMethod('below', assertBelow);
562
+ Assertion.addMethod('lt', assertBelow);
563
+ Assertion.addMethod('lessThan', assertBelow);
564
+
565
+ /**
566
+ * ### .most(value)
567
+ *
568
+ * Asserts that the target is less than or equal to `value`.
569
+ *
570
+ * expect(5).to.be.at.most(5);
571
+ *
572
+ * Can also be used in conjunction with `length` to
573
+ * assert a maximum length. The benefit being a
574
+ * more informative error message than if the length
575
+ * was supplied directly.
576
+ *
577
+ * expect('foo').to.have.length.of.at.most(4);
578
+ * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);
579
+ *
580
+ * @name most
581
+ * @alias lte
582
+ * @param {Number} value
583
+ * @param {String} message _optional_
584
+ * @api public
585
+ */
586
+
587
+ function assertMost (n, msg) {
588
+ if (msg) flag(this, 'message', msg);
589
+ var obj = flag(this, 'object');
590
+ if (flag(this, 'doLength')) {
591
+ new Assertion(obj, msg).to.have.property('length');
592
+ var len = obj.length;
593
+ this.assert(
594
+ len <= n
595
+ , 'expected #{this} to have a length at most #{exp} but got #{act}'
596
+ , 'expected #{this} to have a length above #{exp}'
597
+ , n
598
+ , len
599
+ );
600
+ } else {
601
+ this.assert(
602
+ obj <= n
603
+ , 'expected #{this} to be at most ' + n
604
+ , 'expected #{this} to be above ' + n
605
+ );
606
+ }
607
+ }
608
+
609
+ Assertion.addMethod('most', assertMost);
610
+ Assertion.addMethod('lte', assertMost);
611
+
612
+ /**
613
+ * ### .within(start, finish)
614
+ *
615
+ * Asserts that the target is within a range.
616
+ *
617
+ * expect(7).to.be.within(5,10);
618
+ *
619
+ * Can also be used in conjunction with `length` to
620
+ * assert a length range. The benefit being a
621
+ * more informative error message than if the length
622
+ * was supplied directly.
623
+ *
624
+ * expect('foo').to.have.length.within(2,4);
625
+ * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
626
+ *
627
+ * @name within
628
+ * @param {Number} start lowerbound inclusive
629
+ * @param {Number} finish upperbound inclusive
630
+ * @param {String} message _optional_
631
+ * @api public
632
+ */
633
+
634
+ Assertion.addMethod('within', function (start, finish, msg) {
635
+ if (msg) flag(this, 'message', msg);
636
+ var obj = flag(this, 'object')
637
+ , range = start + '..' + finish;
638
+ if (flag(this, 'doLength')) {
639
+ new Assertion(obj, msg).to.have.property('length');
640
+ var len = obj.length;
641
+ this.assert(
642
+ len >= start && len <= finish
643
+ , 'expected #{this} to have a length within ' + range
644
+ , 'expected #{this} to not have a length within ' + range
645
+ );
646
+ } else {
647
+ this.assert(
648
+ obj >= start && obj <= finish
649
+ , 'expected #{this} to be within ' + range
650
+ , 'expected #{this} to not be within ' + range
651
+ );
652
+ }
653
+ });
654
+
655
+ /**
656
+ * ### .instanceof(constructor)
657
+ *
658
+ * Asserts that the target is an instance of `constructor`.
659
+ *
660
+ * var Tea = function (name) { this.name = name; }
661
+ * , Chai = new Tea('chai');
662
+ *
663
+ * expect(Chai).to.be.an.instanceof(Tea);
664
+ * expect([ 1, 2, 3 ]).to.be.instanceof(Array);
665
+ *
666
+ * @name instanceof
667
+ * @param {Constructor} constructor
668
+ * @param {String} message _optional_
669
+ * @alias instanceOf
670
+ * @api public
671
+ */
672
+
673
+ function assertInstanceOf (constructor, msg) {
674
+ if (msg) flag(this, 'message', msg);
675
+ var name = _.getName(constructor);
676
+ this.assert(
677
+ flag(this, 'object') instanceof constructor
678
+ , 'expected #{this} to be an instance of ' + name
679
+ , 'expected #{this} to not be an instance of ' + name
680
+ );
681
+ };
682
+
683
+ Assertion.addMethod('instanceof', assertInstanceOf);
684
+ Assertion.addMethod('instanceOf', assertInstanceOf);
685
+
686
+ /**
687
+ * ### .property(name, [value])
688
+ *
689
+ * Asserts that the target has a property `name`, optionally asserting that
690
+ * the value of that property is strictly equal to `value`.
691
+ * If the `deep` flag is set, you can use dot- and bracket-notation for deep
692
+ * references into objects and arrays.
693
+ *
694
+ * // simple referencing
695
+ * var obj = { foo: 'bar' };
696
+ * expect(obj).to.have.property('foo');
697
+ * expect(obj).to.have.property('foo', 'bar');
698
+ *
699
+ * // deep referencing
700
+ * var deepObj = {
701
+ * green: { tea: 'matcha' }
702
+ * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
703
+ * };
704
+
705
+ * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
706
+ * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
707
+ * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
708
+ *
709
+ * You can also use an array as the starting point of a `deep.property`
710
+ * assertion, or traverse nested arrays.
711
+ *
712
+ * var arr = [
713
+ * [ 'chai', 'matcha', 'konacha' ]
714
+ * , [ { tea: 'chai' }
715
+ * , { tea: 'matcha' }
716
+ * , { tea: 'konacha' } ]
717
+ * ];
718
+ *
719
+ * expect(arr).to.have.deep.property('[0][1]', 'matcha');
720
+ * expect(arr).to.have.deep.property('[1][2].tea', 'konacha');
721
+ *
722
+ * Furthermore, `property` changes the subject of the assertion
723
+ * to be the value of that property from the original object. This
724
+ * permits for further chainable assertions on that property.
725
+ *
726
+ * expect(obj).to.have.property('foo')
727
+ * .that.is.a('string');
728
+ * expect(deepObj).to.have.property('green')
729
+ * .that.is.an('object')
730
+ * .that.deep.equals({ tea: 'matcha' });
731
+ * expect(deepObj).to.have.property('teas')
732
+ * .that.is.an('array')
733
+ * .with.deep.property('[2]')
734
+ * .that.deep.equals({ tea: 'konacha' });
735
+ *
736
+ * @name property
737
+ * @alias deep.property
738
+ * @param {String} name
739
+ * @param {Mixed} value (optional)
740
+ * @param {String} message _optional_
741
+ * @returns value of property for chaining
742
+ * @api public
743
+ */
744
+
745
+ Assertion.addMethod('property', function (name, val, msg) {
746
+ if (msg) flag(this, 'message', msg);
747
+
748
+ var descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
749
+ , negate = flag(this, 'negate')
750
+ , obj = flag(this, 'object')
751
+ , value = flag(this, 'deep')
752
+ ? _.getPathValue(name, obj)
753
+ : obj[name];
754
+
755
+ if (negate && undefined !== val) {
756
+ if (undefined === value) {
757
+ msg = (msg != null) ? msg + ': ' : '';
758
+ throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name));
759
+ }
760
+ } else {
761
+ this.assert(
762
+ undefined !== value
763
+ , 'expected #{this} to have a ' + descriptor + _.inspect(name)
764
+ , 'expected #{this} to not have ' + descriptor + _.inspect(name));
765
+ }
766
+
767
+ if (undefined !== val) {
768
+ this.assert(
769
+ val === value
770
+ , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
771
+ , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'
772
+ , val
773
+ , value
774
+ );
775
+ }
776
+
777
+ flag(this, 'object', value);
778
+ });
779
+
780
+
781
+ /**
782
+ * ### .ownProperty(name)
783
+ *
784
+ * Asserts that the target has an own property `name`.
785
+ *
786
+ * expect('test').to.have.ownProperty('length');
787
+ *
788
+ * @name ownProperty
789
+ * @alias haveOwnProperty
790
+ * @param {String} name
791
+ * @param {String} message _optional_
792
+ * @api public
793
+ */
794
+
795
+ function assertOwnProperty (name, msg) {
796
+ if (msg) flag(this, 'message', msg);
797
+ var obj = flag(this, 'object');
798
+ this.assert(
799
+ obj.hasOwnProperty(name)
800
+ , 'expected #{this} to have own property ' + _.inspect(name)
801
+ , 'expected #{this} to not have own property ' + _.inspect(name)
802
+ );
803
+ }
804
+
805
+ Assertion.addMethod('ownProperty', assertOwnProperty);
806
+ Assertion.addMethod('haveOwnProperty', assertOwnProperty);
807
+
808
+ /**
809
+ * ### .length(value)
810
+ *
811
+ * Asserts that the target's `length` property has
812
+ * the expected value.
813
+ *
814
+ * expect([ 1, 2, 3]).to.have.length(3);
815
+ * expect('foobar').to.have.length(6);
816
+ *
817
+ * Can also be used as a chain precursor to a value
818
+ * comparison for the length property.
819
+ *
820
+ * expect('foo').to.have.length.above(2);
821
+ * expect([ 1, 2, 3 ]).to.have.length.above(2);
822
+ * expect('foo').to.have.length.below(4);
823
+ * expect([ 1, 2, 3 ]).to.have.length.below(4);
824
+ * expect('foo').to.have.length.within(2,4);
825
+ * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
826
+ *
827
+ * @name length
828
+ * @alias lengthOf
829
+ * @param {Number} length
830
+ * @param {String} message _optional_
831
+ * @api public
832
+ */
833
+
834
+ function assertLengthChain () {
835
+ flag(this, 'doLength', true);
836
+ }
837
+
838
+ function assertLength (n, msg) {
839
+ if (msg) flag(this, 'message', msg);
840
+ var obj = flag(this, 'object');
841
+ new Assertion(obj, msg).to.have.property('length');
842
+ var len = obj.length;
843
+
844
+ this.assert(
845
+ len == n
846
+ , 'expected #{this} to have a length of #{exp} but got #{act}'
847
+ , 'expected #{this} to not have a length of #{act}'
848
+ , n
849
+ , len
850
+ );
851
+ }
852
+
853
+ Assertion.addChainableMethod('length', assertLength, assertLengthChain);
854
+ Assertion.addMethod('lengthOf', assertLength, assertLengthChain);
855
+
856
+ /**
857
+ * ### .match(regexp)
858
+ *
859
+ * Asserts that the target matches a regular expression.
860
+ *
861
+ * expect('foobar').to.match(/^foo/);
862
+ *
863
+ * @name match
864
+ * @param {RegExp} RegularExpression
865
+ * @param {String} message _optional_
866
+ * @api public
867
+ */
868
+
869
+ Assertion.addMethod('match', function (re, msg) {
870
+ if (msg) flag(this, 'message', msg);
871
+ var obj = flag(this, 'object');
872
+ this.assert(
873
+ re.exec(obj)
874
+ , 'expected #{this} to match ' + re
875
+ , 'expected #{this} not to match ' + re
876
+ );
877
+ });
878
+
879
+ /**
880
+ * ### .string(string)
881
+ *
882
+ * Asserts that the string target contains another string.
883
+ *
884
+ * expect('foobar').to.have.string('bar');
885
+ *
886
+ * @name string
887
+ * @param {String} string
888
+ * @param {String} message _optional_
889
+ * @api public
890
+ */
891
+
892
+ Assertion.addMethod('string', function (str, msg) {
893
+ if (msg) flag(this, 'message', msg);
894
+ var obj = flag(this, 'object');
895
+ new Assertion(obj, msg).is.a('string');
896
+
897
+ this.assert(
898
+ ~obj.indexOf(str)
899
+ , 'expected #{this} to contain ' + _.inspect(str)
900
+ , 'expected #{this} to not contain ' + _.inspect(str)
901
+ );
902
+ });
903
+
904
+
905
+ /**
906
+ * ### .keys(key1, [key2], [...])
907
+ *
908
+ * Asserts that the target has exactly the given keys, or
909
+ * asserts the inclusion of some keys when using the
910
+ * `include` or `contain` modifiers.
911
+ *
912
+ * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
913
+ * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
914
+ *
915
+ * @name keys
916
+ * @alias key
917
+ * @param {String...|Array} keys
918
+ * @api public
919
+ */
920
+
921
+ function assertKeys (keys) {
922
+ var obj = flag(this, 'object')
923
+ , str
924
+ , ok = true;
925
+
926
+ keys = keys instanceof Array
927
+ ? keys
928
+ : Array.prototype.slice.call(arguments);
929
+
930
+ if (!keys.length) throw new Error('keys required');
931
+
932
+ var actual = Object.keys(obj)
933
+ , len = keys.length;
934
+
935
+ // Inclusion
936
+ ok = keys.every(function(key){
937
+ return ~actual.indexOf(key);
938
+ });
939
+
940
+ // Strict
941
+ if (!flag(this, 'negate') && !flag(this, 'contains')) {
942
+ ok = ok && keys.length == actual.length;
943
+ }
944
+
945
+ // Key string
946
+ if (len > 1) {
947
+ keys = keys.map(function(key){
948
+ return _.inspect(key);
949
+ });
950
+ var last = keys.pop();
951
+ str = keys.join(', ') + ', and ' + last;
952
+ } else {
953
+ str = _.inspect(keys[0]);
954
+ }
955
+
956
+ // Form
957
+ str = (len > 1 ? 'keys ' : 'key ') + str;
958
+
959
+ // Have / include
960
+ str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
961
+
962
+ // Assertion
963
+ this.assert(
964
+ ok
965
+ , 'expected #{this} to ' + str
966
+ , 'expected #{this} to not ' + str
967
+ );
968
+ }
969
+
970
+ Assertion.addMethod('keys', assertKeys);
971
+ Assertion.addMethod('key', assertKeys);
972
+
973
+ /**
974
+ * ### .throw(constructor)
975
+ *
976
+ * Asserts that the function target will throw a specific error, or specific type of error
977
+ * (as determined using `instanceof`), optionally with a RegExp or string inclusion test
978
+ * for the error's message.
979
+ *
980
+ * var err = new ReferenceError('This is a bad function.');
981
+ * var fn = function () { throw err; }
982
+ * expect(fn).to.throw(ReferenceError);
983
+ * expect(fn).to.throw(Error);
984
+ * expect(fn).to.throw(/bad function/);
985
+ * expect(fn).to.not.throw('good function');
986
+ * expect(fn).to.throw(ReferenceError, /bad function/);
987
+ * expect(fn).to.throw(err);
988
+ * expect(fn).to.not.throw(new RangeError('Out of range.'));
989
+ *
990
+ * Please note that when a throw expectation is negated, it will check each
991
+ * parameter independently, starting with error constructor type. The appropriate way
992
+ * to check for the existence of a type of error but for a message that does not match
993
+ * is to use `and`.
994
+ *
995
+ * expect(fn).to.throw(ReferenceError)
996
+ * .and.not.throw(/good function/);
997
+ *
998
+ * @name throw
999
+ * @alias throws
1000
+ * @alias Throw
1001
+ * @param {ErrorConstructor} constructor
1002
+ * @param {String|RegExp} expected error message
1003
+ * @param {String} message _optional_
1004
+ * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
1005
+ * @api public
1006
+ */
1007
+
1008
+ function assertThrows (constructor, errMsg, msg) {
1009
+ if (msg) flag(this, 'message', msg);
1010
+ var obj = flag(this, 'object');
1011
+ new Assertion(obj, msg).is.a('function');
1012
+
1013
+ var thrown = false
1014
+ , desiredError = null
1015
+ , name = null
1016
+ , thrownError = null;
1017
+
1018
+ if (arguments.length === 0) {
1019
+ errMsg = null;
1020
+ constructor = null;
1021
+ } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
1022
+ errMsg = constructor;
1023
+ constructor = null;
1024
+ } else if (constructor && constructor instanceof Error) {
1025
+ desiredError = constructor;
1026
+ constructor = null;
1027
+ errMsg = null;
1028
+ } else if (typeof constructor === 'function') {
1029
+ name = (new constructor()).name;
1030
+ } else {
1031
+ constructor = null;
1032
+ }
1033
+
1034
+ try {
1035
+ obj();
1036
+ } catch (err) {
1037
+ // first, check desired error
1038
+ if (desiredError) {
1039
+ this.assert(
1040
+ err === desiredError
1041
+ , 'expected #{this} to throw #{exp} but #{act} was thrown'
1042
+ , 'expected #{this} to not throw #{exp}'
1043
+ , desiredError
1044
+ , err
1045
+ );
1046
+
1047
+ return this;
1048
+ }
1049
+ // next, check constructor
1050
+ if (constructor) {
1051
+ this.assert(
1052
+ err instanceof constructor
1053
+ , 'expected #{this} to throw #{exp} but #{act} was thrown'
1054
+ , 'expected #{this} to not throw #{exp} but #{act} was thrown'
1055
+ , name
1056
+ , err
1057
+ );
1058
+
1059
+ if (!errMsg) return this;
1060
+ }
1061
+ // next, check message
1062
+ var message = 'object' === _.type(err) && "message" in err
1063
+ ? err.message
1064
+ : '' + err;
1065
+
1066
+ if ((message != null) && errMsg && errMsg instanceof RegExp) {
1067
+ this.assert(
1068
+ errMsg.exec(message)
1069
+ , 'expected #{this} to throw error matching #{exp} but got #{act}'
1070
+ , 'expected #{this} to throw error not matching #{exp}'
1071
+ , errMsg
1072
+ , message
1073
+ );
1074
+
1075
+ return this;
1076
+ } else if ((message != null) && errMsg && 'string' === typeof errMsg) {
1077
+ this.assert(
1078
+ ~message.indexOf(errMsg)
1079
+ , 'expected #{this} to throw error including #{exp} but got #{act}'
1080
+ , 'expected #{this} to throw error not including #{act}'
1081
+ , errMsg
1082
+ , message
1083
+ );
1084
+
1085
+ return this;
1086
+ } else {
1087
+ thrown = true;
1088
+ thrownError = err;
1089
+ }
1090
+ }
1091
+
1092
+ var actuallyGot = ''
1093
+ , expectedThrown = name !== null
1094
+ ? name
1095
+ : desiredError
1096
+ ? '#{exp}' //_.inspect(desiredError)
1097
+ : 'an error';
1098
+
1099
+ if (thrown) {
1100
+ actuallyGot = ' but #{act} was thrown'
1101
+ }
1102
+
1103
+ this.assert(
1104
+ thrown === true
1105
+ , 'expected #{this} to throw ' + expectedThrown + actuallyGot
1106
+ , 'expected #{this} to not throw ' + expectedThrown + actuallyGot
1107
+ , desiredError
1108
+ , thrownError
1109
+ );
1110
+ };
1111
+
1112
+ Assertion.addMethod('throw', assertThrows);
1113
+ Assertion.addMethod('throws', assertThrows);
1114
+ Assertion.addMethod('Throw', assertThrows);
1115
+
1116
+ /**
1117
+ * ### .respondTo(method)
1118
+ *
1119
+ * Asserts that the object or class target will respond to a method.
1120
+ *
1121
+ * Klass.prototype.bar = function(){};
1122
+ * expect(Klass).to.respondTo('bar');
1123
+ * expect(obj).to.respondTo('bar');
1124
+ *
1125
+ * To check if a constructor will respond to a static function,
1126
+ * set the `itself` flag.
1127
+ *
1128
+ * Klass.baz = function(){};
1129
+ * expect(Klass).itself.to.respondTo('baz');
1130
+ *
1131
+ * @name respondTo
1132
+ * @param {String} method
1133
+ * @param {String} message _optional_
1134
+ * @api public
1135
+ */
1136
+
1137
+ Assertion.addMethod('respondTo', function (method, msg) {
1138
+ if (msg) flag(this, 'message', msg);
1139
+ var obj = flag(this, 'object')
1140
+ , itself = flag(this, 'itself')
1141
+ , context = ('function' === _.type(obj) && !itself)
1142
+ ? obj.prototype[method]
1143
+ : obj[method];
1144
+
1145
+ this.assert(
1146
+ 'function' === typeof context
1147
+ , 'expected #{this} to respond to ' + _.inspect(method)
1148
+ , 'expected #{this} to not respond to ' + _.inspect(method)
1149
+ );
1150
+ });
1151
+
1152
+ /**
1153
+ * ### .itself
1154
+ *
1155
+ * Sets the `itself` flag, later used by the `respondTo` assertion.
1156
+ *
1157
+ * function Foo() {}
1158
+ * Foo.bar = function() {}
1159
+ * Foo.prototype.baz = function() {}
1160
+ *
1161
+ * expect(Foo).itself.to.respondTo('bar');
1162
+ * expect(Foo).itself.not.to.respondTo('baz');
1163
+ *
1164
+ * @name itself
1165
+ * @api public
1166
+ */
1167
+
1168
+ Assertion.addProperty('itself', function () {
1169
+ flag(this, 'itself', true);
1170
+ });
1171
+
1172
+ /**
1173
+ * ### .satisfy(method)
1174
+ *
1175
+ * Asserts that the target passes a given truth test.
1176
+ *
1177
+ * expect(1).to.satisfy(function(num) { return num > 0; });
1178
+ *
1179
+ * @name satisfy
1180
+ * @param {Function} matcher
1181
+ * @param {String} message _optional_
1182
+ * @api public
1183
+ */
1184
+
1185
+ Assertion.addMethod('satisfy', function (matcher, msg) {
1186
+ if (msg) flag(this, 'message', msg);
1187
+ var obj = flag(this, 'object');
1188
+ this.assert(
1189
+ matcher(obj)
1190
+ , 'expected #{this} to satisfy ' + _.objDisplay(matcher)
1191
+ , 'expected #{this} to not satisfy' + _.objDisplay(matcher)
1192
+ , this.negate ? false : true
1193
+ , matcher(obj)
1194
+ );
1195
+ });
1196
+
1197
+ /**
1198
+ * ### .closeTo(expected, delta)
1199
+ *
1200
+ * Asserts that the target is equal `expected`, to within a +/- `delta` range.
1201
+ *
1202
+ * expect(1.5).to.be.closeTo(1, 0.5);
1203
+ *
1204
+ * @name closeTo
1205
+ * @param {Number} expected
1206
+ * @param {Number} delta
1207
+ * @param {String} message _optional_
1208
+ * @api public
1209
+ */
1210
+
1211
+ Assertion.addMethod('closeTo', function (expected, delta, msg) {
1212
+ if (msg) flag(this, 'message', msg);
1213
+ var obj = flag(this, 'object');
1214
+ this.assert(
1215
+ Math.abs(obj - expected) <= delta
1216
+ , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
1217
+ , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
1218
+ );
1219
+ });
1220
+
1221
+ function isSubsetOf(subset, superset) {
1222
+ return subset.every(function(elem) {
1223
+ return superset.indexOf(elem) !== -1;
1224
+ })
1225
+ }
1226
+
1227
+ /**
1228
+ * ### .members
1229
+ *
1230
+ * Asserts that the target is a superset of `set`,
1231
+ * or that the target and `set` have the same members.
1232
+ *
1233
+ * expect([1, 2, 3]).to.include.members([3, 2]);
1234
+ * expect([1, 2, 3]).to.not.include.members([3, 2, 8]);
1235
+ *
1236
+ * expect([4, 2]).to.have.members([2, 4]);
1237
+ * expect([5, 2]).to.not.have.members([5, 2, 1]);
1238
+ *
1239
+ * @name members
1240
+ * @param {Array} set
1241
+ * @param {String} message _optional_
1242
+ * @api public
1243
+ */
1244
+
1245
+ Assertion.addMethod('members', function (subset, msg) {
1246
+ if (msg) flag(this, 'message', msg);
1247
+ var obj = flag(this, 'object');
1248
+
1249
+ new Assertion(obj).to.be.an('array');
1250
+ new Assertion(subset).to.be.an('array');
1251
+
1252
+ if (flag(this, 'contains')) {
1253
+ return this.assert(
1254
+ isSubsetOf(subset, obj)
1255
+ , 'expected #{this} to be a superset of #{act}'
1256
+ , 'expected #{this} to not be a superset of #{act}'
1257
+ , obj
1258
+ , subset
1259
+ );
1260
+ }
1261
+
1262
+ this.assert(
1263
+ isSubsetOf(obj, subset) && isSubsetOf(subset, obj)
1264
+ , 'expected #{this} to have the same members as #{act}'
1265
+ , 'expected #{this} to not have the same members as #{act}'
1266
+ , obj
1267
+ , subset
1268
+ );
1269
+ });
1270
+ };