├── .gitignore ├── .travis.yml ├── Gruntfile.js ├── README.md ├── bower.json ├── dist ├── agile.js ├── agile.min.js └── agile.zip ├── example ├── chain.js └── compared-to-underscore.md ├── index.js ├── license.md ├── package.json ├── src ├── _agile │ ├── array │ │ ├── after-where.js │ │ ├── after.js │ │ ├── before-where.js │ │ ├── before.js │ │ ├── contains.js │ │ ├── count-by.js │ │ ├── defaults.js │ │ ├── every.js │ │ ├── filter.js │ │ ├── find-index.js │ │ ├── find-last-index.js │ │ ├── find-last.js │ │ ├── find.js │ │ ├── first.js │ │ ├── flatten.js │ │ ├── group-by.js │ │ ├── last.js │ │ ├── map.js │ │ ├── max.js │ │ ├── min.js │ │ ├── omit.js │ │ ├── order-by.js │ │ ├── remove.js │ │ ├── reverse.js │ │ ├── sum.js │ │ ├── unique.js │ │ └── xor.js │ ├── boolean.js │ ├── chain.js │ ├── object │ │ ├── keys.js │ │ └── to-array.js │ ├── string │ │ ├── ends-with.js │ │ ├── ltrim.js │ │ ├── repeat.js │ │ ├── rtrim.js │ │ ├── slugify.js │ │ ├── starts-with.js │ │ ├── stringular.js │ │ ├── strip-tags.js │ │ ├── trim.js │ │ ├── truncate.js │ │ ├── ucfirst.js │ │ └── wrap.js │ └── utils.js ├── _parse │ └── parse.js ├── agile.js └── common.js └── test ├── .jshintrc ├── karma.conf.js ├── karma.underscore.conf.js └── spec ├── agile ├── agile.js ├── array │ ├── after-where.js │ ├── after.js │ ├── before-where.js │ ├── before.js │ ├── contains.js │ ├── count-by.js │ ├── defaults.js │ ├── every.js │ ├── filter.js │ ├── find-index.js │ ├── find-last-index.js │ ├── find-last.js │ ├── find.js │ ├── first.js │ ├── flatten.js │ ├── group-by.js │ ├── last.js │ ├── map.js │ ├── max.js │ ├── min.js │ ├── omit.js │ ├── order-by.js │ ├── remove.js │ ├── reverse.js │ ├── sum.js │ ├── unique.js │ └── xor.js ├── boolean.js ├── chain.js ├── object │ ├── keys.js │ └── to-array.js ├── string │ ├── ends-with.js │ ├── ltrim.js │ ├── repeat.js │ ├── rtrim.js │ ├── slugify.js │ ├── starts-with.js │ ├── stringular.js │ ├── strip-tags.js │ ├── trim.js │ ├── truncate.js │ ├── ucfirst.js │ └── wrap.js └── utils.js └── parse.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | test/coverage -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | before_install: 4 | - "export DISPLAY=:99.0" 5 | - "sh -e /etc/init.d/xvfb start" 6 | 7 | node_js: 8 | - '0.10' 9 | 10 | before_script: 11 | - 'npm install -g bower grunt-cli' 12 | 13 | after_script: "npm install coveralls@2.10.0 && cat ./test/coverage/*/lcov.info | coveralls" -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 'use strict'; 3 | 4 | // Project configuration. 5 | grunt.initConfig({ 6 | pkg: grunt.file.readJSON('package.json'), 7 | meta: { 8 | banner: [ 9 | '/**', 10 | ' * <%= pkg.description %>', 11 | ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>' + 12 | ' * @link <%= pkg.homepage %>', 13 | ' * @author <%= pkg.author %>', 14 | ' * @license MIT License, http://www.opensource.org/licenses/MIT', 15 | ' */' 16 | ].join('\n') 17 | }, 18 | dirs: { 19 | dest: 'dist' 20 | }, 21 | concat: { 22 | options: { 23 | banner: '<%= meta.banner %>' + '\n' + 24 | '(function ( context, undefined ) {' + '\n', 25 | footer: '//@expose agile' + '\n' + 26 | 'runInContext(context);' + '\n\n' + 27 | '})( this );' 28 | }, 29 | dist: { 30 | src: ['src/common.js', 'src/**/*.js', 'src/agile.js'], 31 | dest: '<%= dirs.dest %>/<%= pkg.name %>.js' 32 | } 33 | }, 34 | zip: { 35 | '<%= dirs.dest %>/agile.zip': [ 36 | '<%= dirs.dest %>/<%= pkg.name %>.js', 37 | '<%= dirs.dest %>/<%= pkg.name %>.min.js' 38 | ] 39 | }, 40 | bowerInstall: { 41 | install: { 42 | options: { 43 | targetDir: './bower_components' 44 | } 45 | } 46 | }, 47 | uglify: { 48 | options: { 49 | banner: '<%= meta.banner %>' 50 | }, 51 | dist: { 52 | src: ['<%= concat.dist.dest %>'], 53 | dest: '<%= dirs.dest %>/<%= pkg.name %>.min.js' 54 | } 55 | }, 56 | jshint: { 57 | files: ['Gruntfile.js', 'src/**/*.js'], 58 | options: { 59 | jshintrc: true 60 | } 61 | }, 62 | karma: { 63 | options: { 64 | configFile: 'test/karma.conf.js' 65 | }, 66 | build: { 67 | singleRun: true, 68 | autoWatch: false 69 | }, 70 | debug: { 71 | singleRun: false, 72 | autoWatch: true, 73 | browsers: ['Chrome'] 74 | }, 75 | travis: { 76 | singleRun: true, 77 | autoWatch: false, 78 | browsers: ['Firefox'] 79 | }, 80 | travisUnderscore: { 81 | singleRun: true, 82 | autoWatch: false, 83 | browsers: ['Firefox'], 84 | configFile: 'test/karma.underscore.conf.js' 85 | }, 86 | buildUnderscore: { 87 | configFile: 'test/karma.underscore.conf.js', 88 | singleRun: true, 89 | autoWatch: false 90 | }, 91 | dev: { 92 | autoWatch: true 93 | } 94 | }, 95 | changelog: { 96 | options: { 97 | dest: 'CHANGELOG.md' 98 | } 99 | } 100 | }); 101 | 102 | // Load the plugin that provides the "jshint" task. 103 | grunt.loadNpmTasks('grunt-contrib-jshint'); 104 | 105 | // Load the plugin that provides the "concat" task. 106 | grunt.loadNpmTasks('grunt-contrib-concat'); 107 | 108 | // Load the plugin that provides the "uglify" task. 109 | grunt.loadNpmTasks('grunt-contrib-uglify'); 110 | 111 | grunt.loadNpmTasks('grunt-bower-task'); 112 | 113 | grunt.renameTask('bower', 'bowerInstall'); 114 | 115 | grunt.loadNpmTasks('grunt-karma'); 116 | 117 | grunt.loadNpmTasks('grunt-conventional-changelog'); 118 | 119 | grunt.loadNpmTasks('grunt-zip'); 120 | 121 | // Default task. 122 | grunt.registerTask('default', ['build']); 123 | 124 | // Build task. 125 | grunt.registerTask('build', ['bowerInstall', 'karma:build', 'karma:buildUnderscore', 'concat', 'uglify', 'zip']); 126 | 127 | grunt.registerTask('test', ['karma:build', 'karma:buildUnderscore']); 128 | 129 | grunt.registerTask('test-debug', ['karma:debug']); 130 | 131 | grunt.registerTask('travis', ['karma:travis', 'karma:travisUnderscore']); 132 | 133 | // Provides the "bump" task. 134 | grunt.registerTask('bump', 'Increment version number', function() { 135 | var versionType = grunt.option('type'); 136 | function bumpVersion(version, versionType) { 137 | var type = {patch: 2, minor: 1, major: 0}, 138 | parts = version.split('.'), 139 | idx = type[versionType || 'patch']; 140 | parts[idx] = parseInt(parts[idx], 10) + 1; 141 | while(++idx < parts.length) { parts[idx] = 0; } 142 | return parts.join('.'); 143 | } 144 | var version; 145 | function updateFile(file) { 146 | var json = grunt.file.readJSON(file); 147 | version = json.version = bumpVersion(json.version, versionType || 'patch'); 148 | grunt.file.write(file, JSON.stringify(json, null, ' ')); 149 | } 150 | updateFile('package.json'); 151 | updateFile('bower.json'); 152 | grunt.log.ok('Version bumped to ' + version); 153 | }); 154 | 155 | }; -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agile", 3 | "version": "0.0.2", 4 | "main": "dist/agile.js", 5 | "description": "Like Underscore, but with zero callbacks and really more fun", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/a8m/agile.git" 9 | }, 10 | "dependencies": { 11 | }, 12 | "devDependencies": { 13 | }, 14 | "ignore": [ 15 | "node_modules", 16 | "bower_components", 17 | "package.json", 18 | "lib", 19 | "test", 20 | "src", 21 | "Gruntfile.js", 22 | ".gitignore", 23 | "README.md", 24 | "travis.yml", 25 | ".bowercc" 26 | ] 27 | } -------------------------------------------------------------------------------- /dist/agile.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Like Underscore, but with zero callbacks and really more fun 3 | * @version v0.0.2 - 2014-11-15 * @link https://github.com/a8m/agile 4 | * @author Ariel Mashraki 5 | * @license MIT License, http://www.opensource.org/licenses/MIT 6 | */!function(a,b){"use strict";function c(a,b){return b=Error,function(c){var d=Array.prototype.slice.call(arguments,1),e="["+a+":]"+c.replace(/{(\d+)}/g,function(a,b){return P(d[b])?a:d[b]});return b(e)}}function d(a){return function(){return a}}function e(a,b,c){var d,f;if(a)if(S(a))for(d in a)"prototype"==d||"length"==d||"name"==d||a.hasOwnProperty&&!a.hasOwnProperty(d)||b.call(c,a[d],d,a);else if(Lb(a)||h(a)){var g="object"!=typeof a;for(d=0,f=a.length;f>d;d++)(g||d in a)&&b.call(c,a[d],d,a)}else if(a.forEach&&a.forEach!==e)a.forEach(b,c,a);else for(d in a)a.hasOwnProperty(d)&&b.call(c,a[d],d,a);return a}function f(a,b,c){var d=0;return a.filter(function(a){var e=Q(c)?b>d&&c(a):b>d;return d=e?d+1:d,e})}function g(a,b,c){var d=b.map(function(a){return Xb(c)(a)});return d.indexOf(Math[a].apply(Math,d))}function h(a){if(null==a||i(a))return!1;var b=a.length;return a.nodeType===Kb&&b?!0:M(a)||Lb(a)||0===b||"number"==typeof b&&b>0&&b-1 in a}function i(a){return a&&a.window===a}function j(a,b,c){for(var d,e=-1;++e=a.length?a:Lb(a[b])?z(a.slice(0,b).concat(a[b],a.slice(b+1)),b):z(a,b+1)}function A(a,b){var c,d={},f=Xb(b);return!Lb(a)||P(b)?a:(e(a,function(a){c=f(a),d[c]||(d[c]=[]),d[c].push(a)}),d)}function B(a){var c,d,e,g;return Lb(a)?(g=a.slice(),e=Array.prototype.slice.call(arguments,1),c=O(e[0])?e[0]:1,d=O(e[0])?O(e[1])?b:e[1]:e[0],e.length?f(g.reverse(),c,d?Xb(d):d).reverse():g[g.length-1]):a}function C(a,b){return!Lb(a)||P(b)?a:a.map(function(a){return Xb(b)(a)})}function D(a,b){return Lb(a)?P(b)?Math.max.apply(Math,a):a[g("max",a,b)]:a}function E(a,b){return Lb(a)?P(b)?Math.min.apply(Math,a):a[g("min",a,b)]:a}function F(a,b){return!Lb(a)||P(b)?a:a.filter(function(a){return N(a)||S(b)?!Xb(b)(a):a!==b})}function G(a,b,c){function d(a,c){for(var d=0;da?-1:1):d>c?-1:1}if(!h(a))return a;b=Lb(b)?b:[b],0===b.length&&(b=["+"]),b=b.map(function(a){var b=!1,c=a||nb;if(M(a)){if(("+"==a.charAt(0)||"-"==a.charAt(0))&&(b="-"==a.charAt(0),a=a.substring(1)),""===a)return e(function(a,b){return f(a,b)},b);if(c=Xb(a),c.constant){var d=c();return e(function(a,b){return f(a[d],b[d])},b)}}return e(function(a,b){return f(c(a),c(b))},b)});for(var g=[],i=0;i>=1);return c}function db(a,b){var c=b||"\\s";return M(a)?a.replace(new RegExp(c+"+$"),""):a}function eb(a,b){var c=b||"-";return M(a)?a.toLowerCase().replace(/\s+/g,c):a}function fb(a,b,c){var d=c||!1;return!M(a)||P(b)?a:(a=d?a:a.toLowerCase(),!a.indexOf(d?b:b.toLowerCase()))}function gb(a){var b=Array.prototype.slice.call(arguments,1);return a.replace(/{(\d+)}/g,function(a,c){return P(b[c])?a:b[c]})}function hb(a){return M(a)?a.replace(/<\S[^><]*>/g,""):a}function ib(a,b){var c=b||"\\s";return M(a)?a.replace(new RegExp("^"+c+"+|"+c+"+$","g"),""):a}function jb(a,b,c,d){return b=P(b)?a.length:b,d=d||!1,c=c||"",!M(a)||a.length<=b?a:a.substring(0,d?-1===a.indexOf(" ",b)?a.length:a.indexOf(" ",b):b)+c}function kb(a){return M(a)?a.split(" ").map(function(a){return a.charAt(0).toUpperCase()+a.substring(1)}).join(" "):a}function lb(a,b,c){return!M(a)||P(b)?a:[b,a,c||b].join("")}function mb(a,c){if(a===c)return!0;if(null===a||null===c)return!1;if(a!==a&&c!==c)return!0;var d,e,f,g=typeof a,h=typeof c;if(g==h&&"object"==g){if(!Lb(a)){if(R(a))return R(c)?mb(a.getTime(),c.getTime()):!1;if(T(a)&&T(c))return a.toString()==c.toString();if(i(a)||i(c)||Lb(c))return!1;f={};for(e in a)if(!S(a[e])){if(!mb(a[e],c[e]))return!1;f[e]=!0}for(e in c)if(!f.hasOwnProperty(e)&&c[e]!==b&&!S(c[e]))return!1;return!0}if(!Lb(c))return!1;if((d=a.length)==c.length){for(e=0;d>e;e++)if(!mb(a[e],c[e]))return!1;return!0}}return!1}function nb(a){return a}function ob(a){for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];if(d)for(var e=Object.keys(d),f=0,g=e.length;g>f;f++){var h=e[f];a[h]=d[h]}}return a}function pb(){return Object.create(null)}function qb(){}function rb(a){return"undefined"==typeof a?b:JSON.stringify(a)}function sb(a,b,c,d){if(i(a))throw Error("Can't copy! Making copies of Window instances is not supported.");if(b){if(a===b)throw Error("Can't copy! Source and destination are identical.");if(c=c||[],d=d||[],N(a)){var f=c.indexOf(a);if(-1!==f)return d[f];c.push(a),d.push(b)}var g;if(Lb(a)){b.length=0;for(var h=0;h1;g++){e=tb(f.shift(),d);var h=ub(a[e],d);h||(h={},a[e]=h),a=h}return e=tb(f.shift(),d),ub(a[e],d),a[e]=c,c}function yb(a,c,d,e,f,g){return tb(a,g),tb(c,g),tb(d,g),tb(e,g),tb(f,g),function(g,h){var i=h&&h.hasOwnProperty(a)?h:g;return null==i?i:(i=i[a],c?null==i?b:(i=i[c],d?null==i?b:(i=i[d],e?null==i?b:(i=i[e],f?null==i?b:i=i[f]:i):i):i):i)}}function zb(a,c,f){var g=Wb[a];if(g)return g;var h=a.split("."),i=h.length;if(c.csp)g=6>i?yb(h[0],h[1],h[2],h[3],h[4],f):function(a,c){var d,e=0;do d=yb(h[e++],h[e++],h[e++],h[e++],h[e++],f)(a,c),c=b,a=d;while(i>e);return d};else{var j="";e(h,function(a,b){tb(a,f),j+="if(s == null) return undefined;\ns="+(b?"s":'((l&&l.hasOwnProperty("'+a+'"))?l:s)')+"."+a+";\n"}),j+="return s;";var k=new Function("s","l",j);k.toString=d(j),g=k}return g.sharedGetter=!0,g.assign=function(b,c){return xb(b,a,c,a)},Wb[a]=g,g}function Ab(a,b,c){e(b,function(b){var d=M(b)?b:b.name,e=M(b)?c[b]:N(b)?b.action:b,f=M(b)&&!c.E;a.prototype[d]=function(){var a=Array.prototype.slice.call(arguments),b=[this.__value__].concat(a),c=f?e.call(this.__value__,a):e.apply(this,b);return Yb.test(d)||V(c)?c:Hb(c)}})}function Bb(a,b){e(b,function(b){a[b.name]=S(b)?b:b.action})}function Cb(a){this.__value__=a}function Db(a){this.__value__=a}function Eb(a){this.__value__=a}function Fb(a){this.__value__=a}function Gb(a){switch(typeof a){case"string":return Cb;case"number":return Fb;case"object":return Lb(a)?Db:Eb;default:throw Error("Agile value can't be ["+typeof a+"] as an argument")}}function Hb(a){if(a&&a.__wrapped__)return a;var b,c=Gb(a);return(b=new c(a)).__wrapped__=!0,b}function Ib(a){return"object"==typeof module&&module&&module.exports===a?module.exports=Hb:a[a._?"agile":"_"]=Hb}var Jb=c("$parse"),Kb=(Object.prototype.hasOwnProperty,1),Lb=Array.isArray,Mb=function(a){return M(a)?a.toUpperCase():a},Nb=function(a){return M(a)?a.toLowerCase():a},Ob=Function.prototype.call,Pb=Function.prototype.apply,Qb=Function.prototype.bind,Rb=pb();e({"null":function(){return null},"true":function(){return!0},"false":function(){return!1},undefined:function(){}},function(a,b){a.constant=a.literal=a.sharedGetter=!0,Rb[b]=a}),Rb["this"]=function(a){return a},Rb["this"].sharedGetter=!0;var Sb=ob(pb(),{"+":function(a,c,d,e){return d=d(a,c),e=e(a,c),Q(d)?Q(e)?d+e:d:Q(e)?e:b},"-":function(a,b,c,d){return c=c(a,b),d=d(a,b),(Q(c)?c:0)-(Q(d)?d:0)},"*":function(a,b,c,d){return c(a,b)*d(a,b)},"/":function(a,b,c,d){return c(a,b)/d(a,b)},"%":function(a,b,c,d){return c(a,b)%d(a,b)},"===":function(a,b,c,d){return c(a,b)===d(a,b)},"!==":function(a,b,c,d){return c(a,b)!==d(a,b)},"==":function(a,b,c,d){return c(a,b)==d(a,b)},"!=":function(a,b,c,d){return c(a,b)!=d(a,b)},"<":function(a,b,c,d){return c(a,b)":function(a,b,c,d){return c(a,b)>d(a,b)},"<=":function(a,b,c,d){return c(a,b)<=d(a,b)},">=":function(a,b,c,d){return c(a,b)>=d(a,b)},"&&":function(a,b,c,d){return c(a,b)&&d(a,b)},"||":function(a,b,c,d){return c(a,b)||d(a,b)},"!":function(a,b,c){return!c(a,b)},"=":!0,"|":!0}),Tb={n:"\n",f:"\f",r:"\r",t:" ",v:" ","'":"'",'"':'"'},Ub=function(a){this.options=a};Ub.prototype={constructor:Ub,lex:function(a){for(this.text=a,this.index=0,this.ch=b,this.tokens=[];this.index="0"&&"9">=a},isWhitespace:function(a){return" "===a||"\r"===a||" "===a||"\n"===a||" "===a||" "===a},isIdent:function(a){return a>="a"&&"z">=a||a>="A"&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,b,c){c=c||this.index;var d=Q(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,c)+"]":" "+c;throw Jb("lexerr","Lexer Error: {0} at column{1} in expression [{2}].",a,d,this.text)},readNumber:function(){for(var a="",b=this.index;this.index0){var e=this.tokens[0],f=e.text;if(f===a||f===b||f===c||f===d||!a&&!b&&!c&&!d)return e}return!1},expect:function(a,b,c,d){var e=this.peek(a,b,c,d);return e?(this.tokens.shift(),e):!1},consume:function(a){this.expect(a)||this.throwError("is unexpected, expecting ["+a+"]",this.peek())},unaryFn:function(a,b){return ob(function(c,d){return a(c,d,b)},{constant:b.constant,inputs:[b]})},binaryFn:function(a,b,c,d){return ob(function(d,e){return b(d,e,a,c)},{constant:a.constant&&c.constant,inputs:!d&&[a,c]})},statements:function(){for(var a=[];;)if(this.tokens.length>0&&!this.peek("}",")",";","]")&&a.push(this.filterChain()),!this.expect(";"))return 1===a.length?a[0]:function(b,c){for(var d,e=0,f=a.length;f>e;e++)d=a[e](b,c);return d}},filterChain:function(){for(var a,b=this.expression();a=this.expect("|");)b=!0;return b},expression:function(){return this.assignment()},assignment:function(){var a,b,c=this.ternary();return(b=this.expect("="))?(c.assign||this.throwError("implies assignment but ["+this.text.substring(0,b.index)+"] can not be assigned to",b),a=this.ternary(),ob(function(b,d){return c.assign(b,a(b,d),d)},{inputs:[c,a]})):c},ternary:function(){var a,b,c=this.logicalOR();if(b=this.expect("?")){if(a=this.assignment(),b=this.expect(":")){var d=this.assignment();return ob(function(b,e){return c(b,e)?a(b,e):d(b,e)},{constant:c.constant&&a.constant&&d.constant})}this.throwError("expected :",b)}return c},logicalOR:function(){for(var a,b=this.logicalAND();a=this.expect("||");)b=this.binaryFn(b,a.fn,this.logicalAND(),!0);return b},logicalAND:function(){var a,b=this.equality();return(a=this.expect("&&"))&&(b=this.binaryFn(b,a.fn,this.logicalAND(),!0)),b},equality:function(){var a,b=this.relational();return(a=this.expect("==","!=","===","!=="))&&(b=this.binaryFn(b,a.fn,this.equality())),b},relational:function(){var a,b=this.additive();return(a=this.expect("<",">","<=",">="))&&(b=this.binaryFn(b,a.fn,this.relational())),b},additive:function(){for(var a,b=this.multiplicative();a=this.expect("+","-");)b=this.binaryFn(b,a.fn,this.multiplicative());return b},multiplicative:function(){for(var a,b=this.unary();a=this.expect("*","/","%");)b=this.binaryFn(b,a.fn,this.unary());return b},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(Vb.ZERO,a.fn,this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()):this.primary()},fieldAccess:function(a){var b=this.text,c=this.expect().text,d=zb(c,this.options,b);return ob(function(b,c,e){return d(e||a(b,c))},{assign:function(d,e,f){var g=a(d,f);return g||a.assign(d,g={}),xb(g,c,e,b)}})},objectIndex:function(a){var c=this.text,d=this.expression();return this.consume("]"),ob(function(e,f){var g,h=a(e,f),i=d(e,f);return tb(i,c),h?g=ub(h[i],c):b},{assign:function(b,e,f){var g=tb(d(b,f),c),h=ub(a(b,f),c);return h||a.assign(b,h={}),h[g]=e}})},functionCall:function(a,b){var c=[];if(")"!==this.peekToken().text)do c.push(this.expression());while(this.expect(","));this.consume(")");var d=this.text,e=c.length?[]:null;return function(f,g){var h=b?b(f,g):f,i=a(f,g,h)||qb;if(e)for(var j=c.length;j--;)e[j]=ub(c[j](f,g),d);ub(h,d),vb(i,d);var k=i.apply?i.apply(h,e):i(e[0],e[1],e[2],e[3],e[4]);return ub(k,d)}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text)do{if(this.peek("]"))break;var b=this.expression();a.push(b)}while(this.expect(","));return this.consume("]"),ob(function(b,c){for(var d=[],e=0,f=a.length;f>e;e++)d.push(a[e](b,c));return d},{literal:!0,constant:a.every(wb),inputs:a})},object:function(){var a=[],b=[];if("}"!==this.peekToken().text)do{if(this.peek("}"))break;var c=this.expect();a.push(c.string||c.text),this.consume(":");var d=this.expression();b.push(d)}while(this.expect(","));return this.consume("}"),ob(function(c,d){for(var e={},f=0,g=b.length;g>f;f++)e[a[f]]=b[f](c,d);return e},{literal:!0,constant:b.every(wb),inputs:b})}};var Wb=pb(),Xb=(Object.prototype.valueOf,function(){function a(a,b){return b?function(c,d){var e=a(c,d),f=b(e,c,d);return Q(e)?f:e}:a}var b=pb(),c={csp:!1};return function(d,e){var f,g,h;switch(typeof d){case"string":if(h=d=d.trim(),f=b[h],!f){":"===d.charAt(0)&&":"===d.charAt(1)&&(g=!0,d=d.substring(2));var i=new Ub(c),j=new Vb(i,c);f=j.parse(d),b[h]=f}return a(f,e);case"function":return a(d,e);default:return a(qb,e)}}}()),Yb=/^(?:value|identity)$/,Zb={STRING:["charAt","concat","indexOf","lastIndexOf","match","replace","slice","substr","substring","toLowerCase","toUpperCase"],ARRAY:["concat","join","pop","push","shift","sort","splice","unshift","indexOf","lastIndexOf"],NUMBER:["abs","ceil","cos","floor","round","sin","sqrt","pow","tan"]},$b={BASE:[{name:"add",action:W},{name:"value",action:nb}],OBJECT:[{name:"keys",action:Y},{name:"toArray",action:$},{name:"extend",action:ob},{name:"forEach",action:e}],STRING:[{name:"startsWith",action:fb},{name:"endsWith",action:_},{name:"trim",action:ib},{name:"ltrim",action:ab},{name:"rtrim",action:db},{name:"repeat",action:bb},{name:"slugify",action:eb},{name:"stringular",action:gb},{name:"stripTags",action:hb},{name:"truncate",action:jb},{name:"ucfirst",action:kb},{name:"wrap",action:lb},{name:"reverse",action:I}],ARRAY:[{name:"after",action:l},{name:"afterWhere",action:k},{name:"before",action:n},{name:"beforeWhere",action:m},{name:"contains",action:o},{name:"countBy",action:p},{name:"defaults",action:q},{name:"map",action:C},{name:"contains",action:o},{name:"find",action:w},{name:"findIndex",action:t},{name:"findLast",action:v},{name:"findLastIndex",action:u},{name:"first",action:x},{name:"last",action:B},{name:"flatten",action:y},{name:"every",action:r},{name:"groupBy",action:A},{name:"omit",action:F},{name:"filter",action:s},{name:"remove",action:H},{name:"reverse",action:I},{name:"unique",action:K},{name:"uniq",action:K},{name:"xor",action:L},{name:"max",action:D},{name:"min",action:E},{name:"sum",action:J},{name:"pluck",action:C},{name:"pick",action:s},{name:"some",action:o},{name:"orderBy",action:G},{name:"sortBy",action:G},{name:"forEach",action:e}]},_b=y([Zb.STRING,$b.STRING,$b.BASE]);Ab(Cb,_b,String.prototype);var ac=y([Zb.ARRAY,$b.ARRAY,$b.BASE]);Ab(Db,ac,Array.prototype);var bc=y([$b.OBJECT,$b.BASE]);Ab(Eb,bc,Object.prototype);var cc=y([Zb.NUMBER,$b.BASE]);Ab(Fb,cc,Math);var dc=y([$b.BASE,$b.ARRAY,$b.STRING,$b.OBJECT]);Bb(Hb,dc),Hb.isString=M,Hb.isObject=N,Hb.isNumber=O,Hb.isUndefined=P,Hb.isDefined=Q,Hb.isArray=Lb,Hb.isDate=R,Hb.isFunction=S,Hb.isEmpty=U,Hb.copy=sb,Hb.equals=mb,Hb.identity=nb,Hb.dictionary=pb,Hb.noop=qb,Hb.uppercase=Mb,Hb.lowercase=Nb,Hb.toJson=rb,Hb.parse=Xb,Ib(a)}(this); -------------------------------------------------------------------------------- /dist/agile.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a8m/agile/fcf3f8667e44c621bcdc3065c3a03b29e16851eb/dist/agile.zip -------------------------------------------------------------------------------- /example/chain.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var _ = require('..'); 3 | 4 | // Wrappers Types: 5 | _([]); // ArrayWrapper {__value__: Array[0], __wrapped__: true, concat: functi... 6 | 7 | _('string'); // StringWrapper {__value__: "string", __wrapped__: true, charAt: functi... 8 | 9 | _({}); // ObjectWrapper {__value__: Object, __wrapped__: true, keys: function, ... 10 | 11 | _(1); // NumberWrapper {__value__: 1, __wrapped__: true, abs: function, ceil: ... 12 | 13 | 14 | var users = [ 15 | { id: 1, details: { name: 'Ariel M', age: 25 }, isAdmin: true }, 16 | { id: 2, details: { name: 'Danny L', age: 19 }, isAdmin: false }, 17 | { id: 3, details: { name: 'Eitan O', age: 31 }, isAdmin: true }, 18 | { id: 4, details: { name: 'Cati P', age: 26 }, isAdmin: true }, 19 | { id: 5, details: { name: 'Mike P', age: 50 }, isAdmin: false }, 20 | { id: 6, details: { name: 'Niko M', age: 30 }, isAdmin: false } 21 | ]; 22 | 23 | //get the admins names 24 | _(users) 25 | .pick('isAdmin') 26 | .map('details.name') 27 | .join(', ') 28 | .value(); 29 | 30 | 31 | //get the average age of users 32 | var average = _(users) 33 | .map('details.age') 34 | .sum() 35 | .value() / users.length; 36 | 37 | //get all users that greater than 25 and not admin 38 | _(users) 39 | .pick('details.age > 30 && !isAdmin') 40 | .value(); 41 | 42 | 43 | var orders = [ 44 | { id: 21, customer: { id: 2, name: 'John P.' }, product: { price: 21.12 } }, 45 | { id: 22, customer: { id: 1, name: 'Cati P.' }, product: { price: 89.21 } }, 46 | { id: 23, customer: { id: 1, name: 'Cati P.' }, product: { price: 49.00 } }, 47 | { id: 24, customer: { id: 3, name: 'Poul S.' }, product: { price: 10.22 } }, 48 | { id: 25, customer: { id: 4, name: 'Erik L.' }, product: { price: 11.31 } }, 49 | { id: 26, customer: { id: 4, name: 'Erik L.' }, product: { price: 90.99 } }, 50 | { id: 27, customer: { id: 2, name: 'Cati P.' }, product: { price: 88.99 } } 51 | ]; 52 | 53 | //list of customers 54 | _(orders) 55 | .uniq('customer.id') 56 | .value(); 57 | 58 | //get the greatest purchase 59 | _(orders) 60 | .max('product.price') 61 | .value(); 62 | 63 | //group orders by customer name 64 | _(orders) 65 | .groupBy('customer.name') 66 | .value(); 67 | 68 | var n = _(orders) // ArrayWrapper 69 | .map('product.price') // [21.12, 89.21, 49, 10.22, 11.31, 90.99, 88.99] 70 | .sum() // 360.84 71 | .round() // 361 72 | .add(10) // 371 73 | .value(); // get the value; 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /example/compared-to-underscore.md: -------------------------------------------------------------------------------- 1 | **Quick examples compared to Underscore:** 2 | ```js 3 | var orders = [ 4 | { id: 21, customer: { id: 2, name: 'John P.' }, product: { price: 21.12 } }, 5 | { id: 22, customer: { id: 1, name: 'Cati P.' }, product: { price: 89.21 } }, 6 | { id: 23, customer: { id: 1, name: 'Cati P.' }, product: { price: 49.00 } }, 7 | { id: 24, customer: { id: 3, name: 'Poul S.' }, product: { price: 10.22 } }, 8 | { id: 25, customer: { id: 4, name: 'Erik L.' }, product: { price: 11.31 } }, 9 | { id: 26, customer: { id: 4, name: 'Erik L.' }, product: { price: 90.99 } }, 10 | { id: 27, customer: { id: 2, name: 'Cati P.' }, product: { price: 88.99 } }, 11 | { id: 28, customer: 'PickUp order', product: { price: 19.20 } } 12 | ]; 13 | 14 | //Underscore: get unique customers 15 | _.uniq(orders, function(order) { 16 | if(order.hasOwnProperty('customer')) { 17 | return order.customer.id; 18 | } 19 | return order; 20 | }); 21 | //Agile: get unique customers 22 | _.uniq(orders, 'customer.id'); 23 | 24 | //Underscore: get the greatest purchase 25 | _.max(orders, function(order) { 26 | if(order.hasOwnProperty('product')) { 27 | return order.product.price || 0; 28 | } 29 | return 0; 30 | }); 31 | //Agile: get the greatest purchase 32 | _.max(orders, 'product.price'); 33 | 34 | //Underscore: get sum of all orders 35 | _.chain(orders) 36 | .map(function(order) { 37 | if(order.hasOwnProperty('product')) { 38 | return order.product.price || 0; 39 | } 40 | return 0; 41 | }) 42 | .reduce(function(memo, num) { 43 | return memo + num; 44 | },0) 45 | .value(); // → 380.03 46 | //Agile: get sum of all orders 47 | _(orders) 48 | .map('product.price || 0') 49 | .sum() 50 | .value(); // → 380.03 51 | ``` 52 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./dist/agile.js"); -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 Ariel Mashraki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agile", 3 | "description": "Like Underscore, but with zero callbacks and really more fun", 4 | "version": "0.0.2", 5 | "filename": "agile.js", 6 | "main": "dist/agile.js", 7 | "homepage": "https://github.com/a8m/agile", 8 | "author": "Ariel Mashraki ", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/a8m/agile.git" 12 | }, 13 | "engines": { 14 | "node": ">=0.10.0" 15 | }, 16 | "keywords": [ 17 | "client", 18 | "browser", 19 | "filter", 20 | "lodash", 21 | "underscore", 22 | "collection", 23 | "arrays", 24 | "objects" 25 | ], 26 | "dependencies": { 27 | }, 28 | "devDependencies": { 29 | "grunt": "^0.4.1", 30 | "grunt-cli": ">= 0.1.7", 31 | "grunt-contrib-concat": "*", 32 | "grunt-contrib-jshint": "*", 33 | "grunt-contrib-uglify": "*", 34 | "grunt-bower": "*", 35 | "grunt-bower-task": "*", 36 | "grunt-karma": "latest", 37 | "grunt-conventional-changelog": "0.0.12", 38 | "grunt-zip": "*", 39 | "karma-chrome-launcher": "~0.1.2", 40 | "karma-firefox-launcher": "~0.1.3", 41 | "karma": "~0.12.16", 42 | "karma-jasmine": "~0.1.5", 43 | "karma-phantomjs-launcher": "~0.1.4", 44 | "karma-coverage": "~0.2.4" 45 | }, 46 | "scripts": { 47 | "test": "grunt test --verbose" 48 | }, 49 | "license": "MIT" 50 | } -------------------------------------------------------------------------------- /src/_agile/array/after-where.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name after-where 3 | * @kind function 4 | * 5 | * @description 6 | * get a an array and $parse:expression, and returns all of the items 7 | * in the array after the first that return true, include it. 8 | * 9 | */ 10 | function afterWhere(array, exp) { 11 | 12 | if(!isArray(array) || isUndefined(exp)) 13 | return array; 14 | 15 | var index = array.map(function(elm) { 16 | return $parse(exp)(elm); 17 | }).indexOf(true); 18 | 19 | return array.slice((index === -1) ? 0 : index); 20 | } -------------------------------------------------------------------------------- /src/_agile/array/after.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name after 3 | * @kind function 4 | * 5 | * @description 6 | * get an array and specified count, and returns all of the items 7 | * in the collection after the specified count. 8 | */ 9 | function after(array, count) { 10 | return (isArray(array)) 11 | ? array.slice(count) 12 | : array; 13 | } -------------------------------------------------------------------------------- /src/_agile/array/before-where.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc filter 3 | * @name before-where 4 | * @kind function 5 | * 6 | * @description 7 | * get an array and $parse:expression, and returns all of the items 8 | * in the array before the first that return true. 9 | */ 10 | 11 | function beforeWhere(array, exp) { 12 | if(!isArray(array) || isUndefined(exp)) 13 | return array; 14 | 15 | var index = array.map(function(elm) { 16 | return $parse(exp)(elm); 17 | }).indexOf(true); 18 | 19 | return array.slice(0, (index === -1) ? array.length : ++index); 20 | } -------------------------------------------------------------------------------- /src/_agile/array/before.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name before 3 | * @kind function 4 | * 5 | * @description 6 | * get a array and specified count, and returns all of the items 7 | * in the array before the specified count. 8 | */ 9 | function before(array, count) { 10 | return isArray(array) 11 | ? array.slice(0, (!count) ? count : --count) 12 | : array; 13 | } 14 | -------------------------------------------------------------------------------- /src/_agile/array/contains.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name contains 3 | * @kind function 4 | * 5 | * @description 6 | * Checks if given exp is present in one or more object in the array 7 | * aliases: _.some 8 | */ 9 | 10 | function contains(array, exp) { 11 | 12 | if(!isArray(array) || isUndefined(exp)) { 13 | return true; 14 | } 15 | 16 | return array.some(function(elm) { 17 | return (isObject(elm) || isFunction(exp)) 18 | ? $parse(exp)(elm) 19 | : elm === exp; 20 | }); 21 | } -------------------------------------------------------------------------------- /src/_agile/array/count-by.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name countBy 3 | * @kind function 4 | * 5 | * @description 6 | * Gets an array and $parse:expression, 7 | * and returns a count for the number of objects in each group. 8 | */ 9 | 10 | function countBy(array, exp) { 11 | 12 | var result = {}, 13 | prop; 14 | 15 | if(!isArray(array) || isUndefined(exp)) { 16 | return array; 17 | } 18 | 19 | array.forEach( function(elm) { 20 | prop = $parse(exp)(elm); 21 | 22 | if(!result[prop]) { 23 | result[prop] = 0; 24 | } 25 | 26 | result[prop]++; 27 | }); 28 | 29 | return result; 30 | } -------------------------------------------------------------------------------- /src/_agile/array/defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name defaults 3 | * @kind function 4 | * 5 | * @description 6 | * defaults allows to specify a default fallback value for properties that resolve to undefined. 7 | */ 8 | 9 | function defaults(array, defaults) { 10 | 11 | if(!isArray(array) || !isObject(defaults)) { 12 | return array; 13 | } 14 | //get defaults keys(include nested). 15 | var keys = deepKeys(defaults); 16 | 17 | array.forEach(function(elm) { 18 | //loop through all the keys 19 | keys.forEach(function(key) { 20 | var getter = $parse(key); 21 | var setter = getter.assign; 22 | //if it's not exist 23 | if(isUndefined(getter(elm))) { 24 | //get from defaults, and set to the returned object 25 | setter(elm, getter(defaults)) 26 | } 27 | }); 28 | }); 29 | 30 | return array; 31 | } -------------------------------------------------------------------------------- /src/_agile/array/every.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name every 3 | * @kind function 4 | * 5 | * @description 6 | * Checks if given exp is present in all members in the array 7 | */ 8 | function every(array, exp) { 9 | 10 | if(!isArray(array) || isUndefined(exp)) { 11 | return true; 12 | } 13 | 14 | return array.every(function(elm) { 15 | return (isObject(elm) || isFunction(exp)) 16 | ? $parse(exp)(elm) 17 | : elm === exp; 18 | }); 19 | 20 | } -------------------------------------------------------------------------------- /src/_agile/array/filter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name filter 3 | * @kind function 4 | * 5 | * @description 6 | * filter by $parse:expression, 7 | * return all elements that return true, avoid the rest 8 | */ 9 | function filter(array, exp) { 10 | 11 | if(!isArray(array) || isUndefined(exp)) { 12 | return array; 13 | } 14 | 15 | return array.filter(function(elm) { 16 | return (isObject(elm) || isFunction(exp)) 17 | ? $parse(exp)(elm) 18 | : elm === exp; 19 | }); 20 | } -------------------------------------------------------------------------------- /src/_agile/array/find-index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name findIndex 3 | * @kind function 4 | * 5 | * @description 6 | * Iterate over the given array and return the index of the first member that the expression 7 | * returns truthy for 8 | */ 9 | function findIndex(array, exp) { 10 | return (isArray(array) && isDefined(exp)) 11 | //return the the index of the member 12 | ? findInArray(array, $parse(exp), true) 13 | : array; 14 | } 15 | -------------------------------------------------------------------------------- /src/_agile/array/find-last-index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name findLastIndex 3 | * @kind function 4 | * 5 | * @description 6 | * Iterate over the given array and return the index of the last member that the expression 7 | * returns truthy for 8 | */ 9 | function findLastIndex(array, exp) { 10 | 11 | if(!isArray(array) || isUndefined(exp)) { 12 | return array; 13 | } 14 | //return the the index of the last member 15 | var index = (array.length - 1) - findInArray(reverse(array), $parse(exp), true); 16 | //if it's a NaN 17 | return index === index ? index : -1; 18 | } 19 | -------------------------------------------------------------------------------- /src/_agile/array/find-last.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name findLast 3 | * @kind function 4 | * 5 | * @description 6 | * Iterate over the given array and return the last member that the expression 7 | * returns truthy for, 8 | */ 9 | function findLast(array, exp) { 10 | return (isArray(array) && isDefined(exp)) 11 | //return the member and not an array like `last` 12 | ? findInArray(reverse(array), $parse(exp), false) 13 | : array; 14 | } 15 | -------------------------------------------------------------------------------- /src/_agile/array/find.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name find 3 | * @kind function 4 | * 5 | * @description 6 | * Iterate over the given array and return the first member that the expression 7 | * returns truthy for, 8 | */ 9 | function find(array, exp) { 10 | return (isArray(array) && isDefined(exp)) 11 | //return the member and not an array like `first` 12 | ? findInArray(array, $parse(exp), false) 13 | : array; 14 | } 15 | -------------------------------------------------------------------------------- /src/_agile/array/first.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name first 3 | * @kind function 4 | * 5 | * @description 6 | * Gets the first element or first `n` elements of an array 7 | * if expression is provided, is returns as long the expression return truthy 8 | */ 9 | function first(array) { 10 | 11 | var n, 12 | getter, 13 | args; 14 | 15 | if(!isArray(array)) { 16 | return array; 17 | } 18 | 19 | args = Array.prototype.slice.call(arguments, 1); 20 | n = (isNumber(args[0])) ? args[0] : 1; 21 | getter = (!isNumber(args[0])) ? args[0] : (!isNumber(args[1])) ? args[1] : undefined; 22 | 23 | return (args.length) 24 | ? getFirstMatches(array, n,(getter) ? $parse(getter) : getter) 25 | : array[0]; 26 | } -------------------------------------------------------------------------------- /src/_agile/array/flatten.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name flatten 3 | * @kind function 4 | * 5 | * @description 6 | * Flattens a nested array (the nesting can be to any depth). 7 | * If shallow, the array will only be flattened a one level 8 | */ 9 | function flatten(array, shallow) { 10 | 11 | shallow = shallow || false; 12 | 13 | if(!isArray(array)) { 14 | return array; 15 | } 16 | 17 | return !shallow 18 | ? depthFlatten(array, 0) 19 | : [].concat.apply([], array); 20 | } 21 | 22 | /** 23 | * flatten nested array (the nesting can be to any depth). 24 | * @param array {Array} 25 | * @param i {int} 26 | * @returns {Array} 27 | * @private 28 | */ 29 | function depthFlatten(array, i) { 30 | i = i || 0; 31 | 32 | if(i >= array.length) 33 | return array; 34 | 35 | if(isArray(array[i])) { 36 | return depthFlatten(array.slice(0,i) 37 | .concat(array[i], array.slice(i+1)), i); 38 | } 39 | return depthFlatten(array, i+1); 40 | } -------------------------------------------------------------------------------- /src/_agile/array/group-by.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name groupBy 3 | * @kind function 4 | * 5 | * @description 6 | * Create an object composed of keys generated from the result of running each element of a array, 7 | * each key is an array contains the results members. 8 | */ 9 | function groupBy(array, property) { 10 | var result = {}, 11 | prop, 12 | getter = $parse(property); 13 | 14 | if(!isArray(array) || isUndefined(property)) { 15 | return array; 16 | } 17 | 18 | forEach(array, function(elm) { 19 | prop = getter(elm); 20 | 21 | if(!result[prop]) { 22 | result[prop] = []; 23 | } 24 | 25 | result[prop].push(elm); 26 | }); 27 | 28 | return result; 29 | } -------------------------------------------------------------------------------- /src/_agile/array/last.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name last 3 | * @kind function 4 | * 5 | * @description 6 | * Gets the last element or last n elements of an array 7 | * if expression is provided, is returns as long the expression return truthy 8 | */ 9 | function last(array) { 10 | 11 | var n, 12 | getter, 13 | args, 14 | reversed; 15 | 16 | if(!isArray(array)) { 17 | return array; 18 | } 19 | 20 | //cuz reverse change our src array 21 | //and we don't want side effects 22 | reversed = array.slice(); 23 | 24 | args = Array.prototype.slice.call(arguments, 1); 25 | n = (isNumber(args[0])) ? args[0] : 1; 26 | getter = (!isNumber(args[0])) ? args[0] : (!isNumber(args[1])) ? args[1] : undefined; 27 | 28 | return (args.length) 29 | //send reversed array as arguments, and reverse it back as result 30 | ? getFirstMatches(reversed.reverse(), n,(getter) ? $parse(getter) : getter).reverse() 31 | //get the last element 32 | : reversed[reversed.length-1]; 33 | } 34 | -------------------------------------------------------------------------------- /src/_agile/array/map.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name map 3 | * @kind function 4 | * 5 | * @description 6 | * Returns a new Array with the results of each expression execution. 7 | */ 8 | function map(array, expression) { 9 | 10 | if(!isArray(array) || isUndefined(expression)) { 11 | return array; 12 | } 13 | 14 | return array.map(function (elm) { 15 | return $parse(expression)(elm); 16 | }); 17 | } -------------------------------------------------------------------------------- /src/_agile/array/max.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name max 3 | * @kind function 4 | * 5 | * @description 6 | * Math.max will get an array return the max value. if an expression 7 | * is provided, will return max value by expression. 8 | */ 9 | function max(input, expression) { 10 | if(!isArray(input)) { 11 | return input; 12 | } 13 | return isUndefined(expression) 14 | ? Math.max.apply(Math, input) 15 | : input[indexByMath('max', input, expression)] 16 | } 17 | -------------------------------------------------------------------------------- /src/_agile/array/min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc filter 3 | * @name min 4 | * @kind function 5 | * 6 | * @description 7 | * Math.min will get an array return the min value. if an expression 8 | * is provided, will return min value by expression. 9 | */ 10 | function min(input, expression) { 11 | if(!isArray(input)) { 12 | return input; 13 | } 14 | return isUndefined(expression) 15 | ? Math.min.apply(Math, input) 16 | : input[indexByMath('min', input, expression)] 17 | } 18 | -------------------------------------------------------------------------------- /src/_agile/array/omit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name omit 3 | * @kind function 4 | * 5 | * @description 6 | * get an array, and return a new array without the omitted objects(by expression). 7 | */ 8 | function omit(array, exp) { 9 | 10 | if(!isArray(array) || isUndefined(exp)) { 11 | return array; 12 | } 13 | 14 | return array.filter(function(elm) { 15 | return (isObject(elm) || isFunction(exp)) 16 | ? !$parse(exp)(elm) 17 | : elm !== exp; 18 | }); 19 | } -------------------------------------------------------------------------------- /src/_agile/array/order-by.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name orderBy 3 | * @kind function 4 | * fork of AngularJS#orderByFilter 5 | * 6 | * @description 7 | * Orders a specified array by the expression predicate. 8 | * It is ordered alphabetically for strings and numerically for numbers. 9 | */ 10 | function orderBy(array, sortPredicate, reverseOrder) { 11 | if (!isArrayLike(array)) { 12 | return array; 13 | } 14 | sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate]; 15 | if (sortPredicate.length === 0) { sortPredicate = ['+']; } 16 | sortPredicate = sortPredicate.map(function(predicate) { 17 | var descending = false; 18 | var get = predicate || value; 19 | if (isString(predicate)) { 20 | if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) { 21 | descending = predicate.charAt(0) == '-'; 22 | predicate = predicate.substring(1); 23 | } 24 | if (predicate === '') { 25 | // Effectively no predicate was passed so we compare identity 26 | return reverseComparator(function(a, b) { 27 | return compare(a, b); 28 | }, descending); 29 | } 30 | get = $parse(predicate); 31 | if (get.constant) { 32 | var key = get(); 33 | return reverseComparator(function(a, b) { 34 | return compare(a[key], b[key]); 35 | }, descending); 36 | } 37 | } 38 | return reverseComparator(function(a, b) { 39 | return compare(get(a),get(b)); 40 | }, descending); 41 | }); 42 | var arrayCopy = []; 43 | for (var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); } 44 | return arrayCopy.sort(reverseComparator(comparator, reverseOrder)); 45 | 46 | function comparator(o1, o2) { 47 | for (var i = 0; i < sortPredicate.length; i++) { 48 | var comp = sortPredicate[i](o1, o2); 49 | if (comp !== 0) break; 50 | } 51 | return comp; 52 | } 53 | function reverseComparator(comp, descending) { 54 | return descending 55 | ? function(a, b) {return comp(b,a);} 56 | : comp; 57 | } 58 | function compare(v1, v2) { 59 | var t1 = typeof v1; 60 | var t2 = typeof v2; 61 | if (t1 == t2) { 62 | if (isDate(v1) && isDate(v2)) { 63 | v1 = v1.valueOf(); 64 | v2 = v2.valueOf(); 65 | } 66 | if (t1 == "string") { 67 | v1 = v1.toLowerCase(); 68 | v2 = v2.toLowerCase(); 69 | } 70 | if (v1 === v2) return 0; 71 | return v1 < v2 ? -1 : 1; 72 | } else { 73 | return t1 < t2 ? -1 : 1; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/_agile/array/remove.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name remove 3 | * @kind function 4 | * 5 | * @description 6 | * remove specific members from array by equality 7 | */ 8 | function remove(array) { 9 | 10 | var args = Array.prototype.slice.call(arguments, 1); 11 | 12 | if(!isArray(array) || isEmpty(args)) { 13 | return array; 14 | } 15 | 16 | return array.filter(function(member) { 17 | return !args.some(function(nest) { 18 | return equals(nest, member); 19 | }) 20 | }); 21 | 22 | } -------------------------------------------------------------------------------- /src/_agile/array/reverse.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name reverse 3 | * @kind function 4 | * 5 | * @description 6 | * Reverses a string or collection 7 | */ 8 | function reverse(input) { 9 | 10 | if(isString(input)) { 11 | return input.split('').reverse().join(''); 12 | } 13 | 14 | return (isArray(input)) 15 | ? input.slice().reverse() 16 | : input; 17 | } -------------------------------------------------------------------------------- /src/_agile/array/sum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name sum 3 | * @kind function 4 | * 5 | * @description 6 | * Sum up all values within an array 7 | */ 8 | 9 | function sum(input, initial) { 10 | 11 | return (!isArray(input)) ? input : 12 | input.reduce(function(prev, curr) { 13 | return prev + curr; 14 | }, initial || 0); 15 | } -------------------------------------------------------------------------------- /src/_agile/array/unique.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name unique/uniq 3 | * @kind function 4 | * 5 | * @description 6 | * get array and filter duplicate members 7 | * if uniqueFilter get a property(nested to) as argument it's 8 | * filter by this property as unique identifier 9 | */ 10 | function unique(array, property) { 11 | 12 | if (!isArray(array)) { 13 | return array; 14 | } 15 | 16 | //store all unique identifiers 17 | var uniqueItems = [], 18 | get = $parse(property); 19 | 20 | return (isUndefined(property)) ? 21 | //if it's kind of primitive array 22 | array.filter(function (elm, pos, self) { 23 | return self.indexOf(elm) === pos; 24 | }) : 25 | //else compare with equals 26 | array.filter(function (elm) { 27 | var prop = get(elm); 28 | if(some(uniqueItems, prop)) { 29 | return false; 30 | } 31 | uniqueItems.push(prop); 32 | return true; 33 | }); 34 | 35 | //checked if the unique identifier is already exist 36 | function some(array, member) { 37 | if(isUndefined(member)) { 38 | return false; 39 | } 40 | return array.some(function(el) { 41 | return equals(el, member); 42 | }); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/_agile/array/xor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name xor 3 | * @kind function 4 | * 5 | * @description 6 | * Exclusive or filter by expression 7 | */ 8 | function xor(col1, col2, expression) { 9 | 10 | expression = expression || false; 11 | 12 | if(!isArray(col1) || !isArray(col2)) return col1; 13 | 14 | return col1.concat(col2) 15 | .filter(function(elm) { 16 | return !(some(elm, col1) && some(elm, col2)); 17 | }); 18 | 19 | function some(el, col) { 20 | var getter = $parse(expression); 21 | return col.some(function(dElm) { 22 | return expression 23 | ? equals(getter(dElm), getter(el)) 24 | : equals(dElm, el); 25 | }); 26 | } 27 | } -------------------------------------------------------------------------------- /src/_agile/boolean.js: -------------------------------------------------------------------------------- 1 | // AngularJS Boolean 2 | /** 3 | * @description 4 | * Determines if a reference is a `String`. 5 | * @param {*} value Reference to check. 6 | * @returns {boolean} True if `value` is a `String`. 7 | */ 8 | function isString(value){return typeof value === 'string';} 9 | 10 | /** 11 | * @description 12 | * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not 13 | * considered to be objects. Note that JavaScript arrays are objects. 14 | * @param {*} value Reference to check. 15 | * @returns {boolean} True if `value` is an `Object` but not `null`. 16 | */ 17 | function isObject(value){ 18 | // http://jsperf.com/isobject4 19 | return value !== null && typeof value === 'object'; 20 | } 21 | 22 | /** 23 | * @description 24 | * Determines if a reference is a `Number`. 25 | * @param {*} value Reference to check. 26 | * @returns {boolean} True if `value` is a `Number`. 27 | */ 28 | function isNumber(value){return typeof value === 'number';} 29 | 30 | /** 31 | * @description 32 | * Determines if a reference is undefined. 33 | * @param {*} value Reference to check. 34 | * @returns {boolean} True if `value` is undefined. 35 | */ 36 | function isUndefined(value){return typeof value === 'undefined';} 37 | 38 | 39 | /** 40 | * @description 41 | * Determines if a reference is defined. 42 | * @param {*} value Reference to check. 43 | * @returns {boolean} True if `value` is defined. 44 | */ 45 | function isDefined(value){return typeof value !== 'undefined';} 46 | 47 | /** 48 | * @description 49 | * Determines if a value is a date. 50 | * @param {*} value Reference to check. 51 | * @returns {boolean} True if `value` is a `Date`. 52 | */ 53 | function isDate(value) { 54 | return toString.call(value) === '[object Date]'; 55 | } 56 | 57 | /** 58 | * @description 59 | * Determines if a reference is an `Array`. 60 | * @param {*} value Reference to check. 61 | * @returns {boolean} True if `value` is an `Array`. 62 | */ 63 | var isArray = Array.isArray; 64 | 65 | /** 66 | * @description 67 | * Determines if a reference is a `Function`. 68 | * @param {*} value Reference to check. 69 | * @returns {boolean} True if `value` is a `Function`. 70 | */ 71 | function isFunction(value){return typeof value === 'function';} 72 | 73 | /** 74 | * @description 75 | * Determines if a value is a regular expression object. 76 | * @private 77 | * @param {*} value Reference to check. 78 | * @returns {boolean} True if `value` is a `RegExp`. 79 | */ 80 | function isRegExp(value) { 81 | return toString.call(value) === '[object RegExp]'; 82 | } 83 | 84 | /** 85 | * @description 86 | * get Array or String and return if is empty 87 | * @param {*} value Reference to check. 88 | * @returns {boolean} True if `value` is a Empty. 89 | */ 90 | function isEmpty(value) { 91 | return (isString(value) || isArray(value)) ? !value.length : false; 92 | } 93 | 94 | /** 95 | * @description 96 | * Determines if a reference is a `Boolean`. 97 | * @param {*} value Reference to check. 98 | * @returns {boolean} True if `value` is a `Boolean`. 99 | */ 100 | function isBoolean(value){return typeof value === 'boolean';} -------------------------------------------------------------------------------- /src/_agile/chain.js: -------------------------------------------------------------------------------- 1 | //these methods is kind of common methods for chaining wrappers 2 | /** 3 | * @description 4 | * add methods get an object extend(based on type) and return it. 5 | * @param object 6 | * @returns {*} 7 | * @example 8 | * add(1,2) ==> 3 9 | * add([],1) ==> [1] 10 | * add('f','g') ==> 'fg' 11 | * add({}, {a:1}) ==> {a:1} 12 | */ 13 | function add(object) { 14 | var args = Array.prototype.slice.call(arguments, 1); 15 | //loop through all over the arguments 16 | forEach(args, function(value, i) { 17 | switch(typeof object) { 18 | case 'object': 19 | isArray(object) 20 | ? object.push(value) 21 | : extend(object, isObject(value) ? value : creObject(i, value)); 22 | break; 23 | case 'string': 24 | object += isString(value) ? value : ''; 25 | break; 26 | case 'number': 27 | object += isNumber(value) ? value : 0; 28 | } 29 | }); 30 | return object; 31 | } 32 | 33 | /** 34 | * @private 35 | * @description 36 | * return an object that index is the key 37 | * @param i {Index} 38 | * @param value 39 | * @returns {Object} 40 | */ 41 | function creObject(i, value) { 42 | var o = {}; 43 | o[i] = value; 44 | return o; 45 | } 46 | -------------------------------------------------------------------------------- /src/_agile/object/keys.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 3 | * get object and return it's keys, 4 | * if deep set to true, it will return it deeply. 5 | * @param obj {Object} 6 | * @param deep {Boolean} 7 | */ 8 | function objKeys(obj, deep) { 9 | return isObject(obj) 10 | ? (deep) ? deepKeys(obj) : Object.keys(obj) 11 | : obj; 12 | } 13 | 14 | /** 15 | * @description 16 | * Get an object, and return an array composed of it's properties names(nested too). 17 | * @param obj {Object} 18 | * @param stack {Array} 19 | * @param parent {String} 20 | * @returns {Array} 21 | * @example 22 | * deepKeys({ a:1, b: { c:2, d: { e: 3 } } }) ==> ["a", "b.c", "b.d.e"] 23 | */ 24 | function deepKeys(obj, stack, parent) { 25 | stack = stack || []; 26 | var keys = Object.keys(obj); 27 | 28 | keys.forEach(function(el) { 29 | //if it's a nested object 30 | if(isObject(obj[el]) && !isArray(obj[el])) { 31 | //concatenate the new parent if exist 32 | var p = parent ? parent + '.' + el : parent; 33 | deepKeys(obj[el], stack, p || el); 34 | } else { 35 | //create and save the key 36 | var key = parent ? parent + '.' + el : el; 37 | stack.push(key); 38 | } 39 | }); 40 | return stack; 41 | } -------------------------------------------------------------------------------- /src/_agile/object/to-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name toArray 3 | * @kind function 4 | * 5 | * @description 6 | * Convert objects into stable arrays. 7 | * if addKey set to true,the filter also attaches a new property 8 | * $key to the value containing the original key that was used in 9 | * the object we are iterating over to reference the property 10 | */ 11 | function toArray(collection, addKey) { 12 | 13 | if(!isObject(collection)) { 14 | return collection; 15 | } 16 | 17 | return Object.keys(collection).map(function (key) { 18 | return addKey 19 | ? extend(collection[key], { $key: key }) 20 | : collection[key]; 21 | }); 22 | } -------------------------------------------------------------------------------- /src/_agile/string/ends-with.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name endsWith 3 | * @kind function 4 | * 5 | * @description 6 | * checks whether string ends with the ends parameter. 7 | */ 8 | function endsWith(input, ends, csensitive) { 9 | 10 | var sensitive = csensitive || false, 11 | position; 12 | 13 | if(!isString(input) || isUndefined(ends)) { 14 | return input; 15 | } 16 | 17 | input = (sensitive) ? input : input.toLowerCase(); 18 | position = input.length - ends.length; 19 | 20 | return input.indexOf((sensitive) ? ends : ends.toLowerCase(), position) !== -1; 21 | } -------------------------------------------------------------------------------- /src/_agile/string/ltrim.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name ltrim 3 | * @kind function 4 | * 5 | * @description 6 | * Left trim. Similar to trim, but only for left side. 7 | */ 8 | function ltrim(input, chars) { 9 | 10 | var trim = chars || '\\s'; 11 | 12 | return isString(input) 13 | ? input.replace(new RegExp('^' + trim + '+'), '') 14 | : input; 15 | } -------------------------------------------------------------------------------- /src/_agile/string/repeat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name repeat 3 | * @kind function 4 | * 5 | * @description 6 | * Repeats a string n times. 7 | */ 8 | function repeat(input, n) { 9 | 10 | var times = ~~n; 11 | 12 | return (!isString(input) || !times) 13 | ? input 14 | : strRepeat(input, n); 15 | } 16 | 17 | /** 18 | * Repeats a string n times with given separator 19 | * @param str string to repeat 20 | * @param n number of times 21 | * @returns {*} 22 | */ 23 | function strRepeat(str, n) { 24 | var res = ''; 25 | do { 26 | if (n & 1) { 27 | res += str; 28 | } 29 | 30 | str += str; 31 | } while (n = n >> 1); 32 | 33 | return res; 34 | } -------------------------------------------------------------------------------- /src/_agile/string/rtrim.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name rtrim 3 | * @kind function 4 | * 5 | * @description 6 | * Right trim. Similar to trim, but only for the right side. 7 | */ 8 | function rtrim(input, chars) { 9 | 10 | var trim = chars || '\\s'; 11 | 12 | return isString(input) 13 | ? input.replace(new RegExp(trim + '+$'), '') 14 | : input; 15 | } -------------------------------------------------------------------------------- /src/_agile/string/slugify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name slugify 3 | * @kind function 4 | * 5 | * @description 6 | * remove spaces from string, replace with "-" or given argument 7 | */ 8 | function slugify(input, sub) { 9 | 10 | var replace = sub || '-'; 11 | 12 | return isString(input) 13 | ? input.toLowerCase().replace(/\s+/g, replace) 14 | : input; 15 | } -------------------------------------------------------------------------------- /src/_agile/string/starts-with.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name startsWith 3 | * @kind function 4 | * 5 | * @description 6 | * checks whether string starts with the starts parameter. 7 | */ 8 | function startsWith(input, start, csensitive) { 9 | 10 | var sensitive = csensitive || false; 11 | 12 | if(!isString(input) || isUndefined(start)) { 13 | return input; 14 | } 15 | 16 | input = (sensitive) ? input : input.toLowerCase(); 17 | 18 | return !input.indexOf((sensitive) ? start : start.toLowerCase()); 19 | } -------------------------------------------------------------------------------- /src/_agile/string/stringular.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name stringular 3 | * @kind function 4 | * 5 | * @description 6 | * get string with {n} and replace match with enumeration values 7 | */ 8 | function stringular(input) { 9 | var args = Array.prototype.slice.call(arguments, 1); 10 | 11 | return input.replace(/{(\d+)}/g, function (match, number) { 12 | return isUndefined(args[number]) ? match : args[number]; 13 | }); 14 | } -------------------------------------------------------------------------------- /src/_agile/string/strip-tags.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name stripTags 3 | * @kind function 4 | * 5 | * @description 6 | * strip html tags from string 7 | */ 8 | function stripTags(input) { 9 | return isString(input) 10 | ? input.replace(/<\S[^><]*>/g, '') 11 | : input; 12 | } -------------------------------------------------------------------------------- /src/_agile/string/trim.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name trim 3 | * @kind function 4 | * 5 | * @description 6 | * Strip whitespace (or other characters) from the beginning and end of a string 7 | */ 8 | function trim(input, chars) { 9 | 10 | var trim = chars || '\\s'; 11 | 12 | return isString(input) 13 | ? input.replace(new RegExp('^' + trim + '+|' + trim + '+$', 'g'), '') 14 | : input; 15 | } -------------------------------------------------------------------------------- /src/_agile/string/truncate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name truncate 3 | * @kind function 4 | * 5 | * @description 6 | * truncates a string given a specified length, providing a custom string to denote an omission. 7 | */ 8 | 9 | function truncate(input, length, suffix, preserve) { 10 | 11 | length = isUndefined(length) ? input.length : length; 12 | preserve = preserve || false; 13 | suffix = suffix || ''; 14 | 15 | if(!isString(input) || (input.length <= length)) return input; 16 | 17 | return input.substring(0, (preserve) 18 | ? ((input.indexOf(' ', length) === -1) ? input.length : input.indexOf(' ', length)) 19 | : length) + suffix; 20 | } -------------------------------------------------------------------------------- /src/_agile/string/ucfirst.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name ucfirst 3 | * @kind function 4 | * 5 | * @description 6 | * upper case first char 7 | */ 8 | function ucfirst(input) { 9 | return isString(input) 10 | ? input.split(' ') 11 | .map(function (char) { 12 | return char.charAt(0).toUpperCase() + char.substring(1); 13 | }) 14 | .join(' ') 15 | : input; 16 | } 17 | -------------------------------------------------------------------------------- /src/_agile/string/wrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name wrap 3 | * @kind function 4 | * 5 | * @description 6 | * Wrap a string with another string 7 | */ 8 | function wrap(input, wrap, ends) { 9 | return isString(input) && isDefined(wrap) 10 | ? [wrap, input, ends || wrap].join('') 11 | : input; 12 | } -------------------------------------------------------------------------------- /src/_agile/utils.js: -------------------------------------------------------------------------------- 1 | // AngularJS Utils 2 | /** 3 | * @description 4 | * Determines if two objects or two values are equivalent. Supports value types, regular 5 | * expressions, arrays and objects. 6 | * 7 | * @param {*} o1 Object or value to compare. 8 | * @param {*} o2 Object or value to compare. 9 | * @returns {boolean} True if arguments are equal. 10 | */ 11 | function equals(o1, o2) { 12 | if (o1 === o2) return true; 13 | if (o1 === null || o2 === null) return false; 14 | if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN 15 | var t1 = typeof o1, t2 = typeof o2, length, key, keySet; 16 | if (t1 == t2) { 17 | if (t1 == 'object') { 18 | if (isArray(o1)) { 19 | if (!isArray(o2)) return false; 20 | if ((length = o1.length) == o2.length) { 21 | for (key=0; key function (e) { return e } 31 | * 2. valueFn(e)() ==> e 32 | * @param value 33 | * @returns {Function} 34 | */ 35 | function valueFn(value) {return function() {return value;};} 36 | 37 | /** 38 | * 39 | * @param {Object|Array} obj Object to iterate over. 40 | * @param {Function} iterator Iterator function. 41 | * @param {Object=} context Object to become context (`this`) for the iterator function. 42 | * @returns {Object|Array} Reference to `obj`. 43 | */ 44 | 45 | function forEach(obj, iterator, context) { 46 | var key, length; 47 | if (obj) { 48 | if (isFunction(obj)) { 49 | for (key in obj) { 50 | // Need to check if hasOwnProperty exists, 51 | // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function 52 | if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { 53 | iterator.call(context, obj[key], key, obj); 54 | } 55 | } 56 | } else if (isArray(obj) || isArrayLike(obj)) { 57 | var isPrimitive = typeof obj !== 'object'; 58 | for (key = 0, length = obj.length; key < length; key++) { 59 | if (isPrimitive || key in obj) { 60 | iterator.call(context, obj[key], key, obj); 61 | } 62 | } 63 | } else if (obj.forEach && obj.forEach !== forEach) { 64 | obj.forEach(iterator, context, obj); 65 | } else { 66 | for (key in obj) { 67 | if (obj.hasOwnProperty(key)) { 68 | iterator.call(context, obj[key], key, obj); 69 | } 70 | } 71 | } 72 | } 73 | return obj; 74 | } 75 | 76 | /** 77 | * @description 78 | * return the first n element of an array, 79 | * if expression provided, is returns as long the expression return truthy 80 | * @param array 81 | * @param n {number} 82 | * @param expression {$parse} 83 | * @return array or single object 84 | */ 85 | function getFirstMatches(array, n, expression) { 86 | var count = 0; 87 | 88 | return array.filter(function(elm) { 89 | var rest = isDefined(expression) ? (count < n && expression(elm)) : count < n; 90 | count = rest ? count+1 : count; 91 | 92 | return rest; 93 | }); 94 | } 95 | 96 | /** 97 | * @description 98 | * gets method name, array and expression 99 | * @param method {String} 100 | * @param array {Array} 101 | * @param exp {String} expression to parse 102 | * @returns {Number} 103 | */ 104 | function indexByMath(method, array, exp) { 105 | var mappedArray = array.map(function(elm){ 106 | return $parse(exp)(elm); 107 | }); 108 | return mappedArray.indexOf(Math[method].apply(Math, mappedArray)); 109 | } 110 | 111 | //Parse Dependencies 112 | var $parseMinErr = minErr('$parse'); 113 | var hasOwnProperty = Object.prototype.hasOwnProperty; 114 | var NODE_TYPE_ELEMENT = 1; 115 | 116 | /** 117 | * @param {*} obj 118 | * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, String ...) 119 | */ 120 | function isArrayLike(obj) { 121 | if (obj == null || isWindow(obj)) { 122 | return false; 123 | } 124 | 125 | var length = obj.length; 126 | 127 | if (obj.nodeType === NODE_TYPE_ELEMENT && length) { 128 | return true; 129 | } 130 | 131 | return isString(obj) || isArray(obj) || length === 0 || 132 | typeof length === 'number' && length > 0 && (length - 1) in obj; 133 | } 134 | /** 135 | * @private 136 | * @param obj 137 | * @returns {*|boolean} 138 | */ 139 | function isWindow(obj) { 140 | return obj && obj.window === obj; 141 | } 142 | 143 | /** 144 | * @description 145 | * Iterate over the given array and return the first member that the getterFn 146 | * returns true, if `isIndex` set to `true`, return the index. 147 | * @param array 148 | * @param getterFn 149 | * @param isIndex 150 | * @returns {*} 151 | */ 152 | function findInArray(array, getterFn, isIndex) { 153 | 154 | var index = -1; 155 | var res; 156 | 157 | while(++index < array.length) { 158 | if(getterFn(array[index])) { 159 | res = isIndex ? index : array[index]; 160 | break; 161 | } 162 | } 163 | 164 | return res; 165 | } -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "after": false, 23 | "afterEach": false, 24 | "angular": false, 25 | "before": false, 26 | "beforeEach": false, 27 | "browser": false, 28 | "describe": false, 29 | "expect": false, 30 | "inject": false, 31 | "it": false, 32 | "jasmine": false, 33 | "spyOn": false, 34 | "toEqual": false 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.12/config/configuration-file.html 3 | // Generated on 2014-07-06 using 4 | // generator-karma 0.8.3 5 | 6 | module.exports = function(config) { 7 | 'use strict'; 8 | 9 | config.set({ 10 | // enable / disable watching file and executing tests whenever any file changes 11 | autoWatch: true, 12 | 13 | // base path, that will be used to resolve files and exclude 14 | basePath: '../', 15 | 16 | // testing framework to use (jasmine/mocha/qunit/...) 17 | frameworks: ['jasmine'], 18 | 19 | reporters: ['coverage'], 20 | //files to coverage 21 | preprocessors: { 22 | "src/_agile/*": "coverage", 23 | "src/_agile/*/*": "coverage", 24 | "src/*": "coverage" 25 | }, 26 | 27 | coverageReporter: { 28 | type: "lcov", 29 | dir: "test/coverage/" 30 | }, 31 | 32 | // list of files / patterns to load in the browser 33 | files: [ 34 | 'src/_agile/boolean.js', 35 | 'src/_agile/utils.js', 36 | 'src/common.js', 37 | 'src/_parse/*.js', 38 | 'src/_agile/**/*.js', 39 | 'src/agile.js', 40 | 'test/spec/**/*.js', 41 | 'test/spec/**/**/*.js' 42 | ], 43 | 44 | // list of files / patterns to exclude 45 | exclude: [], 46 | 47 | included: true, 48 | 49 | // web server port 50 | port: 8080, 51 | 52 | // Start these browsers, currently available: 53 | // - Chrome 54 | // - ChromeCanary 55 | // - Firefox 56 | // - Opera 57 | // - Safari (only Mac) 58 | // - PhantomJS 59 | // - IE (only Windows) 60 | browsers: [ 61 | 'PhantomJS' 62 | ], 63 | 64 | // Which plugins to enable 65 | plugins: [ 66 | 'karma-phantomjs-launcher', 67 | 'karma-jasmine', 68 | 'karma-coverage' 69 | ], 70 | 71 | // Continuous Integration mode 72 | // if true, it capture browsers, run tests and exit 73 | singleRun: false, 74 | 75 | colors: true, 76 | 77 | // level of logging 78 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 79 | logLevel: config.LOG_INFO 80 | 81 | // Uncomment the following lines if you are using grunt's server to run the tests 82 | // proxies: { 83 | // '/': 'http://localhost:9000/' 84 | // }, 85 | // URL root prevent conflicts with the site root 86 | // urlRoot: '_karma_' 87 | }); 88 | }; 89 | -------------------------------------------------------------------------------- /test/karma.underscore.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Fri Aug 09 2013 14:14:35 GMT-0500 (CDT) 3 | 4 | module.exports = function(config) { 5 | 'use strict'; 6 | 7 | config.set({ 8 | 9 | // base path, that will be used to resolve files and exclude 10 | basePath: '../', 11 | 12 | frameworks: ["jasmine"], 13 | 14 | // list of files / patterns to load in the browser 15 | files: [ 16 | 'src/_agile/boolean.js', 17 | 'src/_agile/utils.js', 18 | 'src/common.js', 19 | 'src/_parse/*.js', 20 | 'src/_agile/**/*.js', 21 | 'src/agile.js', 22 | 'test/spec/**/*.js', 23 | 'test/spec/**/**/*.js' 24 | ], 25 | 26 | 27 | // list of files to exclude 28 | exclude: [ 29 | 30 | ], 31 | 32 | 33 | // test results reporter to use 34 | // possible values: 'dots', 'progress', 'junit' 35 | reporters: ['progress'], 36 | 37 | 38 | // web server port 39 | port: 9877, 40 | 41 | 42 | // cli runner port 43 | runnerPort: 9101, 44 | 45 | 46 | // enable / disable colors in the output (reporters and logs) 47 | colors: true, 48 | 49 | 50 | // level of logging 51 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 52 | logLevel: config.LOG_INFO, 53 | 54 | 55 | // enable / disable watching file and executing tests whenever any file changes 56 | autoWatch: true, 57 | 58 | 59 | // Start these browsers, currently available: 60 | // - Chrome 61 | // - ChromeCanary 62 | // - Firefox 63 | // - Opera 64 | // - Safari (only Mac) 65 | // - PhantomJS 66 | // - IE (only Windows) 67 | browsers: ['PhantomJS'], 68 | 69 | 70 | // If browser does not capture in given timeout [ms], kill it 71 | captureTimeout: 60000, 72 | 73 | 74 | // Continuous Integration mode 75 | // if true, it capture browsers, run tests and exit 76 | singleRun: false 77 | 78 | }); 79 | }; 80 | -------------------------------------------------------------------------------- /test/spec/agile/agile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('agile.js', function() { 3 | var _ = agile; 4 | 5 | describe('@static methods', function() { 6 | it('should have the aliases static methods', function() { 7 | expect(_.pluck).toEqual(_.map); 8 | expect(_.pluck).not.toEqual(_.filter); 9 | expect(_.pick).toEqual(_.filter); 10 | expect(_.pick).not.toEqual(_.map); 11 | expect(_.some).toEqual(_.contains); 12 | expect(_.keys).toEqual(objKeys); 13 | expect(_.toArray).toEqual(toArray); 14 | expect(_.parse).toEqual($parse); 15 | expect(_.sortBy).toEqual(_.orderBy); 16 | }); 17 | }); 18 | 19 | describe('::agile()', function() { 20 | it('should return instance of Wrapper based on the type', function() { 21 | expect(_([]).constructor.name).toEqual('ArrayWrapper'); 22 | expect(_({}).constructor.name).toEqual('ObjectWrapper'); 23 | expect(_('').constructor.name).toEqual('StringWrapper'); 24 | expect(_(1).constructor.name).toEqual('NumberWrapper'); 25 | }); 26 | 27 | it('should return istance Wrapper based on the result', function() { 28 | expect(_([]).join().constructor.name).toEqual('StringWrapper'); 29 | expect(_({a:1}).toArray().constructor.name).toEqual('ArrayWrapper'); 30 | expect(_('as').indexOf('a').constructor.name).toEqual('NumberWrapper'); 31 | }); 32 | 33 | it('should throw an error if it\'s invalid argument', function() { 34 | expect(function () {_(function(){})}).toThrow(Error("Agile value can't be [function] as an argument")); 35 | expect(function () {_()}).toThrow(Error("Agile value can't be [undefined] as an argument")); 36 | }); 37 | 38 | it('should return an object', function() { 39 | expect(typeof _([])).toEqual('object'); 40 | }); 41 | 42 | it('should return the __value__ on value() invoke', function() { 43 | expect(_([1,2,3]).value()).toEqual([1,2,3]); 44 | }); 45 | 46 | it('should get wrapped value and return it as-is', function() { 47 | var wrapped = _([]); 48 | expect(_(wrapped) === wrapped).toBeTruthy(); 49 | }); 50 | }); 51 | 52 | describe('::ArrayWrapper', function() { 53 | 54 | var nums = [1,2,3,5,1,2,3,5]; 55 | var teams = [ 56 | { id: 2, team: { name: 'alpha' } }, 57 | { id: 1, team: { name: 'beta' } }, 58 | { id: 3, team: { name: 'gamma' } }, 59 | { id: 2, team: { name: 'beta' } }, 60 | { id: 1, team: { name: 'gamma' } } 61 | ]; 62 | 63 | describe('#unique', function() { 64 | it('should works without given argument', function() { 65 | expect(_(nums).unique().value()).toEqual([1,2,3,5]); 66 | expect(_([1,1,1,1,1]).unique().value()).toEqual([1]); 67 | }); 68 | it('should works with given property', function() { 69 | var uniqById = _(teams).unique('id').value(); 70 | var uniqByName = _(teams).unique('team.name').value(); 71 | expect(uniqById).toEqual([teams[0], teams[1], teams[2]]); 72 | expect(uniqByName).toEqual([teams[0], teams[1], teams[2]]); 73 | }); 74 | }); 75 | 76 | describe('#map', function() { 77 | it('should work with given property', function() { 78 | var ids = _(teams).map('id').value(); 79 | var names = _(teams).map('team.name').value(); 80 | expect(ids).toEqual([2, 1, 3, 2, 1]); 81 | expect(names).toEqual(['alpha', 'beta', 'gamma', 'beta', 'gamma']); 82 | }); 83 | }); 84 | 85 | describe('#groupBy', function() { 86 | it('should work with given property', function() { 87 | var groups = _(teams).groupBy('team.name').value(); 88 | var ids = _(teams).groupBy('id').value(); 89 | expect(groups).toEqual({ 90 | alpha: [teams[0]], 91 | beta: [teams[1], teams[3]], 92 | gamma: [teams[2], teams[4]] }); 93 | expect(ids).toEqual({ 94 | 2: [teams[0], teams[3]], 95 | 1: [teams[1], teams[4]], 96 | 3: [teams[2]] 97 | }); 98 | }); 99 | }); 100 | 101 | describe('#omit', function() { 102 | it('should work with given expression', function() { 103 | expect(_(teams).omit('id < 10').value()).toEqual([]); 104 | expect(_(teams).omit('team.name.indexOf("a") !== -1').value()).toEqual([]); 105 | expect(_(teams).omit('id > 10').value()).toEqual(teams); 106 | expect(_(teams).omit('id === 1 || id === 2').value()).toEqual([teams[2]]); 107 | }); 108 | it('should work with given function', function() { 109 | var omitted = _(nums).omit(function(e){ return !(e%2) }).value(); 110 | expect(omitted).toEqual([1, 3, 5, 1, 3, 5]); 111 | }); 112 | }); 113 | }); 114 | 115 | describe('::StringWrapper', function() { 116 | describe('#repeat', function() { 117 | it('should repeat string', function() { 118 | expect(_('foo').repeat(2).value()).toEqual('foofoo'); 119 | expect(_('1').repeat(8).value()).toEqual('11111111'); 120 | expect(_('').repeat(2).value()).toEqual(''); 121 | }); 122 | }); 123 | }); 124 | describe('#trim, #ltrim, #rtrim', function() { 125 | it('should trim space by default', function() { 126 | expect(_(' trim ').trim().value()).toEqual('trim'); 127 | expect(_(' rtrim ').rtrim().value()).toEqual(' rtrim'); 128 | expect(_(' ltrim ').ltrim().value()).toEqual('ltrim '); 129 | }); 130 | it('should trim based on the given argument', function() { 131 | expect(_('barfoobar').trim('bar').value()).toEqual('foo'); 132 | expect(_('barfoobar').rtrim('bar').value()).toEqual('barfoo'); 133 | expect(_('barfoobar').ltrim('bar').value()).toEqual('foobar'); 134 | }); 135 | }); 136 | 137 | describe('::NumberWrapper', function() { 138 | it('should works with Math methods', function() { 139 | expect(_(3).pow(2).value()).toEqual(9); 140 | expect(_(3).pow(2).sqrt(2).value()).toEqual(3); 141 | expect(_([-1,-2,-3]).sum().abs().value()).toEqual(6); 142 | }); 143 | }); 144 | 145 | describe('::ObjectWrapper', function() { 146 | it('#toArray, should return ArrayWrapper with array value', function() { 147 | var array = _({ 148 | 0: { id: 1 }, 149 | 1: { id: 2 } 150 | }).toArray(); 151 | expect(array instanceof ArrayWrapper).toBeTruthy(); 152 | expect(array.value()).toEqual([{ id : 1 }, { id : 2 }]); 153 | }); 154 | 155 | it('#keys, should return the objKeys method', function() { 156 | var o1 = { a: { b: 1 }, c: 2, d: { e: 1 } }; 157 | expect(_(o1).keys().value()).toEqual(['a', 'c', 'd']); 158 | expect(_(o1).keys(true).value()).toEqual(['a.b', 'c', 'd.e']); 159 | }); 160 | }); 161 | 162 | describe('chaining in action', function() { 163 | var orders = [ 164 | { id:1, customer: { name: 'foo', id: 10 } }, 165 | { id:2, customer: { name: 'bar', id: 20 } }, 166 | { id:3, customer: { name: 'baz', id: 10 } }, 167 | { id:4, customer: { name: 'zoe', id: 20 } }, 168 | { id:5, customer: { name: 'toy', id: 30 } } 169 | ]; 170 | it('should works with different chaining', function() { 171 | 172 | expect(_(orders) 173 | .unique('customer.id') 174 | .map('id') 175 | .sum() 176 | .pow(3) 177 | .value()).toEqual(512); 178 | 179 | expect(_(orders) 180 | .filter('!(id%2)') 181 | .map('id') 182 | .join() 183 | .repeat(2) 184 | .value()).toEqual('2424'); 185 | 186 | expect(_(orders) 187 | .first(2, 'id > 1') 188 | .map('id') 189 | .max() 190 | .value()).toEqual(3); 191 | 192 | expect(_(orders) 193 | .last(2, 'id') 194 | .map('id') 195 | .min() 196 | .value()).toEqual(4); 197 | 198 | //aliases pluck 199 | expect(_(orders).pluck('id').value()) 200 | .toEqual(_(orders).map('id').value()); 201 | 202 | //aliases pick 203 | expect(_(orders).pick('id > 3').value()) 204 | .toEqual(_(orders).filter('id > 3').value()); 205 | 206 | //aliases some 207 | expect(_(orders).some('id === 5')) 208 | .toEqual(_(orders).contains('id === 5')); 209 | 210 | //objects 211 | expect(_({a:1}) 212 | .extend({b:2}, {c:3}) 213 | .keys() 214 | .value()).toEqual(['a', 'b', 'c']); 215 | 216 | expect(_({a:1}) 217 | .forEach(function(){}, this) 218 | .value()).toEqual({a:1}); 219 | 220 | expect(_([1,2,3]) 221 | .forEach(function(){}, this) 222 | .value()).toEqual([1,2,3]); 223 | }); 224 | 225 | it('should return a value and not wrapper object', function() { 226 | expect(_([{ a:1 }]) 227 | .some('a == 1')) 228 | .toEqual(true); 229 | expect(_([{ b:2 }, { b:4 }, { b:2 }]) 230 | .every('b <= 2')) 231 | .toEqual(false); 232 | }); 233 | 234 | it('should return the find value', function() { 235 | var orders = [ 236 | { id: 1, product: { price: 21.12 } }, 237 | { id: 2, product: { price: 99.21 } }, 238 | { id: 3, product: { price: 99.21 } }, 239 | { id: 4, product: { price: 70.90 } } 240 | ]; 241 | expect(_(orders) 242 | .findLast('product.price === 99.21') 243 | .value()).toEqual(orders[2]); 244 | 245 | expect(_(orders) 246 | .find('product.price === 99.21') 247 | .value()).toEqual(orders[1]); 248 | 249 | expect(_(orders) 250 | .findLastIndex('product.price === 99.21') 251 | .value()).toEqual(2); 252 | 253 | expect(_(orders) 254 | .findIndex('product.price === 99.21') 255 | .value()).toEqual(1); 256 | }); 257 | 258 | it('should sort in chaining object', function() { 259 | var orders = [ 260 | { id: 1, product: { price: 21.12 }, date: new Date('01/01/2014') }, 261 | { id: 2, product: { price: 99.21 }, date: new Date('01/01/2014') }, 262 | { id: 3, product: { price: 99.90 }, date: new Date('01/01/2013') }, 263 | { id: 4, product: { price: 99.99 }, date: new Date('01/01/1970') } 264 | ]; 265 | 266 | expect(_([2,3,4,1]) 267 | .orderBy() 268 | .value()).toEqual([1,2,3,4]); 269 | 270 | expect(_(orders) 271 | .sortBy('date') 272 | .value()).toEqual([orders[3], orders[2], orders[0], orders[1]]); 273 | 274 | expect(_(orders) 275 | .sortBy('-date') 276 | .value()).toEqual([orders[0], orders[1], orders[2], orders[3]]); 277 | 278 | expect(_(orders) 279 | .orderBy('+product.price') 280 | .value()).toEqual(orders); 281 | 282 | expect(_(orders) 283 | .orderBy('-product.price') 284 | .value()).toEqual(orders.slice().reverse()); 285 | 286 | expect(_(orders) 287 | .orderBy(['-date', '-id']) 288 | .value()).toEqual([orders[1], orders[0], orders[2], orders[3]]); 289 | }); 290 | }); 291 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/after-where.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('afterWhere', function() { 4 | 5 | it('get a an array and $parse:expression, and returns all of the items' + 6 | 'in the array after the first that return true', function() { 7 | 8 | var array = [{ a: 1 }, { a: 2 }, { a: 3 }], 9 | orders = [ 10 | { id: 1, customer: { name: 'foo' }, date: 'Tue Jul 15 2014' }, 11 | { id: 2, customer: { name: 'foo' }, date: 'Tue Jul 16 2014' }, 12 | { id: 3, customer: { name: 'foo' }, date: 'Tue Jul 17 2014' }, 13 | { id: 4, customer: { name: 'foo' }, date: 'Tue Jul 18 2014' }, 14 | { id: 5, customer: { name: 'foo' }, date: 'Tue Jul 19 2014' } 15 | ]; 16 | 17 | expect(afterWhere(array, 'a == 2')).toEqual([{ a: 2 }, { a: 3 }]); 18 | //get all orders after July include 19 | expect(afterWhere(orders, 'date == \'Tue Jul 17 2014\'')).toEqual([ orders[2], orders[3], orders[4] ]); 20 | //if identifier not exist, return it as-is 21 | expect(afterWhere(orders, 'date == \'Tue Jul 20 2014\'')).toEqual(orders); 22 | }); 23 | 24 | it('should get a array and return it as-is', function() { 25 | expect(afterWhere(!1)).toBeFalsy(); 26 | expect(afterWhere(1)).toEqual(1); 27 | expect(afterWhere('string')).toEqual('string'); 28 | }); 29 | 30 | it('should return the collection as-is, if not get an expression', function() { 31 | expect(afterWhere([{}, {}])).toEqual([{}, {}]); 32 | expect(afterWhere([])).toEqual([]); 33 | }); 34 | 35 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/after.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('after', function() { 4 | 5 | it('should get array as a collection and specified count, and returns all of the items' + 6 | 'in the collection after the specified count.', function() { 7 | var array = [{ a: 1 }, { a: 2 }]; 8 | 9 | expect(after(array, 1)).toEqual([{ a:2 }]); 10 | expect(after([1,2,3,4], 1)).toEqual([2,3,4]); 11 | expect(after([1,2,3,4], 5)).toEqual([]); 12 | }); 13 | 14 | 15 | it('should get a !collection and return it as-is', function() { 16 | expect(after(!1)).toBeFalsy(); 17 | expect(after(1)).toEqual(1); 18 | expect(after('string')).toEqual('string'); 19 | }); 20 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/before-where.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('beforeWhere', function() { 4 | 5 | it('get a an array and $parse:expression, and returns all of the items' + 6 | 'in the array after the first that return true', function() { 7 | 8 | var array = [{ a: 1 }, { a: 2 }, { a: 3 }], 9 | orders = [ 10 | { id: 1, customer: { name: 'foo' }, date: 'Tue Jul 15 2014' }, 11 | { id: 2, customer: { name: 'foo' }, date: 'Tue Jul 16 2014' }, 12 | { id: 3, customer: { name: 'foo' }, date: 'Tue Jul 17 2014' }, 13 | { id: 4, customer: { name: 'foo' }, date: 'Tue Jul 18 2014' }, 14 | { id: 5, customer: { name: 'foo' }, date: 'Tue Jul 19 2014' } 15 | ]; 16 | 17 | expect(beforeWhere(array, 'a == 2')).toEqual([{ a: 1 }, { a: 2 }]); 18 | //get all orders after July include 19 | expect(beforeWhere(orders, 'date == \'Tue Jul 17 2014\'')).toEqual([ orders[0], orders[1], orders[2] ]); 20 | //if identifier not exist, return it as-is 21 | expect(beforeWhere(orders, 'date == \'Tue Jul 20 2014\'')).toEqual(orders); 22 | }); 23 | 24 | it('should get a array and return it as-is', function() { 25 | expect(beforeWhere(!1)).toBeFalsy(); 26 | expect(beforeWhere(1)).toEqual(1); 27 | expect(beforeWhere('string')).toEqual('string'); 28 | }); 29 | 30 | it('should return the collection as-is, if not get an expression', function() { 31 | expect(beforeWhere([{}, {}])).toEqual([{}, {}]); 32 | expect(beforeWhere([])).toEqual([]); 33 | }); 34 | 35 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/before.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('before', function() { 4 | 5 | it('should get array as a collection and specified count, and returns all of the items' + 6 | 'in the collection before the specified count.', function() { 7 | var array = [{ a: 1 }, { a: 2 }]; 8 | 9 | expect(before(array, 2)).toEqual([{ a: 1 }]); 10 | expect(before([1,2,3,4], 4)).toEqual([1,2,3]); 11 | expect(before([1,2,3,4], 5)).toEqual([1,2,3,4]); 12 | }); 13 | 14 | it('should not get count and return the array as-is', function() { 15 | expect(before([1,2,4])).toEqual([1,2,4]); 16 | }); 17 | 18 | it('should get a !collection and return it as-is', function() { 19 | expect(before(!1)).toBeFalsy(); 20 | expect(before(1)).toEqual(1); 21 | expect(before('string')).toEqual('string'); 22 | }); 23 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/contains.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('contains', function() { 4 | 5 | it('should get collection of primitives and use strict comparison(===)', function() { 6 | expect(contains(['foo', 'bar'], 'bar')).toBeTruthy(); 7 | expect(contains([1,2,3,4], 4)).toBeTruthy(); 8 | 9 | expect(contains(['foo', 'bar'], 'baz')).toBeFalsy(); 10 | expect(contains([1,2,3,4], -1)).toBeFalsy(); 11 | }); 12 | 13 | it('should get array as collection and return if given expression is ' + 14 | 'present in one or more object in the collection', function() { 15 | var array = [ 16 | { id: 1, name: 'foo' }, 17 | { id: 2, name: 'baz' }, 18 | { id: 1, name: 'ariel' }, 19 | { id: 1, name: 'bar' } 20 | ]; 21 | 22 | expect(contains(array, 'id === 2')).toBeTruthy(); 23 | expect(contains(array, 'id >= 1 && name === \'foo\'')).toBeTruthy(); 24 | expect(contains(array)).toBeTruthy(); 25 | 26 | expect(contains(array, 'id > 77')).toBeFalsy(); 27 | expect(contains(array, 'name.indexOf(\'u\') !== -1')).toBeFalsy(); 28 | }); 29 | 30 | it('should get function as expression', function() { 31 | var array = [1, 2, 3, 4, 5]; 32 | 33 | function mod2(elm) { 34 | return !(elm % 2); 35 | } 36 | 37 | expect(contains(array, mod2)).toBeTruthy(); 38 | }); 39 | 40 | it('should get !collection and return always true', function() { 41 | expect(contains('lorem ipsum')).toBeTruthy(); 42 | expect(contains(1, null)).toBeTruthy(); 43 | expect(contains(!1)).toBeTruthy(); 44 | }); 45 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/count-by.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('countBy', function() { 4 | 5 | it('should returns a count for the number of objects in each group.', function() { 6 | var players = [ 7 | {name: 'Gene', team: { name: 'alpha' } }, 8 | {name: 'George', team: { name: 'beta' } }, 9 | {name: 'Steve', team: { name: 'beta' } }, 10 | {name: 'Paula', team: { name: 'alpha' } }, 11 | {name: 'Scruath', team: { name: 'gamma' } } 12 | ]; 13 | 14 | expect(countBy(players, 'team.name')).toEqual( { 15 | alpha: 2, 16 | beta: 2, 17 | gamma: 1 18 | }); 19 | }); 20 | 21 | it('should returns a count for the number of objects in each group.', function() { 22 | var players = [ 23 | {name: 'Gene', team: { members: 123 } }, 24 | {name: 'George', team: { members: 123 } }, 25 | {name: 'Steve', team: { members: 424 } }, 26 | {name: 'Paula', team: { members: 624 } }, 27 | {name: 'Scruath', team: { members: 224 } }, 28 | ]; 29 | 30 | expect(countBy(players, 'team.members > 300')).toEqual( { 31 | 'false': 3, 32 | 'true' : 2 33 | }); 34 | }); 35 | 36 | it('should handle nested properties safety', function() { 37 | var orders = [ 38 | { id:10, customer: { name: 'foo', id: 1 } }, 39 | { id:11, customer: { name: 'bar', id: 2 } }, 40 | { id:12, customer: { name: 'foo', id: 1 } }, 41 | { id:13, customer: { name: 'bar', id: 2 } }, 42 | { id:14, customer: { name: 'bar', id: 3 } }, 43 | 2, null, true 44 | ]; 45 | 46 | expect(countBy(orders, 'customer.name')).toEqual( { 47 | foo: 2, 48 | bar: 3, 49 | undefined: 3 50 | }); 51 | }); 52 | 53 | 54 | it('should get !collection and return it as-is ', function() { 55 | expect(countBy('string')).toEqual('string'); 56 | expect(countBy(1)).toEqual(1); 57 | expect(countBy(!1)).toBeFalsy(); 58 | expect(countBy(null)).toBeNull(); 59 | }); 60 | 61 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/defaults.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('defaults', function() { 4 | 5 | it('should return the collection as-is, if default object not provided', function() { 6 | expect(defaults([{}])).toEqual([{}]); 7 | expect(defaults([])).toEqual([]); 8 | }); 9 | 10 | it('should change the source object', function() { 11 | var array = [{ a: 1 }]; 12 | var defaultsObj = { b: 2 }; 13 | var copy = window.copy(array); 14 | 15 | expect(defaults(array, defaultsObj)).toEqual([{ a:1, b: 2 }]); 16 | expect(array).not.toEqual(copy); 17 | }); 18 | 19 | //test the simple usage 20 | describe('should use fallback value', function() { 21 | var expectOrders = [ 22 | { id:1, destination: { zip: 21908 }, name: 'Ariel M.' }, 23 | { id:2, destination: { zip: 'Pickup' }, name: 'John F.' }, 24 | { id:3, destination: { zip: 45841 }, name: 'Not available'}, 25 | { id:4, destination: { zip: 78612 }, name: 'Danno L.' } 26 | ]; 27 | var defaultsObj = { name: 'Not available', destination: { zip: 'Pickup' } }; 28 | 29 | it('should work with array', function() { 30 | var orders = [ 31 | { id:1, destination: { zip: 21908 }, name: 'Ariel M.' }, 32 | { id:2, name: 'John F.' }, 33 | { id:3, destination: { zip: 45841 } }, 34 | { id:4, destination: { zip: 78612 }, name: 'Danno L.' } 35 | ]; 36 | var copyOrders = window.copy(orders); 37 | 38 | expect(defaults(copyOrders, defaultsObj)).toEqual(expectOrders); 39 | expect(defaults(copyOrders, defaultsObj)).not.toEqual(orders); 40 | }); 41 | 42 | }); 43 | 44 | it('should work fine with complex objects', function() { 45 | var array = [ 46 | { a: 'string', 47 | b: { c: 1 }, 48 | d: { e: { f: new Function() } }, 49 | g: [], 50 | h: undefined, 51 | i: { j: { k: { l: 'm' } } }, 52 | o: new RegExp } 53 | ]; 54 | var copy = window.copy(array); 55 | var defaultsObj = { z: 'z', z1: { z2: 'z2' } , h: 1 }; 56 | extend(array[0], defaultsObj); 57 | expect(defaults(copy, defaultsObj)).toEqual(array); 58 | }); 59 | 60 | it('should get !collection and return it as-is ', function() { 61 | expect(defaults('string')).toEqual('string'); 62 | expect(defaults(1)).toEqual(1); 63 | expect(defaults(!1)).toBeFalsy(); 64 | expect(defaults(null)).toBeNull(); 65 | }); 66 | 67 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/every.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('every', function() { 4 | 5 | it('should get collection of primitives and use strict comparison(===)', function() { 6 | expect(every(['bar', 'bar'], 'bar')).toBeTruthy(); 7 | expect(every([4,4,4,4], 4)).toBeTruthy(); 8 | 9 | expect(every(['foo', 'bar'], 'bar')).toBeFalsy(); 10 | expect(every([1,4,4,4], 4)).toBeFalsy(); 11 | }); 12 | 13 | it('should get array as collection and return if given expression is ' + 14 | 'present all members in the collection', function() { 15 | 16 | var array = [ 17 | { id: 1, name: 'faa' }, 18 | { id: 1, name: 'baz' }, 19 | { id: 1, name: 'ariel' }, 20 | { id: 1, name: 'bar' } 21 | ]; 22 | 23 | expect(every(array, 'id === 1')).toBeTruthy(); 24 | expect(every(array, 'id >= 1 && name.indexOf(\'a\') !== -1')).toBeTruthy(); 25 | expect(every(array)).toBeTruthy(); 26 | 27 | expect(every(array, 'id > 77')).toBeFalsy(); 28 | expect(every(array, 'name.indexOf(\'b\') !== -1')).toBeFalsy(); 29 | }); 30 | 31 | it('should get function as expression', function() { 32 | var array = [0, 2, 4, 6, 8]; 33 | 34 | function mod2(elm) { 35 | return !(elm % 2); 36 | } 37 | 38 | expect(every(array, mod2)).toBeTruthy(); 39 | }); 40 | 41 | it('should get !collection and return always true', function() { 42 | 43 | expect(every('lorem ipsum')).toBeTruthy(); 44 | expect(every(1, null)).toBeTruthy(); 45 | expect(every(!1)).toBeTruthy(); 46 | }); 47 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('filter', function() { 3 | 4 | it('should filter primitive simply', function() { 5 | expect(filter([1,2,3,4,1,2], 1)).toEqual([1,1]) 6 | }); 7 | 8 | it('should filter by the given function', function() { 9 | function mod2(x) { 10 | return !(x%2); 11 | } 12 | expect(filter([1,2,3,4,1,2], mod2)).toEqual([2,4, 2]); 13 | }); 14 | 15 | it('should filter by expression', function() { 16 | var array = [ 17 | { id: 2, name: 'faa' }, 18 | { id: 4, name: 'baz' }, 19 | { id: 3, name: 'ariel' }, 20 | { id: 5, name: 'bar' } 21 | ]; 22 | 23 | expect(filter(array, 'name.indexOf("ba") != -1')) 24 | .toEqual([array[1], array[3]]); 25 | expect(filter(array, '!(id%2)')) 26 | .toEqual([array[0], array[1]]); 27 | }); 28 | 29 | it('should handle nested properties safety', function() { 30 | var array = [ 31 | {},{},[],null, 32 | { details: { name: 'Eddi' } } 33 | ]; 34 | expect(filter(array, 'details.name')) 35 | .toEqual([ { details: { name: 'Eddi' } }]); 36 | }); 37 | 38 | it('should get !array ot !exp and return it as-is', function() { 39 | expect(filter('string')).toEqual('string'); 40 | expect(filter(1)).toEqual(1); 41 | 42 | expect(filter([1,2])).toEqual([1,2]); 43 | }); 44 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/find-index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('findIndex', function() { 4 | 5 | var orders = [ 6 | { id: 21, customer: { id: 2, name: 'John P.' }, product: { price: 21.12 } }, 7 | { id: 22, customer: { id: 1, name: 'Cati P.' }, product: { price: 89.21 } }, 8 | { id: 23, customer: { id: 1, name: 'Cati P.' }, product: { price: 49.00 } }, 9 | { id: 24, customer: { id: 3, name: 'Poul S.' }, product: { price: 10.22 } }, 10 | { id: 25, customer: { id: 4, name: 'Erik L.' }, product: { price: 11.31 } } 11 | ]; 12 | 13 | it('should return the first member the return truthy for the expression', function() { 14 | expect(findIndex(orders, 'id > 20')).toEqual(0); 15 | expect(findIndex(orders, 'id > 22')).toEqual(2); 16 | expect(findIndex(orders, 'customer.id === 1 && product.price < 80')).toEqual(2); 17 | expect(findIndex(orders, 'product.price > 50')).toEqual(1); 18 | }); 19 | 20 | it('should accept functions as an argument', function() { 21 | function mod2(n) { 22 | return !(n%2); 23 | } 24 | expect(findIndex([1,3,3,3,4,5,6], mod2)).toEqual(4); 25 | }); 26 | 27 | it('should get !array or !expression and return it as-is', function() { 28 | expect(findIndex('string')).toEqual('string'); 29 | expect(findIndex(1010)).toEqual(1010); 30 | expect(findIndex(!0)).toBeTruthy(); 31 | expect(findIndex([1,2])).toEqual([1,2]); 32 | }); 33 | 34 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/find-last-index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('findLastIndex', function() { 4 | 5 | // describe('given a not array', function() { 6 | // var inputs = [{}, 'string', 1, true, new Function]; 7 | // 8 | // it('should not be applied', function() { 9 | // inputs.forEach(function(input) { 10 | // expect(findLastIndex(input)).toEqual(input); 11 | // }); 12 | // }) 13 | // }); 14 | 15 | describe('get an array as a first argument', function() { 16 | var orders = [ 17 | { id: 21, customer: { id: 2, name: 'John P.' }, product: { price: 21.12 } }, 18 | { id: 22, customer: { id: 1, name: 'Cati P.' }, product: { price: 89.21 } }, 19 | { id: 23, customer: { id: 1, name: 'Cati P.' }, product: { price: 49.00 } }, 20 | { id: 24, customer: { id: 3, name: 'Poul S.' }, product: { price: 10.22 } }, 21 | { id: 25, customer: { id: 4, name: 'Erik L.' }, product: { price: 11.31 } } 22 | ]; 23 | 24 | describe('get a !(expression || function)', function() { 25 | it('should not be applied', function() { 26 | expect(findLastIndex(orders)).toEqual(orders); 27 | }); 28 | }); 29 | 30 | describe('get an expression as a second argument', function() { 31 | it('should return the index of the last member that the expression returns truthy for', function() { 32 | expect(findLastIndex(orders, 'id')).toEqual(4); 33 | expect(findLastIndex(orders, 'id > 22')).toEqual(4); 34 | expect(findLastIndex(orders, 'customer.id == 1')).toEqual(2); 35 | expect(findLastIndex(orders, 'product.price > 50')).toEqual(1); 36 | }); 37 | it('should return -1 if not found an comparison', function() { 38 | expect(findLastIndex(orders, 'id > 29')).toEqual(-1); 39 | expect(findLastIndex(orders, 'ID')).toEqual(-1); 40 | }); 41 | }); 42 | 43 | describe('get a function as a second argument', function() { 44 | it('should return the index of the last member that the function returns truthy for', function() { 45 | function mod2(n) { 46 | return !(n%2); 47 | } 48 | expect(findLast([1,3,3,3,4,5,6], mod2)).toEqual(6); 49 | expect(findLastIndex([2,3,3,3,5,5,7], mod2)).toEqual(0); 50 | }); 51 | }); 52 | }); 53 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/find-last.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('findLast', function() { 4 | 5 | describe('given a not array', function() { 6 | var inputs = [{}, 'string', 1, true, new Function]; 7 | 8 | it('should not be applied', function() { 9 | inputs.forEach(function(input) { 10 | expect(findLast(input)).toEqual(input); 11 | }); 12 | }) 13 | }); 14 | 15 | describe('get an array as a first argument', function() { 16 | var orders = [ 17 | { id: 21, customer: { id: 2, name: 'John P.' }, product: { price: 21.12 } }, 18 | { id: 22, customer: { id: 1, name: 'Cati P.' }, product: { price: 89.21 } }, 19 | { id: 23, customer: { id: 1, name: 'Cati P.' }, product: { price: 49.00 } }, 20 | { id: 24, customer: { id: 3, name: 'Poul S.' }, product: { price: 10.22 } }, 21 | { id: 25, customer: { id: 4, name: 'Erik L.' }, product: { price: 11.31 } } 22 | ]; 23 | 24 | describe('get a !(expression || function)', function() { 25 | it('should not be applied', function() { 26 | expect(findLast(orders)).toEqual(orders); 27 | }); 28 | }); 29 | 30 | describe('get an expression as a second argument', function() { 31 | it('should return the last member that the expression returns truthy for', function() { 32 | expect(findLast(orders, 'id > 20')).toEqual(orders[4]); 33 | expect(findLast(orders, 'id > 22')).toEqual(orders[4]); 34 | expect(findLast(orders, 'customer.id === 1')).toEqual(orders[2]); 35 | expect(findLast(orders, 'product.price > 50')).toEqual(orders[1]); 36 | }); 37 | }); 38 | 39 | describe('get a function as a second argument', function() { 40 | it('should return the last member that the function returns truthy for', function() { 41 | function mod2(n) { 42 | return !(n%2); 43 | } 44 | expect(findLast([1,3,3,3,4,5,6], mod2)).toEqual(6); 45 | expect(findLast([2,3,3,3,5,5,7], mod2)).toEqual(2); 46 | }); 47 | }); 48 | }); 49 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/find.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('find', function() { 4 | 5 | var orders = [ 6 | { id: 21, customer: { id: 2, name: 'John P.' }, product: { price: 21.12 } }, 7 | { id: 22, customer: { id: 1, name: 'Cati P.' }, product: { price: 89.21 } }, 8 | { id: 23, customer: { id: 1, name: 'Cati P.' }, product: { price: 49.00 } }, 9 | { id: 24, customer: { id: 3, name: 'Poul S.' }, product: { price: 10.22 } }, 10 | { id: 25, customer: { id: 4, name: 'Erik L.' }, product: { price: 11.31 } } 11 | ]; 12 | 13 | it('should return the first member the return truthy for the expression', function() { 14 | expect(find(orders, 'id > 20')).toEqual(orders[0]); 15 | expect(find(orders, 'id > 22')).toEqual(orders[2]); 16 | expect(find(orders, 'customer.id === 1')).toEqual(orders[1]); 17 | expect(find(orders, 'product.price > 50')).toEqual(orders[1]); 18 | }); 19 | 20 | it('should accept functions as an argument', function() { 21 | function mod2(n) { 22 | return !(n%2); 23 | } 24 | expect(find([1,3,3,3,4,5,6], mod2)).toEqual(4); 25 | }); 26 | 27 | it('should get !array or !expression and return it as-is', function() { 28 | expect(find('string')).toEqual('string'); 29 | expect(find(1010)).toEqual(1010); 30 | expect(find(!0)).toBeTruthy(); 31 | expect(find([1,2])).toEqual([1,2]); 32 | }); 33 | 34 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/first.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('first', function() { 4 | 5 | it('should return the first member in a collection', function() { 6 | expect(first([1,2,3,4,5])).toEqual(1); 7 | expect(first(['a', 'b', 'c', 'd'])).toEqual('a'); 8 | expect(first([undefined, null, null])).toEqual(undefined); 9 | expect(first([ {0: 'foo'} ])).toEqual({ 0: 'foo' }); 10 | }); 11 | 12 | it('should return first n elements of a collection', function() { 13 | expect(first([1,2,3,4,5], 3)).toEqual([1,2,3]); 14 | expect(first([undefined, null, null], 1)).toEqual([undefined]); 15 | expect(first({0: 'foo', 1: 'bar'}, 2)).toEqual(['foo', 'bar']); 16 | }); 17 | 18 | it('should return the first element that match the expression', function() { 19 | var users = [ 20 | { id: 1, name: { first: 'foo', last: 'bar' } }, 21 | { id: 2, name: { first: 'baz', last: 'bar' } }, 22 | { id: 3, name: { first: 'bar', last: 'bar' } }, 23 | { id: 4, name: { first: 'lol', last: 'bar' } } 24 | ]; 25 | 26 | expect(first(users, 'name.first === name.last')).toEqual([ users[2] ]); 27 | expect(first(users, '!(id % 2)')).toEqual([ users[1] ]); 28 | expect(first(users, 'name.first === \'lol\' && name.last === \'bar\'')).toEqual([ users[3] ]); 29 | expect(first(users, 'id > 5')).toEqual([]); 30 | }); 31 | 32 | it('should return the first n element that match the expression', function() { 33 | var users = [ 34 | { id: 1, name: { first: 'foo', last: 'bar' } }, 35 | { id: 2, name: { first: 'baz', last: 'bar' } }, 36 | { id: 3, name: { first: 'bar', last: 'bar' } }, 37 | { id: 4, name: { first: 'lol', last: 'bar' } } 38 | ]; 39 | 40 | expect(first(users, 2, 'name.first === name.last')).toEqual([ users[2] ]); 41 | expect(first(users, 2, '!(id % 2)')).toEqual([ users[1], users[3] ]); 42 | expect(first(users, 'id > 5')).toEqual([]); 43 | 44 | function mod2(elm) { 45 | return !(elm%2); 46 | } 47 | 48 | expect(first([1, 2, 3, 4], 2, mod2)).toEqual([2, 4]); 49 | expect(first([1, 2, 3, 4, 6], 2, mod2)).toEqual([2, 4]); 50 | expect(first([1, 2], 2, mod2)).toEqual([2]); 51 | }); 52 | 53 | it('should get !collection and return it as-is', function() { 54 | expect(first('string')).toEqual('string'); 55 | expect(first(1010)).toEqual(1010); 56 | expect(first(!0)).toBeTruthy(); 57 | }); 58 | 59 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/flatten.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 'use strict'; 4 | 5 | describe('flatten', function() { 6 | 7 | it('should get a multiple nested array and return it flatten', function() { 8 | expect(flatten([[[[[0]]]]])).toEqual([0]); 9 | 10 | expect(flatten([[], 'A', 'B', ['C', 'D'], ['E', ['F'], []]])) 11 | .toEqual(['A', 'B', 'C', 'D', 'E', 'F']); 12 | 13 | expect(flatten([[[[null]]], [[null]], [null]])) 14 | .toEqual([null, null, null]); 15 | 16 | expect(flatten([[], 1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, [12, [[[[[13], [[[[14, 15]]]]]]]]]]]]])) 17 | .toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); 18 | }); 19 | 20 | it('should flattened a single level, if shallow set to true', function() { 21 | expect(flatten(['out', ['out', ['in']], ['out', 'out', ['in', 'in']], ['out', 'out']], true)) 22 | .toEqual(['out', 'out', ['in'], 'out', 'out', ['in', 'in'], 'out', 'out']); 23 | expect(flatten([[], 1, [1, [0, [0, [0]]], 1, [0]], 1, [1, [0]]], true)) 24 | .toEqual([1, 1, [0, [0, [0]]], 1, [0], 1, 1, [0]]); 25 | }); 26 | 27 | it('should get !collection, and return it as-is', function() { 28 | expect(flatten('string')).toEqual('string'); 29 | expect(flatten(1, true)).toEqual(1); 30 | expect(flatten(~~undefined)).toEqual(0); 31 | expect(flatten(null)).toEqual(null); 32 | }); 33 | 34 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/group-by.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('groupBy', function() { 4 | 5 | it('should get array as collection, property(nested to) as identifier and ' + 6 | 'returns the composed aggregate object.', function() { 7 | var players = [ 8 | {name: 'Gene', team: 'alpha'}, 9 | {name: 'George', team: 'beta'}, 10 | {name: 'Steve', team: 'gamma'}, 11 | {name: 'Paula', team: 'beta'}, 12 | {name: 'Scruath', team: 'gamma'} 13 | ]; 14 | 15 | expect(groupBy(players, 'team')).toEqual( { 16 | alpha: [players[0]], 17 | beta: [players[1], players[3]], 18 | gamma: [players[2], players[4]] 19 | }); 20 | }); 21 | 22 | it('should support nested properties to', function() { 23 | var orders = [ 24 | { id:10, customer: { name: 'foo', id: 1 } }, 25 | { id:11, customer: { name: 'bar', id: 2 } }, 26 | { id:12, customer: { name: 'foo', id: 1 } }, 27 | { id:13, customer: { name: 'bar', id: 2 } }, 28 | { id:14, customer: { name: 'bar', id: 3 } }, 29 | 2, null, true 30 | ]; 31 | 32 | expect(groupBy(orders, 'customer.name')).toEqual( { 33 | foo: [orders[0], orders[2]], 34 | bar: [orders[1], orders[3], orders[4]], 35 | undefined: [2, null, true] 36 | }); 37 | }); 38 | 39 | it('should get !collection and return it as-is ', function() { 40 | expect(groupBy('string')).toEqual('string'); 41 | expect(groupBy(1)).toEqual(1); 42 | expect(groupBy(!1)).toBeFalsy(); 43 | expect(groupBy(null)).toBeNull(); 44 | }); 45 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/last.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('last', function() { 3 | 4 | it('should return the last member in a collection', function() { 5 | expect(last([1,2,3,4,5])).toEqual(5); 6 | expect(last(['a', 'b', 'c', 'd'])).toEqual('d'); 7 | expect(last([undefined, null, null])).toEqual(null); 8 | expect(last([{0: 'foo'}, { 1: 'bar'}])).toEqual({ 1: 'bar' }); 9 | }); 10 | 11 | it('should return last n elements of a collection', function() { 12 | expect(last([1, 2, 3, 4, 5], 3)).toEqual([3, 4, 5]); 13 | expect(last([undefined, null, null], 2)).toEqual([null, null]); 14 | expect(last({0: 'foo', 1: 'bar'}, 2)).toEqual(['foo', 'bar']); 15 | }); 16 | 17 | it('should return the last element that match the expression', function() { 18 | var users = [ 19 | { id: 1, name: { first: 'foo', last: 'bar' } }, 20 | { id: 2, name: { first: 'baz', last: 'bar' } }, 21 | { id: 3, name: { first: 'bar', last: 'bar' } }, 22 | { id: 4, name: { first: 'lol', last: 'bar' } } 23 | ]; 24 | 25 | expect(last(users, 'name.first === name.last')).toEqual([ users[2] ]); 26 | expect(last(users, '!(id % 2)')).toEqual([ users[3] ]); 27 | expect(last(users, 'name.first !== \'lol\' && name.last === \'bar\'')).toEqual([ users[2] ]); 28 | expect(last(users, 'id > 5')).toEqual([]); 29 | }); 30 | 31 | it('should return the last n element that match the expression', function() { 32 | var users = [ 33 | { id: 1, name: { first: 'foo', last: 'bar' } }, 34 | { id: 2, name: { first: 'baz', last: 'bar' } }, 35 | { id: 3, name: { first: 'bar', last: 'bar' } }, 36 | { id: 4, name: { first: 'lol', last: 'bar' } } 37 | ]; 38 | 39 | expect(last(users, 2, 'name.first !== name.last')).toEqual([users[1], users[3]]); 40 | expect(last(users, 2, '(id % 2)')).toEqual([users[0], users[2]]); 41 | expect(last(users, 'id > 5')).toEqual([]); 42 | 43 | function mod2(elm) { 44 | return !(elm%2); 45 | } 46 | 47 | expect(last([1, 2, 3, 4, 5, 6], 2, mod2)).toEqual([4, 6]); 48 | expect(last([1, 2, 3, 4, 6, 11], 2, mod2)).toEqual([4, 6]); 49 | expect(last([2,1], 2, mod2)).toEqual([2]); 50 | }); 51 | 52 | it('should get !collection and return it as-is', function() { 53 | expect(last('string')).toEqual('string'); 54 | expect(last(1010)).toEqual(1010); 55 | expect(last(!0)).toBeTruthy(); 56 | }); 57 | 58 | it('should run the test from the readme file', function() { 59 | var users = [ 60 | { id: 1, user: { name: 'foo', isAdmin: true } }, 61 | { id: 2, user: { name: 'bar', isAdmin: false } }, 62 | { id: 3, user: { name: 'baz', isAdmin: false } }, 63 | { id: 4, user: { name: 'zak', isAdmin: true } } 64 | ]; 65 | 66 | expect(last(users)).toEqual(users[3]); 67 | expect(last(users, '!user.isAdmin')).toEqual([users[2]]); 68 | expect(last(users, 2)).toEqual([users[2], users[3]]); 69 | expect(last(users, 2, 'user.isAdmin')).toEqual([users[0], users[3]]); 70 | }); 71 | 72 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/map.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('map', function() { 4 | 5 | it('should returns a new array with the results of each expression execution', function() { 6 | var array = [ 7 | { id: 1, name: 'foo' }, 8 | { id: 2, name: 'baz' }, 9 | { id: 1, name: 'ariel' }, 10 | { id: 1, name: 'bar' } 11 | ]; 12 | 13 | expect(map(array, 'name')).toEqual(['foo', 'baz', 'ariel', 'bar']); 14 | expect(map(array, 'id === 1 && name === "foo"')).toEqual([true, false, false, false]); 15 | expect(map(array)).toEqual(array); 16 | }); 17 | 18 | it('should support nested properties, and handle error safety', function() { 19 | var array = [ 20 | { name: 'Ariel', details: { age: 25 } }, 21 | { name: 'Dan', details: { age: 22 } }, 22 | { name: 'Sharon', details: { age: 29 } }, 23 | { name: 'Eddi', details: { age: 20 } } 24 | ]; 25 | 26 | expect(map(array, 'details.age >= 20')).toEqual([true, true, true, true]); 27 | expect(map(array, 'details.age.now.age')).toEqual([undefined, undefined, undefined, undefined]); 28 | expect(map(array, '!(details.age % 2)')).toEqual([false, true, false, true]); 29 | }); 30 | 31 | 32 | it('should get function as expression', function() { 33 | var array = [1, 2, 3, 4, 5]; 34 | 35 | function divide(elm) { 36 | return (elm/2); 37 | } 38 | expect(map(array, divide)).toEqual([0.5, 1, 1.5, 2, 2.5]); 39 | }); 40 | 41 | it('should get !collection and return it as-is', function() { 42 | expect(map('lorem ipsum')).toEqual('lorem ipsum'); 43 | expect(map(1, null)).toEqual(1); 44 | expect(map(!1)).toBeFalsy(); 45 | }); 46 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/max.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('max', function () { 4 | 5 | it('should Math.max with the given arguments', function() { 6 | var spy = spyOn(Math, 'max'); 7 | max([1,2,3]); 8 | expect(spy).toHaveBeenCalledWith(1,2,3); 9 | }); 10 | 11 | it('should get an array of numbers and return the biggest one', function() { 12 | expect(max([1,2,3,4,5])).toEqual(5); 13 | expect(max([2,2,2,2,2])).toEqual(2); 14 | expect(max([1])).toEqual(1); 15 | }); 16 | 17 | it('should get array with expression and return object', function() { 18 | var users = [ 19 | { name: 'foo', score: 89 }, 20 | { name: 'bar', score: 32 }, 21 | { name: 'baz', score: 49 } 22 | ]; 23 | expect(max(users, 'score')).toEqual(users[0]); 24 | }); 25 | 26 | it('should get an !array and return it as-is', function() { 27 | expect(max('string')).toEqual('string'); 28 | expect(max({})).toEqual({}); 29 | expect(max(!0)).toBeTruthy(); 30 | }); 31 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/min.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('min', function () { 4 | 5 | it('should Math.min with the given arguments', function() { 6 | var spy = spyOn(Math, 'min'); 7 | min([1,2,3]); 8 | expect(spy).toHaveBeenCalledWith(1,2,3); 9 | }); 10 | 11 | it('should get an array of numbers and return the biggest one', function() { 12 | expect(min([1,2,3,4,5])).toEqual(1); 13 | expect(min([2,2,2,2,2])).toEqual(2); 14 | expect(min([1])).toEqual(1); 15 | }); 16 | 17 | it('should get an array, and expression and return an object', function() { 18 | var users = [ 19 | { user: { score: 197 } }, 20 | { user: { score: 212 } }, 21 | { user: { score: 978 } }, 22 | { user: { score: 121 } } 23 | ]; 24 | expect(min(users, 'user.score')).toEqual(users[3]); 25 | }); 26 | 27 | it('should get an !array and return it as-is', function() { 28 | expect(min('string')).toEqual('string'); 29 | expect(min({})).toEqual({}); 30 | expect(min(!0)).toBeTruthy(); 31 | }); 32 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/omit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('omit', function() { 4 | 5 | it('should get array as a collection and omit by expression', function() { 6 | var array = [ 7 | { id: 1, name: 'foo' }, 8 | { id: 2, name: 'baz' }, 9 | { id: 1, name: 'ariel' }, 10 | { id: 1, name: 'bar' } 11 | ]; 12 | 13 | expect(omit(array, 'id === 1')).toEqual([array[1]]); 14 | expect(omit(array, 'id === 1 && name === "foo"')).toEqual([array[1], array[2], array[3]]); 15 | expect(omit(array)).toEqual(array); 16 | }); 17 | 18 | it('should work safety', function() { 19 | var array = [ 20 | null, false, 2, 'string', 21 | { details: { id: 2 } }, 22 | { details: { id: 1 } } 23 | ]; 24 | expect(omit(array, 'details.id > 0')).toEqual([null, false, 2, 'string']); 25 | }); 26 | 27 | it('should work with primitives', function() { 28 | var array = [7,7,4,3,6,7,7]; 29 | expect(omit(array, 7)).toEqual([4,3,6]); 30 | }); 31 | 32 | it('should get function as expression', function() { 33 | var array = [1, 2, 3, 4, 5]; 34 | 35 | function mod2(elm) { 36 | return !(elm % 2); 37 | } 38 | 39 | expect(omit(array, mod2)).toEqual([1, 3, 5]); 40 | }); 41 | 42 | it('should get !collection and return it as-is', function() { 43 | expect(omit('lorem ipsum')).toEqual('lorem ipsum'); 44 | expect(omit(1, null)).toEqual(1); 45 | expect(omit(!1)).toBeFalsy(); 46 | }); 47 | 48 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/order-by.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('orderBy', function() { 4 | 5 | describe('(Arrays)', function() { 6 | it('should return sorted array if predicate is not provided', function() { 7 | expect(orderBy([2, 1, 3])).toEqual([1, 2, 3]); 8 | 9 | expect(orderBy([2, 1, 3], '')).toEqual([1, 2, 3]); 10 | expect(orderBy([2, 1, 3], [])).toEqual([1, 2, 3]); 11 | expect(orderBy([2, 1, 3], [''])).toEqual([1, 2, 3]); 12 | 13 | expect(orderBy([2, 1, 3], '+')).toEqual([1, 2, 3]); 14 | expect(orderBy([2, 1, 3], ['+'])).toEqual([1, 2, 3]); 15 | 16 | expect(orderBy([2, 1, 3], '-')).toEqual([3, 2, 1]); 17 | expect(orderBy([2, 1, 3], ['-'])).toEqual([3, 2, 1]); 18 | 19 | expect(orderBy(['a', 1])).toEqual(['a', 1].sort()); 20 | expect(orderBy([1, 'a'])).toEqual(['a', 1].sort()); 21 | }); 22 | 23 | 24 | it('should sort array in reverse if it\'s defined', function() { 25 | expect(orderBy([{a:15}, {a:2}], 'a')).toEqual([{a:2}, {a:15}]); 26 | expect(orderBy([{a:15}, {a:2}], 'a', true)).toEqual([{a:15}, {a:2}]); 27 | expect(orderBy([{a:15}, {a:2}], 'a', "T")).toEqual([{a:15}, {a:2}]); 28 | expect(orderBy([{a:15}, {a:2}], 'a', "reverse")).toEqual([{a:15}, {a:2}]); 29 | }); 30 | 31 | 32 | it('should sort inherited from array', function() { 33 | function BaseCollection() {} 34 | BaseCollection.prototype = Array.prototype; 35 | var child = new BaseCollection(); 36 | child.push({a:2}); 37 | child.push({a:15}); 38 | 39 | expect(Array.isArray(child)).toBe(false); 40 | expect(child instanceof Array).toBe(true); 41 | 42 | expect(orderBy(child, 'a', true)).toEqual([{a:15}, {a:2}]); 43 | }); 44 | 45 | it('should sort array by predicate', function() { 46 | expect(orderBy([{a:15, b:1}, {a:2, b:1}], ['a', 'b'])).toEqual([{a:2, b:1}, {a:15, b:1}]); 47 | expect(orderBy([{a:15, b:1}, {a:2, b:1}], ['b', 'a'])).toEqual([{a:2, b:1}, {a:15, b:1}]); 48 | expect(orderBy([{a:15, b:1}, {a:2, b:1}], ['+b', '-a'])).toEqual([{a:15, b:1}, {a:2, b:1}]); 49 | }); 50 | 51 | it('should sort array by date predicate', function() { 52 | // same dates 53 | expect(orderBy([ 54 | { a:new Date('01/01/2014'), b:1 }, 55 | { a:new Date('01/01/2014'), b:3 }, 56 | { a:new Date('01/01/2014'), b:4 }, 57 | { a:new Date('01/01/2014'), b:2 }], 58 | ['a', 'b'])) 59 | .toEqual([ 60 | { a:new Date('01/01/2014'), b:1 }, 61 | { a:new Date('01/01/2014'), b:2 }, 62 | { a:new Date('01/01/2014'), b:3 }, 63 | { a:new Date('01/01/2014'), b:4 }]); 64 | 65 | // one different date 66 | expect(orderBy([ 67 | { a:new Date('01/01/2014'), b:1 }, 68 | { a:new Date('01/01/2014'), b:3 }, 69 | { a:new Date('01/01/2013'), b:4 }, 70 | { a:new Date('01/01/2014'), b:2 }], 71 | ['a', 'b'])) 72 | .toEqual([ 73 | { a:new Date('01/01/2013'), b:4 }, 74 | { a:new Date('01/01/2014'), b:1 }, 75 | { a:new Date('01/01/2014'), b:2 }, 76 | { a:new Date('01/01/2014'), b:3 }]); 77 | }); 78 | 79 | it('should use function as a compare function', function() { 80 | expect( 81 | orderBy( 82 | [{a:15, b:1},{a:2, b:1}], 83 | function(value) { return value['a']; })). 84 | toEqual([{a:2, b:1},{a:15, b:1}]); 85 | }); 86 | 87 | it('should support string predicates with names containing non-identifier characters', function() { 88 | /*jshint -W008 */ 89 | expect(orderBy([{"Tip %": .25}, {"Tip %": .15}, {"Tip %": .40}], '"Tip %"')) 90 | .toEqual([{"Tip %": .15}, {"Tip %": .25}, {"Tip %": .40}]); 91 | expect(orderBy([{"원": 76000}, {"원": 31000}, {"원": 156000}], '"원"')) 92 | .toEqual([{"원": 31000}, {"원": 76000}, {"원": 156000}]); 93 | }); 94 | 95 | it('should throw if quoted string predicate is quoted incorrectly', function() { 96 | /*jshint -W008 */ 97 | expect(function() { 98 | return orderBy([{"Tip %": .15}, {"Tip %": .25}, {"Tip %": .40}], '"Tip %\''); 99 | }).toThrow(); 100 | }); 101 | }); 102 | 103 | describe('get Number, Boolean and ObjectLiteral as an arguments', function() { 104 | it('should not applied', function() { 105 | var inputs = [1, {}, false]; 106 | inputs.forEach(function(input) { 107 | expect(orderBy(input)).toEqual(input); 108 | }); 109 | }); 110 | }); 111 | 112 | describe('get String as an argument', function() { 113 | it('should return an array of characters sort by ascii code', function() { 114 | expect(orderBy('ariel')).toEqual(['a', 'e', 'i', 'l', 'r']); 115 | expect(orderBy('abc2dez')).toEqual(['2', 'a', 'b', 'c', 'd', 'e', 'z']); 116 | expect(orderBy('!@za')).toEqual(['!', '@', 'a', 'z']); 117 | }); 118 | }); 119 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/remove.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('remove', function() { 4 | 5 | it('should get array as a collection and members as an arguments' + 6 | 'and remove them from collection', function() { 7 | var array = [ 8 | { id: 1, name: 'ariel' }, 9 | { id: 2, name: 'baz' }, 10 | { id: 1, name: 'ariel' }, 11 | { id: 1, name: 'bar' } 12 | ]; 13 | 14 | expect(remove(array, { id: 1 , name: 'ariel' })).toEqual([{ id: 2, name: 'baz' }, { id: 1, name: 'bar' }]); 15 | expect(remove(array, { id: 1, name: 'ariel' }, { id: 1, name: 'bar' })).toEqual([{ id: 2, name: 'baz' }]); 16 | expect(remove([1,2,3, null], null, 2, 1)).toEqual([3]); 17 | expect(remove(array, {})).toEqual(array); 18 | }); 19 | 20 | it('should get an array and not arguments and return the array as-is', function() { 21 | expect(remove([1,2,3])).toEqual([1,2,3]); 22 | expect(remove([undefined, undefined])).toEqual([undefined, undefined]); 23 | }); 24 | 25 | it('should not arguments and return the collection as is', function() { 26 | expect(remove([{ a: 1 }])).toEqual([{ a:1 }]); 27 | expect(remove([{ a: 1 }, { b: 2 }])).toEqual([{ a:1 }, { b: 2 }]); 28 | }); 29 | 30 | it('should get !collection and return it as-is', function() { 31 | expect(remove('lorem ipsum')).toEqual('lorem ipsum'); 32 | expect(remove(1, null)).toEqual(1); 33 | }); 34 | 35 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/reverse.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('reverse', function() { 4 | 5 | it('should get array as array and return it revered', function() { 6 | var array = [1,2,3,4]; 7 | 8 | expect(reverse(array)).toEqual(array.reverse()); 9 | expect(reverse([1])).toEqual([1]); 10 | expect(reverse(['foo', 'bar'])).toEqual(['bar', 'foo']); 11 | }); 12 | 13 | it('should not change the source array', function() { 14 | var src = [1,2,3]; 15 | 16 | expect(reverse(src)).toEqual([3,2,1]); 17 | expect(src).not.toEqual([3,2,1]); 18 | }); 19 | 20 | it('should get string as a parameter and return it reversed', function() { 21 | expect(reverse('foobar')).toEqual('raboof'); 22 | expect(reverse('Lorem Ipsum')).toEqual('muspI meroL'); 23 | expect(reverse('FOO, BAR, BAZ')).toEqual('ZAB ,RAB ,OOF'); 24 | }); 25 | 26 | it('should get !string and !array and return it as-is', function() { 27 | expect(reverse(999)).toEqual(999); 28 | expect(reverse(!1)).toBeFalsy(); 29 | expect(null).toEqual(null); 30 | }); 31 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/sum.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('sum', function () { 4 | 5 | it('should return the sum of all members in array', function() { 6 | expect(sum([1,2,3,4,5,6])).toEqual(21); 7 | expect(sum([0,0,0,0,0,1])).toEqual(1); 8 | }); 9 | 10 | it('should be able to get an initial value', function() { 11 | expect(sum([2,3,5], 10)).toEqual(20); 12 | expect(sum([2,3,5], -10)).toEqual(0); 13 | }); 14 | 15 | it('should return a string if the members type != number', function() { 16 | expect(typeof sum([{}, 'string', 'foo'])).toEqual('string') 17 | }); 18 | 19 | it('should return the input as-is if is not an array', function() { 20 | expect(sum('string')).toEqual('string'); 21 | expect(sum(1)).toEqual(1); 22 | expect(sum(!1)).toBeFalsy(); 23 | }) 24 | 25 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/unique.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('unique', function() { 4 | 5 | it('should get a collection of primitives and return filtered collection', function() { 6 | //Boolean 7 | expect(unique([true, true, false, false, true])).toEqual([true, false]); 8 | //numbers 9 | expect(unique([1, 1, 2, 3, 4, 5, 5, 5, 5])).toEqual([1, 2, 3, 4, 5]); 10 | //strings 11 | expect(unique(["Ariel", "Ariel", "Ariel"])).toEqual(["Ariel"]); 12 | }); 13 | 14 | it('should get array as collection, property(nested to) as identifier and unique', function() { 15 | 16 | var orders = [ 17 | { id:10, customer: { name: 'foo', id: 1 } }, 18 | { id:11, customer: { name: 'bar', id: 2 } }, 19 | { id:12, customer: { name: 'foo', id: 1 } }, 20 | { id:13, customer: { name: 'bar', id: 2 } }, 21 | { id:14, customer: { name: 'baz', id: 3 } }, 22 | ]; 23 | 24 | var uniqueedOrders = [ 25 | { id:10, customer: { name: 'foo', id: 1 } }, 26 | { id:11, customer: { name: 'bar', id: 2 } }, 27 | { id:14, customer: { name: 'baz', id: 3 } }, 28 | ]; 29 | 30 | expect(unique(orders, 'customer.id')).toEqual(uniqueedOrders); 31 | expect(unique(orders, 'customer.id').length).toEqual(uniqueedOrders.length); 32 | 33 | expect(unique(orders, 'customer.name')).toEqual(uniqueedOrders); 34 | expect(unique(orders, 'customer.name').length).toEqual(uniqueedOrders.length); 35 | 36 | expect(unique(orders, 'id')).toEqual(orders); 37 | expect(unique(orders, 'id').length).toEqual(orders.length); 38 | 39 | }); 40 | 41 | it('should uniqueed by property and not touch members without this property', function() { 42 | 43 | var array = [ 44 | { id: 1, person: { name: 'Ariel' , age: 25 } }, 45 | { id: 2, person: { name: 'Joe' , age: 25 } }, 46 | { id: 3, person: { name: 'Bob' , age: 42 } }, 47 | { id: 4, person: { name: 'Marie' , age: 42 } }, 48 | {}, [], 1,2, 'foo', true, null 49 | ]; 50 | 51 | var uniqueedArray = [ 52 | { id: 1, person: { name: 'Ariel' , age: 25 } }, 53 | { id: 3, person: { name: 'Bob' , age: 42 } }, 54 | {}, [], 1,2, 'foo', true, null 55 | ]; 56 | 57 | //unique by person.age 58 | expect(unique(array, 'person.age')).toEqual(uniqueedArray); 59 | 60 | //should not touch members without this property 61 | expect(unique(array, 'id')).toEqual(array); 62 | 63 | }); 64 | 65 | it('should support advance nested properties', function() { 66 | var orders = [ 67 | { order: { person: { credit: { information: { num: 99999 } } } } }, 68 | { order: { person: { credit: { information: { num: 99999 } } } } }, 69 | { order: { person: { credit: { information: { num: 99999 } } } } } 70 | ]; 71 | expect(unique(orders, 'order.person.credit.information.num')).toEqual([orders[0]]); 72 | }); 73 | 74 | it('should get a !collection and return as-is', function() { 75 | expect(unique(undefined)).toEqual(undefined); 76 | expect(unique('foo')).toEqual('foo'); 77 | expect(unique(1)).toEqual(1); 78 | expect(unique(!1)).toBeFalsy(); 79 | }); 80 | }); -------------------------------------------------------------------------------- /test/spec/agile/array/xor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('xor', function() { 4 | 5 | it('should get 2 array collection and return exclusive or between them', function() { 6 | expect(xor([1,2], [1])).toEqual([2]); 7 | expect(xor([1, 2, 3], [5, 2, 1, 4])).toEqual([3, 5, 4]); 8 | 9 | expect(xor([1, 2, 3], [4, 5])).toEqual([1, 2, 3, 4, 5]); 10 | expect(xor([1, 2, 3], [2, 3, 4])).toEqual([1, 4]); 11 | }); 12 | 13 | it('should get an objects collection and filters by value', function() { 14 | 15 | var array = [ 16 | { id: 1, name: 'foo' }, 17 | { id: 2, name: 'bar' }, 18 | { id: 3, name: 'baz' } 19 | ]; 20 | 21 | expect(xor(array, array)).toEqual([]); // A (xor) A 22 | expect(xor(array, [ { id: 1, name:'foo' } ])).toEqual([array[1], array[2]]); 23 | expect(xor(array, [ { id: 1 } ])).toEqual( 24 | array.concat([{ id: 1 }]) 25 | ); 26 | }); 27 | 28 | it('should xor by specific property', function() { 29 | var users = [ 30 | { id: 0, details: { first_name: 'foo', last_name: 'bar' } }, 31 | { id: 1, details: { first_name: 'foo', last_name: 'baz' } }, 32 | { id: 2, details: { first_name: 'foo', last_name: 'bag' } } 33 | ]; 34 | 35 | expect(xor(users, [{ details: { first_name: 'foo' } }], 'details.first_name')) 36 | .toEqual([]); 37 | expect(xor(users, [{ id: 0 }, { id: 1 }], 'id')).toEqual([users[2]]); 38 | expect(xor(users, [{ id: 3, details: { first_name: 'foo', last_name: 'bag' }}], 'id')) 39 | .toEqual( 40 | users.concat([{ id: 3, details: { first_name: 'foo', last_name: 'bag' }}] 41 | )); 42 | }); 43 | 44 | it('should xor by expression', function() { 45 | expect(xor([ { id: 2 }, { id: 3 }], [ { id: 4 } ], 'id % 2')).toEqual([{ id: 3 }]) 46 | }); 47 | 48 | 49 | it('should get !collection and return it as-is', function() { 50 | expect(xor(999)).toEqual(999); 51 | expect(xor(!1)).toBeFalsy(); 52 | expect(null).toEqual(null); 53 | }); 54 | 55 | }); -------------------------------------------------------------------------------- /test/spec/agile/boolean.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('boolean', function() { 4 | 5 | describe('#isString', function() { 6 | it('should get !string and return false', function() { 7 | expect(isString(1)).toBeFalsy(); 8 | expect(isString(!0)).toBeFalsy(); 9 | expect(isString({})).toBeFalsy(); 10 | expect(isString([])).toBeFalsy(); 11 | expect(isString(new Function)).toBeFalsy(); 12 | }); 13 | 14 | it('should get string and return true', function() { 15 | expect(isString('')).toBeTruthy(); 16 | expect(isString('2')).toBeTruthy(); 17 | expect(isString('A')).toBeTruthy(); 18 | }); 19 | }); 20 | 21 | describe('#isObject', function() { 22 | it('should get !object and return false', function() { 23 | expect(isObject('')).toBeFalsy(); 24 | expect(isObject(1)).toBeFalsy(); 25 | expect(isObject(!1)).toBeFalsy(); 26 | }); 27 | 28 | it('should get object and return true', function() { 29 | expect(isObject({})).toBeTruthy(); 30 | expect(isObject([])).toBeTruthy(); 31 | expect(isObject(new Date)).toBeTruthy(); 32 | expect(isObject(new RegExp)).toBeTruthy(); 33 | }); 34 | }); 35 | 36 | describe('#isNumber', function() { 37 | it('should get !number and return false', function() { 38 | expect(isNumber('')).toBeFalsy(); 39 | expect(isNumber('1')).toBeFalsy(); 40 | expect(isNumber({})).toBeFalsy(); 41 | }); 42 | 43 | it('should get number and return true', function() { 44 | expect(isNumber(1e3)).toBeTruthy(); 45 | expect(isNumber(NaN)).toBeTruthy(); 46 | expect(isNumber(-0.001)).toBeTruthy(); 47 | }); 48 | }); 49 | 50 | describe('#isDefined, #isUndefined', function() { 51 | it('should distinguish between two values', function() { 52 | expect(isUndefined(undefined)).toBeTruthy(); 53 | expect(isDefined(undefined)).toBeFalsy(); 54 | expect(isUndefined(1)).toBeFalsy(); 55 | expect(isDefined(1)).toBeTruthy(); 56 | }); 57 | }); 58 | 59 | describe('#isDate', function() { 60 | it('should get a !Date object and return false', function() { 61 | expect(isDate({})).toBeFalsy(); 62 | expect(isDate('Sat Oct 25 2014 16:17:17')).toBeFalsy(); 63 | }); 64 | 65 | it('should get a Date object and return true', function() { 66 | expect(isDate(new Date)).toBeTruthy(); 67 | expect(isDate(new Date('Sat Oct 25 2014 16:17:17'))).toBeTruthy(); 68 | }); 69 | }); 70 | 71 | describe('#isArray', function() { 72 | it('should get a !Array and return false', function() { 73 | expect(isArray({})).toBeFalsy(); 74 | expect(isArray('[]')).toBeFalsy(); 75 | expect(isArray(new Function)).toBeFalsy(); 76 | }); 77 | 78 | it('should get a Array and return true', function() { 79 | expect(isArray([])).toBeTruthy(); 80 | }); 81 | }); 82 | 83 | describe('#isFunction', function() { 84 | it('should get a !Function and return false', function() { 85 | expect(isFunction({})).toBeFalsy(); 86 | expect(isFunction('[]')).toBeFalsy(); 87 | expect(isFunction(3)).toBeFalsy(); 88 | }); 89 | 90 | it('should get a Function and return true', function() { 91 | expect(isFunction(new Function)).toBeTruthy(); 92 | expect(isFunction(function(){})).toBeTruthy(); 93 | }); 94 | }); 95 | 96 | describe('#isRegExp', function() { 97 | it('should get a !RegExp and return false', function() { 98 | expect(isRegExp({})).toBeFalsy(); 99 | expect(isRegExp('[]')).toBeFalsy(); 100 | expect(isRegExp(3)).toBeFalsy(); 101 | }); 102 | 103 | it('should get a RegExp and return true', function() { 104 | expect(isRegExp(/^as/g)).toBeTruthy(); 105 | expect(isRegExp(new RegExp())).toBeTruthy(); 106 | }); 107 | }); 108 | 109 | describe('#isEmpty', function() { 110 | it('should get an array or string and return if it empty', function() { 111 | expect(isEmpty([1])).toBeFalsy(); 112 | expect(isEmpty(' ')).toBeFalsy(); 113 | expect(isEmpty([])).toBeTruthy(); 114 | expect(isEmpty('')).toBeTruthy(); 115 | }); 116 | 117 | it('should get not string/array and return false', function() { 118 | expect(isEmpty(1)).toBeFalsy(); 119 | expect(isEmpty({})).toBeFalsy(); 120 | }); 121 | }); 122 | }); -------------------------------------------------------------------------------- /test/spec/agile/chain.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('common chain methods', function() { 3 | var _ = agile; 4 | describe('#add', function() { 5 | it('should works with arrays', function() { 6 | expect(add([1,2,3], 4,5,6)).toEqual([1, 2, 3, 4, 5, 6]); 7 | expect(add([1,2,3], [1,2,3])).toEqual([1, 2, 3, [1,2,3]]); 8 | expect(add([1,2,3], null)).toEqual([1, 2, 3, null]); 9 | }); 10 | 11 | it('should works with object', function() { 12 | expect(add({},{a:1})).toEqual({a:1}); 13 | expect(add({a:1},{a:2})).toEqual({a:2}); 14 | expect(add({}, 1)).toEqual({0:1}); 15 | expect(add({},'a')).toEqual({0:'a'}); 16 | }); 17 | 18 | it('should work with numbers', function() { 19 | expect(add(10, 1,1,1)).toEqual(13); 20 | expect(add(10, 'a',2)).toEqual(12); 21 | expect(add(10, [], 1,5,[])).toEqual(16); 22 | }); 23 | 24 | it('should work with strings', function() { 25 | expect(add('a', 'b')).toEqual('ab'); 26 | expect(add('a', 'b', 'c')).toEqual('abc'); 27 | expect(add('a', [])).toEqual('a'); 28 | expect(add('a', 3)).toEqual('a'); 29 | }); 30 | 31 | it('should work on chaining', function() { 32 | //arrays 33 | expect(_([]) 34 | .add(3,4,5,6) 35 | .value()) 36 | .toEqual([3,4,5,6]); 37 | //strings 38 | expect(_('') 39 | .add('a', 'b', 'c') 40 | .repeat(2) 41 | .value()) 42 | .toEqual('abcabc'); 43 | //nums 44 | expect(_([1,2,3,4]) 45 | .max() 46 | .add(100,200) 47 | .value()) 48 | .toEqual(304); 49 | //object 50 | expect(_({}) 51 | .add({v:4}) 52 | .value()) 53 | .toEqual({v:4}); 54 | }); 55 | }); 56 | 57 | }); -------------------------------------------------------------------------------- /test/spec/agile/object/keys.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('deep-keys', function() { 3 | 4 | var keys = objKeys; 5 | 6 | it('should return array composed of it\'s properties names', function() { 7 | expect(keys({ a:1, b:2, c:3, d:4 })).toEqual(['a', 'b', 'c', 'd']); 8 | expect(keys({})).toEqual([]); 9 | }); 10 | 11 | it('should return owned properties, `Object.keys`', function() { 12 | var obj = { 13 | a: { b: 1, c: 2, d: { f: 3 } } 14 | }; 15 | expect(keys(obj.a)).toEqual(['b', 'c', 'd']); 16 | }); 17 | 18 | it('should return deep keys', function() { 19 | var obj1 = { 20 | a: 1, 21 | b: { c: 1 }, 22 | c: { d: { e: 1 }, f: 1 }, 23 | d: { e: { f: { g: 1, h: 2 } } }, 24 | e: 2, 25 | f: { g: [] } 26 | }; 27 | expect(keys(obj1, true)).toEqual(['a', 'b.c', 'c.d.e', 'c.f', 'd.e.f.g', 'd.e.f.h', 'e', 'f.g']); 28 | 29 | var obj2 = { 30 | type: 'customer', 31 | details: { 32 | name: 'Ariel', age: 26, address: { city: 'Tel Aviv', country: 'Israel' } 33 | }, 34 | isActive: true 35 | }; 36 | expect(keys(obj2, true)).toEqual([ 37 | 'type', 38 | 'details.name', 39 | 'details.age', 40 | 'details.address.city', 41 | 'details.address.country', 42 | 'isActive' 43 | ]); 44 | }); 45 | 46 | it('should get a !not object, and return it as-is', function() { 47 | expect(keys('a')).toEqual('a'); 48 | expect(keys(1)).toEqual(1); 49 | expect(keys(true)).toEqual(true); 50 | }); 51 | 52 | }); -------------------------------------------------------------------------------- /test/spec/agile/object/to-array.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('toArray', function() { 4 | 5 | it('should convert an object to an array of values', function() { 6 | var object = { 7 | 0: { f: 'foo' }, 8 | 1: { b: 'bar' }, 9 | 2: { b: 'baz' } 10 | }; 11 | 12 | expect(toArray(object)).toEqual([object[0], object[1], object[2]]); 13 | expect(toArray({ 0: 0, 1: 1, 2: 2 })).toEqual([0, 1, 2]); 14 | }); 15 | 16 | it('should add $key property if addKey param is true', function() { 17 | var object = { 18 | 0: { f: 'foo' }, 19 | 1: { b: 'bar' }, 20 | 2: { b: 'baz' } 21 | }; 22 | 23 | expect(toArray(object, true)).toEqual([ 24 | { $key: '0', f: 'foo' }, 25 | { $key: '1', b: 'bar' }, 26 | { $key: '2', b: 'baz' } 27 | ]); 28 | }); 29 | 30 | it('should get !object and return it as-is', function() { 31 | expect(toArray(1)).toEqual(1); 32 | expect(toArray(!0)).toBeTruthy(); 33 | expect(toArray('string')).toEqual('string'); 34 | expect(toArray(undefined)).toEqual(undefined); 35 | }); 36 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/ends-with.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('The endsWith filter', function () { 4 | var input; 5 | 6 | describe('given an object, array, number or boolean', function () { 7 | var inputs = [{}, [], 1, false]; 8 | 9 | it('should not be applied', function () { 10 | inputs.forEach(function (input) { 11 | expect(endsWith(input)).toEqual(input); 12 | }); 13 | }); 14 | }); 15 | 16 | describe('given a string as input', function () { 17 | var input = 'string', 18 | isCS; 19 | 20 | describe('when the case insensitive parameter is omitted', function () { 21 | 22 | describe('and the input ends with the term', function () { 23 | 24 | it('should return true regardless of the case', function () { 25 | expect(endsWith(input, 'g')).toBeTruthy(); 26 | expect(endsWith(input, 'ing')).toBeTruthy(); 27 | expect(endsWith(input, 'ING')).toBeTruthy(); 28 | }); 29 | 30 | }); 31 | 32 | describe('and the input doesn\'t end with the term', function () { 33 | 34 | it('should return false regardless of the case', function () { 35 | expect(endsWith(input, 'str')).toBeFalsy(); 36 | expect(endsWith(input, 'fing')).toBeFalsy(); 37 | expect(endsWith(input, 'TING')).toBeFalsy(); 38 | }); 39 | }); 40 | 41 | }); 42 | 43 | describe('when case insensitive is true', function () { 44 | beforeEach(function () { 45 | isCS = true; 46 | }); 47 | 48 | describe('and the input ends with the term', function () { 49 | 50 | it('should return false if the case is different', function () { 51 | expect(endsWith(input, 'inG', isCS)).not.toBeTruthy(); 52 | expect(endsWith(input, 'ING', isCS)).not.toBeTruthy(); 53 | }); 54 | 55 | it('should return true if they are in the same case', function () { 56 | expect(endsWith(input, 'ing', isCS)).toBeTruthy(); 57 | }); 58 | }); 59 | }); 60 | 61 | describe('when case insensitive is false', function () { 62 | beforeEach(function () { 63 | isCS = false; 64 | }); 65 | 66 | describe('and the input ends with the term', function () { 67 | 68 | it('should return true even if the case is different', function () { 69 | expect(endsWith(input, 'inG', isCS)).toBeTruthy(); 70 | expect(endsWith(input, 'ING', isCS)).toBeTruthy(); 71 | }); 72 | 73 | it('should return true if they are in the same case', function () { 74 | expect(endsWith(input, 'ing', isCS)).toBeTruthy(); 75 | }); 76 | }); 77 | }); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /test/spec/agile/string/ltrim.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ltrim', function () { 4 | it('should strip whitespace from the beginning of a string', function() { 5 | 6 | expect(ltrim(' a')).toEqual('a'); 7 | expect(ltrim(' foo bar ')).toEqual('foo bar '); 8 | expect(ltrim(' ')).toEqual(''); 9 | 10 | }); 11 | 12 | it('should strip specific chars from the beginning of a string', function() { 13 | 14 | expect(ltrim('__a__', '__')).toEqual('a__'); 15 | expect(ltrim('//foo bar//', '//')).toEqual('foo bar//'); 16 | expect(ltrim('barfoobar', 'bar')).toEqual('foobar'); 17 | 18 | expect(ltrim('barfoobar', 'foo')).toEqual('barfoobar'); 19 | 20 | }); 21 | 22 | it('should get a !string and not touch it', function() { 23 | expect(ltrim({})).toEqual({}); 24 | expect(ltrim([])).toEqual([]); 25 | expect(ltrim(1)).toEqual(1); 26 | expect(ltrim(!1)).toBeFalsy(); 27 | }); 28 | 29 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/repeat.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('repeat', function () { 4 | 5 | it('should repeat a string n times', function() { 6 | expect(repeat('a')).toEqual('a'); 7 | expect(repeat('a', 3)).toEqual('aaa'); 8 | expect(repeat('a ', 3)).toEqual('a a a '); 9 | expect(repeat('foo', 3)).toEqual('foofoofoo'); 10 | }); 11 | 12 | it('should return the string as-is if `n` is undefined || 0', function() { 13 | expect(repeat('a')).toEqual('a'); 14 | expect(repeat('a', 0)).toEqual('a'); 15 | }); 16 | 17 | it('should get a !string and not touch it', function() { 18 | expect(repeat({})).toEqual({}); 19 | expect(repeat([])).toEqual([]); 20 | expect(repeat(1)).toEqual(1); 21 | expect(repeat(!1)).toBeFalsy(); 22 | }); 23 | 24 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/rtrim.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('rtrimrtrim', function () { 4 | 5 | it('should strip whitespace from the beginning of a string', function() { 6 | expect(rtrim('a ')).toEqual('a'); 7 | expect(rtrim(' foo bar ')).toEqual(' foo bar'); 8 | expect(rtrim(' ')).toEqual(''); 9 | }); 10 | 11 | it('should strip specific chars from the beginning of a string', function() { 12 | expect(rtrim('__a__', '__')).toEqual('__a'); 13 | expect(rtrim('//foo bar//', '//')).toEqual('//foo bar'); 14 | expect(rtrim('barfoobar', 'bar')).toEqual('barfoo'); 15 | expect(rtrim('barfoobar', 'foo')).toEqual('barfoobar'); 16 | }); 17 | 18 | it('should get a !string and not touch it', function() { 19 | expect(rtrim({})).toEqual({}); 20 | expect(rtrim([])).toEqual([]); 21 | expect(rtrim(1)).toEqual(1); 22 | expect(rtrim(!1)).toBeFalsy(); 23 | }); 24 | 25 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/slugify.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('slugify', function () { 4 | 5 | it('should get a string with no replacer and replace spaces with dash(-)', function() { 6 | expect(slugify('a a')).toEqual('a-a'); 7 | expect(slugify('foo bar baz')).toEqual('foo-bar-baz'); 8 | expect(slugify('Lorem ipsum dolor sit amet')).toEqual('lorem-ipsum-dolor-sit-amet'); 9 | }); 10 | 11 | it('should get a string with replacer and replace spaces withit', function() { 12 | expect(slugify('a a', 1)).toEqual('a1a'); 13 | expect(slugify('foo bar baz', '!')).toEqual('foo!bar!baz'); 14 | expect(slugify('lorem ipsum dolor sit amet', ' ')).toEqual('lorem ipsum dolor sit amet'); 15 | expect(slugify('Lorem ipsum dolor sit amet', '-')).toEqual('lorem-ipsum-dolor-sit-amet'); 16 | }); 17 | 18 | it('should get a !string and not touch it', function() { 19 | expect(slugify({})).toEqual({}); 20 | expect(slugify([])).toEqual([]); 21 | expect(slugify(1)).toEqual(1); 22 | expect(slugify(!1)).toBeFalsy(); 23 | }); 24 | 25 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/starts-with.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('startsWith', function () { 4 | 5 | it('should return whether string starts with the starts parameter', function() { 6 | expect(startsWith('string', 's')).toBeTruthy(); 7 | expect(startsWith('string', 'str')).toBeTruthy(); 8 | expect(startsWith('foo bar', 'Foo B')).toBeTruthy(); 9 | expect(startsWith('string', 'tring')).toBeFalsy(); 10 | expect(startsWith('string', 'ig')).toBeFalsy(); 11 | expect(startsWith('foo bar', 'bar')).toBeFalsy(); 12 | }); 13 | 14 | it('should be case sensitive', function() { 15 | expect(startsWith('string', 'STR', true)).toBeFalsy(); 16 | expect(startsWith('string', 'STR', false)).toBeTruthy(); 17 | expect(startsWith('foo bar', 'Foo B', true)).toBeFalsy(); 18 | }); 19 | 20 | it('should get a !string and not touch it', function() { 21 | expect(startsWith({})).toEqual({}); 22 | expect(startsWith([])).toEqual([]); 23 | expect(startsWith(1)).toEqual(1); 24 | expect(startsWith(!1)).toBeFalsy(); 25 | }); 26 | 27 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/stringular.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('stringular', function () { 4 | 5 | it('should return the text as it was if only one argument is passed', function () { 6 | expect(stringular('lorem ipsum dolor sit amet')).toEqual('lorem ipsum dolor sit amet'); 7 | }); 8 | 9 | it('should replace {n} with arguments passed after the text argument', function () { 10 | expect(stringular('lorem {0} dolor sit amet', 'ipsum')).toEqual('lorem ipsum dolor sit amet'); 11 | expect(stringular('lorem {0} dolor {1} amet', 'ipsum', 'sit')).toEqual('lorem ipsum dolor sit amet'); 12 | expect(stringular('{3} {0} dolor {1} amet', 'ipsum', 'sit', null, 'lorem')).toEqual('lorem ipsum dolor sit amet'); 13 | }); 14 | 15 | it('should keep {n} if no matching argument was found', function () { 16 | expect(stringular('lorem {0} dolor sit amet')).toEqual('lorem {0} dolor sit amet'); 17 | expect(stringular('lorem {0} dolor {1} amet', 'ipsum')).toEqual('lorem ipsum dolor {1} amet'); 18 | }); 19 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/strip-tags.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('stripTags', function () { 4 | 5 | it('should get a string with tags and splash it', function() { 6 | expect(stripTags('

