├── .gitignore ├── .hound.yml ├── .travis.yml ├── bower.json ├── .jshint-rules.js ├── package.json ├── LICENSE ├── brototype.js ├── README.md └── tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | javascript: 2 | config_file: .jshint-rules.js 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.12 4 | - 0.10 5 | - 0.8 6 | 7 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brototype", 3 | "main": "brototype.js", 4 | "homepage": "http://brototypejs.com/", 5 | "authors": [ 6 | "Randy Hunt " 7 | ], 8 | "description": "Bro, do you even Javascript?", 9 | "moduleType": [ 10 | "amd" 11 | ], 12 | "keywords": [ 13 | "brototype", 14 | "bro" 15 | ], 16 | "license": "MIT", 17 | "ignore": [ 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "test", 22 | "tests" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.jshint-rules.js: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "browser": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "forin": true, 8 | "immed": true, 9 | "latedef": "nofunc", 10 | "maxlen": 80, 11 | "newcap": true, 12 | "noarg": true, 13 | "noempty": true, 14 | "nonew": false, 15 | "predef": [ 16 | "$", 17 | "jQuery", 18 | 19 | "jasmine", 20 | "beforeEach", 21 | "describe", 22 | "expect", 23 | "it", 24 | 25 | "angular", 26 | "inject", 27 | "module" 28 | ], 29 | "trailing": true, 30 | "undef": true, 31 | "unused": true 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brototype", 3 | "version": "0.0.6", 4 | "description": "Bro, do you even Javascript?", 5 | "main": "brototype.js", 6 | "scripts": { 7 | "test": "mocha tests.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/letsgetrandy/brototype.git" 12 | }, 13 | "author": "Randy Hunt", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/letsgetrandy/brototype/issues" 17 | }, 18 | "homepage": "http://brototypejs.com", 19 | "dependencies": {}, 20 | "devDependencies": { 21 | "mocha": "~2.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Randy Hunt 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /brototype.js: -------------------------------------------------------------------------------- 1 | /*global module:true, window:true, require:false, define:false*/ 2 | (function() { 3 | 'use strict'; 4 | 5 | // Bromise... it's stronger than a Promise 6 | function Bromise(object, method, args) { 7 | this.object = object; 8 | this.method = method; 9 | this.args = args.length > 1 ? args.slice(1) : []; 10 | } 11 | 12 | Bromise.brototype = Bromise.prototype = { 13 | "butWhenIdo": function(callback, context) { 14 | if (this.method instanceof Function) { 15 | var returnValue = this.method.apply(this.object, this.args); 16 | if (returnValue) { 17 | (callback || function(){}).call(context || this.object, returnValue); 18 | } 19 | } 20 | return context; 21 | }, 22 | 23 | "hereComeTheErrors": function(callback) { 24 | if (this.method instanceof Function) { 25 | try { 26 | this.method.apply(this.object, this.args); 27 | } catch(e) { 28 | callback(e); 29 | } 30 | } else { 31 | callback(this.method + ' is not a function.'); 32 | } 33 | }, 34 | "errorsAreComing": function () { 35 | this.hereComeTheErrors.apply(this, arguments); 36 | } 37 | }; 38 | 39 | function Bro(obj) { 40 | if (this instanceof Bro) { 41 | this.obj = obj; 42 | } else { 43 | return new Bro(obj); 44 | } 45 | } 46 | 47 | Bro.TOTALLY = true; 48 | Bro.NOWAY = false; 49 | 50 | Bro.brototype = Bro.prototype = { 51 | "isThatEvenAThing": function() { 52 | return this.obj !== void 0; 53 | }, 54 | 55 | "doYouEven": function(key, callback, options) { 56 | if (!(callback instanceof Function)) { 57 | options = callback; 58 | } 59 | var optionsBro = Bro(options || {}); 60 | if (!(key instanceof Array)) { 61 | key = [key]; 62 | } 63 | var self = this; 64 | if (key.every(function(k) { 65 | var bro = self.iCanHaz(k); 66 | return (Bro(bro).isThatEvenAThing() === Bro.TOTALLY); 67 | })) { 68 | optionsBro.iDontAlways('forSure').butWhenIdo(); 69 | 70 | // Perform callback function 71 | if (callback) { 72 | for (var i = 0; i < key.length; i++) { 73 | callback(self.obj[key[i]], key[i]); 74 | } 75 | } 76 | 77 | return Bro.TOTALLY; 78 | } else { 79 | optionsBro.iDontAlways('sorryBro').butWhenIdo(); 80 | return Bro.NOWAY; 81 | } 82 | }, 83 | 84 | "iCanHaz": function(key) { 85 | if (Array.isArray(key)) { 86 | var index, value, result = []; 87 | for (index in key) { 88 | if (key.hasOwnProperty(index)) { 89 | value = this.iCanHaz(key[index]); 90 | result.push(value); 91 | } 92 | } 93 | return result; 94 | } 95 | var props = key.split('.'), 96 | item = this.obj; 97 | for (var i = 0; i < props.length; i++) { 98 | if (typeof item === "undefined" || item === null || Bro(item = item[props[i]]).isThatEvenAThing() === Bro.NOWAY) { 99 | return undefined; 100 | } 101 | } 102 | return item; 103 | }, 104 | 105 | "comeAtMe": function(brobject) { 106 | var i, prop, 107 | bro = Bro(brobject), 108 | keys = bro.giveMeProps(), 109 | obj = (this instanceof Bro) ? this.obj : Bro.prototype; 110 | for (i = 0; i < keys.length; i++) { 111 | prop = keys[i]; 112 | if (bro.hasRespect(prop)) { 113 | obj[prop] = brobject[prop]; 114 | } 115 | } 116 | }, 117 | 118 | "giveMeProps": function() { 119 | var key, props = []; 120 | if (Object.keys) { 121 | props = Object.keys(this.obj); 122 | } else { 123 | for (key in this.obj) { 124 | if (this.obj.hasRespect(key)) { 125 | props.push(key); 126 | } 127 | } 128 | } 129 | return props; 130 | }, 131 | 132 | "hasRespect": function(prop) { 133 | return this.obj.hasOwnProperty(prop); 134 | }, 135 | 136 | 137 | "iDontAlways": function(methodString) { 138 | var method = this.iCanHaz(methodString); 139 | return new Bromise(this.obj, method, arguments); 140 | }, 141 | 142 | "braceYourself": function(methodString) { 143 | var method = this.iCanHaz(methodString); 144 | return new Bromise(this.obj, method, arguments); 145 | }, 146 | "makeItHappen": function(key, value) { 147 | var brobj = this.obj; 148 | var props = key.split('.'); 149 | for (var i = 0; i < props.length - 1; ++i) { 150 | if (brobj[props[i]] === undefined) { 151 | brobj[props[i]] = {}; 152 | } 153 | brobj = brobj[props[i]]; 154 | } 155 | // the deepest key is set to either an empty object or the value provided 156 | brobj[props[props.length - 1]] = value === undefined ? {} : value; 157 | } 158 | }; 159 | 160 | (function() { 161 | if (typeof define === 'function' && typeof define.amd === 'object') { 162 | define(function() { 163 | return Bro; 164 | }); 165 | } else if (typeof module !== 'undefined' && module.exports) { 166 | module.exports = Bro; 167 | } else if (typeof window !== 'undefined') { 168 | window.Bro = Bro; 169 | } 170 | 171 | if (typeof(angular) !== 'undefined') { 172 | angular.module('brototype', []).factory('Bro', function() { return Bro; }); 173 | } 174 | })(); 175 | })(); 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![build status][travis-image]][travis-url] 2 | [![Codacy Badge](https://www.codacy.com/project/badge/ec7e9f08d94447188b0b5072ba3eac31)](https://www.codacy.com/app/letsgetrandy/brototype) 3 | [![Code Climate](https://codeclimate.com/repos/555a0d98695680378e0034bd/badges/04a1db801508665091d9/gpa.svg)](https://codeclimate.com/repos/555a0d98695680378e0034bd/feed) 4 | [![bitHound Score](https://www.bithound.io/github/letsgetrandy/brototype/badges/score.svg)](https://www.bithound.io/github/letsgetrandy/brototype) 5 | 6 | brototype 7 | ========= 8 | 9 | Bro, do you even javascript? 10 | 11 | ## Features 12 | 13 | You've got a deeply-nested set of objects that may or may not always be there. 14 | We've all seen something like this: 15 | `var myURL = app.config.environment.buildURL('dev');` 16 | which leads to one of our favorite javascript errors... 17 | `error: undefined is not a function` 18 | 19 | And the solution only makes the code base ugly: 20 | ```js 21 | var myURL; 22 | if (app && app.config && app.config.environment && app.config.environment.buildURL) { 23 | myURL = app.config.environment.buildURL('dev'); 24 | } 25 | ``` 26 | 27 | We all hate that, don't we? 28 | 29 | So what if you could just type: 30 | ```js 31 | var myURL; 32 | if (Bro(app).doYouEven('config.environment.buildURL')) { 33 | myURL = app.config.environment.buildURL('dev'); 34 | } 35 | ``` 36 | 37 | Or better yet, how about: 38 | ```js 39 | var myURL; 40 | Bro(app) 41 | .iDontAlways('config.environment.buildURL') 42 | .butWhenIdo(function(buildURL){ 43 | myURL = buildURL('dev'); 44 | }); 45 | ``` 46 | 47 | Well, now you can! 48 | 49 | But what if you have something like this: 50 | 51 | ```js 52 | app['soap:Envelope']['soap:Body'][0].getResponse[0]['rval'][0].customerId[0] 53 | ``` 54 | 55 | We got you covered. 56 | 57 | ```js 58 | if (Bro(app).doYouEven("soap:Envelope.soap:Body.0.getResponse.0.rval.0.customerId.0")) { 59 | var thisVar = app['soap:Envelope']['soap:Body'][0].getResponse[0]['rval'][0].customerId[0]; 60 | } 61 | ``` 62 | 63 | ## Features 64 | 65 | ### Testing nested members 66 | ```js 67 | if(Bro(object).doYouEven('lift') === Bro.TOTALLY) { 68 | console.log(object.lift); 69 | } 70 | ``` 71 | 72 | Or, ensure that multiple nested members exist by passing an array of paths 73 | ```js 74 | if (Bro(object) 75 | .doYouEven(['property.one', 'property.two']) { 76 | // returns true if all referenced properties exist 77 | console.log(object.property.one, object.property.two); 78 | }) 79 | ``` 80 | 81 | Or, just use a callback... 82 | ```js 83 | Bro(object) 84 | .doYouEven('property.subproperty', function(subproperty) { 85 | console.log(subproperty); 86 | }); 87 | ``` 88 | 89 | ### Fetching nested members 90 | ```js 91 | // get a value if it exists 92 | var value = Bro(object).iCanHaz('cheezeburger'); 93 | 94 | // get an array of values for paths that exist 95 | var values = Bro(object).iCanHaz(['cheezeburger', 'money', 'beer']); 96 | ``` 97 | 98 | ### Creating nested members 99 | ```js 100 | // add properties to an object 101 | Bro(object).makeItHappen('cheezeburger.with.pickles'); 102 | ``` 103 | 104 | ```js 105 | // set a deeply nested property by the Bro string 106 | Bro(object).makeItHappen('bro.props', 'high five'); // object.bro.props = 'high five' 107 | ``` 108 | 109 | ### Calling nested functions 110 | ```js 111 | Bro(object) 112 | .iDontAlways('method') 113 | .butWhenIdo(function(returnVal) { 114 | console.log('object.method() returned ', returnVal); 115 | }); 116 | ``` 117 | 118 | ### Handling exceptions 119 | ```js 120 | Bro(object) 121 | .braceYourself('method.name') 122 | .hereComeTheErrors(function(e) { 123 | console.log('error ' + e + ' happened.'); 124 | }); 125 | ``` 126 | 127 | ### Bro-oleans 128 | ```js 129 | Bro.TOTALLY // true; 130 | Bro.NOWAY // false; 131 | ``` 132 | 133 | ### Check for undefined 134 | ```js 135 | if (Bro(someVar).isThatEvenAThing() === Bro.TOTALLY) { 136 | // do stuff 137 | } 138 | ``` 139 | 140 | ### Get a list of object keys 141 | ```js 142 | var object = {foo: 1, bar: 2}; 143 | Bro(object).giveMeProps(); 144 | // returns ['foo', 'bar']; 145 | ``` 146 | 147 | ### Extending objects 148 | ```js 149 | var obj1 = {foo: 'boo', bar: 'bar'}, 150 | obj2 = {foo: 'bar', yes: 'no'}; 151 | Bro(obj1).comeAtMe(obj2); 152 | 153 | // now obj1.foo == 'bar' and obj1.yes == 'no' 154 | ``` 155 | 156 | ### Extending Brototype! 157 | Yes, extend me, Bro! 158 | 159 | ```js 160 | var plugin = { foo: function() { whatever; }}; 161 | Bro.prototype.comeAtMe(plugin); 162 | ``` 163 | 164 | 165 | ## Installing 166 | brototype is available via npm or bower 167 | ```bash 168 | # via npm 169 | $ npm install brototype 170 | 171 | # via bower 172 | $ bower install brototype 173 | ``` 174 | 175 | ## Contributing 176 | Brototype.js may be funny, but it is also quite useful, as demonstrated by the 177 | number of people who have already installed it via 178 | [npm](https://www.npmjs.org/package/brototype). 179 | 180 | Therefore, there is some responsibility to add/update the library responsibly. 181 | Please have a look at the 182 | [guidelines for contributing to Brototype](https://github.com/letsgetrandy/brototype/wiki/Contributing) 183 | before submitting your pull request. 184 | 185 | 186 | ## Bro-tie 187 | For the brofessional. Want to use Brototype.js but it's too bro for your work 188 | environment? Just give it the [Bro-tie](http://pepperthecat.github.io/brotie/) treatment 189 | so you can bro down at the office! 190 | Alias some or all of the names to make your boss happy. 191 | 192 | ## Do you even Brototype? 193 | Are you using Brototype in the wild? 194 | If so, [tell the world](https://github.com/letsgetrandy/brototype/issues/10)! 195 | 196 | Also, don't forget to follow [@BrototypeJS](https://twitter.com/Brototypejs) on Twitter! 197 | 198 | 199 | ## Author 200 | 201 | Randy Hunt 202 | 203 | ## License 204 | 205 | The MIT License 206 | 207 | Copyright © 2014 208 | 209 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 210 | 211 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 212 | 213 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 214 | 215 | 216 | [travis-image]: https://img.shields.io/travis/letsgetrandy/brototype/master.svg?style=flat-square 217 | [travis-url]: https://travis-ci.org/letsgetrandy/brototype 218 | -------------------------------------------------------------------------------- /tests.js: -------------------------------------------------------------------------------- 1 | /*global describe:false, it:false, beforeEach:false */ 2 | 3 | var Bro = require('./brototype'); 4 | var assert = require('assert'); 5 | 6 | describe('Bro.doYouEven', function() { 7 | it('should be defined', function() { 8 | var a = {}, 9 | bro = Bro(a); 10 | assert.notEqual(bro.doYouEven, undefined); 11 | }); 12 | 13 | it('should return true for defined properties', function() { 14 | var a = {foo: 'bar'}, 15 | bro = Bro(a); 16 | assert.equal(bro.doYouEven('foo'), true); 17 | }); 18 | 19 | it('should return true for nested properties', function() { 20 | var a = {foo: {bar: 'baz'}}, 21 | bro = Bro(a); 22 | assert.equal(bro.doYouEven('foo.bar'), true); 23 | }); 24 | 25 | it('should return true for more than one nested property', function() { 26 | var a = {b: {c: 'foo'},d: {e: 'bar'}}, 27 | bro = Bro(a); 28 | assert.equal(bro.doYouEven(['b.c', 'd.x']), false); 29 | assert.equal(bro.doYouEven(['b.c', 'd.e']), true); 30 | }); 31 | 32 | it('should return false for undefined properties', function() { 33 | var a = {foo: 'bar'}, 34 | bro = Bro(a); 35 | assert.equal(bro.doYouEven('bar'), false); 36 | }); 37 | 38 | it('should fail gracefully if the object is not defined', function() { 39 | var a = undefined, 40 | bro = Bro(a); 41 | assert.equal(bro.doYouEven('foo.bar'), false); 42 | }); 43 | 44 | it('should fail gracefully if the object is null', function() { 45 | var a = null, 46 | bro = Bro(a); 47 | assert.equal(bro.doYouEven('foo.bar'), false); 48 | }); 49 | 50 | it('should fail gracefully if a traversed subproperty is null', function(){ 51 | var a = {test: null}, 52 | bro = Bro(a); 53 | assert.equal(bro.doYouEven('test.0.test'), false); 54 | }); 55 | 56 | it('should pass a simple callback function', function() { 57 | var a = {foo: 'bar'}, 58 | bro = Bro(a); 59 | bro.doYouEven('foo', function(prop) { 60 | assert.equal(prop, 'bar'); 61 | }); 62 | }); 63 | 64 | it('should pass callback function to more than one nested property', function() { 65 | var a = {foo: 'bar', a: {b: 'c'}}, 66 | bro = Bro(a); 67 | bro.doYouEven(['foo', 'b.c'], function(prop, key) { 68 | assert.equal(prop, a[key]); 69 | }); 70 | }); 71 | }); 72 | 73 | describe('Bro.iCanHaz', function() { 74 | it('should return the value of the deep property', function() { 75 | var a = {b: {c: {d: 32}}}, 76 | bro = Bro(a); 77 | assert.equal(bro.iCanHaz('b.c.d'), 32); 78 | }); 79 | 80 | it('should return undefined for missing property', function() { 81 | var a = {b: 32}, 82 | bro = Bro(a); 83 | assert.equal(bro.iCanHaz('b.c.d'), undefined); 84 | }); 85 | 86 | it('should return an array when an array is requested', function() { 87 | var a = {a: 'foo', b: 'bar', c: 'fred'}, 88 | values = Bro(a).iCanHaz(['a', 'b', 'c', 'd']); 89 | 90 | assert.notEqual(values.indexOf('foo'), -1); 91 | assert.notEqual(values.indexOf('bar'), -1); 92 | assert.notEqual(values.indexOf('fred'), -1); 93 | }); 94 | }); 95 | 96 | describe('Bro.giveMeProps', function() { 97 | it('should return an object\'s keys', function() { 98 | var a = { 99 | "foo": 1, 100 | "bar": 2 101 | }, 102 | keys = Bro(a).giveMeProps(); 103 | assert.equal(keys.length, 2); 104 | assert.notEqual(keys.indexOf('foo'), -1); 105 | assert.notEqual(keys.indexOf('bar'), -1); 106 | }); 107 | }); 108 | 109 | describe('Bro.comeAtMe', function() { 110 | it('should extend first object with second object', function() { 111 | var a = { 112 | "foo": 1, 113 | "bar": 2 114 | },b = { 115 | "bar": 3, 116 | "baz": function(){return false;} 117 | }; 118 | Bro(a).comeAtMe(b); 119 | assert.equal(a.foo, 1); 120 | assert.equal(a.bar, 3); 121 | assert.equal(a.baz(), false); 122 | }); 123 | }); 124 | 125 | describe('Bro.iDontAlways', function() { 126 | var fired, 127 | success, 128 | param, 129 | context, 130 | obj = { 131 | "foo": function() { 132 | fired = true; 133 | context = this; 134 | return 91; 135 | }, 136 | "bar": 3 137 | }, 138 | fn = function(p) { 139 | success = true; 140 | param = p; 141 | }; 142 | 143 | beforeEach(function() { 144 | fired = false; 145 | success = false; 146 | param = null; 147 | context = null; 148 | }); 149 | 150 | it('should check that the requested method is a function', function() { 151 | var bro = Bro(obj); 152 | bro.iDontAlways('bar').butWhenIdo(fn); 153 | assert.equal(success, false); 154 | bro.iDontAlways('foo').butWhenIdo(fn); 155 | assert.equal(success, true); 156 | }); 157 | 158 | it('should run the requested method if a function', function() { 159 | var bro = Bro(obj); 160 | bro.iDontAlways('foo').butWhenIdo(fn); 161 | assert.equal(fired, true); 162 | }); 163 | 164 | it('should pass the method\'s return value as param to callback', function() { 165 | var bro = Bro(obj); 166 | bro.iDontAlways('foo').butWhenIdo(fn); 167 | assert.equal(param, 91); 168 | }); 169 | 170 | it('should apply the object as its own context', function() { 171 | var bro = Bro(obj); 172 | bro.iDontAlways('foo').butWhenIdo(fn); 173 | assert.equal(context, obj); 174 | }); 175 | }); 176 | 177 | describe('Bro.braceYourself', function() { 178 | var success, 179 | error, 180 | obj = { 181 | "foo": function() { 182 | throw 'an error'; 183 | } 184 | }, 185 | fn = function(e) { 186 | success = true; 187 | error = e; 188 | }; 189 | 190 | beforeEach(function() { 191 | success = null; 192 | error = null; 193 | }); 194 | 195 | it('should fire the callback when an exception is thrown', function() { 196 | var bro = Bro(obj); 197 | bro.braceYourself('foo').hereComeTheErrors(fn); 198 | assert.equal(success, true); 199 | }); 200 | 201 | it('should pass the error to the callback', function() { 202 | var bro = Bro(obj); 203 | bro.braceYourself('foo').hereComeTheErrors(fn); 204 | assert.equal(error, 'an error'); 205 | }); 206 | }); 207 | 208 | describe('Bro.makeItHappen', function() { 209 | var expected, 210 | obj; 211 | 212 | beforeEach(function() { 213 | obj = { "foo": { "bar": {} } }; 214 | }); 215 | 216 | it('should add properties to object, in a nested fashion', function() { 217 | expected = { "foo": { "bar": {} }, "stuff": { "and": { "things": {} } } }; 218 | var bro = Bro(obj); 219 | bro.makeItHappen('stuff.and.things'); 220 | assert.deepEqual(expected, obj); 221 | }); 222 | 223 | it('should add properties to object, extending deeper nested objects', function() { 224 | expected = { "foo": { "bar": { "stuff": { "and": { "things": {} } } } } }; 225 | var bro = Bro(obj); 226 | bro.makeItHappen('foo.bar.stuff.and.things'); 227 | assert.deepEqual(expected, obj); 228 | }); 229 | 230 | it('should set existing deeply nested properties on an object', function() { 231 | expected = { "foo": { "bar": 'awesome' } }; 232 | var bro = Bro(obj); 233 | bro.makeItHappen('foo.bar', 'awesome'); 234 | assert.deepEqual(expected, obj); 235 | }); 236 | 237 | it('should create new properties, then set them, as needed', function() { 238 | expected = { "foo": { "bar": { "stuff": { "and": { "things": 'super awesome' } } } } }; 239 | var bro = Bro(obj); 240 | bro.makeItHappen('foo.bar.stuff.and.things', 'super awesome'); 241 | assert.deepEqual(expected, obj); 242 | }); 243 | }); 244 | 245 | describe('brototype alias', function(){ 246 | it('kind of basically works', function(){ 247 | assert.notEqual(Bro.brototype.doYouEven, undefined); 248 | }); 249 | }); 250 | --------------------------------------------------------------------------------