├── README.md ├── package.json ├── test ├── a.js ├── all.js ├── amd.html ├── array_is.js ├── array_util.js ├── arrays.js ├── b.js ├── binary.js ├── common.js ├── d.js ├── dep.js ├── events.js ├── expect.js ├── functions.js ├── mocha.css ├── mocha.html ├── mocha.js ├── numbers.js ├── objects.js ├── one.js ├── ready.js ├── strings.js ├── sub.js ├── sub │ ├── add.js │ ├── c.js │ ├── e.js │ ├── four.js │ ├── object_copy.js │ ├── object_get.js │ ├── object_has.js │ ├── object_is.js │ ├── object_union.js │ ├── object_util.js │ ├── three.js │ └── z.js └── time.js └── theory.js /README.md: -------------------------------------------------------------------------------- 1 | Theory 2 | ====== 3 | 4 | Theory is an abstraction layer for server side and client side JavaScript. 5 | 6 | Motivation 7 | ========== 8 | 9 | 1. **Deep existence**. It all started because a program would crash via 10 | `if(obj.x.y.z)` rather than `if(obj && obj.x && obj.x.y && obj.x.y.z)`, so I 11 | wanted an elegant way to check and access deeply nested objects in a safe 12 | yet concise manner. 13 | 14 | 2. **Dependency management**. You should not have to declare dependencies in 15 | another language (HTML) to import required code or rely on globals. Other 16 | tools that solve this foolishly break Node's style in order to make it work 17 | asynchronously. 18 | 19 | 3. **Universal normalization**. Write once, run everywhere. This dream gets 20 | broken when you discover different implementations of JavaScript behave in 21 | unique ways, whether browsers or phones and tablets, or IE6 versus server 22 | side. I needed a reliable yet tiny library (at **7KB** gzipped) that would 23 | normalize everything so any code written would literally work everywhere. 24 | 25 | Require 26 | ======= 27 | 28 | As simple as `npm install theory` on Node and a single `` client side. The brilliant thing is that you do not 30 | have to declare anything else after that, you can handle the rest within your 31 | module. 32 | 33 | module.exports=require('theory') 34 | ('hello', function(a){ 35 | 36 | var say = "Hello World!"; 37 | console.log(say); 38 | return say; 39 | 40 | }, ['./needed', './dependency']); 41 | 42 | This is the beautiful fix that works everywhere. You get your own closure which 43 | executes only after all your dependencies (and all of their sub-dependencies) 44 | have loaded - then whatever you return from your closure gets exported out! 45 | 46 | Say you name this file as 'world.js', all you have to do is run `node world.js` 47 | on the server or put `require('world')` on the client inside the 'theory.js' 48 | script tag (or have a normal 'world.js' script tag below theory.js). All 49 | dependencies are relative to your file, not the HTML page or the parent module! 50 | 51 | If the dependency you require uses some global variable, you can access it from 52 | there (such as `jQuery`) as usual. You can access `theory` as a global, but you 53 | should not use it globally - theory copies itself into the scope of each module 54 | (the `a` argument, henceforth used for the rest of this documentation). 55 | 56 | All dependencies that use exports (normal Node modules and theory specific 57 | modules) get attached to your module's local scope with their base filename 58 | (`a.needed` and `a.dependency` in the example above). If you have conflicting 59 | names or just want a different name then use an object to declare dependencies 60 | instead of an array (`{'./needed': 'foo', './dependency': 'bar'}` become `a.foo` 61 | and `a.bar`). Theory modules also attach to their own namespace, such as 62 | `theory.hello` in above. 63 | 64 | You can also specify sub dependencies, such as `{'./jquery':['./jquery-ui', 65 | './jquery-ext']}`. Define environment specific dependencies by checking for 66 | `root.page` or `root.node`. Finally, [imports.js](https://gist.github.com/amark/6291429) 67 | is an unmaintained version of just the require feature, without anything below. 68 | 69 | *Now let's dive into the API.* 70 | 71 | Binary 72 | ====== 73 | 74 | - **is** `a.bi.is(what)` 75 | 76 | - determines to see if what is a boolean or not. 77 | 78 | - Examples 79 | 80 | - `a.bi.is(false)` → `true` 81 | 82 | - `a.bi.is(true)` → `true` 83 | 84 | - `a.bi.is(0)` → `false` 85 | 86 | - `a.bi.is('yes')` → `false` 87 | 88 | Numbers 89 | ======= 90 | 91 | - **is** `a.num.is(what)` 92 | 93 | - determines to see if what is a number or not. 94 | 95 | - Examples 96 | 97 | - `a.num.is(0)` → `true` 98 | 99 | - `a.num.is(NaN)` → `false` 100 | 101 | - `a.num.is(1.1)` → `true` 102 | 103 | - `a.num.is(Infinity)` → `true` 104 | 105 | - **ify** `a.num.ify(what, opt)` 106 | 107 | - what is the number, text, whatever that needs to be converted into a 108 | number. 109 | 110 | - opt is options parameter. 111 | 112 | - `[]` indicates you want a list of numbers returned. 113 | 114 | - Examples 115 | 116 | - `a.num.ify("A37")` → `37` 117 | 118 | - `a.num("It is -22.7 degrees").ify()` → `-22.7` 119 | 120 | - `a.num("My values are 33, -2.2, and 6.").ify([])` → `[33, -2.2, 6]` 121 | 122 | - **random** `a.num.random(what)` or `a.num.r(what)` 123 | 124 | - if what is a number, it represents how many digits long you want your 125 | random number. 126 | 127 | - if what is a list, it represents the inclusive range you want your 128 | random number to be in. 129 | 130 | - *Note:* Maximum length is 14, what defaults to 6. 131 | 132 | - Examples 133 | 134 | - `a.num.random()` → `583587` 135 | 136 | - `a.num(2).r()` → `64` 137 | 138 | - `a.num([-10,10]).random()` → `-7` 139 | 140 | - `a.num.r([1,99])` → `99` 141 | 142 | Text 143 | ==== 144 | 145 | - **is** `a.text.is(what)` 146 | 147 | - determines to see if what is text or not. 148 | 149 | - Examples 150 | 151 | - `a.text.is("")` → `true` 152 | 153 | - `a.text.is([])` → `false` 154 | 155 | - `a.text.is("Hello World!")` → `true` 156 | 157 | - **ify** `a.text.ify(what)` 158 | 159 | - what is the number, text, list, object, whatever you want to turn into 160 | text. 161 | 162 | - *Note:* Essentially just a wrapper for `JSON.stringify()` for now. 163 | 164 | - Examples 165 | 166 | - `a.text.ify({a:0,b:'1',c:[0,'1'],d:{e:'f'}})` → 167 | `"{a:0,b:'1',c:[0,'1'],d:{e:'f'}}"` 168 | 169 | - **random** `a.text.random(what, length)` or `a.text.r(what, length)` 170 | 171 | - what is a text of allowed characters to be used. Defaults to 172 | alpha-numeric characters. 173 | 174 | - length is how many characters long you want your random text. Defaults 175 | to 16. 176 | 177 | - *Note:* Does not matter what order you call the parameters in. 178 | 179 | - Examples 180 | 181 | - `a.text.random()` → `"uTkphuTCmzQ7Pl3e"` 182 | 183 | - `a.text.r("AaSsDdFf",4)` → `"fDds"` 184 | 185 | - `a.text(4).random("j$k4")` → `"kj$k"` 186 | 187 | - `a.text("randomize").r()` → `"oadomneradnimarz"` 188 | 189 | - **clip** `a.text(what).clip(split, start, end)` 190 | 191 | - what is the text to clip. 192 | 193 | - split is the text or regex to split and rejoin upon. 194 | 195 | - start is the start position of the slice. 196 | 197 | - end is the end position of the slice. 198 | 199 | - Examples 200 | 201 | - `a.text('A B C D').clip(' ',0,-1)` → `"A B C"` 202 | 203 | - `a.text.clip("path/to/awesome.js",'.',-1)` → `"js"` 204 | 205 | - **caps** `a.text.caps(what)` 206 | 207 | - what is the text you want to capitalize. 208 | 209 | - Examples 210 | 211 | - `a.text.caps("shout1")` → `"SHOUT1"` 212 | 213 | - **low** `a.text.low(what)` 214 | 215 | - what is the text you want to make lower case. 216 | 217 | - Examples 218 | 219 | - `a.text.low("HUSH!")` → `"hush!"` 220 | 221 | - **find** a collection of Regular Expressions. 222 | 223 | - *Note:* No guarantee of these working or being available in future 224 | versions. 225 | 226 | Lists 227 | ===== 228 | 229 | - **is** `a.list.is(what)` 230 | 231 | - determines to see if what is a list or not. 232 | 233 | - Examples 234 | 235 | - `a.list.is([])` → `true` 236 | 237 | - `a.list.is("list")` → `false` 238 | 239 | - `a.list.is([0,false])` → `true` 240 | 241 | - **ify** `a.list.ify(what, opt)` 242 | 243 | - what is the text or object that you want to convert into a list. 244 | 245 | - opt is the options parameter. 246 | 247 | - split: what to divide upon for text, whitespace auto handled. `','` 248 | is default. 249 | 250 | - wedge: what token to use as the divider between an object’s key and 251 | value. `':'` default. 252 | 253 | - Examples 254 | 255 | - `a.list.ify("Bob, Joe,Isaac , Fred")` → 256 | `["Bob","Joe","Isaac","Fred"]` 257 | 258 | - `a.list({a:1,b:'c',d:[1,2,3]}).ify()` → `['a:1','b:c','d:0,1,2']` 259 | 260 | - `a.list({session:'AK41795'}).ify({wedge:'='})` → 261 | `['session=AK41795']` 262 | 263 | - `a.list.ify("1,2,3 ; 4,5,6",{split:';'})` → `["1,2,3", "4,5,6"]` 264 | 265 | - **at** `a.list.at(what, index, opt)` 266 | 267 | - what is the list you want to access. 268 | 269 | - index is the where in the list you want to retrieve the value. 270 | 271 | - opt is the options parameter. 272 | 273 | - ebb: causes an over reaching index to cascade till it finds the 274 | closest item. 275 | 276 | - Examples 277 | 278 | - `a.list.at([5,6,7,8,9],-2)` → `8` 279 | 280 | - `a.list([5,6,7,8,9]).at(2)` → `6` 281 | 282 | - `a.list.at([2,3,4],9,{ebb:true})` → `4` 283 | 284 | - `a.list([0,1,2]).at(-9,{ebb:true})` → `0` 285 | 286 | - `a.list.at([5,6,7],-2,{ebb:true})` → `6` 287 | 288 | - **fuse** `a.list.fuse(what, ...)` 289 | 290 | - what is the list that other lists will fuse into. 291 | 292 | - … any number of extra list parameters. 293 | 294 | - Examples 295 | 296 | - `a.list.fuse([2,3],[4,5],[6,7])` → `[2,3,4,5,6,7]` 297 | 298 | - `a.list([2,3]).fuse([3,4],[4,5])` → `[2,3,3,4,4,5]` 299 | 300 | - **less** `a.list.less(what, ...)` 301 | 302 | - what is the list you want to subtract items from. 303 | 304 | - … the items you want to remove from the list, 305 | 306 | - Examples 307 | 308 | - `a.list.less([0,1,false,'a',false],false)` → `[0,1,'a']` 309 | 310 | - `a.list([2,2,7,['a'],1,9,0,31]).less(0,['a'],2)` → `[7, 1, 9, 31]` 311 | 312 | - *Note:* An option to pass a list of items to be removed exists by 313 | indicating you only want `2` parameters, such that 314 | `a.list(2).less([0,1,2,2,3,4],[0,2])` → `[1,3,4]`. 315 | 316 | - **find** `a.list.find(list, what)` 317 | 318 | - list is the list you want to search. 319 | 320 | - what is the item you are looking for. 321 | 322 | - Examples 323 | 324 | - `a.list([4,5]).find(9)` → `0` 325 | 326 | - `a.list([4,5]).find(5)` → `2` 327 | 328 | - `a.list.find([4,5],4)` → `1` 329 | 330 | - **each** `a.list.each(list, function, this)` 331 | 332 | - list is the list you want to iterate through each of its items. 333 | 334 | - function is your callback which gets executed sequentially, on each 335 | item. 336 | 337 | - the first parameter is the current item’s value. 338 | 339 | - the second parameter is the current index of that value in the list. 340 | 341 | - the third parameter is a map function, which when called pushes its 342 | argument into a list that is returned by default by `each`. 343 | 344 | - `return;` or `return undefined;` immediately proceeds to the next 345 | item. 346 | 347 | - return anything else and the loop breaks, then `each` returns the 348 | value you returned instead. 349 | 350 | - this is an optional argument that will become the `this` inside the 351 | function. 352 | 353 | - Examples 354 | 355 | - `a.list([1,2,3]).each(function(val, i, map){ map(val + i) })` → `[2, 356 | 4, 6]` 357 | 358 | - `a.list([1,2,3]).each(function(){ return "Hello World!"; })` → 359 | `"Hello World!"` 360 | 361 | - `a.list([1,2,3]).each(function(val, i, map){ if(val == 2){ return } 362 | map(val); })` → `[1,3]` 363 | 364 | - `a.list([1,2,3]).each(function(val, i, map){ map(val); if(val == 2){ 365 | return val } })` → `2` 366 | 367 | - `a.list([{name:'joe',age:27},{name:'bob',age:42}]).each(function(val, 368 | i, map){ map(val.name) })` → `['joe','bob']` 369 | 370 | - `a.list(['a','b','c']).each(function(){ return this })` → `// 371 | current context` 372 | 373 | - `a.list(['a','b','c']).each(function(){ return this }, {z:1})` → 374 | `{z:1}` 375 | 376 | Notes 377 | ----- 378 | 379 | Theory uses lists and index notation, not arrays and offset notation. Offset 380 | notation is the common practice of describing the position of an element in an 381 | array by its corresponding location in the physically allocated space of 382 | contiguous memory, which logically starts at a zeroth initial. This is otherwise 383 | shortened to "0 based index arrays", despite the misnomer of it actually being 384 | an offset. The author of this library has chosen index notation instead because 385 | it offers the following advantages: 386 | 387 | 1. Naturally, the first element in a list cardinally corresponds to `1`. 388 | Contrarily, even official documentation of JavaScript has explicit 389 | disclaimers that the "first element of an array is actually at index 0" - 390 | this is easily forgotten, especially by novices, and can lead to errors. 391 | 392 | 2. Mathematically, a closed interval is properly represented in code as `for(i 393 | = 1; i <= items.length; i++)`, because it includes its endpoints. Offset 394 | notation instead is technically a left-closed right-open interval set, 395 | represented in code as `for(i = 0; i < items.length; i++)`. This matters 396 | because code deals with integer intervals, because all elements have a fixed 397 | size - you can not access a fractional part of an element. Integer intervals 398 | are closed intervals, thus conclusively proving this importance. 399 | 400 | 3. Mathematically, matrix notation also starts with `1`. 401 | 402 | 4. The last element in a list cardinally corresponds to the length of the list, 403 | thus allowing easy access with `items.length` rather than having frustrating 404 | `(items.length - 1)` arithmetic everywhere in your code. 405 | 406 | 5. Negative indices are symmetric with positive indices. Such that `-1` and `1` 407 | respectively refer to the last and first element, and in the case where 408 | there is only one item in the list, it matches the same element. This 409 | convenience allows for simple left and right access that offset notation 410 | does not provide. 411 | 412 | 6. Non existence of an element can be represented by `0`, which would 413 | conveniently code elegantly as `if( !items.indexOf('z') ) return;`. Rather, 414 | one must decide upon whether `if( items.indexOf('z') == -1 ) return;` is 415 | philosophically more meaningful than `if( items.indexOf('z') < 0 ) return;` 416 | with offset notation despite ignoring the asymmetry of the equation. 417 | 418 | Still irrational? Then switch it back via `a.list.index = 0` in your closure. 419 | 420 | Objects 421 | ======= 422 | 423 | - **is** `a.obj.is(what)` 424 | 425 | - determines to see if what is an object or not. 426 | 427 | - Examples 428 | 429 | - `a.obj.is({})` → `true` 430 | 431 | - `a.obj.is(function(){})` → `false` 432 | 433 | - `a.obj.is([])` → `false` 434 | 435 | - **ify** `a.obj.ify(what)` 436 | 437 | - what is the text-ified object you want to parse into an object. 438 | 439 | - *Note:* Essentially just a wrapper for `JSON.parse()` for now. 440 | 441 | - Examples 442 | 443 | - `a.obj.ify('[0,1]')` → `[0,1]` 444 | 445 | - `a.obj('{"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}}').ify()` → 446 | `{"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}}` 447 | 448 | - **has** `a.obj.has(what, key)` 449 | 450 | - what is the object you want to test the existence of a key or property 451 | on. 452 | 453 | - key is the property you want to see if exists in what. 454 | 455 | - Examples 456 | 457 | - `a.obj.has({yay:false},'yay')` → `true` 458 | 459 | - `a.obj({yay:false}).has('toString')` → `false` 460 | 461 | - **empty** `a.obj.empty(what)` 462 | 463 | - what is the object you want to test to see if it is empty. 464 | 465 | - Examples 466 | 467 | - `a.obj.empty({})` → `true` 468 | 469 | - `a.obj({a:0}).empty()` → `false` 470 | 471 | - **copy** `a.obj.copy(what)` 472 | 473 | - what is the object or list that you want to make a deep duplicate of. 474 | 475 | - Examples 476 | 477 | - `a.obj.copy({a:[0,1],b:function(){ return 1 }})` → 478 | `{a:[0,1],b:function(){ return 1 }}` 479 | 480 | - `a.obj([{a:1},{b:2}]).copy()` → `[{a:1},{b:2}]` 481 | 482 | - **union** `a.obj.union(what, ...)` or `a.obj(what).u(...)` 483 | 484 | - what is the object you want to merge into, or a list of objects to 485 | merge. 486 | 487 | - ... are more objects to be merged. 488 | 489 | - *Note:* You can provide a list of objects instead, which will be merged. 490 | 491 | - Examples 492 | 493 | - `a.obj.union({a:'b',c:'d'},{c:1,z:2})` → `{a:'b',c:'d',z:2}` 494 | 495 | - `a.obj([{a:1},{b:2}]).union()` → `{a:1,b:2}` 496 | 497 | - `a.obj({a:'b',c:'d'}).u({c:1,z:2},{x:3,y:4})` → 498 | `{a:'b',c:'d',x:3,y:4,z:2}` 499 | 500 | - `a.obj.u([{a:1,b:2},{b:3,x:4},{y:5}])` → `{a:1,b:2,x:4,y:5}` 501 | 502 | - **get** `a.obj.get(what, where)` or `a(what, where)` 503 | 504 | - what is the object you want to get something from. 505 | 506 | - where is a dot separated text of keys to the thing you want to get. 507 | 508 | - numbers indicate a list index, if not specified it will scan through 509 | the list. 510 | 511 | - "-\>" postfix indicates you will be calling a function, but if not 512 | found it will return a fail safe function. 513 | 514 | - *Note:* Warning, fails if the property name itself contains a '.' dot in 515 | it. 516 | 517 | - Examples 518 | 519 | - `a.obj.get({a:4,b:6,c:8},'b')` → `6` 520 | 521 | - `a.obj({a:4,b:6,c:8}).get('z')` → `undefined` 522 | 523 | - `a.obj({a:{z:{b:{y:{c:{x:'deep'}}}}}}).get('a.z.b.y.c.x')` → 524 | `'deep'` 525 | 526 | - `a.obj({a:[1,[2,{b:{c:'scan'}},3],4]}).get('a.b.c')` → `'scan'` 527 | 528 | - `a.obj({a:[1,{b:'index'},3]}).get('a.2.b')` → `'index'` 529 | 530 | - `a.obj({a:[1,{b:'index'},3]}).get('a.-2.b')` → `'index'` 531 | 532 | - `a.obj({a:{b:function(c){return c*c}}}).get('a.b->')(2)` → `4` 533 | 534 | - `a.obj({a:1}).get('a.b->')(2)` → `undefined // fail safe` 535 | 536 | - `a.obj({a:1}).get('a.b')(2)` → `TypeError: undefined is not a 537 | function` 538 | 539 | - **each** `a.obj.each(object, function, this)` 540 | 541 | - object is the object you want to iterate through each of its key/value 542 | pairs. 543 | 544 | - function is your callback which gets executed on each pair. 545 | 546 | - the first parameter is the current value. 547 | 548 | - the second parameter is the key of the value in the object. 549 | 550 | - the third parameter is a map function, which when called adds a 551 | key/value pair to the object that is returned by default by `each`. 552 | 553 | - `return;` or `return undefined;` immediately proceeds to the next 554 | pair. 555 | 556 | - return anything else and the loop breaks, then `each` returns the 557 | value you returned instead. 558 | 559 | - this is an optional argument that will become the `this` inside the 560 | function. 561 | 562 | - Examples 563 | 564 | - `a.obj({a:'z',b:'y'}).each(function(val, key, map){ map(val,key) })` 565 | → `{y:'b',z:'a'}` 566 | 567 | - `a.obj({a:'z',b:'y'}).each(function(){ return "Hello World!"; })` → 568 | `"Hello World!"` 569 | 570 | - `a.obj({a:1,b:2,c:3}).each(function(val, key, map){ if(val == 2){ 571 | return } map(key,val); })` → `{a:1,c:3}` 572 | 573 | - `a.obj({a:1,b:2,c:3}).each(function(val, key, map){ map(key,val); 574 | if(val == 2){ return val } })` → `2` 575 | 576 | - `a.obj({z:4}).each(function(){ return this })` → `// current 577 | context` 578 | 579 | - `a.obj({z:4}).each(function(){ return this }, [1,2])` → `[1,2]` 580 | 581 | Functions 582 | ========= 583 | 584 | - **is** `a.fns.is(what)` 585 | 586 | - determines to see if what is a function or not. 587 | 588 | - Examples 589 | 590 | - `a.fns.is(function(){})` → `true` 591 | 592 | - `a.fns.is({})` → `false` 593 | 594 | - **pass** `a.fns.pass(function, this)` 595 | 596 | - function is the function that you want this bound to. 597 | 598 | - this will become the `this` inside the function. 599 | 600 | - *Note:* The original function is returned for you to then immediately 601 | call. 602 | 603 | - Examples 604 | 605 | - `a.fns.pass(function(z){ return this.b + z },{b:1})(2)` → `3` 606 | 607 | - `a.fns(function(z){ return this.b + z }).pass({b:2})(3)` → `5` 608 | 609 | - **sort** `a.fns.sort(what)` 610 | 611 | - what is the arguments object of the function you want sorted. 612 | 613 | - *Note:* An object containing the first letter of each type is returned. 614 | The value of these keys is a list with the corresponding arguments of 615 | that type, in the same order as they appeared in the original function 616 | call. 617 | 618 | - *Note:* If something goes wrong, an error type is included, with a text 619 | value explaining why. 620 | 621 | - Examples 622 | 623 | - `(function(){ return a.fns.sort(arguments) })("a",0,"b",1,{z:2})` → 624 | `{b:[],n:[0,1],t:['a','b'],l:[],o:[{z:2}],f:[]}` 625 | 626 | - `a.fns.sort()` → `{e:"Empty"}` 627 | 628 | - **flow** `a.fns.flow(what, function)` 629 | 630 | - what is a sequential list of functions to asynchronously iterate 631 | through. 632 | 633 | - the last parameter of each function is the next function in the 634 | list. 635 | 636 | - at any point, the flow can be canceled by calling `.end()` on the 637 | last parameter. 638 | 639 | - function is the callback to be executed at the end of the operations. 640 | 641 | - Examples 642 | 643 | - `a.fns.flow([function(next){ next(6) },function(six, next){ next(six 644 | / 3) }],function(two){ alert(two) })` 645 | 646 | - `a.fns.flow([function(next){ next.end(2) },function(){ /* skipped */ 647 | }],function(two){ alert(two) })` 648 | 649 | Events 650 | ====== 651 | 652 | - **event** `a.on(what).event(function)` 653 | 654 | - what is a string name of the event you want to listen on. 655 | 656 | - function is the callback function that will be called when the event is 657 | emitted. 658 | 659 | - the `this` object of the callback is the listener object. 660 | 661 | - returns the listener, which you can call `.off()` on to stop receiving 662 | events. 663 | 664 | - Examples 665 | 666 | - `a.on('alarm').event(function(task){ alert('Remember to ' + task); 667 | this.off(); })` 668 | 669 | - **emit** `a.on(what).emit(data, ...)` 670 | 671 | - what is a string name of the event you want to emit on. 672 | 673 | - data and ... are your parameters to emit to the receivers. 674 | 675 | - Examples 676 | 677 | - `a.on('alarm').emit('exercise!')` 678 | 679 | Time 680 | ==== 681 | 682 | - **is** `a.time.is()` 683 | 684 | - timestamp wrapper for `new Date().getTime()`, but if a parameter is 685 | provided it will test if it is an instance of `Date`. 686 | 687 | - Examples 688 | 689 | - `a.time.is()` → `1357457565462` 690 | 691 | - `a.time(new Date()).is()` → `true` 692 | 693 | - **now** `a.time.now()` 694 | 695 | - hyper precise timestamp, up to four decimals longer than the above. 696 | 697 | - Examples 698 | 699 | - `a.time.now()` → `1357457866774.292` 700 | 701 | - **loop** `a.time.loop(function, interval)` 702 | 703 | - repeatedly calls function every interval millisecond, wrapper for 704 | `setInterval`. 705 | 706 | - *Note:* Does not matter what order you call the parameters in. 707 | 708 | - Examples 709 | 710 | - `a.time.loop(function(){ alert('loop') },1000)` → `// returns ID for 711 | clearing` 712 | 713 | - **wait** `a.time.wait(function, delay)` 714 | 715 | - calls function after waiting millisecond delay, wrapper for 716 | `setTimeout`. 717 | 718 | - *Note:* Does not matter what order you call the parameters in. 719 | 720 | - Examples 721 | 722 | - `a.time.wait(1000,function(){ alert('wait') })` → `// returns ID for 723 | clearing` 724 | 725 | - **stop** `a.time.stop(ID)` 726 | 727 | - stops the wait or loop associated with the ID from further being 728 | executed. 729 | 730 | - Examples 731 | 732 | - `a.time.stop(1111)` → `true` 733 | 734 | Tests 735 | ===== 736 | 737 | - **is** `a.test.is(what, thing)` 738 | 739 | - what is what you want to compare equivalency against thing. 740 | 741 | - thing is the thing you want to compare equivalency to what. 742 | 743 | - Examples 744 | 745 | - `a.test.is({a:1,b:'c',d:{f:function(){return 746 | false}}},{a:1,b:'c',d:{f:function(){return false}}})` → `true` 747 | 748 | - `a.test(NaN).is(NaN)` → `true` 749 | 750 | - `a.test.is(function(){return true},function(){ return true; })` → 751 | `false` 752 | 753 | - `a.test(undefined).is(null)` → `false` 754 | 755 | - **test** `a.test(function)()` 756 | 757 | - function is the function that might break, and you want to test. 758 | 759 | - *Note:* all this does is wrap it in a `try{}catch(){}` block. 760 | 761 | - Examples 762 | 763 | - `a.test(function(){ explode_with_spam })()` → `// error object` 764 | 765 | - `a.test(function(){ return 'ok'; })()` → `'ok'` 766 | 767 | Run them! Using mocha, just `mocha` with Node or `./test/mocha.html` in any 768 | browser. 769 | 770 | Crafted with love by Mark Nadal, whom is not responsible for any liabilities 771 | from the use of this code. 772 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { "name": "theory" 2 | , "version": "0.2.8" 3 | , "author": "Mark Nadal" 4 | , "description": "Abstraction layer for server side and client side JavaScript." 5 | , "homepage": "http://github.com/amark/theory" 6 | , "engines": ["node >= 0.6.6"] 7 | , "main": "theory" 8 | } -------------------------------------------------------------------------------- /test/a.js: -------------------------------------------------------------------------------- 1 | describe('seq',function(){ 2 | it('a',function(){ 3 | expect(root.Dep).to.be.ok(); 4 | }); 5 | }); 6 | root.DepA = 2; -------------------------------------------------------------------------------- /test/all.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** tests have relative paths to theory, 3 | ** although you should always use theory as an installed module 4 | */ 5 | 6 | var expect = global.expect = require("./expect"); 7 | require('./common'); -------------------------------------------------------------------------------- /test/amd.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | AMD Off 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Theory without AMD 18 |
19 |
20 | 37 | 38 | -------------------------------------------------------------------------------- /test/array_is.js: -------------------------------------------------------------------------------- 1 | //alert('array is'); 2 | describe('Lists',function(){ 3 | beforeEach(function(done){ // IE6 stack release 4 | setTimeout(function(){done()}, 0); 5 | }); 6 | it('is()',function(){ 7 | expect(theory.list([]).is()).to.be(true); 8 | expect(theory.list([1]).is()).to.be(true); 9 | expect(theory.list(0).is()).to.be(false); 10 | expect(theory.list(1).is()).to.be(false); 11 | expect(theory.list('').is()).to.be(false); 12 | expect(theory.list('a').is()).to.be(false); 13 | expect(theory.list({}).is()).to.be(false); 14 | expect(theory.list({a:1}).is()).to.be(false); 15 | expect(theory.list(false).is()).to.be(false); 16 | expect(theory.list(true).is()).to.be(false); 17 | expect(theory.list(function(){}).is()).to.be(false); 18 | }); 19 | it('is',function(){ 20 | expect(theory.list.is([])).to.be(true); 21 | expect(theory.list.is([1])).to.be(true); 22 | expect(theory.list.is(0)).to.be(false); 23 | expect(theory.list.is(1)).to.be(false); 24 | expect(theory.list.is('')).to.be(false); 25 | expect(theory.list.is('a')).to.be(false); 26 | expect(theory.list.is({})).to.be(false); 27 | expect(theory.list.is({a:1})).to.be(false); 28 | expect(theory.list.is(false)).to.be(false); 29 | expect(theory.list.is(true)).to.be(false); 30 | expect(theory.list.is(function(){})).to.be(false); 31 | }); 32 | }); 33 | root.ArrayIs = true; -------------------------------------------------------------------------------- /test/array_util.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('list_utils',function(a){ 3 | //alert('arrays util'); 4 | describe('arrays',function(){ 5 | beforeEach(function(done){ // IE6 stack release 6 | setTimeout(function(){done()}, 0); 7 | }); 8 | it('at',function(){ 9 | expect(theory.list([1,2,3,4,5,6,7,8,9]).at(2)).to.be(2); 10 | expect(theory.list.at([1,2,3,4,5,6,7,8,9],2)).to.be(2); 11 | expect(theory.list([1,2,3,4,5,6,7,8,9]).at(-2)).to.be(8); 12 | expect(theory.list.at([1,2,3,4,5,6,7,8,9],-2)).to.be(8); 13 | expect(theory.list([1,2]).at(9)).to.be(undefined); 14 | expect(theory.list.at([1,2],9)).to.be(undefined); 15 | expect(theory.list([2,3,4]).at(2,{ebb:true})).to.be(3); 16 | expect(theory.list.at([2,3,4],2,{ebb:1})).to.be(3); 17 | expect(theory.list([2,3,4]).at(-2,{ebb:1})).to.be(3); 18 | expect(theory.list.at([2,3,4],-2,{ebb:true})).to.be(3); 19 | expect(theory.list([2,3,4]).at(9,{ebb:true})).to.be(4); 20 | expect(theory.list.at([2,3,4],9,{ebb:true})).to.be(4); 21 | expect(theory.list([2,3,4]).at(-9,{ebb:true})).to.be(2); 22 | expect(theory.list.at([2,3,4],-9,{ebb:true})).to.be(2); 23 | expect(theory.list([2,3,0]).at(9,{ebb:true})).to.be(0); 24 | expect(theory.list.at([2,3,0],9,{ebb:true})).to.be(0); 25 | expect(theory.list([false,3,0]).at(-9,{ebb:true})).to.be(false); 26 | expect(theory.list.at([false,3,0],-9,{ebb:true})).to.be(false); 27 | }); 28 | it('ify',function(){ 29 | expect(theory.list("Bob, Joe,Isaac , Fred").ify()).to.eql(["Bob","Joe","Isaac","Fred"]); 30 | expect(theory.list.ify("Bob, Joe,Isaac , Fred")).to.eql(["Bob","Joe","Isaac","Fred"]); 31 | expect(theory.list("1,2,3 ; 4,5,6").ify({split:';'})).to.eql(["1,2,3","4,5,6"]); 32 | expect(theory.list.ify("1,2,3 ; 4,5,6",{split:';'})).to.eql(["1,2,3","4,5,6"]); 33 | expect(theory.list({a:1,b:'c',d:[0,1,2]}).ify()).to.eql(['a:1','b:c','d:0,1,2']); 34 | expect(theory.list.ify({a:1,b:'c',d:[0,1,2]})).to.eql(['a:1','b:c','d:0,1,2']); 35 | expect(theory.list({a:1,b:'c',d:[0,1,2],e:{f:'g'}}).ify({wedge:'='})).to.eql(["a=1", "b=c", "d=0,1,2", 'e={"f":"g"}']); 36 | expect(theory.list.ify({a:1,b:'c',d:[0,1,2],e:{f:'g'}},{wedge:'='})).to.eql(["a=1", "b=c", "d=0,1,2", 'e={"f":"g"}']); 37 | }); 38 | it('fuse',function(){ 39 | expect(theory.list([2,3]).fuse([4,5],[6,7])).to.eql([2,3,4,5,6,7]); 40 | expect(theory.list.fuse([2,3],[4,5],[6,7])).to.eql([2,3,4,5,6,7]); 41 | }); 42 | it('less',function(){ 43 | expect(theory.list([1]).less(1)).to.eql([]); 44 | expect(theory.list.less([1],1)).to.eql([]); 45 | expect(theory.list([4,5]).less(1)).to.eql([4,5]); 46 | expect(theory.list.less([4,5],1)).to.eql([4,5]); 47 | expect(theory.list([0,1,'a','b','c','b','d']).less('b')).to.eql([0,1,'a','c','d']); 48 | expect(theory.list.less([0,1,'a','b','c','b','d'],'b')).to.eql([0,1,'a','c','d']); 49 | expect(theory.list([0,1,NaN,'','c',false,true,[1],[]]).less(NaN,false,0,[],'')).to.eql([1,'c',true,[1]]); 50 | expect(theory.list.less([0,1,NaN,'','c',false,true,[1],[]],NaN,false,0,[],'')).to.eql([1,'c',true,[1]]); 51 | expect(theory.list(2).less([0,0,1,2,2,3],[0,2])).to.eql([1,3]); 52 | }); 53 | it('find',function(){ 54 | expect(theory.list([-2,-1,0,1,2]).find(0)).to.be(3); 55 | expect(theory.list.find([-2,-1,0,1,2],0)).to.be(3); 56 | expect(theory.list(['a','b','c']).find('z')).to.be(0); 57 | expect(theory.list.find(['a','b','c'],'z')).to.be(0); 58 | expect(theory.list([false,true,NaN,0,1,'','a',['b'],{c:'d'}]).find(NaN)).to.be(3); 59 | expect(theory.list.find([false,true,NaN,0,1,'','a',['b'],{c:'d'}],NaN)).to.be(3); 60 | expect(theory.list([false,true,NaN,0,1,'','a',['b'],{c:'d'}]).find(['b'])).to.be(8); 61 | expect(theory.list.find([false,true,NaN,0,1,'','a',['b'],{c:'d'}],['b'])).to.be(8); 62 | expect(theory.list([false,true,NaN,0,1,'','a',['b'],{c:'d'}]).find({c:'d'})).to.be(9); 63 | expect(theory.list.find([false,true,NaN,0,1,'','a',['b'],{c:'d'}],{c:'d'})).to.be(9); 64 | }); 65 | it('each',function(){ 66 | expect(theory.list([1,2,3,4,5]).each(function(v,i,t){ t(v+=this.d); this.d=v; },{d:0})).to.eql([1,3,6,10,15]); 67 | expect(theory.list.each([1,2,3,4,5],function(v,i,t){ t(v+=this.d); this.d=v; },{d:0})).to.eql([1,3,6,10,15]); 68 | expect(theory.list([2,3,0,4]).each(function(v,i,t){ if(!v){ return } t(v*=this.d); this.d=v; },{d:1})).to.eql([2,6,24]); 69 | expect(theory.list.each([2,3,0,4],function(v,i,t){ if(!v){ return } t(v*=this.d); this.d=v; },{d:1})).to.eql([2,6,24]); 70 | expect(theory.list([true,false,NaN,Infinity,'',9]).each(function(v,i,t){ if(i===3){ return 0 }})).to.be(0); 71 | expect(theory.list.each([true,false,NaN,Infinity,'',9],function(v,i,t){ if(i===3){ return 0 }})).to.be(0); 72 | }); 73 | }); 74 | return [3,2,1]; 75 | }); -------------------------------------------------------------------------------- /test/arrays.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('syllabus',function(a){ 3 | describe('arrays',function(){ 4 | it('deps',function(){ 5 | expect(root.ArrayIs).to.be(true); 6 | expect(a.array_is).to.be(undefined); 7 | }); 8 | }); 9 | return [1,2,3]; 10 | },['./array_util', './array_is']); -------------------------------------------------------------------------------- /test/b.js: -------------------------------------------------------------------------------- 1 | describe('seq',function(){ 2 | it('b',function(){ 3 | expect(root.Dep).to.be.ok(); 4 | }); 5 | }); 6 | root.DepB = 3; -------------------------------------------------------------------------------- /test/binary.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('binary',function(a){ 3 | describe('Binary',function(){ 4 | it('is()',function(){ 5 | expect(theory.bi(false).is()).to.be(true); 6 | expect(theory.bi(true).is()).to.be(true); 7 | expect(theory.bi('').is()).to.be(false); 8 | expect(theory.bi('a').is()).to.be(false); 9 | expect(theory.bi(0).is()).to.be(false); 10 | expect(theory.bi(1).is()).to.be(false); 11 | expect(theory.bi([]).is()).to.be(false); 12 | expect(theory.bi([1]).is()).to.be(false); 13 | expect(theory.bi({}).is()).to.be(false); 14 | expect(theory.bi({a:1}).is()).to.be(false); 15 | expect(theory.bi(function(){}).is()).to.be(false); 16 | }); 17 | it('is',function(){ 18 | expect(theory.bi.is(false)).to.be(true); 19 | expect(theory.bi.is(true)).to.be(true); 20 | expect(theory.bi.is('')).to.be(false); 21 | expect(theory.bi.is('a')).to.be(false); 22 | expect(theory.bi.is(0)).to.be(false); 23 | expect(theory.bi.is(1)).to.be(false); 24 | expect(theory.bi.is([])).to.be(false); 25 | expect(theory.bi.is([1])).to.be(false); 26 | expect(theory.bi.is({})).to.be(false); 27 | expect(theory.bi.is({a:1})).to.be(false); 28 | expect(theory.bi.is(function(){})).to.be(false); 29 | }); 30 | }); 31 | return true; 32 | }); -------------------------------------------------------------------------------- /test/common.js: -------------------------------------------------------------------------------- 1 | var TS = new Date().getTime(); 2 | module.exports=require('../theory') 3 | ('tests',function(a){ 4 | var s='',i;for(i in a){s+=i+', '};console.log(s); 5 | root.page && (document.getElementById('debug').innerHTML = (new Date().getTime() - TS)/1000+'s '+module.sync); 6 | describe('Dependencies',function(){ 7 | it('are',function(){ 8 | expect(a.binary).to.be(true); 9 | expect(a.count).to.be(42); 10 | expect(a.texts).to.be("Hello World!"); 11 | expect(theory.language).to.be("Hello World!"); 12 | expect(a.enumerate).to.eql([1,2,3]); 13 | expect(theory.syllabus).to.eql([1,2,3]); 14 | expect(a.array_util).to.eql(undefined); 15 | expect(theory.list_utils).to.eql([3,2,1]); 16 | expect(a.hash).to.eql({all:'your',tests:'belong',to:'us'}); 17 | expect(root.TimeFull).to.be.ok(); 18 | expect(a.events).to.be.ok(); 19 | }); 20 | }); 21 | describe('Test',function(){ 22 | it('equality',function(){ 23 | (function(){ 24 | expect(theory.test(function(){ return 1; })()).to.be(1); 25 | expect(theory.test(function(){ explode; return 1; })()).to.not.be(1); 26 | })(); 27 | expect(theory.test(function(){ return 'testing'; }).is(function(){ return 'testing'; })).to.be.ok(); 28 | expect(theory.test(NaN).is(NaN)).to.be.ok(); 29 | expect(theory.test(null).is(null)).to.be.ok(); 30 | expect(theory.test(-0).is(-0)).to.be.ok(); 31 | expect(theory.test({a:1,b:'c',d:[false,'e'],f:{g:function(){return false}}}) 32 | .is({a:1,b:'c',d:[false,'e'],f:{g:function(){return false}}})).to.be.ok(); 33 | expect(theory.test(function(){return 'tests'}).is(function(){ return 'testing'; })).to.not.be.ok(); 34 | expect(theory.test(undefined).is(null)).to.not.be.ok(); 35 | expect(theory.test(null).is(undefined)).to.not.be.ok(); 36 | expect(theory.test.is(undefined,null)).to.not.be.ok(); 37 | expect(theory.test(undefined).is(0)).to.not.be.ok(); 38 | expect(theory.test(0).is(undefined)).to.not.be.ok(); 39 | expect(theory.test.is(0,undefined)).to.not.be.ok(); 40 | expect(theory.test(null).is(0)).to.not.be.ok(); 41 | expect(theory.test(0).is(null)).to.not.be.ok(); 42 | expect(theory.test.is(null,0)).to.not.be.ok(); 43 | expect(theory.test(true).is(1)).to.not.be.ok(); 44 | expect(theory.test(1).is(true)).to.not.be.ok(); 45 | expect(theory.test.is(1,true)).to.not.be.ok(); 46 | expect(theory.test(0).is(-0)).to.not.be.ok(); 47 | expect(theory.test(-0).is(0)).to.not.be.ok(); 48 | }); 49 | }); 50 | describe('Require',function(){ 51 | it('callback',function(){ 52 | if(root.node){ 53 | return expect('use native require').to.ok(); 54 | } 55 | require(['./sub/three','./sub/four'])(function(){ 56 | expect(root.Three).to.be(3); 57 | expect(root.Four).to.be(4); 58 | require('./ready')(function(){ 59 | expect(root.Ready).to.be.ok(); 60 | }); 61 | }); 62 | }); 63 | }); 64 | if(root.page){ 65 | mocha.run(); 66 | } 67 | },{ 68 | './dep':[ 69 | './a' 70 | ,'./b' 71 | ] 72 | ,'./sub':'' 73 | ,'./binary':'' 74 | ,'./numbers':'count' 75 | ,'./strings':'texts' 76 | ,'./arrays':'enumerate' 77 | ,'./objects':'hash' 78 | ,'./functions':'' 79 | ,'./time':'travel' 80 | ,'./events':'' 81 | }); -------------------------------------------------------------------------------- /test/d.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('d',function(a){ 3 | describe('d',function(){ 4 | it('z',function(){ 5 | expect(root.ZERO).to.be(0); 6 | }); 7 | }); 8 | return 'd'; 9 | },['./sub/z','./sub/add']); -------------------------------------------------------------------------------- /test/dep.js: -------------------------------------------------------------------------------- 1 | root.Dep = !0; -------------------------------------------------------------------------------- /test/events.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ({name: 'events' 3 | , init: function(a){ 4 | var t = {}; 5 | describe('On',function(){ 6 | it('event',function(){ 7 | t.on = theory.on('test').event(function(b,c,d){ t.ont = [b,c,d] }); 8 | theory.on('test').emit(4,5,6); 9 | expect(t.ont).to.eql([4,5,6]); 10 | }); 11 | it('emit',function(){ 12 | t.on2 = theory.on('test').event(function(b,c,d){ t.ont2 = [b,c,d] }); 13 | theory.on('test').emit(1,2,3); 14 | expect(t.ont).to.eql([1,2,3]); 15 | expect(t.ont2).to.eql([1,2,3]); 16 | }); 17 | it('off',function(){ 18 | t.on.off(); t.ont = 1; 19 | theory.on('test').emit(-4,-8,0); 20 | expect(t.ont).to.be(1); 21 | expect(t.ont2).to.eql([-4,-8,0]); 22 | t.on2.off(); t.ont2 = 5; 23 | theory.on('test').emit(9, 9, 9); 24 | expect(t.ont).to.be(1); 25 | expect(t.ont2).to.be(5); 26 | }); 27 | it('on',function(){ 28 | t.on = theory.on('test').event(function(b,c,d){ t.ont = [b,c,d] }); 29 | theory.on('test').emit(11, 22, 33); 30 | expect(t.ont).to.eql([11,22,33]); 31 | t.on = theory.on('test').event(function(b,c,d){ t.ont = ['a','b','c']; t.ont2 = [0,0,0] }, -1); 32 | theory.on('test').emit(12, 23, 34); 33 | expect(t.ont).to.eql([12,23,34]); 34 | expect(t.ont2).to.eql([0,0,0]); 35 | }); 36 | }); 37 | return true; 38 | }}); -------------------------------------------------------------------------------- /test/expect.js: -------------------------------------------------------------------------------- 1 | (function (global, module) { 2 | 3 | var exports = module.exports; 4 | 5 | /** 6 | * Exports. 7 | */ 8 | 9 | module.exports = expect; 10 | expect.Assertion = Assertion; 11 | 12 | /** 13 | * Exports version. 14 | */ 15 | 16 | expect.version = '0.1.2'; 17 | 18 | /** 19 | * Possible assertion flags. 20 | */ 21 | 22 | var flags = { 23 | not: ['to', 'be', 'have', 'include', 'only'] 24 | , to: ['be', 'have', 'include', 'only', 'not'] 25 | , only: ['have'] 26 | , have: ['own'] 27 | , be: ['an'] 28 | }; 29 | 30 | function expect (obj) { 31 | return new Assertion(obj); 32 | } 33 | 34 | /** 35 | * Constructor 36 | * 37 | * @api private 38 | */ 39 | 40 | function Assertion (obj, flag, parent) { 41 | this.obj = obj; 42 | this.flags = {}; 43 | 44 | if (undefined != parent) { 45 | this.flags[flag] = true; 46 | 47 | for (var i in parent.flags) { 48 | if (parent.flags.hasOwnProperty(i)) { 49 | this.flags[i] = true; 50 | } 51 | } 52 | } 53 | 54 | var $flags = flag ? flags[flag] : keys(flags) 55 | , self = this; 56 | 57 | if ($flags) { 58 | for (var i = 0, l = $flags.length; i < l; i++) { 59 | // avoid recursion 60 | if (this.flags[$flags[i]]) continue; 61 | 62 | var name = $flags[i] 63 | , assertion = new Assertion(this.obj, name, this) 64 | 65 | if ('function' == typeof Assertion.prototype[name]) { 66 | // clone the function, make sure we dont touch the prot reference 67 | var old = this[name]; 68 | this[name] = function () { 69 | return old.apply(self, arguments); 70 | }; 71 | 72 | for (var fn in Assertion.prototype) { 73 | if (Assertion.prototype.hasOwnProperty(fn) && fn != name) { 74 | this[name][fn] = bind(assertion[fn], assertion); 75 | } 76 | } 77 | } else { 78 | this[name] = assertion; 79 | } 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * Performs an assertion 86 | * 87 | * @api private 88 | */ 89 | 90 | Assertion.prototype.assert = function (truth, msg, error, expected) { 91 | var msg = this.flags.not ? error : msg 92 | , ok = this.flags.not ? !truth : truth 93 | , err; 94 | 95 | if (!ok) { 96 | err = new Error(msg.call(this)); 97 | if (arguments.length > 3) { 98 | err.actual = this.obj; 99 | err.expected = expected; 100 | err.showDiff = true; 101 | } 102 | throw err; 103 | } 104 | 105 | this.and = new Assertion(this.obj); 106 | }; 107 | 108 | /** 109 | * Check if the value is truthy 110 | * 111 | * @api public 112 | */ 113 | 114 | Assertion.prototype.ok = function () { 115 | this.assert( 116 | !!this.obj 117 | , function(){ return 'expected ' + i(this.obj) + ' to be truthy' } 118 | , function(){ return 'expected ' + i(this.obj) + ' to be falsy' }); 119 | }; 120 | 121 | /** 122 | * Creates an anonymous function which calls fn with arguments. 123 | * 124 | * @api public 125 | */ 126 | 127 | Assertion.prototype.withArgs = function() { 128 | expect(this.obj).to.be.a('function'); 129 | var fn = this.obj; 130 | var args = Array.prototype.slice.call(arguments); 131 | return expect(function() { fn.apply(null, args); }); 132 | }; 133 | 134 | /** 135 | * Assert that the function throws. 136 | * 137 | * @param {Function|RegExp} callback, or regexp to match error string against 138 | * @api public 139 | */ 140 | 141 | Assertion.prototype.throwError = 142 | Assertion.prototype.throwException = function (fn) { 143 | expect(this.obj).to.be.a('function'); 144 | 145 | var thrown = false 146 | , not = this.flags.not; 147 | 148 | try { 149 | this.obj(); 150 | } catch (e) { 151 | if (isRegExp(fn)) { 152 | var subject = 'string' == typeof e ? e : e.message; 153 | if (not) { 154 | expect(subject).to.not.match(fn); 155 | } else { 156 | expect(subject).to.match(fn); 157 | } 158 | } else if ('function' == typeof fn) { 159 | fn(e); 160 | } 161 | thrown = true; 162 | } 163 | 164 | if (isRegExp(fn) && not) { 165 | // in the presence of a matcher, ensure the `not` only applies to 166 | // the matching. 167 | this.flags.not = false; 168 | } 169 | 170 | var name = this.obj.name || 'fn'; 171 | this.assert( 172 | thrown 173 | , function(){ return 'expected ' + name + ' to throw an exception' } 174 | , function(){ return 'expected ' + name + ' not to throw an exception' }); 175 | }; 176 | 177 | /** 178 | * Checks if the array is empty. 179 | * 180 | * @api public 181 | */ 182 | 183 | Assertion.prototype.empty = function () { 184 | var expectation; 185 | 186 | if ('object' == typeof this.obj && null !== this.obj && !isArray(this.obj)) { 187 | if ('number' == typeof this.obj.length) { 188 | expectation = !this.obj.length; 189 | } else { 190 | expectation = !keys(this.obj).length; 191 | } 192 | } else { 193 | if ('string' != typeof this.obj) { 194 | expect(this.obj).to.be.an('object'); 195 | } 196 | 197 | expect(this.obj).to.have.property('length'); 198 | expectation = !this.obj.length; 199 | } 200 | 201 | this.assert( 202 | expectation 203 | , function(){ return 'expected ' + i(this.obj) + ' to be empty' } 204 | , function(){ return 'expected ' + i(this.obj) + ' to not be empty' }); 205 | return this; 206 | }; 207 | 208 | /** 209 | * Checks if the obj exactly equals another. 210 | * 211 | * @api public 212 | */ 213 | 214 | Assertion.prototype.be = 215 | Assertion.prototype.equal = function (obj) { 216 | this.assert( 217 | obj === this.obj 218 | , function(){ return 'expected ' + i(this.obj) + ' to equal ' + i(obj) } 219 | , function(){ return 'expected ' + i(this.obj) + ' to not equal ' + i(obj) }); 220 | return this; 221 | }; 222 | 223 | /** 224 | * Checks if the obj sortof equals another. 225 | * 226 | * @api public 227 | */ 228 | 229 | Assertion.prototype.eql = function (obj) { 230 | this.assert( 231 | expect.eql(this.obj, obj) 232 | , function(){ return 'expected ' + i(this.obj) + ' to sort of equal ' + i(obj) } 233 | , function(){ return 'expected ' + i(this.obj) + ' to sort of not equal ' + i(obj) } 234 | , obj); 235 | return this; 236 | }; 237 | 238 | /** 239 | * Assert within start to finish (inclusive). 240 | * 241 | * @param {Number} start 242 | * @param {Number} finish 243 | * @api public 244 | */ 245 | 246 | Assertion.prototype.within = function (start, finish) { 247 | var range = start + '..' + finish; 248 | this.assert( 249 | this.obj >= start && this.obj <= finish 250 | , function(){ return 'expected ' + i(this.obj) + ' to be within ' + range } 251 | , function(){ return 'expected ' + i(this.obj) + ' to not be within ' + range }); 252 | return this; 253 | }; 254 | 255 | /** 256 | * Assert typeof / instance of 257 | * 258 | * @api public 259 | */ 260 | 261 | Assertion.prototype.a = 262 | Assertion.prototype.an = function (type) { 263 | if ('string' == typeof type) { 264 | // proper english in error msg 265 | var n = /^[aeiou]/.test(type) ? 'n' : ''; 266 | 267 | // typeof with support for 'array' 268 | this.assert( 269 | 'array' == type ? isArray(this.obj) : 270 | 'regexp' == type ? isRegExp(this.obj) : 271 | 'object' == type 272 | ? 'object' == typeof this.obj && null !== this.obj 273 | : type == typeof this.obj 274 | , function(){ return 'expected ' + i(this.obj) + ' to be a' + n + ' ' + type } 275 | , function(){ return 'expected ' + i(this.obj) + ' not to be a' + n + ' ' + type }); 276 | } else { 277 | // instanceof 278 | var name = type.name || 'supplied constructor'; 279 | this.assert( 280 | this.obj instanceof type 281 | , function(){ return 'expected ' + i(this.obj) + ' to be an instance of ' + name } 282 | , function(){ return 'expected ' + i(this.obj) + ' not to be an instance of ' + name }); 283 | } 284 | 285 | return this; 286 | }; 287 | 288 | /** 289 | * Assert numeric value above _n_. 290 | * 291 | * @param {Number} n 292 | * @api public 293 | */ 294 | 295 | Assertion.prototype.greaterThan = 296 | Assertion.prototype.above = function (n) { 297 | this.assert( 298 | this.obj > n 299 | , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n } 300 | , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n }); 301 | return this; 302 | }; 303 | 304 | /** 305 | * Assert numeric value below _n_. 306 | * 307 | * @param {Number} n 308 | * @api public 309 | */ 310 | 311 | Assertion.prototype.lessThan = 312 | Assertion.prototype.below = function (n) { 313 | this.assert( 314 | this.obj < n 315 | , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n } 316 | , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n }); 317 | return this; 318 | }; 319 | 320 | /** 321 | * Assert string value matches _regexp_. 322 | * 323 | * @param {RegExp} regexp 324 | * @api public 325 | */ 326 | 327 | Assertion.prototype.match = function (regexp) { 328 | this.assert( 329 | regexp.exec(this.obj) 330 | , function(){ return 'expected ' + i(this.obj) + ' to match ' + regexp } 331 | , function(){ return 'expected ' + i(this.obj) + ' not to match ' + regexp }); 332 | return this; 333 | }; 334 | 335 | /** 336 | * Assert property "length" exists and has value of _n_. 337 | * 338 | * @param {Number} n 339 | * @api public 340 | */ 341 | 342 | Assertion.prototype.length = function (n) { 343 | expect(this.obj).to.have.property('length'); 344 | var len = this.obj.length; 345 | this.assert( 346 | n == len 347 | , function(){ return 'expected ' + i(this.obj) + ' to have a length of ' + n + ' but got ' + len } 348 | , function(){ return 'expected ' + i(this.obj) + ' to not have a length of ' + len }); 349 | return this; 350 | }; 351 | 352 | /** 353 | * Assert property _name_ exists, with optional _val_. 354 | * 355 | * @param {String} name 356 | * @param {Mixed} val 357 | * @api public 358 | */ 359 | 360 | Assertion.prototype.property = function (name, val) { 361 | if (this.flags.own) { 362 | this.assert( 363 | Object.prototype.hasOwnProperty.call(this.obj, name) 364 | , function(){ return 'expected ' + i(this.obj) + ' to have own property ' + i(name) } 365 | , function(){ return 'expected ' + i(this.obj) + ' to not have own property ' + i(name) }); 366 | return this; 367 | } 368 | 369 | if (this.flags.not && undefined !== val) { 370 | if (undefined === this.obj[name]) { 371 | throw new Error(i(this.obj) + ' has no property ' + i(name)); 372 | } 373 | } else { 374 | var hasProp; 375 | try { 376 | hasProp = name in this.obj 377 | } catch (e) { 378 | hasProp = undefined !== this.obj[name] 379 | } 380 | 381 | this.assert( 382 | hasProp 383 | , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) } 384 | , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) }); 385 | } 386 | 387 | if (undefined !== val) { 388 | this.assert( 389 | val === this.obj[name] 390 | , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) 391 | + ' of ' + i(val) + ', but got ' + i(this.obj[name]) } 392 | , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) 393 | + ' of ' + i(val) }); 394 | } 395 | 396 | this.obj = this.obj[name]; 397 | return this; 398 | }; 399 | 400 | /** 401 | * Assert that the array contains _obj_ or string contains _obj_. 402 | * 403 | * @param {Mixed} obj|string 404 | * @api public 405 | */ 406 | 407 | Assertion.prototype.string = 408 | Assertion.prototype.contain = function (obj) { 409 | if ('string' == typeof this.obj) { 410 | this.assert( 411 | ~this.obj.indexOf(obj) 412 | , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) } 413 | , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) }); 414 | } else { 415 | this.assert( 416 | ~indexOf(this.obj, obj) 417 | , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) } 418 | , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) }); 419 | } 420 | return this; 421 | }; 422 | 423 | /** 424 | * Assert exact keys or inclusion of keys by using 425 | * the `.own` modifier. 426 | * 427 | * @param {Array|String ...} keys 428 | * @api public 429 | */ 430 | 431 | Assertion.prototype.key = 432 | Assertion.prototype.keys = function ($keys) { 433 | var str 434 | , ok = true; 435 | 436 | $keys = isArray($keys) 437 | ? $keys 438 | : Array.prototype.slice.call(arguments); 439 | 440 | if (!$keys.length) throw new Error('keys required'); 441 | 442 | var actual = keys(this.obj) 443 | , len = $keys.length; 444 | 445 | // Inclusion 446 | ok = every($keys, function (key) { 447 | return ~indexOf(actual, key); 448 | }); 449 | 450 | // Strict 451 | if (!this.flags.not && this.flags.only) { 452 | ok = ok && $keys.length == actual.length; 453 | } 454 | 455 | // Key string 456 | if (len > 1) { 457 | $keys = map($keys, function (key) { 458 | return i(key); 459 | }); 460 | var last = $keys.pop(); 461 | str = $keys.join(', ') + ', and ' + last; 462 | } else { 463 | str = i($keys[0]); 464 | } 465 | 466 | // Form 467 | str = (len > 1 ? 'keys ' : 'key ') + str; 468 | 469 | // Have / include 470 | str = (!this.flags.only ? 'include ' : 'only have ') + str; 471 | 472 | // Assertion 473 | this.assert( 474 | ok 475 | , function(){ return 'expected ' + i(this.obj) + ' to ' + str } 476 | , function(){ return 'expected ' + i(this.obj) + ' to not ' + str }); 477 | 478 | return this; 479 | }; 480 | 481 | /** 482 | * Assert a failure. 483 | * 484 | * @param {String ...} custom message 485 | * @api public 486 | */ 487 | Assertion.prototype.fail = function (msg) { 488 | var error = function() { return msg || "explicit failure"; } 489 | this.assert(false, error, error); 490 | return this; 491 | }; 492 | 493 | /** 494 | * Function bind implementation. 495 | */ 496 | 497 | function bind (fn, scope) { 498 | return function () { 499 | return fn.apply(scope, arguments); 500 | } 501 | } 502 | 503 | /** 504 | * Array every compatibility 505 | * 506 | * @see bit.ly/5Fq1N2 507 | * @api public 508 | */ 509 | 510 | function every (arr, fn, thisObj) { 511 | var scope = thisObj || global; 512 | for (var i = 0, j = arr.length; i < j; ++i) { 513 | if (!fn.call(scope, arr[i], i, arr)) { 514 | return false; 515 | } 516 | } 517 | return true; 518 | } 519 | 520 | /** 521 | * Array indexOf compatibility. 522 | * 523 | * @see bit.ly/a5Dxa2 524 | * @api public 525 | */ 526 | 527 | function indexOf (arr, o, i) { 528 | if (Array.prototype.indexOf) { 529 | return Array.prototype.indexOf.call(arr, o, i); 530 | } 531 | 532 | if (arr.length === undefined) { 533 | return -1; 534 | } 535 | 536 | for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0 537 | ; i < j && arr[i] !== o; i++); 538 | 539 | return j <= i ? -1 : i; 540 | } 541 | 542 | // https://gist.github.com/1044128/ 543 | var getOuterHTML = function(element) { 544 | if ('outerHTML' in element) return element.outerHTML; 545 | var ns = "http://www.w3.org/1999/xhtml"; 546 | var container = document.createElementNS(ns, '_'); 547 | var xmlSerializer = new XMLSerializer(); 548 | var html; 549 | if (document.xmlVersion) { 550 | return xmlSerializer.serializeToString(element); 551 | } else { 552 | container.appendChild(element.cloneNode(false)); 553 | html = container.innerHTML.replace('><', '>' + element.innerHTML + '<'); 554 | container.innerHTML = ''; 555 | return html; 556 | } 557 | }; 558 | 559 | // Returns true if object is a DOM element. 560 | var isDOMElement = function (object) { 561 | if (typeof HTMLElement === 'object') { 562 | return object instanceof HTMLElement; 563 | } else { 564 | return object && 565 | typeof object === 'object' && 566 | object.nodeType === 1 && 567 | typeof object.nodeName === 'string'; 568 | } 569 | }; 570 | 571 | /** 572 | * Inspects an object. 573 | * 574 | * @see taken from node.js `util` module (copyright Joyent, MIT license) 575 | * @api private 576 | */ 577 | 578 | function i (obj, showHidden, depth) { 579 | var seen = []; 580 | 581 | function stylize (str) { 582 | return str; 583 | } 584 | 585 | function format (value, recurseTimes) { 586 | // Provide a hook for user-specified inspect functions. 587 | // Check that value is an object with an inspect function on it 588 | if (value && typeof value.inspect === 'function' && 589 | // Filter out the util module, it's inspect function is special 590 | value !== exports && 591 | // Also filter out any prototype objects using the circular check. 592 | !(value.constructor && value.constructor.prototype === value)) { 593 | return value.inspect(recurseTimes); 594 | } 595 | 596 | // Primitive types cannot have properties 597 | switch (typeof value) { 598 | case 'undefined': 599 | return stylize('undefined', 'undefined'); 600 | 601 | case 'string': 602 | var simple = '\'' + json.stringify(value).replace(/^"|"$/g, '') 603 | .replace(/'/g, "\\'") 604 | .replace(/\\"/g, '"') + '\''; 605 | return stylize(simple, 'string'); 606 | 607 | case 'number': 608 | return stylize('' + value, 'number'); 609 | 610 | case 'boolean': 611 | return stylize('' + value, 'boolean'); 612 | } 613 | // For some reason typeof null is "object", so special case here. 614 | if (value === null) { 615 | return stylize('null', 'null'); 616 | } 617 | 618 | if (isDOMElement(value)) { 619 | return getOuterHTML(value); 620 | } 621 | 622 | // Look up the keys of the object. 623 | var visible_keys = keys(value); 624 | var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys; 625 | 626 | // Functions without properties can be shortcutted. 627 | if (typeof value === 'function' && $keys.length === 0) { 628 | if (isRegExp(value)) { 629 | return stylize('' + value, 'regexp'); 630 | } else { 631 | var name = value.name ? ': ' + value.name : ''; 632 | return stylize('[Function' + name + ']', 'special'); 633 | } 634 | } 635 | 636 | // Dates without properties can be shortcutted 637 | if (isDate(value) && $keys.length === 0) { 638 | return stylize(value.toUTCString(), 'date'); 639 | } 640 | 641 | // Error objects can be shortcutted 642 | if (value instanceof Error) { 643 | return stylize("["+value.toString()+"]", 'Error'); 644 | } 645 | 646 | var base, type, braces; 647 | // Determine the object type 648 | if (isArray(value)) { 649 | type = 'Array'; 650 | braces = ['[', ']']; 651 | } else { 652 | type = 'Object'; 653 | braces = ['{', '}']; 654 | } 655 | 656 | // Make functions say that they are functions 657 | if (typeof value === 'function') { 658 | var n = value.name ? ': ' + value.name : ''; 659 | base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; 660 | } else { 661 | base = ''; 662 | } 663 | 664 | // Make dates with properties first say the date 665 | if (isDate(value)) { 666 | base = ' ' + value.toUTCString(); 667 | } 668 | 669 | if ($keys.length === 0) { 670 | return braces[0] + base + braces[1]; 671 | } 672 | 673 | if (recurseTimes < 0) { 674 | if (isRegExp(value)) { 675 | return stylize('' + value, 'regexp'); 676 | } else { 677 | return stylize('[Object]', 'special'); 678 | } 679 | } 680 | 681 | seen.push(value); 682 | 683 | var output = map($keys, function (key) { 684 | var name, str; 685 | if (value.__lookupGetter__) { 686 | if (value.__lookupGetter__(key)) { 687 | if (value.__lookupSetter__(key)) { 688 | str = stylize('[Getter/Setter]', 'special'); 689 | } else { 690 | str = stylize('[Getter]', 'special'); 691 | } 692 | } else { 693 | if (value.__lookupSetter__(key)) { 694 | str = stylize('[Setter]', 'special'); 695 | } 696 | } 697 | } 698 | if (indexOf(visible_keys, key) < 0) { 699 | name = '[' + key + ']'; 700 | } 701 | if (!str) { 702 | if (indexOf(seen, value[key]) < 0) { 703 | if (recurseTimes === null) { 704 | str = format(value[key]); 705 | } else { 706 | str = format(value[key], recurseTimes - 1); 707 | } 708 | if (str.indexOf('\n') > -1) { 709 | if (isArray(value)) { 710 | str = map(str.split('\n'), function (line) { 711 | return ' ' + line; 712 | }).join('\n').substr(2); 713 | } else { 714 | str = '\n' + map(str.split('\n'), function (line) { 715 | return ' ' + line; 716 | }).join('\n'); 717 | } 718 | } 719 | } else { 720 | str = stylize('[Circular]', 'special'); 721 | } 722 | } 723 | if (typeof name === 'undefined') { 724 | if (type === 'Array' && key.match(/^\d+$/)) { 725 | return str; 726 | } 727 | name = json.stringify('' + key); 728 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 729 | name = name.substr(1, name.length - 2); 730 | name = stylize(name, 'name'); 731 | } else { 732 | name = name.replace(/'/g, "\\'") 733 | .replace(/\\"/g, '"') 734 | .replace(/(^"|"$)/g, "'"); 735 | name = stylize(name, 'string'); 736 | } 737 | } 738 | 739 | return name + ': ' + str; 740 | }); 741 | 742 | seen.pop(); 743 | 744 | var numLinesEst = 0; 745 | var length = reduce(output, function (prev, cur) { 746 | numLinesEst++; 747 | if (indexOf(cur, '\n') >= 0) numLinesEst++; 748 | return prev + cur.length + 1; 749 | }, 0); 750 | 751 | if (length > 50) { 752 | output = braces[0] + 753 | (base === '' ? '' : base + '\n ') + 754 | ' ' + 755 | output.join(',\n ') + 756 | ' ' + 757 | braces[1]; 758 | 759 | } else { 760 | output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 761 | } 762 | 763 | return output; 764 | } 765 | return format(obj, (typeof depth === 'undefined' ? 2 : depth)); 766 | } 767 | 768 | expect.stringify = i; 769 | 770 | function isArray (ar) { 771 | return Object.prototype.toString.call(ar) === '[object Array]'; 772 | } 773 | 774 | function isRegExp(re) { 775 | var s; 776 | try { 777 | s = '' + re; 778 | } catch (e) { 779 | return false; 780 | } 781 | 782 | return re instanceof RegExp || // easy case 783 | // duck-type for context-switching evalcx case 784 | typeof(re) === 'function' && 785 | re.constructor.name === 'RegExp' && 786 | re.compile && 787 | re.test && 788 | re.exec && 789 | s.match(/^\/.*\/[gim]{0,3}$/); 790 | } 791 | 792 | function isDate(d) { 793 | return d instanceof Date; 794 | } 795 | 796 | function keys (obj) { 797 | if (Object.keys) { 798 | return Object.keys(obj); 799 | } 800 | 801 | var keys = []; 802 | 803 | for (var i in obj) { 804 | if (Object.prototype.hasOwnProperty.call(obj, i)) { 805 | keys.push(i); 806 | } 807 | } 808 | 809 | return keys; 810 | } 811 | 812 | function map (arr, mapper, that) { 813 | if (Array.prototype.map) { 814 | return Array.prototype.map.call(arr, mapper, that); 815 | } 816 | 817 | var other= new Array(arr.length); 818 | 819 | for (var i= 0, n = arr.length; i= 2) { 845 | var rv = arguments[1]; 846 | } else { 847 | do { 848 | if (i in this) { 849 | rv = this[i++]; 850 | break; 851 | } 852 | 853 | // if array contains no values, no initial value to return 854 | if (++i >= len) 855 | throw new TypeError(); 856 | } while (true); 857 | } 858 | 859 | for (; i < len; i++) { 860 | if (i in this) 861 | rv = fun.call(null, rv, this[i], i, this); 862 | } 863 | 864 | return rv; 865 | } 866 | 867 | /** 868 | * Asserts deep equality 869 | * 870 | * @see taken from node.js `assert` module (copyright Joyent, MIT license) 871 | * @api private 872 | */ 873 | 874 | expect.eql = function eql(actual, expected) { 875 | // 7.1. All identical values are equivalent, as determined by ===. 876 | if (actual === expected) { 877 | return true; 878 | } else if ('undefined' != typeof Buffer 879 | && Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { 880 | if (actual.length != expected.length) return false; 881 | 882 | for (var i = 0; i < actual.length; i++) { 883 | if (actual[i] !== expected[i]) return false; 884 | } 885 | 886 | return true; 887 | 888 | // 7.2. If the expected value is a Date object, the actual value is 889 | // equivalent if it is also a Date object that refers to the same time. 890 | } else if (actual instanceof Date && expected instanceof Date) { 891 | return actual.getTime() === expected.getTime(); 892 | 893 | // 7.3. Other pairs that do not both pass typeof value == "object", 894 | // equivalence is determined by ==. 895 | } else if (typeof actual != 'object' && typeof expected != 'object') { 896 | return actual == expected; 897 | // If both are regular expression use the special `regExpEquiv` method 898 | // to determine equivalence. 899 | } else if (isRegExp(actual) && isRegExp(expected)) { 900 | return regExpEquiv(actual, expected); 901 | // 7.4. For all other Object pairs, including Array objects, equivalence is 902 | // determined by having the same number of owned properties (as verified 903 | // with Object.prototype.hasOwnProperty.call), the same set of keys 904 | // (although not necessarily the same order), equivalent values for every 905 | // corresponding key, and an identical "prototype" property. Note: this 906 | // accounts for both named and indexed properties on Arrays. 907 | } else { 908 | return objEquiv(actual, expected); 909 | } 910 | }; 911 | 912 | function isUndefinedOrNull (value) { 913 | return value === null || value === undefined; 914 | } 915 | 916 | function isArguments (object) { 917 | return Object.prototype.toString.call(object) == '[object Arguments]'; 918 | } 919 | 920 | function regExpEquiv (a, b) { 921 | return a.source === b.source && a.global === b.global && 922 | a.ignoreCase === b.ignoreCase && a.multiline === b.multiline; 923 | } 924 | 925 | function objEquiv (a, b) { 926 | if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) 927 | return false; 928 | // an identical "prototype" property. 929 | if (a.prototype !== b.prototype) return false; 930 | //~~~I've managed to break Object.keys through screwy arguments passing. 931 | // Converting to array solves the problem. 932 | if (isArguments(a)) { 933 | if (!isArguments(b)) { 934 | return false; 935 | } 936 | a = pSlice.call(a); 937 | b = pSlice.call(b); 938 | return expect.eql(a, b); 939 | } 940 | try{ 941 | var ka = keys(a), 942 | kb = keys(b), 943 | key, i; 944 | } catch (e) {//happens when one is a string literal and the other isn't 945 | return false; 946 | } 947 | // having the same number of owned properties (keys incorporates hasOwnProperty) 948 | if (ka.length != kb.length) 949 | return false; 950 | //the same set of keys (although not necessarily the same order), 951 | ka.sort(); 952 | kb.sort(); 953 | //~~~cheap key test 954 | for (i = ka.length - 1; i >= 0; i--) { 955 | if (ka[i] != kb[i]) 956 | return false; 957 | } 958 | //equivalent values for every corresponding key, and 959 | //~~~possibly expensive deep test 960 | for (i = ka.length - 1; i >= 0; i--) { 961 | key = ka[i]; 962 | if (!expect.eql(a[key], b[key])) 963 | return false; 964 | } 965 | return true; 966 | } 967 | 968 | var json = (function () { 969 | "use strict"; 970 | 971 | if ('object' == typeof JSON && JSON.parse && JSON.stringify) { 972 | return { 973 | parse: nativeJSON.parse 974 | , stringify: nativeJSON.stringify 975 | } 976 | } 977 | 978 | var JSON = {}; 979 | 980 | function f(n) { 981 | // Format integers to have at least two digits. 982 | return n < 10 ? '0' + n : n; 983 | } 984 | 985 | function date(d, key) { 986 | return isFinite(d.valueOf()) ? 987 | d.getUTCFullYear() + '-' + 988 | f(d.getUTCMonth() + 1) + '-' + 989 | f(d.getUTCDate()) + 'T' + 990 | f(d.getUTCHours()) + ':' + 991 | f(d.getUTCMinutes()) + ':' + 992 | f(d.getUTCSeconds()) + 'Z' : null; 993 | } 994 | 995 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 996 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 997 | gap, 998 | indent, 999 | meta = { // table of character substitutions 1000 | '\b': '\\b', 1001 | '\t': '\\t', 1002 | '\n': '\\n', 1003 | '\f': '\\f', 1004 | '\r': '\\r', 1005 | '"' : '\\"', 1006 | '\\': '\\\\' 1007 | }, 1008 | rep; 1009 | 1010 | 1011 | function quote(string) { 1012 | 1013 | // If the string contains no control characters, no quote characters, and no 1014 | // backslash characters, then we can safely slap some quotes around it. 1015 | // Otherwise we must also replace the offending characters with safe escape 1016 | // sequences. 1017 | 1018 | escapable.lastIndex = 0; 1019 | return escapable.test(string) ? '"' + string.replace(escapable, function (a) { 1020 | var c = meta[a]; 1021 | return typeof c === 'string' ? c : 1022 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 1023 | }) + '"' : '"' + string + '"'; 1024 | } 1025 | 1026 | 1027 | function str(key, holder) { 1028 | 1029 | // Produce a string from holder[key]. 1030 | 1031 | var i, // The loop counter. 1032 | k, // The member key. 1033 | v, // The member value. 1034 | length, 1035 | mind = gap, 1036 | partial, 1037 | value = holder[key]; 1038 | 1039 | // If the value has a toJSON method, call it to obtain a replacement value. 1040 | 1041 | if (value instanceof Date) { 1042 | value = date(key); 1043 | } 1044 | 1045 | // If we were called with a replacer function, then call the replacer to 1046 | // obtain a replacement value. 1047 | 1048 | if (typeof rep === 'function') { 1049 | value = rep.call(holder, key, value); 1050 | } 1051 | 1052 | // What happens next depends on the value's type. 1053 | 1054 | switch (typeof value) { 1055 | case 'string': 1056 | return quote(value); 1057 | 1058 | case 'number': 1059 | 1060 | // JSON numbers must be finite. Encode non-finite numbers as null. 1061 | 1062 | return isFinite(value) ? String(value) : 'null'; 1063 | 1064 | case 'boolean': 1065 | case 'null': 1066 | 1067 | // If the value is a boolean or null, convert it to a string. Note: 1068 | // typeof null does not produce 'null'. The case is included here in 1069 | // the remote chance that this gets fixed someday. 1070 | 1071 | return String(value); 1072 | 1073 | // If the type is 'object', we might be dealing with an object or an array or 1074 | // null. 1075 | 1076 | case 'object': 1077 | 1078 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 1079 | // so watch out for that case. 1080 | 1081 | if (!value) { 1082 | return 'null'; 1083 | } 1084 | 1085 | // Make an array to hold the partial results of stringifying this object value. 1086 | 1087 | gap += indent; 1088 | partial = []; 1089 | 1090 | // Is the value an array? 1091 | 1092 | if (Object.prototype.toString.apply(value) === '[object Array]') { 1093 | 1094 | // The value is an array. Stringify every element. Use null as a placeholder 1095 | // for non-JSON values. 1096 | 1097 | length = value.length; 1098 | for (i = 0; i < length; i += 1) { 1099 | partial[i] = str(i, value) || 'null'; 1100 | } 1101 | 1102 | // Join all of the elements together, separated with commas, and wrap them in 1103 | // brackets. 1104 | 1105 | v = partial.length === 0 ? '[]' : gap ? 1106 | '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : 1107 | '[' + partial.join(',') + ']'; 1108 | gap = mind; 1109 | return v; 1110 | } 1111 | 1112 | // If the replacer is an array, use it to select the members to be stringified. 1113 | 1114 | if (rep && typeof rep === 'object') { 1115 | length = rep.length; 1116 | for (i = 0; i < length; i += 1) { 1117 | if (typeof rep[i] === 'string') { 1118 | k = rep[i]; 1119 | v = str(k, value); 1120 | if (v) { 1121 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 1122 | } 1123 | } 1124 | } 1125 | } else { 1126 | 1127 | // Otherwise, iterate through all of the keys in the object. 1128 | 1129 | for (k in value) { 1130 | if (Object.prototype.hasOwnProperty.call(value, k)) { 1131 | v = str(k, value); 1132 | if (v) { 1133 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 1134 | } 1135 | } 1136 | } 1137 | } 1138 | 1139 | // Join all of the member texts together, separated with commas, 1140 | // and wrap them in braces. 1141 | 1142 | v = partial.length === 0 ? '{}' : gap ? 1143 | '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : 1144 | '{' + partial.join(',') + '}'; 1145 | gap = mind; 1146 | return v; 1147 | } 1148 | } 1149 | 1150 | // If the JSON object does not yet have a stringify method, give it one. 1151 | 1152 | JSON.stringify = function (value, replacer, space) { 1153 | 1154 | // The stringify method takes a value and an optional replacer, and an optional 1155 | // space parameter, and returns a JSON text. The replacer can be a function 1156 | // that can replace values, or an array of strings that will select the keys. 1157 | // A default replacer method can be provided. Use of the space parameter can 1158 | // produce text that is more easily readable. 1159 | 1160 | var i; 1161 | gap = ''; 1162 | indent = ''; 1163 | 1164 | // If the space parameter is a number, make an indent string containing that 1165 | // many spaces. 1166 | 1167 | if (typeof space === 'number') { 1168 | for (i = 0; i < space; i += 1) { 1169 | indent += ' '; 1170 | } 1171 | 1172 | // If the space parameter is a string, it will be used as the indent string. 1173 | 1174 | } else if (typeof space === 'string') { 1175 | indent = space; 1176 | } 1177 | 1178 | // If there is a replacer, it must be a function or an array. 1179 | // Otherwise, throw an error. 1180 | 1181 | rep = replacer; 1182 | if (replacer && typeof replacer !== 'function' && 1183 | (typeof replacer !== 'object' || 1184 | typeof replacer.length !== 'number')) { 1185 | throw new Error('JSON.stringify'); 1186 | } 1187 | 1188 | // Make a fake root object containing our value under the key of ''. 1189 | // Return the result of stringifying the value. 1190 | 1191 | return str('', {'': value}); 1192 | }; 1193 | 1194 | // If the JSON object does not yet have a parse method, give it one. 1195 | 1196 | JSON.parse = function (text, reviver) { 1197 | // The parse method takes a text and an optional reviver function, and returns 1198 | // a JavaScript value if the text is a valid JSON text. 1199 | 1200 | var j; 1201 | 1202 | function walk(holder, key) { 1203 | 1204 | // The walk method is used to recursively walk the resulting structure so 1205 | // that modifications can be made. 1206 | 1207 | var k, v, value = holder[key]; 1208 | if (value && typeof value === 'object') { 1209 | for (k in value) { 1210 | if (Object.prototype.hasOwnProperty.call(value, k)) { 1211 | v = walk(value, k); 1212 | if (v !== undefined) { 1213 | value[k] = v; 1214 | } else { 1215 | delete value[k]; 1216 | } 1217 | } 1218 | } 1219 | } 1220 | return reviver.call(holder, key, value); 1221 | } 1222 | 1223 | 1224 | // Parsing happens in four stages. In the first stage, we replace certain 1225 | // Unicode characters with escape sequences. JavaScript handles many characters 1226 | // incorrectly, either silently deleting them, or treating them as line endings. 1227 | 1228 | text = String(text); 1229 | cx.lastIndex = 0; 1230 | if (cx.test(text)) { 1231 | text = text.replace(cx, function (a) { 1232 | return '\\u' + 1233 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 1234 | }); 1235 | } 1236 | 1237 | // In the second stage, we run the text against regular expressions that look 1238 | // for non-JSON patterns. We are especially concerned with '()' and 'new' 1239 | // because they can cause invocation, and '=' because it can cause mutation. 1240 | // But just to be safe, we want to reject all unexpected forms. 1241 | 1242 | // We split the second stage into 4 regexp operations in order to work around 1243 | // crippling inefficiencies in IE's and Safari's regexp engines. First we 1244 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we 1245 | // replace all simple value tokens with ']' characters. Third, we delete all 1246 | // open brackets that follow a colon or comma or that begin the text. Finally, 1247 | // we look to see that the remaining characters are only whitespace or ']' or 1248 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. 1249 | 1250 | if (/^[\],:{}\s]*$/ 1251 | .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') 1252 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') 1253 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { 1254 | 1255 | // In the third stage we use the eval function to compile the text into a 1256 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity 1257 | // in JavaScript: it can begin a block or an object literal. We wrap the text 1258 | // in parens to eliminate the ambiguity. 1259 | 1260 | j = eval('(' + text + ')'); 1261 | 1262 | // In the optional fourth stage, we recursively walk the new structure, passing 1263 | // each name/value pair to a reviver function for possible transformation. 1264 | 1265 | return typeof reviver === 'function' ? 1266 | walk({'': j}, '') : j; 1267 | } 1268 | 1269 | // If the text is not JSON parseable, then a SyntaxError is thrown. 1270 | 1271 | throw new SyntaxError('JSON.parse'); 1272 | }; 1273 | 1274 | return JSON; 1275 | })(); 1276 | 1277 | if ('undefined' != typeof window) { 1278 | window.expect = module.exports; 1279 | } 1280 | 1281 | })( 1282 | this 1283 | , 'undefined' != typeof module ? module : {exports: {}} 1284 | ); -------------------------------------------------------------------------------- /test/functions.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('functions',function(a){ 3 | function Func(){ 4 | return Func; 5 | } 6 | describe('Functions',function(){ 7 | beforeEach(function(done){ // IE6 stack release 8 | setTimeout(function(){done()}, 0); 9 | }); 10 | it('is()',function(){ 11 | expect(theory.fns(function(){}).is()).to.be(true); 12 | expect(theory.fns('').is()).to.be(false); 13 | expect(theory.fns('a').is()).to.be(false); 14 | expect(theory.fns(0).is()).to.be(false); 15 | expect(theory.fns(1).is()).to.be(false); 16 | expect(theory.fns([]).is()).to.be(false); 17 | expect(theory.fns([1]).is()).to.be(false); 18 | expect(theory.fns({}).is()).to.be(false); 19 | expect(theory.fns({a:1}).is()).to.be(false); 20 | expect(theory.fns(false).is()).to.be(false); 21 | expect(theory.fns(true).is()).to.be(false); 22 | }); 23 | it('is',function(){ 24 | expect(theory.fns.is(function(){})).to.be(true); 25 | expect(theory.fns.is('')).to.be(false); 26 | expect(theory.fns.is('a')).to.be(false); 27 | expect(theory.fns.is(0)).to.be(false); 28 | expect(theory.fns.is(1)).to.be(false); 29 | expect(theory.fns.is([])).to.be(false); 30 | expect(theory.fns.is([1])).to.be(false); 31 | expect(theory.fns.is({})).to.be(false); 32 | expect(theory.fns.is({a:1})).to.be(false); 33 | expect(theory.fns.is(false)).to.be(false); 34 | expect(theory.fns.is(true)).to.be(false); 35 | }); 36 | it('sort',function(){ 37 | Func.sort = theory.fns.sort([true,false,0,1,'','a',[],[2],{},{b:3},function(){}]); 38 | expect(Func.sort.b).to.eql([true,false]); 39 | expect(Func.sort.n).to.eql([0,1]); 40 | expect(Func.sort.t).to.eql(['','a']); 41 | expect(Func.sort.l).to.eql([[],[2]]); 42 | expect(Func.sort.o).to.eql([{},{b:3}]); 43 | expect(Func.sort.f[0]).to.be.a('function'); 44 | }); 45 | it('pass',function(){ 46 | expect(theory.fns(function(){ this.pass = 5; return this.pass +2; }).pass(Func)()).to.be(7); 47 | expect(theory.fns.pass(function(){ this.pass = 5; return this.pass +2; },Func)()).to.be(7); 48 | }); 49 | it('flow',function(done){ 50 | theory.fns.flow([ 51 | function(next){ 52 | next(Func.val = 5); 53 | },function(x,next){ 54 | next(x*x); 55 | } 56 | ],function(x){ 57 | Func.val = x*x; 58 | expect(Func.val).to.be(625); 59 | done(); 60 | }); 61 | }); 62 | }); 63 | return Func; 64 | }); -------------------------------------------------------------------------------- /test/mocha.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 4 | padding: 60px 50px; 5 | } 6 | 7 | #mocha ul, #mocha li { 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | #mocha ul { 13 | list-style: none; 14 | } 15 | 16 | #mocha h1, #mocha h2 { 17 | margin: 0; 18 | } 19 | 20 | #mocha h1 { 21 | margin-top: 15px; 22 | font-size: 1em; 23 | font-weight: 200; 24 | } 25 | 26 | #mocha h1 a { 27 | text-decoration: none; 28 | color: inherit; 29 | } 30 | 31 | #mocha h1 a:hover { 32 | text-decoration: underline; 33 | } 34 | 35 | #mocha .suite .suite h1 { 36 | margin-top: 0; 37 | font-size: .8em; 38 | } 39 | 40 | #mocha h2 { 41 | font-size: 12px; 42 | font-weight: normal; 43 | cursor: pointer; 44 | } 45 | 46 | #mocha .suite { 47 | margin-left: 15px; 48 | } 49 | 50 | #mocha .test { 51 | margin-left: 15px; 52 | } 53 | 54 | #mocha .test:hover h2::after { 55 | position: relative; 56 | top: 0; 57 | right: -10px; 58 | content: '(view source)'; 59 | font-size: 12px; 60 | font-family: arial; 61 | color: #888; 62 | } 63 | 64 | #mocha .test.pending:hover h2::after { 65 | content: '(pending)'; 66 | font-family: arial; 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 | } 134 | 135 | #mocha .test pre { 136 | display: inline-block; 137 | font: 12px/1.5 monaco, monospace; 138 | margin: 5px; 139 | padding: 15px; 140 | border: 1px solid #eee; 141 | border-bottom-color: #ddd; 142 | -webkit-border-radius: 3px; 143 | -webkit-box-shadow: 0 1px 3px #eee; 144 | } 145 | 146 | #error { 147 | color: #c00; 148 | font-size: 1.5 em; 149 | font-weight: 100; 150 | letter-spacing: 1px; 151 | } 152 | 153 | #stats { 154 | position: fixed; 155 | top: 15px; 156 | right: 10px; 157 | font-size: 12px; 158 | margin: 0; 159 | color: #888; 160 | } 161 | 162 | #stats .progress { 163 | float: right; 164 | padding-top: 0; 165 | } 166 | 167 | #stats em { 168 | color: black; 169 | } 170 | 171 | #stats li { 172 | display: inline-block; 173 | margin: 0 5px; 174 | list-style: none; 175 | padding-top: 11px; 176 | } 177 | 178 | code .comment { color: #ddd } 179 | code .init { color: #2F6FAD } 180 | code .string { color: #5890AD } 181 | code .keyword { color: #8A6343 } 182 | code .number { color: #2F6FAD } 183 | -------------------------------------------------------------------------------- /test/mocha.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Theory Tests 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Theory Tests 14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /test/mocha.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amark/theory/223f5e0623d40709f27706409b0d70d4bc6c58e3/test/mocha.js -------------------------------------------------------------------------------- /test/numbers.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('numbers',function(a){ 3 | describe('Numbers',function(){ 4 | it('is()',function(){ 5 | expect(theory.num(0).is()).to.be(true); 6 | expect(theory.num(1).is()).to.be(true); 7 | expect(theory.num(Infinity).is()).to.be(true); 8 | expect(theory.num(NaN).is()).to.be(false); 9 | expect(theory.num('').is()).to.be(false); 10 | expect(theory.num('a').is()).to.be(false); 11 | expect(theory.num([]).is()).to.be(false); 12 | expect(theory.num([1]).is()).to.be(false); 13 | expect(theory.num({}).is()).to.be(false); 14 | expect(theory.num({a:1}).is()).to.be(false); 15 | expect(theory.num(false).is()).to.be(false); 16 | expect(theory.num(true).is()).to.be(false); 17 | expect(theory.num(function(){}).is()).to.be(false); 18 | }); 19 | it('is',function(){ 20 | expect(theory.num.is(0)).to.be(true); 21 | expect(theory.num.is(1)).to.be(true); 22 | expect(theory.num.is(Infinity)).to.be(true); 23 | expect(theory.num.is(NaN)).to.be(false); 24 | expect(theory.num.is('')).to.be(false); 25 | expect(theory.num.is('a')).to.be(false); 26 | expect(theory.num.is([])).to.be(false); 27 | expect(theory.num.is([1])).to.be(false); 28 | expect(theory.num.is({})).to.be(false); 29 | expect(theory.num.is({a:1})).to.be(false); 30 | expect(theory.num.is(false)).to.be(false); 31 | expect(theory.num.is(true)).to.be(false); 32 | expect(theory.num.is(function(){})).to.be(false); 33 | }); 34 | it('ify',function(){ 35 | expect(theory.num('asdf').ify()).to.be(undefined); 36 | expect(theory.num.ify('asdf')).to.be(undefined); 37 | expect(theory.num(0).ify()).to.be(0); 38 | expect(theory.num.ify(0)).to.be(0); 39 | expect(theory.num(1).ify()).to.be(1); 40 | expect(theory.num.ify(1)).to.be(1); 41 | expect(theory.num(-1).ify()).to.be(-1); 42 | expect(theory.num.ify(-1)).to.be(-1); 43 | expect(theory.num('0').ify()).to.be(0); 44 | expect(theory.num.ify('0')).to.be(0); 45 | expect(theory.num('1').ify()).to.be(1); 46 | expect(theory.num.ify('1')).to.be(1); 47 | expect(theory.num('-1').ify()).to.be(-1); 48 | expect(theory.num.ify('-1')).to.be(-1); 49 | expect(theory.num('10').ify()).to.be(10); 50 | expect(theory.num.ify('10')).to.be(10); 51 | expect(theory.num('01').ify()).to.be(1); 52 | expect(theory.num.ify('01')).to.be(1); 53 | expect(theory.num('37.91').ify()).to.be(37.91); 54 | expect(theory.num.ify('37.91')).to.be(37.91); 55 | expect(theory.num('-7.3').ify()).to.be(-7.3); 56 | expect(theory.num.ify('-7.3')).to.be(-7.3); 57 | expect(theory.num('A14C').ify()).to.be(14); 58 | expect(theory.num.ify('A14C')).to.be(14); 59 | expect(theory.num('A14C2').ify()).to.be(14); 60 | expect(theory.num.ify('A14C2')).to.be(14); 61 | expect(theory.num('A2.1,2').ify()).to.be(2.1); 62 | expect(theory.num.ify('A2.1,2')).to.be(2.1); 63 | }); 64 | it('ify []',function(){ 65 | expect(theory.num(0).ify([])).to.eql([0]); 66 | expect(theory.num.ify(0,[])).to.eql([0]); 67 | expect(theory.num(1).ify([])).to.eql([1]); 68 | expect(theory.num.ify(1,[])).to.eql([1]); 69 | expect(theory.num('0').ify([])).to.eql([0]); 70 | expect(theory.num.ify('0',[])).to.eql([0]); 71 | expect(theory.num('A14C').ify([])).to.eql([14]); 72 | expect(theory.num.ify('A14C',[])).to.eql([14]); 73 | expect(theory.num('A14C2').ify([])).to.eql([14,2]); 74 | expect(theory.num.ify('A14C2',[])).to.eql([14,2]); 75 | expect(theory.num('A0.4C45,-100. Z 0032 - 5').ify([])).to.eql([0.4,45,-100,32,5]); 76 | expect(theory.num.ify('A0.4C45,-100. Z 0032 - 5',[])).to.eql([0.4,45,-100,32,5]); 77 | }); 78 | it('random',function(){ 79 | expect(theory.num.r().toString().length).to.be(6); 80 | expect(theory.num(11).r().toString().length).to.be(11); 81 | expect(theory.num.r([10,99]).toString().length).to.be(2); 82 | expect(theory.num([-99,-10]).r().toString().length).to.be(3); 83 | }); 84 | }); 85 | return 42; 86 | }); -------------------------------------------------------------------------------- /test/objects.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('hash',function(a){ 3 | //var s='',i;for(i in a){s+=i+', '};alert('hash: '+s); 4 | describe('Objects',function(){ 5 | it('deps',function(){ 6 | expect(a.object_is).to.be(undefined); 7 | expect(root.ObjectUtils).to.be.ok(); 8 | expect(a.object_util).to.be(undefined); 9 | expect(a.get.has.status).to.be('done'); 10 | expect(theory.object_union).to.eql({u:1}); 11 | expect(root.CopyObject).to.be.ok(); 12 | }); 13 | }); 14 | return {all:'your',tests:'belong',to:'us'}; 15 | },{ 16 | './sub/object_is':'' 17 | ,'./sub/object_util':'util' 18 | ,'./sub/object_get':'get' 19 | }); -------------------------------------------------------------------------------- /test/one.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('one',function(a){ 3 | return 1; 4 | }); -------------------------------------------------------------------------------- /test/ready.js: -------------------------------------------------------------------------------- 1 | root.Ready = true; -------------------------------------------------------------------------------- /test/strings.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('language',function(a){ 3 | var t = {}; 4 | describe('Text',function(){ 5 | it('is()',function(){ 6 | expect(theory.text('').is()).to.be(true); 7 | expect(theory.text('a').is()).to.be(true); 8 | expect(theory.text(false).is()).to.be(false); 9 | expect(theory.text(true).is()).to.be(false); 10 | expect(theory.text(0).is()).to.be(false); 11 | expect(theory.text(1).is()).to.be(false); 12 | expect(theory.text([]).is()).to.be(false); 13 | expect(theory.text([1]).is()).to.be(false); 14 | expect(theory.text({}).is()).to.be(false); 15 | expect(theory.text({a:1}).is()).to.be(false); 16 | expect(theory.text(function(){}).is()).to.be(false); 17 | }); 18 | it('is',function(){ 19 | expect(theory.text.is('')).to.be(true); 20 | expect(theory.text.is('a')).to.be(true); 21 | expect(theory.text.is(false)).to.be(false); 22 | expect(theory.text.is(true)).to.be(false); 23 | expect(theory.text.is(0)).to.be(false); 24 | expect(theory.text.is(1)).to.be(false); 25 | expect(theory.text.is([])).to.be(false); 26 | expect(theory.text.is([1])).to.be(false); 27 | expect(theory.text.is({})).to.be(false); 28 | expect(theory.text.is({a:1})).to.be(false); 29 | expect(theory.text.is(function(){})).to.be(false); 30 | }); 31 | it('ify',function(){ 32 | expect(theory.text(0).ify()).to.be('0'); 33 | expect(theory.text.ify(0)).to.be('0'); 34 | expect(theory.text(22).ify()).to.be('22'); 35 | expect(theory.text.ify(22)).to.be('22'); 36 | expect(theory.text([true,33,'yay']).ify()).to.be('[true,33,"yay"]'); 37 | expect(theory.text.ify([true,33,'yay'])).to.be('[true,33,"yay"]'); 38 | expect(theory.text({a:0,b:'1',c:[0,'1'],d:{e:'f'}}).ify()).to.be('{"a":0,"b":"1","c":[0,"1"],"d":{"e":"f"}}'); 39 | expect(theory.text.ify({a:0,b:'1',c:[0,'1'],d:{e:'f'}})).to.be('{"a":0,"b":"1","c":[0,"1"],"d":{"e":"f"}}'); 40 | expect(theory.text(false).ify()).to.be('false'); 41 | expect(theory.text.ify(false)).to.be('false'); 42 | expect(theory.text(true).ify()).to.be('true'); 43 | expect(theory.text.ify(true)).to.be('true'); 44 | }); 45 | it('random',function(){ 46 | expect(theory.text.r().length).to.be(16); 47 | expect(theory.text(11).r().length).to.be(11); 48 | expect(theory.text.r(4).length).to.be(4); 49 | t.tr = theory.text.r(2,'as'); expect((t.tr=='as'||t.tr=='aa'||t.tr=='sa'||t.tr=='ss')).to.be.ok(); 50 | t.tr = theory.text.random('as',2); expect((t.tr=='as'||t.tr=='aa'||t.tr=='sa'||t.tr=='ss')).to.be.ok(); 51 | t.tr = theory.text(2).random('as'); expect((t.tr=='as'||t.tr=='aa'||t.tr=='sa'||t.tr=='ss')).to.be.ok(); 52 | t.tr = theory.text('as').random(2); expect((t.tr=='as'||t.tr=='aa'||t.tr=='sa'||t.tr=='ss')).to.be.ok(); 53 | }); 54 | it('clip',function(){ 55 | expect(theory.text('A B C D').clip(' ',0,-1)).to.be('A B C'); 56 | expect(theory.text.clip('A B C D',' ',0,-1)).to.be('A B C'); 57 | expect(theory.text("path/to/awesome.js").clip('.',-1)).to.be('js'); 58 | expect(theory.text.clip("path/to/awesome.js",'.',-1)).to.be('js'); 59 | }); 60 | it('caps',function(){ 61 | expect(theory.text("shout!").caps()).to.be("SHOUT!"); 62 | expect(theory.text.caps("shout!")).to.be("SHOUT!"); 63 | }); 64 | it('low',function(){ 65 | expect(theory.text("HUSH 1").low()).to.be("hush 1"); 66 | expect(theory.text.low("HUSH 1")).to.be("hush 1"); 67 | }); 68 | }); 69 | return "Hello World!"; 70 | }); -------------------------------------------------------------------------------- /test/sub.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../theory') 2 | ('sub',function(a){ 3 | describe('sub',function(){ 4 | it('a',function(){ 5 | expect(root.Add(2, a.one)).to.be(3); 6 | }); 7 | }); 8 | return a.one; 9 | },[ 10 | './one' 11 | ,'./sub/c' 12 | ]); -------------------------------------------------------------------------------- /test/sub/add.js: -------------------------------------------------------------------------------- 1 | root.Add = function(z, y){ 2 | return z + y; 3 | } -------------------------------------------------------------------------------- /test/sub/c.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../../theory') 2 | ('check',function(a){ 3 | describe('sub',function(){ 4 | it('c',function(){ 5 | expect(a.f).to.be('g'); 6 | }); 7 | }); 8 | return a; 9 | },{ 10 | '../d':1 11 | ,'./e':'f' 12 | }); -------------------------------------------------------------------------------- /test/sub/e.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../../theory') 2 | ('fan',function(a){ 3 | return 'g'; 4 | }); -------------------------------------------------------------------------------- /test/sub/four.js: -------------------------------------------------------------------------------- 1 | root.Four = 4; -------------------------------------------------------------------------------- /test/sub/object_copy.js: -------------------------------------------------------------------------------- 1 | describe('objects',function(){ 2 | var t = {}; 3 | beforeEach(function(done){ // IE6 stack release 4 | setTimeout(function(){done()}, 0); 5 | }); 6 | it('copy',function(){ 7 | expect(theory.obj([]).copy()).to.eql([]); 8 | expect(theory.obj.copy([])).to.eql([]); 9 | expect(theory.obj({}).copy()).to.eql({}); 10 | expect(theory.obj.copy({})).to.eql({}); 11 | t.val = {a:1,b:'c',d:[0,1,2],e:{f:'g'},h:function(){ return 1 }}; 12 | t.dup = theory.obj(t.val).copy(); 13 | expect(t.dup.a).to.be(t.val.a); 14 | expect(t.dup.b).to.be(t.val.b); 15 | expect(t.dup.d).to.eql(t.val.d); 16 | expect(t.dup.e).to.eql(t.val.e); 17 | expect(t.dup.h()).to.eql(t.val.h()); 18 | t.dup.d = 'diff'; 19 | expect(t.dup.d).to.not.be(t.val.d); 20 | t.val = t.dup = undefined; 21 | t.val = {a:1,b:'c',d:[0,1,2],e:{f:'g'},h:function(){ return 1 }}; 22 | t.dup = theory.obj(t.val).copy(); 23 | expect(t.dup.a).to.be(t.val.a); 24 | expect(t.dup.b).to.be(t.val.b); 25 | expect(t.dup.d).to.eql(t.val.d); 26 | expect(t.dup.e).to.eql(t.val.e); 27 | expect(t.dup.h()).to.eql(t.val.h()); 28 | t.dup.d = 'diff'; 29 | expect(t.dup.d).to.not.be(t.val.d); 30 | }); 31 | }); 32 | root.CopyObject = true; -------------------------------------------------------------------------------- /test/sub/object_get.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../../theory') 2 | ('hash',function(a){ 3 | describe('objects',function(){ 4 | beforeEach(function(done){ // IE6 stack release 5 | setTimeout(function(){done()}, 0); 6 | }); 7 | it('get',function(){ 8 | expect(theory.obj({a:1,b:2,c:3}).get('b')).to.be(2); 9 | expect(theory.obj.get({a:1,b:2,c:3},'b')).to.be(2); 10 | expect(theory.obj({a:1,b:{x:{z:7}},c:3}).get('b.pow.z.x')).to.be(undefined); 11 | expect(theory.obj.get({a:1,b:{x:{z:7}},c:3},'b.pow.z.x')).to.be(undefined); 12 | expect(theory.obj({a:1,b:{x:{z:7}},c:3}).get('b.x.z')).to.be(7); 13 | expect(theory.obj.get({a:1,b:{x:{z:7}},c:3},'b.x.z')).to.be(7); 14 | expect(theory.obj({a:1,b:[[1,2],[3,4],[{x:9}]],c:3}).get('b.x')).to.be(9); 15 | expect(theory.obj.get({a:1,b:[[1,2],[3,4],[{x:9}]],c:3},'b.x')).to.be(9); 16 | expect(theory.obj({a:1,b:[[1,2],[3,4],{x:9}],c:3}).get('b.1.x')).to.be(undefined); 17 | expect(theory.obj.get({a:1,b:[[1,2],[3,4],{x:9}],c:3},'b.1.x')).to.be(undefined); 18 | expect(theory.obj({a:1,b:[[1,2],[3,4],{x:9}],c:3}).get('b.3.x')).to.be(9); 19 | expect(theory.obj.get({a:1,b:[[1,2],[3,4],{x:9}],c:3},'b.3.x')).to.be(9); 20 | expect(theory.obj({a:1,b:[[1,2],[3,4],{x:9}],c:3}).get('b.-1.x')).to.be(9); 21 | expect(theory.obj.get({a:1,b:[[1,2],[3,4],{x:9}],c:3},'b.-1.x')).to.be(9); 22 | expect(theory.obj({a:{b:{c:null}}}).get('a.b.c')).to.be(null); 23 | expect(theory.obj.get({a:{b:{c:null}}},'a.b.c')).to.be(null); 24 | expect(theory.obj({a:{b:{c:null}}}).get('a.b.c->')).to.be.a('function'); 25 | expect(theory.obj.get({a:{b:{c:null}}},'a.b.c->')).to.be.a('function'); 26 | expect(theory.obj({a:{b:{c:function(){return 1}}}}).get('a.b.c->')()).to.be(1); 27 | expect(theory.obj.get({a:{b:{c:function(){return 1}}}},'a.b.c->')()).to.be(1); 28 | }); 29 | }); 30 | //var s='',i;for(i in a){s+=i+', '};alert('get: '+s); 31 | return {has:{status:'done'}}; 32 | },{ 33 | './object_has':'has' 34 | ,'./object_copy':'' 35 | }) -------------------------------------------------------------------------------- /test/sub/object_has.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../../theory') 2 | ('object_has',function(a){ 3 | describe('objects',function(){ 4 | it('has',function(){ 5 | expect(theory.obj({yay:false}).has('yay')).to.be(true); 6 | expect(theory.obj.has({yay:false},'yay')).to.be(true); 7 | expect(theory.obj({yay:false}).has('toString')).to.be(false); 8 | expect(theory.obj.has({yay:false},'toString')).to.be(false); 9 | }); 10 | }); 11 | return {status:'done'}; 12 | },['./object_union']); -------------------------------------------------------------------------------- /test/sub/object_is.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../../theory') 2 | ({name: 'is_object' 3 | , init: function(a){ 4 | describe('objects',function(){ 5 | it('is()',function(){ 6 | expect(theory.obj({}).is()).to.be(true); 7 | expect(theory.obj({a:1}).is()).to.be(true); 8 | expect(theory.obj(0).is()).to.be(false); 9 | expect(theory.obj(1).is()).to.be(false); 10 | expect(theory.obj('').is()).to.be(false); 11 | expect(theory.obj('a').is()).to.be(false); 12 | expect(theory.obj([]).is()).to.be(false); 13 | expect(theory.obj([1]).is()).to.be(false); 14 | expect(theory.obj(false).is()).to.be(false); 15 | expect(theory.obj(true).is()).to.be(false); 16 | expect(theory.obj(function(){}).is()).to.be(false); 17 | }); 18 | it('is',function(){ 19 | expect(theory.obj.is({})).to.be(true); 20 | expect(theory.obj.is({a:1})).to.be(true); 21 | expect(theory.obj.is(0)).to.be(false); 22 | expect(theory.obj.is(1)).to.be(false); 23 | expect(theory.obj.is('')).to.be(false); 24 | expect(theory.obj.is('a')).to.be(false); 25 | expect(theory.obj.is([])).to.be(false); 26 | expect(theory.obj.is([1])).to.be(false); 27 | expect(theory.obj.is(false)).to.be(false); 28 | expect(theory.obj.is(true)).to.be(false); 29 | expect(theory.obj.is(function(){})).to.be(false); 30 | }); 31 | }); 32 | }}); -------------------------------------------------------------------------------- /test/sub/object_union.js: -------------------------------------------------------------------------------- 1 | module.exports=require('../../theory') 2 | ('object_union',function(a){ 3 | describe('objects',function(){ 4 | beforeEach(function(done){ // IE6 stack release 5 | setTimeout(function(){done()}, 0); 6 | }); 7 | it('union',function(){ 8 | expect(theory.obj({a:'b',c:'d'}).union({c:1,z:2})).to.eql({a:'b',c:'d',z:2}); 9 | expect(theory.obj.union({a:'b',c:'d'},{c:1,z:2})).to.eql({a:'b',c:'d',z:2}); 10 | expect(theory.obj({a:'b',c:'d'}).union({c:1,z:2},{x:3,y:4})).to.eql({a:'b',c:'d',z:2,x:3,y:4}); 11 | expect(theory.obj.union({a:'b',c:'d'},{c:1,z:2},{x:3,y:4})).to.eql({a:'b',c:'d',z:2,x:3,y:4}); 12 | expect(theory.obj([{a:'b',c:'d'},{c:1,z:2}]).u({ig:'nore'})).to.eql({a:'b',c:'d',z:2}); 13 | expect(theory.obj.u([{a:'b',c:'d'},{c:1,z:2}],{ig:'nore'})).to.eql({a:'b',c:'d',z:2}); 14 | }); 15 | }); 16 | return {u:1}; 17 | }); -------------------------------------------------------------------------------- /test/sub/object_util.js: -------------------------------------------------------------------------------- 1 | describe('objects',function(){ 2 | beforeEach(function(done){ // IE6 stack release 3 | setTimeout(function(){done()}, 0); 4 | }); 5 | it('ify',function(){ 6 | expect(theory.obj('[0,1]').ify()).to.eql([0,1]); 7 | expect(theory.obj.ify('[0,1]')).to.eql([0,1]); 8 | expect(theory.obj('{"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}}').ify()).to.eql({"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}}); 9 | expect(theory.obj.ify('{"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}}')).to.eql({"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}}); 10 | }); 11 | it('empty',function(){ 12 | expect(theory.obj({}).empty()).to.be(true); 13 | expect(theory.obj.empty({})).to.be(true); 14 | expect(theory.obj({a:false}).empty()).to.be(false); 15 | expect(theory.obj.empty({a:false})).to.be(false); 16 | }); 17 | it('each',function(){ 18 | expect(theory.obj({a:'z',b:'y',c:'x'}).each(function(v,i,t){ t(v,i) })).to.eql({x:'c',y:'b',z:'a'}); 19 | expect(theory.obj.each({a:'z',b:'y',c:'x'},function(v,i,t){ t(v,i) })).to.eql({x:'c',y:'b',z:'a'}); 20 | expect(theory.obj({a:'z',b:false,c:'x'}).each(function(v,i,t){ if(!v){ return } t(i,v) })).to.eql({a:'z',c:'x'}); 21 | expect(theory.obj.each({a:'z',b:false,c:'x'},function(v,i,t){ if(!v){ return } t(i,v) })).to.eql({a:'z',c:'x'}); 22 | expect(theory.obj({a:'z',b:3,c:'x'}).each(function(v,i,t){ if(v===3){ return 0 }})).to.be(0); 23 | expect(theory.obj.each({a:'z',b:3,c:'x'},function(v,i,t){ if(v===3){ return 0 }})).to.be(0); 24 | }); 25 | }); 26 | root.ObjectUtils = true; -------------------------------------------------------------------------------- /test/sub/three.js: -------------------------------------------------------------------------------- 1 | root.Three = 3; -------------------------------------------------------------------------------- /test/sub/z.js: -------------------------------------------------------------------------------- 1 | root.ZERO=0; -------------------------------------------------------------------------------- /test/time.js: -------------------------------------------------------------------------------- 1 | describe('Time',function(){ 2 | var t = {}; 3 | it('is',function(){ 4 | t.ts = theory.time.is(); 5 | expect(13 <= t.ts.toString().length).to.be.ok(); 6 | }); 7 | it('now',function(){ 8 | t.ts = theory.time.now(); 9 | expect(15 <= t.ts.toString().length).to.be.ok(); 10 | }); 11 | it('loop',function(done){ 12 | t.count = 0; 13 | t.loop = theory.time.loop(function(){ 14 | if(t.count === 19){ 15 | expect(theory.time.stop(t.loop)).to.be.ok(); 16 | return done(); 17 | } t.count++; 18 | },7); 19 | }); 20 | it('wait',function(done){ 21 | t.wait = theory.time.wait(function(){ 22 | expect(true).to.be.ok(); 23 | done(); 24 | },57); 25 | }); 26 | }); 27 | root.TimeFull = 'Time Travel'; -------------------------------------------------------------------------------- /theory.js: -------------------------------------------------------------------------------- 1 | /** THEORY **/ 2 | ;var theory=theory||null;if(theory){root.init()}else{ 3 | theory=(function(b,c,fn){ 4 | function theory(b,c){ 5 | var a = (function(b,c){ 6 | var a = a||theory, l = arguments.length; 7 | if(l == 1){ 8 | if(a.text.is(b)){ 9 | return a.obj.get(a,b); 10 | } 11 | } if(l == 2){ 12 | if(a.text.is(c)){ 13 | return a.obj.get(b,c); 14 | } 15 | } 16 | }); 17 | if(this && theory.bi.is(this)){ return theorize(a) } 18 | return a(b,c); 19 | } var $, _; 20 | function theorize(a){ 21 | var $=undefined,_=undefined; 22 | a.log = (function(s){ 23 | //console.log(s); 24 | return a.log; 25 | }); 26 | a.fns = (function(){ 27 | function fns($){ 28 | fns.$_ = $ !== undefined? $ : _; 29 | return fns; 30 | } var $; 31 | fns.is = (function(fn){ 32 | $ = fns.$_;fns.$_=_;fn = $||fn; 33 | return (fn instanceof Function)? true : false; 34 | }); 35 | fns.flow = (function(s,f){ // TODO: BUG: Seriously reconsider then().done() because they fail on .end() after a synchronous callback, provide no doc or support for it until you do. 36 | var t = (function(){ 37 | var args = a.list.slit.call(arguments,0), n; 38 | args.push(t); 39 | n = (function(){ 40 | (t.list[t.i++] || t.end).apply(t,args); 41 | })(); 42 | return t; 43 | }), list = a.list.is(s)? s : a.list.is(f)? f : 0; 44 | f = a.fns.is(f)? f : a.fns.is(s)? s : function(){}; 45 | t.end = list? f : function(){}; // TODO: Receives `next` as param, is this desirable? 46 | t.then = (function(fn){ 47 | if(a.fns.is(fn)){ t.list.push(fn) } 48 | return t; 49 | }); 50 | t.done = (function(fn){ 51 | t.end = a.fns.is(fn)? fn : t.end; 52 | return t; 53 | }); 54 | t.list = list || []; 55 | t.i = 0; 56 | if(list){ t() } 57 | else{ f(t) } 58 | return t; 59 | }); 60 | fns.sort = (function(args){ 61 | if(!args){ return {e:"Empty"} } 62 | var args = a.list.slit.call(args, 0), r = {b:[],n:[],t:[],l:[],o:[],f:[]}; 63 | for(var i = 0; i < args.length; i++){ 64 | if (fns.is(args[i])){ 65 | r.f.push(args[i]); 66 | } else if(a.list.is(args[i])){ 67 | r.l.push(args[i]); 68 | } else if(a.obj.is(args[i])){ 69 | r.o.push(args[i]); 70 | } else if(a.num.is(args[i])){ 71 | r.n.push(args[i]); 72 | } else if(a.text.is(args[i])){ 73 | r.t.push(args[i]); 74 | } else if(a.bi.is(args[i])){ 75 | r.b.push(args[i]); 76 | } 77 | } 78 | return r; 79 | }); 80 | fns.$ = (function(t,v){ 81 | v = t.$; 82 | t.$=_; 83 | return v; 84 | }); 85 | fns.pass = (function(fn,o){ 86 | $ = fns.$_;fns.$_=_;if($){ o=fn;fn=$ } 87 | if(a.text.is(o)){ var tmp = a(fn,o); o = fn; fn = tmp } 88 | if(!fns.is(fn)){ return _ } 89 | return (function(){ 90 | return fn.apply(o, a.list.slit.call(arguments)); 91 | }); 92 | }); 93 | return fns; 94 | })(); 95 | a.list = (function(){ 96 | function list($){ 97 | list.$ = $ !== undefined? $ : _; 98 | return list; 99 | } var $; 100 | list.is = (function(l){ 101 | l = a.fns.$(list)||l; 102 | return (l instanceof Array)? true : false; 103 | }); 104 | list.slit = Array.prototype.slice; 105 | list.at = (function(l,i,opt){ 106 | var r; 107 | if($=a.fns.$(list)){ opt=i;i=l;l=$ } 108 | if(!l||!i){ return undefined } 109 | if(a.text.is(l)){ l = l.split('') } 110 | if(i < 0){ 111 | r = l.slice().reverse(); 112 | i = Math.abs(i); 113 | } opt = opt || {}; 114 | if(opt.ebb){ 115 | for(--i; 0 <= i; i--){ // upgrade to functionalize 116 | if(r && r[i] !== undefined){ return r[i] } 117 | else if(l[i] !== undefined){ return l[i] } 118 | } return undefined; 119 | } 120 | return (r||l)[--i]; 121 | }); 122 | list.ify = (function(l,opt){ 123 | if($=a.fns.$(list)){ opt=l;l=$ } 124 | opt=opt||{}; 125 | opt.wedge = opt.wedge||':'; 126 | opt.split = opt.split||','; 127 | var r = []; 128 | if(a.list.is(l)){ 129 | return l; 130 | } else 131 | if(a.text.is(l)){ 132 | var r = new RegExp("\\s*\\"+opt.split+"\\s*",'ig'); 133 | return l.split(r); 134 | } else 135 | if(a.obj.is(l)){ 136 | a.obj(l).each(function(v,i){ 137 | r.push(i+opt.wedge+(a.obj.is(v)? a.text.ify(v) : v)); 138 | }); 139 | } 140 | return r; 141 | }); 142 | list.fuse = (function(l){ 143 | var args = a.list.slit.call(arguments, 0), ll; 144 | l = ($=a.fns.$(list))||l; 145 | ll = $? a.fns.sort(args).l : a.fns.sort(args).l.slice(1); 146 | return Array.prototype.concat.apply(l,ll); 147 | }); 148 | list.union = list.u = (function(l,ll){ //[1,2,3,4,5] u [3,5,6,7,8] = [1,2,3,4,5,6,7,8] 149 | return not_implemented_yet; 150 | if($=a.fns.$(list)){ ll=l;l=$ } 151 | // yeaaah, try again. 152 | return r; 153 | }); 154 | list.intersect = list.n = (function(l,ll){ //[1,2,3,4,5] n [3,5,6,7,8] = [3,5] 155 | return not_implemented_yet; 156 | if($=a.fns.$(list)){ ll=l;l=$ } 157 | // yeaah, try again. 158 | }); 159 | list.less = (function(l,s){ // ToDo: Add ability to use a function to determine what is removed. 160 | var args = a.list.slit.call(arguments, 0), sl = s, ls = l; 161 | l = ($=a.fns.$(list))||l; 162 | s = $? args : args.slice(1); 163 | if($ === args.length){ l=ls;s=sl } 164 | sl = s.length; 165 | return a.list(l).each(function(v,i,t){ 166 | if(1 == sl && a.test.is(v,s[0])){ return } else 167 | if(a.list(s).each(function(w,j){ 168 | if(a.test.is(v,w)){ return true } 169 | })){ return } 170 | t(v); 171 | })||[]; 172 | }); 173 | list.each = list.find = (function(l,c,t){ 174 | if($=a.fns.$(list)){ t=c;c=l;l=$ } 175 | return a.obj.each(l,c,t); 176 | }); 177 | list.copy = (function(l){ 178 | return a.obj.copy( ($=a.fns.$(list))||l ); 179 | }); 180 | list.index = 1; 181 | return list; 182 | })(); 183 | a.obj = (function(){ 184 | function obj($){ 185 | obj.$ = $ !== undefined? $ : _; 186 | return obj; 187 | } var $; 188 | obj.is = (function(o){ 189 | o = a.fns.$(obj)||o; 190 | return (o instanceof Object && !a.list.is(o) && !a.fns.is(o))? true : false; 191 | }); 192 | obj.ify = (function(o){ 193 | o = a.fns.$(obj)||o; 194 | if(a.obj.is(o)){ return o } 195 | try{ 196 | o = JSON.parse(o); 197 | }catch(e){o={}}; 198 | return o; 199 | }); 200 | obj.empty = (function(o){ 201 | if(!(o = a.fns.$(obj)||o)){ return true } 202 | return obj.each(o,function(v,i){ 203 | if(i){ return true } 204 | })? false : true; 205 | }); 206 | obj.copy = (function(o,r,l){ 207 | if(!r){ 208 | o = a.fns.$(obj) || o; 209 | } l = a.list.is(o); 210 | if(r && !a.obj.is(o) && !l){ return o } 211 | r = {}; o = a.obj.each(o,function(v,i,t){ 212 | l? t(obj.copy(v,true)) : (r[i] = obj.copy(v,true)); 213 | })||[]; 214 | return l? o : r; 215 | }); 216 | obj.union = obj.u = (function(x,y){ // TODO: if both objects have the same property that is an object, these don't get merged. 217 | var args = a.list.slit.call(arguments, 0), r = {}; 218 | if($=a.fns.$(obj)){ y=x;x=$ } 219 | if(a.list.is(x)){ y = x } else 220 | if(a.list.is(y)){ } else { 221 | y = $? args : args.slice(1); 222 | y.splice(0,0,x); 223 | } 224 | a.list(y).each(function(v,i){ 225 | a.obj(v).each(function(w,j){ 226 | if(a.obj(r).has(j)){ return } 227 | r[j] = w; 228 | }); 229 | }); 230 | return r; 231 | }); 232 | obj.has = (function(o,k){ 233 | if($=a.fns.$(obj)){ k=o;o=$ } 234 | return Object.prototype.hasOwnProperty.call(o, k); 235 | }); 236 | obj.each = (function(l,c,_){ 237 | if($=a.fns.$(obj)){ _=c;c=l;l=$ } 238 | var i = 0, ii = 0, x, r, rr, f = a.fns.is(c), 239 | t = (function(k,v){ 240 | if(v !== undefined){ 241 | rr = rr || {}; 242 | rr[k] = v; 243 | return; 244 | } rr = rr || []; 245 | rr.push(k); 246 | }); 247 | if(a.list.is(l)){ 248 | x = l.length; 249 | for(;i < x; i++){ 250 | ii = (i + a.list.index); 251 | if(f){ 252 | r = _? c.call(_, l[i], ii, t) : c(l[i], ii, t); 253 | if(r !== undefined){ return r } 254 | } else { 255 | if(a.test.is(c,l[i])){ return ii } 256 | } 257 | } 258 | } else if(a.obj.is(l)){ 259 | for(i in l){ 260 | if(f){ 261 | if(a.obj(l).has(i)){ 262 | r = _? c.call(_, l[i], i, t) : c(l[i], i, t); 263 | if(r !== undefined){ return r } 264 | } 265 | } else { 266 | if(a.test.is(c,l[i])){ return i } 267 | } 268 | } 269 | } 270 | return f? rr : a.list.index? 0 : -1; 271 | }); 272 | obj.get = (function(o,l,opt,f){ 273 | if($=a.fns.$(obj)){ l=o;o=$ } 274 | if(a.num.is(l)){ l = a.text.ify(l) } 275 | if(a.list.is(l)){ l = l.join('.') } 276 | if(a.text.is(l)){ 277 | f = (l.length == (l = l.replace(a.text.find.__.fn,'')).length)? 278 | undefined : function(){}; l = l.split(a.text.find.__.dot); 279 | } if(!l){ return } 280 | var x = (l||[]).length, r, 281 | deep = (function(o,v){ 282 | return a.list(o).each(function(w,j){ 283 | if(a.obj(w||{}).has(v)){ return w } 284 | if(a.list.is(w)){ return deep(w,v) } 285 | }); 286 | }), get = (function(v,i,t,n){ 287 | if(a.list.is(o)){ 288 | if(/^\-?\d+$/.test(v)){ 289 | n = a.list.index; 290 | v = a.num.ify(v); 291 | } else { 292 | o = deep(o,v); 293 | } 294 | } 295 | if(n || a.obj(o||{}).has(v)){ 296 | o = n? a.list(o).at(v) : o[v]; 297 | if(i === x - (a.list.index? 0 : 1)){ 298 | return f? a.fns.is(o)? o : f : o; 299 | } return; 300 | } 301 | return f || a.test.nil; 302 | }); r = a.list(l).each(get); 303 | return r === a.test.nil? undefined : r; 304 | }); 305 | return obj; 306 | })(); 307 | a.text = (function(){ 308 | function text($){ 309 | text.$ = $ !== undefined? $ : _; 310 | return text; 311 | } var $; 312 | text.is = (function(t){ 313 | t = (($=a.fns.$(text))!==_)?$:t; 314 | return typeof t == 'string'?true:false; 315 | }); 316 | text.get = (function(q){ return }); 317 | text.ify = (function(t){ 318 | t = (($=a.fns.$(text))!==_)?$:t; 319 | if(JSON){ return JSON.stringify(t) } 320 | return t.toString? t.toString():t; 321 | }); 322 | text.random = text.r = (function(l,c){ 323 | if($=a.fns.$(text)){ c=l;l=$ } var $ = $||l, s = ''; 324 | l = a.num.is($)? $ : a.num.is(c)? c : 16; 325 | c = a.text.is($)? $ : a.text.is(c)? c : '0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghiklmnopqrstuvwxyz'; 326 | while(l>0){ s += c.charAt(Math.floor(Math.random()*c.length)); l-- } 327 | return s; 328 | }); 329 | text.clip = (function(t,r,s,e){ 330 | if($=a.fns.$(text)){ e=s;s=r;r=t;t=$ } // IE6 fails if e === undefined with Mocha 331 | return t = (t||'').split(r), t=a.num.is(e)?t.slice(s,e):t.slice(s), t.join(r); 332 | }); 333 | text.find = (function(t){ 334 | var regex = {}; 335 | a.log(regex.name = t.name+'.find'); 336 | regex.is = /[\.\\\?\*\[\]\{\}\(\)\^\$\+\|\,]/ig 337 | regex.special = {'.':1,'\\':1,'?':1,'*':1,'[':1,']':1,'{':1,'}':1,'(':1,')':1,'^':1,'$':1,'+':1,'|':1,',':1} 338 | regex.mail = /^(("[\w-\s]+")|([\w-]+(?:[\.\+][\w-]+)*)|("[\w-\s]+")([\w-]+(?:[\.\+][\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i; 339 | regex.base64 = new RegExp("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$"); 340 | regex.list = /(,\s|;\s|,|;|\s)/ig; 341 | regex.css = /(.+?):(.+?);/ig; 342 | regex.url = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi; 343 | regex.ext = /\.([^\.]+)$/i; 344 | regex.ws_ = /\-/ig; 345 | regex.space = /\s/ig; 346 | regex.num = /(\-\d+\.\d+|\d+\.\d+|\-\d+|\d+)/g; 347 | regex['int'] = /(\-\d+|\d+)/g; 348 | regex.__ = { fn: /\-\>$/, dot: /\./ }; 349 | return regex; 350 | })(text); 351 | text.caps = (function(t){ 352 | t = a.fns.$(text)||t; 353 | t = (text.is(t))?t:""; 354 | return t.toUpperCase(); 355 | }); 356 | text.low = (function(t){ 357 | t = a.fns.$(text)||t; 358 | t = (text.is(t))?t:""; 359 | return t.toLowerCase(); 360 | }); 361 | return text; 362 | })(); 363 | a.num = (function(){ 364 | function num($){ 365 | num.$ = ($ !== undefined? $ : _); 366 | return num; 367 | } var $; 368 | num.is = (function(n){ 369 | n = (($=a.fns.$(num))!==_)?$:n; 370 | return ( (n===0)? true : (!isNaN(n) && !a.bi.is(n) && !a.list.is(n) && !a.text.is(n))? true : false); 371 | }); 372 | num.i = (function(n){return parseInt(a.fns.$(num)||n,10)}); 373 | num.dec = (function(n){return parseFloat(a.fns.$(num)||n)}); 374 | num.ify = (function(n,o){ 375 | if(($=a.fns.$(num))!==_){ o=n;n=$ } 376 | var r, l = a.list.is(o); 377 | if(a.list.is(o)){ 378 | if(a.num.is(n)){ 379 | return [n]; 380 | } if(a.text.is(n)){ 381 | r = n.match(a.text.find.num) || []; 382 | return a.list(r).each(function(v,i,t){ 383 | t(a.num.ify(v)); 384 | }); 385 | } 386 | } 387 | r = num.dec(n); 388 | if(a.num.is(r)){ return r } 389 | if(!n){ return } 390 | if(a.text.is(n)){ 391 | return a.num.ify( (n.match(a.text.find.num)||[])[0] ); 392 | } 393 | }); 394 | num.random = num.r = (function(l){ 395 | l = ((($=a.fns.$(num))!==_)?$:l)||6; 396 | if(a.list.is(l)){ return (Math.floor(Math.random() * (l[1] - l[0] + 1)) + l[0]) } 397 | l = (l<=14)? l : 14; 398 | var n = '9'; 399 | for(var i = 0; i < l-1; i++){ n += '0' } 400 | n = a.num.ify(n); 401 | var r = function(){return Math.floor(Math.random()*10)||(l==1?0:r())}; 402 | n = Math.floor(r() + Math.pow(Math.random(),Math.random()) * (n)); 403 | if(n.toString().length != l){ return num.r(l) } 404 | return n; 405 | }); 406 | return num; 407 | })(); 408 | a.bi = (function(){ 409 | function bi($){ 410 | bi.$ = $ !== undefined? $ : _; 411 | return bi; 412 | } var $; 413 | bi.is = (function(b){ 414 | b = (($=a.fns.$(bi))!==_)?$:b; 415 | return (b instanceof Boolean || typeof b == 'boolean')?true:false; 416 | }); 417 | return bi; 418 | })(); 419 | a.on = (function(){ 420 | function on($){ 421 | on.$ = $ !== undefined? $ : _; 422 | return on; 423 | } var $, events = {}, sort = (function(A,B){ 424 | if(!A || !B){ return 0 } A = A.i; B = B.i; 425 | if(A < B){ return -1 }else if(A > B){ return 1 } 426 | else { return 0 } 427 | }); 428 | on.emit = (function(){ 429 | if(!a.text.is($ = a.fns.$(on))) return; 430 | var e = events[$] = events[$] || (events[$] = []), args = arguments; 431 | if(!(events[$] = a.list(e).each(function(hear, i, t){ 432 | if(!hear.fn) return; t(hear); 433 | hear.fn.apply(hear, args); 434 | }))){ delete events[$]; } 435 | }); 436 | on.event = (function(fn, i){ 437 | if(!a.text.is($ = a.fns.$(on))) return; 438 | var $ = events[$] = events[$] || (events[$] = []) 439 | , e = {fn: fn, i: i || 0, off: function(){ return !(e.fn = false); }}; 440 | return $.push(e), $.sort(sort), e; 441 | }); 442 | return on; 443 | })(); 444 | a.time = (function(){ 445 | function time($){ 446 | time.$ = $ !== undefined? $ : _; 447 | return time; 448 | } 449 | time.is = (function(t){ 450 | t = ($=a.fns.$(time))||t; 451 | return t? t instanceof Date : (+new Date().getTime()); 452 | }); 453 | time.now = (function(){ 454 | var n = a.num.ify((a.time.is().toString())+'.'+a.num.r(4)); 455 | return (theory.time.now.last||0) < n? (theory.time.now.last = n) : time.now(); 456 | }); 457 | time.loop = (function(fn,d){ 458 | var args = a.fns.sort(a.list.slit.call(arguments, 0)); 459 | return (args.f.length)?setInterval(a.list(args.f).at(1),a.list(args.n).at(1)):_; 460 | }); 461 | time.wait = (function(fn,d){ 462 | var args = a.fns.sort(a.list.slit.call(arguments, 0)); 463 | return (args.f.length)?setTimeout(a.list(args.f).at(1),a.list(args.n).at(1)):_; 464 | }); 465 | time.stop = (function(i){ 466 | i = ($=a.fns.$(time))||i; 467 | return (clearTimeout(i)&&clearInterval(i))||true; 468 | }); 469 | return time; 470 | })(); 471 | a.com = (function($){ 472 | var com = a.com; 473 | com.$ = $ !== undefined? $ : _; 474 | com.way = com.way||$;$=_; 475 | com.queue = a.list([]).fuse(theory.com.queue||[]); 476 | theory.com.queue = theory.com.queue||[]; 477 | com.dc = [theory.time.now()]; 478 | com.node = (function(opt){ 479 | if(!process._events){ process._events = {} } 480 | if(process.send && !process._events.theory){ 481 | process._events.theory = (function(m){ 482 | com.msg(a.obj.ify(m)); 483 | }); process.on('message',process._events.theory); 484 | process.send({onOpen:{readyState:(process.readyState = 1)},mod:module.theory[opt.way]}); 485 | com.wire = process; 486 | com.drain(); 487 | return; 488 | } 489 | }); 490 | com.page = (function(){ 491 | com.src = com.src||(window.location.protocol +'//'+ window.location.hostname) 492 | + ((window.location.port)?':'+window.location.port:'') 493 | + (com.path||'/com'); 494 | var municate = (function(){ 495 | if(!window.SockJS){ return } 496 | theory.com.wire = new window.SockJS(com.src); 497 | theory.com.wire.onopen = function(){ 498 | theory.com.open&&theory.com.open(); 499 | console.log("Communication initiated at "+com.src+" with "+com.wire.protocol+"."); 500 | com.drain(); 501 | }; 502 | theory.com.wire.onmessage = theory.com.municate||function(m){ 503 | var fn, m = a.obj.ify(m.data||m); 504 | if(fn = theory.com.asked[m.when]){ 505 | if(a.fns.is(fn)){ fn(m) } 506 | delete theory.com.asked[m.when]; 507 | return; 508 | } 509 | com.msg(m); 510 | }; 511 | theory.com.wire.onclose = function(m){ 512 | console.log('close'); 513 | theory.com.close&&theory.com.close(m); 514 | }; 515 | }); 516 | if(theory.com.off || root.opts.com === false){ return } 517 | if(window.SockJS){ 518 | municate(); 519 | } else { 520 | module.ajax.load(com.url||(location.local+'//cdn.sockjs.org/sockjs-0.3.min.js') 521 | ,function(d){municate()}); 522 | } 523 | }); 524 | com.drain = (function(){ 525 | while(theory.com.queue.length > 0){ 526 | com.write(theory.com.queue.shift()); 527 | } 528 | }); 529 | com.write = (function(m,c){ 530 | c = c||theory.com.wire; 531 | if(!c || c.readyState !== 1){ 532 | theory.com.queue.push(m); 533 | return; 534 | } 535 | if(a.obj.is(m)){ 536 | m = a.text(m).ify(); 537 | } 538 | //console.log("theory: send --> ", m); 539 | c.send(m); 540 | }); 541 | com.init = (function(c){ 542 | //console.log("Starting Theory Communication", c); 543 | if(root.node){ com.node({way:c}) } 544 | if(c){ return } 545 | if(root.page){ com.page() } 546 | return com; 547 | }); 548 | /** Helpers **/ 549 | com.msg = (function(m,c){ 550 | var fn = theory.obj.get(theory,theory.obj.get(m,'how.way')); 551 | if(a.fns.is(fn)){ return fn(m) }; 552 | theory.on('ThEoRy_MsG').emit(m); 553 | }); 554 | com.on = (function(cb){ 555 | return theory.on('ThEoRy_MsG').event(function(m){ 556 | if(a.fns.is(cb)){ cb(m) } 557 | }); 558 | }); 559 | com.ways = (function(m,w){ 560 | var way = w||a.obj.get(m,'how.way')||com.way; 561 | if($=a.fns.$(com)){ 562 | way = ($.charAt(0)=='.')?com.way+$:$; 563 | } return m = com.meta(m,way); 564 | }); 565 | com.ask = (function(m,f){ 566 | if(!a.fns.is(f)){ return } 567 | m = com.ways(m); 568 | delete m.where; 569 | theory.com.asked[m.when] = f; 570 | com.write(m); 571 | });theory.com.asked = theory.com.asked||{}; 572 | com.reply = (function(m){ 573 | m = com.ways(m); 574 | if(m.how.web){ 575 | m.how.way = 'web.reply'; 576 | } m.who = m.who||{}; 577 | m.who.to = m.who.to||m.who.tid; 578 | com.write(m); 579 | }); 580 | com.send = (function(m){ 581 | m = com.ways(m); 582 | com.write(m); 583 | }); 584 | com.meta = (function(m,opt){ 585 | if(!a.obj.is(m)){ m = {what:m} } 586 | var n = {what: (m.what = m.what||{}) }; 587 | opt = opt||{c:{}}; 588 | if(a.text.is(opt)){ opt = {w:opt,c:{}} } 589 | if(opt.protocol){ opt.c = opt } 590 | a.obj(m).each(function(v,i){ 591 | if( i == 'how' || i == 'who' || i == 'what' || 592 | i == 'when'|| i == 'where'){ return } 593 | n.what[i] = m.what[i] = v; delete m[i]; 594 | }); 595 | if(!m.how){ n.how={way: opt.w||com.way} }else{ 596 | n.how = m.how; 597 | n.how.way = opt.w||m.how.way||com.way; 598 | delete m.how; 599 | } m.how = n.how; 600 | if(!m.when){ n.when=a.time.now() }else{ 601 | n.when = m.when; 602 | delete m.when; 603 | } m.when = n.when; 604 | if(!m.who){ 605 | if(root.page && !com.who){ 606 | n.who = { tid: (com.who=root.who) } 607 | } if(root.node){ n.who = {} } 608 | }else{ 609 | if(a.obj.is(m.who)){ n.who=m.who }else{ 610 | n.who = {to: m.who} 611 | } if(root.node){ 612 | } if(root.page && !com.who){ 613 | n.who.tid = com.who = root.who; 614 | } delete m.who; 615 | } m.who = n.who; 616 | if(!m.where){ 617 | if(root.page){ if(a.text.is(m.where)){}else{}; 618 | } if(root.node){ n.where={pid: process.pid} } 619 | }else{ 620 | if(a.obj.is(m.where)){ n.where = m.where }else{ 621 | n.where = {at: m.where}; 622 | } if(root.node){ 623 | if(!a.obj(m.where).has('pid')){ n.where.pid=process.pid } 624 | } delete m.where; 625 | } m.where = n.where; 626 | return n; 627 | }); /** END HELPERS **/ 628 | return com; 629 | }); 630 | a.test = (function(){ 631 | function test($){ 632 | if($===undefined && a.fns.is(test.$)){ try{return test.$()}catch(e){return e} } 633 | test.$ = arguments.length? $ : test.nil; 634 | return test; 635 | } test.nil = test.$ = 'ThEoRy.TeSt.NiL-VaLuE'; 636 | test._ = (function(r){ r = a.fns.$(test); test.$ = test.nil; return r; }); 637 | test.of = (function(t,f){ 638 | if(($=test._()) !== test.nil){ f=t;t=$ } 639 | return t instanceof f; 640 | }); 641 | test.is = (function(a, b, aStack, bStack){ // modified Underscore's to fix flaws 642 | if(($=test._()) !== test.nil){ b=a;a=$ } 643 | var _ = {isFunction:theory.fns.is 644 | ,has:theory.obj.has}, eq = test.is; 645 | aStack = aStack||[]; bStack = bStack||[]; 646 | // Identical objects are equal. `0 === -0`, but they aren't identical. 647 | if(a === b){ return a !== 0 || 1 / a == 1 / b } 648 | if(a == null || b == null){ return a === b } 649 | var className = Object.prototype.toString.apply(a); 650 | if(className != Object.prototype.toString.apply(b)){ return false } 651 | switch(className){ 652 | case '[object String]': return a == String(b); 653 | case '[object Number]': return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); 654 | case '[object Function]': return a.name === b.name && a.toString() === b.toString(); 655 | case '[object Date]': 656 | case '[object Boolean]': return +a == +b; 657 | case '[object RegExp]': return a.source == b.source && a.global == b.global && 658 | a.multiline == b.multiline && a.ignoreCase == b.ignoreCase; 659 | } 660 | if(typeof a != 'object' || typeof b != 'object'){ return false } 661 | var length = aStack.length; 662 | while(length--){ if(aStack[length] == a){ return bStack[length] == b} } 663 | aStack.push(a); bStack.push(b); 664 | var size = 0, result = true; 665 | if(className == '[object Array]'){ 666 | size = a.length; result = size == b.length; 667 | if(result){ 668 | while(size--){ 669 | if(!(result = eq(a[size], b[size], aStack, bStack))){ break } 670 | } 671 | } 672 | }else{ 673 | var aCtor = a.constructor, bCtor = b.constructor; 674 | if(aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && 675 | _.isFunction(bCtor) && (bCtor instanceof bCtor))){ return false } 676 | for(var key in a){ 677 | if(_.has(a, key)){ 678 | size++; 679 | if(!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))){ break } 680 | } 681 | } if(result){ 682 | for(key in b){ 683 | if(_.has(b, key) && !(size--)){ break } 684 | } result = !size; 685 | } 686 | } 687 | aStack.pop(); bStack.pop(); 688 | return result; 689 | }); 690 | return test; 691 | })(); 692 | return a; 693 | } 694 | theory.Name = 'theory'; 695 | theory.version = 2.8; 696 | theorize(theory); 697 | return theory; 698 | })(true); 699 | 700 | /** 701 | BASE 702 | **/ 703 | (function(r){ 704 | var root = root||{}, a = theory; 705 | root.opts = root.opts || {}; 706 | root.deps = {loaded:{},alias:{},all:{},wait:{}}; 707 | root.pollute = ((typeof GLOBAL !== 'undefined' && GLOBAL.global && GLOBAL.process && 708 | GLOBAL.process.env && GLOBAL.process.pid && GLOBAL.process.execPath)? 709 | (function(){ 710 | global.node = root.node = true; 711 | global.opts = root.opts; 712 | global.theory = theory; 713 | module.theory = module.theory||{} 714 | process.env.totheory = __filename; 715 | if(process.env.NODE_ENV==='production'){process.env.LIVE = true}; 716 | module.path = require('path'); 717 | require.sep = module.path.sep; 718 | module.paths = (module.parent||{}).paths || module.paths; // fixes relative npm installs while using theory via link, hopefully no side-effects. 719 | module.exports=(function(cb,deps,name){ 720 | //console.log("arguments", cb, deps, name); 721 | if(!arguments.length) return theory; 722 | var args = a.fns.sort(a.list.slit.call(arguments, 0)), r 723 | ,m = util.require.apply({},arguments); 724 | args.file = root.submodule||(module.parent||{}).filename; // TODO: BUG!!! On node -e we get coalesce recursively calling itself. :( 725 | global.aname = global.aname||m.name; 726 | a.obj(util.deps(m.dependencies,{flat:{},src:args.file})).each(function(name,path){ 727 | var p = require(root.submodule=path=util.resolve(path,path)); 728 | m.theory[name] = (theory.obj.is(p) && theory.obj.empty(p))? undefined : p; 729 | }); 730 | module.theory[m.name] = a.obj.ify(a.text.ify(m)); 731 | //console.log("Let's start they day off with some lovely ugly", 'deps', deps, 'name', name, 'global aname', global.aname); 732 | //console.log('sub.file', root.submodule, (module.parent||{}).filename); 733 | var mod = (theory[m.name] = m.init(m.theory)); 734 | if(global.aname === m.name && theory.com) theory.com(theory.Name).init(m.name); 735 | return mod; 736 | }); 737 | return; 738 | }) : (function(){ 739 | root = window.root = window.root||root; 740 | root.page = true; 741 | root.who = root.who||a.list((document.cookie+';').match(/tid=(.+?);/)||[]).at(-1)||''; 742 | window.console = window.console||{log:function(s){return s}}; 743 | console.saw = (function(s){console.log(a.text(s).ify())}); 744 | location.local=(location.protocol==='file:'?'http:':''); 745 | var noConflict={__dirname: window.__dirname,module:window.module,exports:window.exports,require:window.require}; 746 | window.__dirname = ''; 747 | window.module = {exports: (window.exports = {})}; 748 | window.module.ajax = {load:(function(b,c){ 749 | var d=document,j="script",s=d.createElement(j); module.sync=(s.onload===null||!s.readyState)?0:1; // IE6+ 750 | var e=2166136261,g=b.length,h=c,i=/=\?/,w=window.setTimeout,x,y,a=function(z){ 751 | document.body&&(z=z||x)&&s&&document.body[z]?document.body[y=z](s):w(a,0); 752 | };if(i.test(b)){for(;g--;)e=e*16777619^b.charCodeAt(g); 753 | window[j+=e<0?-e:e]=function(){h.apply(h,arguments);delete window[j]};b=b.replace(i,"="+j);c=0 754 | };s.onload=s.onreadystatechange=function(){if(y&&/de|m/.test(s.readyState||"m")){ 755 | c&&c();a(x='removeChild');try{for(c in s)delete s[c]}catch(b){} 756 | }};s.src=b;c&&a(x='appendChild'); 757 | })};module.ajax.load('#'); 758 | window.module.ajax.code = util.load; 759 | window.onerror = (function(e,w,l){ 760 | console.log(e + " at line "+ l +" on "+ w); 761 | //if(theory.com){ theory.com.send({e:e,url:w,line:l}) } 762 | }); 763 | window.require = module.require = function require(p){ 764 | if(!p){ return require } 765 | if(util.stripify(p) == util.stripify(theory.Name)){ 766 | return util.require; 767 | } var fn, c = 0, cb = function(f){ fn = f; }; 768 | theory.list((p = theory.list.is(p)? p : [p])).each(function(v){ 769 | window.module.ajax.code(v,function(d){++c && (p.length <= c) && fn && fn(d)}); 770 | }); return cb; 771 | }; window.require.sep = '/'; require.resolve = util.resolve; require.cache = {}; 772 | util.init(); 773 | if(root.opts.amd === false){theory.obj(noConflict).each(function(v,i){window[i]=v});} 774 | if(theory.com){ theory.com(theory.Name).init() } 775 | }) 776 | ); 777 | var util = {}; 778 | util.theorize = (function(mod){ 779 | mod.theory = theory.call(true); 780 | if(mod.theory.com){ mod.theory.com(mod.name) } 781 | return mod.theory; 782 | }); 783 | util.require = (function(){ 784 | var mod, args = a.fns.sort(a.list.slit.call(arguments,0)) 785 | , fail = {name:'fail',init:(function(){console.log('module failed to load')})}; 786 | if(args.o.length === 1 && !args.t.length && !args.l.length){ 787 | mod = a.list(args.o).at(1); 788 | } else { 789 | if(args.f.length){ 790 | mod = { 791 | name: a.list(args.t).at(1) 792 | ,init: a.list(args.f).at(1) 793 | ,dependencies: a.list(args.l).at(1) || a.list(args.o).at(1) 794 | } 795 | } 796 | } mod.name = mod.name||fail.name; 797 | mod.init = mod.init||mod.main||mod.start||mod.boot||mod.cb||mod.fn||fail.init; 798 | mod.dependencies = mod.dependencies||mod.require||mod.deps||mod.dep; 799 | mod.dependencies = a.list.is(mod.dependencies)? 800 | a.list(mod.dependencies).each(function(v,i,t){t(v,1)}) : mod.dependencies; 801 | mod.theory = util.theorize(mod); 802 | if(root.node){ return mod } 803 | args = {cb:function(p, opt){ 804 | if(args.launched 805 | || a.list(util.deps(mod.dependencies,{flat:{}})).each(function(v,j){ 806 | if(!(i = root.deps.loaded[j])){ return true } 807 | if(i === 2){ return true } 808 | if(i && i.launch && a.text.is(v) && mod.theory[v] === undefined){ mod.theory[v] = i.launch; } 809 | })){ return } 810 | args.on.off(); 811 | args.launched = {launch: (theory[mod.name] = mod.init(mod.theory||theory)), n:mod.name}; 812 | module.exports = exports = args.launched.launch; 813 | if(mod.src){ 814 | root.deps.loaded[mod.src] = args.launched; 815 | theory.on('ThEoRy_DePs').emit(); 816 | } return args.launched.launch; 817 | }}; args.on = theory.on('ThEoRy_DePs').event(args.cb); 818 | args.start = function(){util.deps(mod.dependencies,args); return args.cb()} 819 | args.name = function(src){ 820 | module.on = args.name = false; 821 | root.deps.alias[args.src = mod.src = src] = mod.name; 822 | if((root.deps.all[src] = mod.dependencies)){ 823 | root.deps.loaded[src] = 2; 824 | } if(!window.JSON){module.ajax.load(root.opts.JSON||location.local // JSON shim when needed 825 | +"//ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js",args.start) 826 | } else { return args.start() }; 827 | }; module.on = (!(require||{}).ing)? args.name(util.src(1))||false : args.name; 828 | }); 829 | util.deps = (function(deps, opt){ 830 | opt = opt || {}; 831 | a.obj(deps).each(function(v,i){ 832 | var path = i, dopt = {p:i}; 833 | if(opt.src){ 834 | delete deps[i]; 835 | deps[path = util.resolve(opt.src, util.pathify(path))] = v; 836 | } if(a.list.is(v)){ 837 | delete deps[i]; 838 | v = deps[path] = a.list(v).each(function(w,i,t){t(util.resolve(opt.src,util.pathify(w)),1)}) 839 | } if(a.obj.is(v)){ 840 | dopt.defer = v; 841 | opt.flat && util.deps(v,{flat: opt.flat}); 842 | } if(v && a.text.is(v)){ 843 | dopt.name = v; 844 | } if(opt.flat){ 845 | var url = util.urlify(util.pathify(path)); 846 | if((i = opt.flat[url]) && i !== 1){ return } 847 | opt.flat[url] = (opt.sub? 1 : dopt.name) || util.stripify(path); 848 | if(i !== 1 && url && a.text.is(url) && (v = root.deps.all[url])){ 849 | (a.obj.is(v) || a.list.is(v)) && util.deps(v,{flat: opt.flat, sub:1}); 850 | } return; 851 | } return util.load(path, dopt); 852 | }); 853 | return opt.flat; 854 | }); 855 | util.urlify = (function(url){ // via SO, IE6+ safe 856 | if(!root.page){ return url; } 857 | var el= document.createElement('div'); 858 | el.innerHTML= 'x'; 859 | return el.firstChild.href; 860 | }); 861 | util.pathify = (function(p){ 862 | if(!root.page){ return p; } 863 | return p = (/\.js$/i.test(p))? p : p+'.js'; 864 | }); 865 | util.stripify = (function(p){ 866 | if(!a.text.is(p)){ return ''; } p=p.replace(/^\./,''); 867 | return (p.split(require.sep).reverse()[0]).replace(/\.js$/i,''); 868 | }); 869 | util.resolve = (function(p1, p2){ // via browserify 870 | if('.' != p2.charAt(0)){ return p2.replace('/',require.sep) } 871 | var path = p1.replace('/',require.sep).split(require.sep) 872 | , segs = p2.replace('/',require.sep).split(require.sep) 873 | path.pop(); 874 | for(var i=0;i