lorem ipsum

')).toEqual('lorem ipsum'); 7 | expect(stripTags('
foo bar
')).toEqual('foo bar'); 8 | expect(stripTags('awesome title')).toEqual('awesome title'); 9 | }); 10 | 11 | it('should get a !string and not touch it', function() { 12 | expect(stripTags({})).toEqual({}); 13 | expect(stripTags([])).toEqual([]); 14 | expect(stripTags(1)).toEqual(1); 15 | expect(stripTags(!1)).toBeFalsy(); 16 | }); 17 | 18 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/trim.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('trim', function () { 4 | 5 | it('should strip whitespace from the beginning and end of a string', function() { 6 | expect(trim(' a ')).toEqual('a'); 7 | expect(trim(' foo bar ')).toEqual('foo bar'); 8 | expect(trim(' ')).toEqual(''); 9 | }); 10 | 11 | it('should strip specific chars from the beginning and end of a string', function() { 12 | expect(trim('__a__', '__')).toEqual('a'); 13 | expect(trim('//foo bar//', '//')).toEqual('foo bar'); 14 | expect(trim('barfoobar', 'bar')).toEqual('foo'); 15 | expect(trim('barfoobar', 'foo')).toEqual('barfoobar'); 16 | }); 17 | 18 | it('should get a !string and not touch it', function() { 19 | expect(trim({})).toEqual({}); 20 | expect(trim([])).toEqual([]); 21 | expect(trim(1)).toEqual(1); 22 | expect(trim(!1)).toBeFalsy(); 23 | }); 24 | 25 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/truncate.js: -------------------------------------------------------------------------------- 1 | describe('truncate', function () { 2 | 3 | it('should cut a string if it is longer than the provided length', function () { 4 | 5 | expect(truncate('lorem ipsum dolor sit amet', 5, '', false)).toEqual('lorem'); 6 | expect(truncate('lorem ipsum dolor sit amet', 11, '', false)).toEqual('lorem ipsum'); 7 | expect(truncate('lorem ipsum dolor sit amet', 50, '', false)).toEqual('lorem ipsum dolor sit amet'); 8 | 9 | expect(truncate('abcdef', 3, '', false)).toEqual('abc'); 10 | expect(truncate('abcd ef', 6, '', false)).toEqual('abcd e'); 11 | 12 | }); 13 | 14 | it('should not cut words in the middle if preserve is true', function () { 15 | 16 | expect(truncate('lorem ipsum dolor sit amet', 7, '', true)).toEqual('lorem ipsum'); 17 | expect(truncate('lorem ipsum dolor sit amet', 13, '', true)).toEqual('lorem ipsum dolor'); 18 | expect(truncate('lorem ipsum dolor sit amet', 50, '', true)).toEqual('lorem ipsum dolor sit amet'); 19 | 20 | expect(truncate('abcdef', 3, '', true)).toEqual('abcdef'); 21 | expect(truncate('abcd ef', 6, '', true)).toEqual('abcd ef'); 22 | 23 | }); 24 | 25 | it('should append the provided prefix if a string has been cut', function () { 26 | 27 | expect(truncate('lorem ipsum dolor sit amet', 7, '...', true)).toEqual('lorem ipsum...'); 28 | expect(truncate('lorem ipsum dolor sit amet', 13, '...', true)).toEqual('lorem ipsum dolor...'); 29 | expect(truncate('lorem ipsum dolor sit amet', 50, '...', true)).toEqual('lorem ipsum dolor sit amet'); 30 | 31 | }); 32 | 33 | it('should get !string and return it as-is', function() { 34 | 35 | expect(truncate([])).toEqual([]); 36 | expect(truncate({})).toEqual({}); 37 | expect(truncate(1)).toEqual(1); 38 | expect(truncate(!1)).toBeFalsy(); 39 | 40 | }); 41 | 42 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/ucfirst.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ucfirst', function () { 4 | 5 | it('should get a string and return it uppercase each first letter', function() { 6 | expect(ucfirst('a')).toEqual('A'); 7 | expect(ucfirst('foo bar baz')).toEqual('Foo Bar Baz'); 8 | expect(ucfirst('lorem ipsum is simply dummy.... industry.')).toEqual('Lorem Ipsum Is Simply Dummy.... Industry.'); 9 | }); 10 | 11 | it('should get a !string and not touch it', function() { 12 | expect(ucfirst({})).toEqual({}); 13 | expect(ucfirst([])).toEqual([]); 14 | expect(ucfirst(1)).toEqual(1); 15 | expect(ucfirst(!1)).toBeFalsy(); 16 | }); 17 | 18 | }); -------------------------------------------------------------------------------- /test/spec/agile/string/wrap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('wrap', function () { 4 | 5 | it('should wrap a string with given wrapper', function() { 6 | expect(wrap('a', 'b')).toEqual('bab'); 7 | expect(wrap('a', 1)).toEqual('1a1'); 8 | expect(wrap('a', '.')).toEqual('.a.'); 9 | }); 10 | 11 | it('should wrap a string with starts and ends wrapper', function() { 12 | expect(wrap('b', 'a', 'c')).toEqual('abc'); 13 | expect(wrap('a', 1, 2)).toEqual('1a2'); 14 | expect(wrap('a', '/', '.')).toEqual('/a.'); 15 | }); 16 | 17 | 18 | it('should get a !string and not touch it', function() { 19 | expect(wrap({})).toEqual({}); 20 | expect(wrap([])).toEqual([]); 21 | expect(wrap(1)).toEqual(1); 22 | expect(wrap(!1)).toBeFalsy(); 23 | }); 24 | 25 | }); -------------------------------------------------------------------------------- /test/spec/agile/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('utils', function() { 4 | 5 | describe('#equals', function() { 6 | it('should return true if same object', function() { 7 | var o = {}; 8 | expect(equals(o, o)).toEqual(true); 9 | expect(equals(o, {})).toEqual(true); 10 | expect(equals(1, '1')).toEqual(false); 11 | expect(equals(1, '2')).toEqual(false); 12 | }); 13 | 14 | it('should recurse into object', function() { 15 | expect(equals({}, {})).toEqual(true); 16 | expect(equals({name:'misko'}, {name:'misko'})).toEqual(true); 17 | expect(equals({name:'misko', age:1}, {name:'misko'})).toEqual(false); 18 | expect(equals({name:'misko'}, {name:'misko', age:1})).toEqual(false); 19 | expect(equals({name:'misko'}, {name:'adam'})).toEqual(false); 20 | expect(equals(['misko'], ['misko'])).toEqual(true); 21 | expect(equals(['misko'], ['adam'])).toEqual(false); 22 | expect(equals(['misko'], ['misko', 'adam'])).toEqual(false); 23 | }); 24 | 25 | it('should ignore undefined member variables during comparison', function() { 26 | var obj1 = {name: 'misko'}, 27 | obj2 = {name: 'misko', undefinedvar: undefined}; 28 | 29 | expect(equals(obj1, obj2)).toBe(true); 30 | expect(equals(obj2, obj1)).toBe(true); 31 | }); 32 | 33 | it('should ignore functions', function() { 34 | expect(equals({func: function() {}}, {bar: function() {}})).toEqual(true); 35 | }); 36 | 37 | it('should work well with nulls', function() { 38 | expect(equals(null, '123')).toBe(false); 39 | expect(equals('123', null)).toBe(false); 40 | 41 | var obj = {foo:'bar'}; 42 | expect(equals(null, obj)).toBe(false); 43 | expect(equals(obj, null)).toBe(false); 44 | 45 | expect(equals(null, null)).toBe(true); 46 | }); 47 | 48 | it('should work well with undefined', function() { 49 | expect(equals(undefined, '123')).toBe(false); 50 | expect(equals('123', undefined)).toBe(false); 51 | 52 | var obj = {foo:'bar'}; 53 | expect(equals(undefined, obj)).toBe(false); 54 | expect(equals(obj, undefined)).toBe(false); 55 | 56 | expect(equals(undefined, undefined)).toBe(true); 57 | }); 58 | 59 | it('should treat two NaNs as equal', function() { 60 | expect(equals(NaN, NaN)).toBe(true); 61 | }); 62 | 63 | it('should compare Window instances only by identity', function() { 64 | expect(equals(window, window)).toBe(true); 65 | expect(equals(window, window.parent)).toBe(false); 66 | expect(equals(window, undefined)).toBe(false); 67 | }); 68 | 69 | it('should compare dates', function() { 70 | expect(equals(new Date(0), new Date(0))).toBe(true); 71 | expect(equals(new Date(0), new Date(1))).toBe(false); 72 | expect(equals(new Date(0), 0)).toBe(false); 73 | expect(equals(0, new Date(0))).toBe(false); 74 | 75 | expect(equals(new Date(undefined), new Date(undefined))).toBe(true); 76 | expect(equals(new Date(undefined), new Date(0))).toBe(false); 77 | expect(equals(new Date(undefined), new Date(null))).toBe(false); 78 | expect(equals(new Date(undefined), new Date('wrong'))).toBe(true); 79 | }); 80 | 81 | it('should correctly test for keys that are present on Object.prototype', function() { 82 | /* jshint -W001 */ 83 | expect(equals({}, {hasOwnProperty: 1})).toBe(false); 84 | expect(equals({}, {toString: null})).toBe(false); 85 | }); 86 | 87 | it('should compare regular expressions', function() { 88 | expect(equals(/abc/, /abc/)).toBe(true); 89 | expect(equals(/abc/i, new RegExp('abc', 'i'))).toBe(true); 90 | expect(equals(new RegExp('abc', 'i'), new RegExp('abc', 'i'))).toBe(true); 91 | expect(equals(new RegExp('abc', 'i'), new RegExp('abc'))).toBe(false); 92 | expect(equals(/abc/i, /abc/)).toBe(false); 93 | expect(equals(/abc/, /def/)).toBe(false); 94 | expect(equals(/^abc/, /abc/)).toBe(false); 95 | expect(equals(/^abc/, '/^abc/')).toBe(false); 96 | }); 97 | 98 | it('should return false when comparing an object and an array', function() { 99 | expect(equals({}, [])).toBe(false); 100 | expect(equals([], {})).toBe(false); 101 | }); 102 | }); 103 | 104 | describe('#extend', function() { 105 | it('should extends object with multiple arguments', function() { 106 | var a = {}, b = { b: 1 }, c = { c: 1 }; 107 | extend(a, b, c); 108 | expect(a).toEqual({ b: 1, c: 1 }); 109 | }); 110 | 111 | it('should override existing keys with the extends keys', function() { 112 | var a = { a: 1 }, b = { b: 1 }, c = { a: 2, c: 1 }; 113 | extend(a, b, c); 114 | expect(a).toEqual({ a: 2, b: 1, c: 1 }); 115 | }); 116 | }); 117 | 118 | describe('#createMap', function() { 119 | it('should create object without prototype', function() { 120 | var map = createMap(); 121 | expect(map.toString).toBeUndefined(); 122 | }); 123 | }); 124 | 125 | describe('#noop', function() { 126 | it('should not performs operations.', function() { 127 | expect(noop()).toBeUndefined(); 128 | }); 129 | }); 130 | 131 | describe('case', function() { 132 | it('should change case', function() { 133 | expect(lowercase('ABC90')).toEqual('abc90'); 134 | expect(uppercase('abc90')).toEqual('ABC90'); 135 | }); 136 | 137 | it('should get a not string and return it as-is', function() { 138 | expect(lowercase({})).toEqual({}); 139 | expect(uppercase([])).toEqual([]); 140 | }); 141 | }); 142 | 143 | describe('toJson', function() { 144 | it('should call to JSON.stringify', function() { 145 | var spy = spyOn(JSON, 'stringify').andCallThrough(); 146 | expect(toJson({})).toEqual('{}'); 147 | expect(spy).toHaveBeenCalledWith({}); 148 | }); 149 | 150 | it('should serialize undefined as undefined', function() { 151 | expect(toJson(undefined)).toEqual(undefined); 152 | }); 153 | }); 154 | 155 | describe("copy", function() { 156 | it("should return same object", function() { 157 | var obj = {}; 158 | var arr = []; 159 | expect(copy({}, obj)).toBe(obj); 160 | expect(copy([], arr)).toBe(arr); 161 | }); 162 | 163 | it("should preserve prototype chaining", function() { 164 | var GrandParentProto = {}; 165 | var ParentProto = Object.create(GrandParentProto); 166 | var obj = Object.create(ParentProto); 167 | expect(ParentProto.isPrototypeOf(copy(obj))).toBe(true); 168 | expect(GrandParentProto.isPrototypeOf(copy(obj))).toBe(true); 169 | var Foo = function() {}; 170 | expect(copy(new Foo()) instanceof Foo).toBe(true); 171 | }); 172 | 173 | it("should copy Date", function() { 174 | var date = new Date(123); 175 | expect(copy(date) instanceof Date).toBeTruthy(); 176 | expect(copy(date).getTime()).toEqual(123); 177 | expect(copy(date) === date).toBeFalsy(); 178 | }); 179 | 180 | it("should copy RegExp", function() { 181 | var re = new RegExp(".*"); 182 | expect(copy(re) instanceof RegExp).toBeTruthy(); 183 | expect(copy(re).source).toBe(".*"); 184 | expect(copy(re) === re).toBe(false); 185 | }); 186 | 187 | it("should copy literal RegExp", function() { 188 | var re = /.*/; 189 | expect(copy(re) instanceof RegExp).toBeTruthy(); 190 | expect(copy(re).source).toEqual(".*"); 191 | expect(copy(re) === re).toBeFalsy(); 192 | }); 193 | 194 | it("should copy RegExp with flags", function() { 195 | var re = new RegExp('.*', 'gim'); 196 | expect(copy(re).global).toBe(true); 197 | expect(copy(re).ignoreCase).toBe(true); 198 | expect(copy(re).multiline).toBe(true); 199 | }); 200 | 201 | it("should copy RegExp with lastIndex", function() { 202 | var re = /a+b+/g; 203 | var str = 'ab aabb'; 204 | expect(re.exec(str)[0]).toEqual('ab'); 205 | expect(copy(re).exec(str)[0]).toEqual('aabb'); 206 | }); 207 | 208 | it("should deeply copy literal RegExp", function() { 209 | var objWithRegExp = { 210 | re: /.*/ 211 | }; 212 | expect(copy(objWithRegExp).re instanceof RegExp).toBeTruthy(); 213 | expect(copy(objWithRegExp).re.source).toEqual(".*"); 214 | expect(copy(objWithRegExp.re) === objWithRegExp.re).toBeFalsy(); 215 | }); 216 | 217 | it("should deeply copy an array into an existing array", function() { 218 | var src = [1, {name:"value"}]; 219 | var dst = [{key:"v"}]; 220 | expect(copy(src, dst)).toBe(dst); 221 | expect(dst).toEqual([1, {name:"value"}]); 222 | expect(dst[1]).toEqual({name:"value"}); 223 | expect(dst[1]).not.toBe(src[1]); 224 | }); 225 | 226 | it("should deeply copy an array into a new array", function() { 227 | var src = [1, {name:"value"}]; 228 | var dst = copy(src); 229 | expect(src).toEqual([1, {name:"value"}]); 230 | expect(dst).toEqual(src); 231 | expect(dst).not.toBe(src); 232 | expect(dst[1]).not.toBe(src[1]); 233 | }); 234 | 235 | it('should copy empty array', function() { 236 | var src = []; 237 | var dst = [{key: "v"}]; 238 | expect(copy(src, dst)).toEqual([]); 239 | expect(dst).toEqual([]); 240 | }); 241 | 242 | it("should deeply copy an object into an existing object", function() { 243 | var src = {a:{name:"value"}}; 244 | var dst = {b:{key:"v"}}; 245 | expect(copy(src, dst)).toBe(dst); 246 | expect(dst).toEqual({a:{name:"value"}}); 247 | expect(dst.a).toEqual(src.a); 248 | expect(dst.a).not.toBe(src.a); 249 | }); 250 | 251 | it("should deeply copy an object into a non-existing object", function() { 252 | var src = {a:{name:"value"}}; 253 | var dst = copy(src, undefined); 254 | expect(src).toEqual({a:{name:"value"}}); 255 | expect(dst).toEqual(src); 256 | expect(dst).not.toBe(src); 257 | expect(dst.a).toEqual(src.a); 258 | expect(dst.a).not.toBe(src.a); 259 | }); 260 | 261 | it("should copy primitives", function() { 262 | expect(copy(null)).toEqual(null); 263 | expect(copy('')).toBe(''); 264 | expect(copy('lala')).toBe('lala'); 265 | expect(copy(123)).toEqual(123); 266 | expect(copy([{key:null}])).toEqual([{key:null}]); 267 | }); 268 | 269 | it('should throw an exception if a Window is being copied', function() { 270 | expect(function() { copy(window); }).toThrow 271 | (Error("Can't copy! Making copies of Window instances is not supported.")); 272 | }); 273 | 274 | it('should throw an exception when source and destination are equivalent', function() { 275 | var src, dst; 276 | src = dst = {key: 'value'}; 277 | expect(function() { copy(src, dst); }).toThrow(Error("Can't copy! Source and destination are identical.")); 278 | src = dst = [2, 4]; 279 | expect(function() { copy(src, dst); }).toThrow(Error("Can't copy! Source and destination are identical.")); 280 | }); 281 | 282 | it('should handle circular references when circularRefs is turned on', function() { 283 | var a = {b: {a: null}, self: null, selfs: [null, null, [null]]}; 284 | a.b.a = a; 285 | a.self = a; 286 | a.selfs = [a, a.b, [a]]; 287 | 288 | var aCopy = copy(a, null); 289 | expect(aCopy).toEqual(a); 290 | 291 | expect(aCopy).not.toBe(a); 292 | expect(aCopy).toBe(aCopy.self); 293 | expect(aCopy.selfs[2]).not.toBe(a.selfs[2]); 294 | }); 295 | 296 | it('should clear destination arrays correctly when source is non-array', function() { 297 | expect(copy(null, [1,2,3])).toEqual([]); 298 | expect(copy(undefined, [1,2,3])).toEqual([]); 299 | expect(copy({0: 1, 1: 2}, [1,2,3])).toEqual([1,2]); 300 | }); 301 | }); 302 | 303 | describe('#identity', function() { 304 | var identity = value; 305 | it('should get a value and return is as-is', function() { 306 | var a = {}; 307 | expect(identity(a) === a).toBeTruthy(); 308 | }) 309 | }); 310 | 311 | describe('forEach', function() { 312 | it('should iterate over *own* object properties', function() { 313 | function MyObj() { 314 | this.bar = 'barVal'; 315 | this.baz = 'bazVal'; 316 | } 317 | MyObj.prototype.foo = 'fooVal'; 318 | 319 | var obj = new MyObj(), 320 | log = []; 321 | 322 | forEach(obj, function(value, key) { log.push(key + ':' + value); }); 323 | 324 | expect(log).toEqual(['bar:barVal', 'baz:bazVal']); 325 | }); 326 | 327 | 328 | it('should not break if obj is an array we override hasOwnProperty', function() { 329 | /* jshint -W001 */ 330 | var obj = []; 331 | obj[0] = 1; 332 | obj[1] = 2; 333 | obj.hasOwnProperty = null; 334 | var log = []; 335 | forEach(obj, function(value, key) { 336 | log.push(key + ':' + value); 337 | }); 338 | expect(log).toEqual(['0:1', '1:2']); 339 | }); 340 | 341 | it('should handle HTMLCollection objects like arrays', function() { 342 | document.body.innerHTML = "

" + 343 | "a" + 344 | "b" + 345 | "c" + 346 | "

"; 347 | 348 | var htmlCollection = document.getElementsByName('x'), 349 | log = []; 350 | 351 | forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML); }); 352 | expect(log).toEqual(['0:a', '1:c']); 353 | }); 354 | 355 | if (document.querySelectorAll) { 356 | it('should handle the result of querySelectorAll in IE8 as it has no hasOwnProperty function', function() { 357 | document.body.innerHTML = "

" + 358 | "a" + 359 | "b" + 360 | "c" + 361 | "

"; 362 | 363 | var htmlCollection = document.querySelectorAll('[name="x"]'), 364 | log = []; 365 | 366 | forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML); }); 367 | expect(log).toEqual(['0:a', '1:c']); 368 | }); 369 | } 370 | 371 | it('should handle arguments objects like arrays', function() { 372 | var args, 373 | log = []; 374 | 375 | (function() { args = arguments; }('a', 'b', 'c')); 376 | 377 | forEach(args, function(value, key) { log.push(key + ':' + value); }); 378 | expect(log).toEqual(['0:a', '1:b', '2:c']); 379 | }); 380 | 381 | it('should handle string values like arrays', function() { 382 | var log = []; 383 | 384 | forEach('bar', function(value, key) { log.push(key + ':' + value); }); 385 | expect(log).toEqual(['0:b', '1:a', '2:r']); 386 | }); 387 | 388 | 389 | it('should handle objects with length property as objects', function() { 390 | var obj = { 391 | 'foo': 'bar', 392 | 'length': 2 393 | }, 394 | log = []; 395 | 396 | forEach(obj, function(value, key) { log.push(key + ':' + value); }); 397 | expect(log).toEqual(['foo:bar', 'length:2']); 398 | }); 399 | 400 | 401 | it('should handle objects of custom types with length property as objects', function() { 402 | function CustomType() { 403 | this.length = 2; 404 | this.foo = 'bar'; 405 | } 406 | 407 | var obj = new CustomType(), 408 | log = []; 409 | 410 | forEach(obj, function(value, key) { log.push(key + ':' + value); }); 411 | expect(log).toEqual(['length:2', 'foo:bar']); 412 | }); 413 | 414 | 415 | it('should not invoke the iterator for indexed properties which are not present in the collection', function() { 416 | var log = []; 417 | var collection = []; 418 | collection[5] = 'SPARSE'; 419 | forEach(collection, function(item, index) { 420 | log.push(item + index); 421 | }); 422 | expect(log.length).toBe(1); 423 | expect(log[0]).toBe('SPARSE5'); 424 | }); 425 | 426 | 427 | describe('ES spec api compliance', function() { 428 | 429 | function testForEachSpec(expectedSize, collection) { 430 | var that = {}; 431 | 432 | forEach(collection, function(value, key, collectionArg) { 433 | expect(collectionArg).toBe(collection); 434 | expect(collectionArg[key]).toBe(value); 435 | 436 | expect(this).toBe(that); 437 | 438 | expectedSize--; 439 | }, that); 440 | 441 | expect(expectedSize).toBe(0); 442 | } 443 | 444 | 445 | it('should follow the ES spec when called with array', function() { 446 | testForEachSpec(2, [1,2]); 447 | }); 448 | 449 | 450 | it('should follow the ES spec when called with arguments', function() { 451 | testForEachSpec(2, (function() { return arguments; }(1,2))); 452 | }); 453 | 454 | 455 | it('should follow the ES spec when called with string', function() { 456 | testForEachSpec(2, '12'); 457 | }); 458 | 459 | it('should follow the ES spec when called with JSON', function() { 460 | testForEachSpec(2, {a: 1, b: 2}); 461 | }); 462 | 463 | 464 | it('should follow the ES spec when called with function', function() { 465 | function f() {} 466 | f.a = 1; 467 | f.b = 2; 468 | testForEachSpec(2, f); 469 | }); 470 | }); 471 | }); 472 | 473 | describe('#minErr', function() { 474 | it('should return a function', function() { 475 | expect(typeof minErr('module')).toEqual('function'); 476 | }); 477 | 478 | it('should throw an error with enumarable params', function() { 479 | expect(minErr('$parse')('parsing {0}', 'error')).toEqual(Error('[$parse:]parsing error')); 480 | expect(minErr('$parse')('{1} {0} {2}', 'error', 'parsing')).toEqual(Error('[$parse:]parsing error {2}')); 481 | }); 482 | }); 483 | 484 | describe('private things', function() { 485 | it('should return if it\'s Array-Like', function() { 486 | expect(isArrayLike(arguments)).toEqual(true); 487 | //fake jQuery 488 | var nodeElm = [document.createTextNode("CLICK ME")]; 489 | nodeElm.nodeType = 1; 490 | expect(isArrayLike(nodeElm)).toEqual(true); 491 | //should return false 492 | expect(isArrayLike(null)).toEqual(false); 493 | expect(isArrayLike(window)).toEqual(false); 494 | }); 495 | }); 496 | 497 | describe('valueFn', function() { 498 | it('should get a value and return a function that return it on invocation', function() { 499 | expect(typeof valueFn(1)).toEqual('function'); 500 | expect(valueFn(1)()).toEqual(1); 501 | }); 502 | }); 503 | }); -------------------------------------------------------------------------------- /test/spec/parse.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////////// 2 | // // 3 | // $parse // 4 | // this unit should nor be tested again, cuz it's actually tested by the angular team, // 5 | // see: github.com/angular.js/angular.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////////////////////// --------------------------------------------------------------------------------