ember-data-factory-guy 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bower.json +1 -1
- data/dist/ember-data-factory-guy.js +60 -11
- data/dist/ember-data-factory-guy.min.js +1 -1
- data/ember-data-factory-guy.gemspec +1 -1
- data/package.json +1 -1
- data/src/factory_guy.js +32 -5
- data/src/model_definition.js +28 -6
- data/tests/factory_guy_test.js +33 -0
- data/tests/support/factories/project_factory.js +7 -0
- data/tests/test_setup.js +7 -0
- data/vendor/assets/javascripts/ember_data_factory_guy.js +60 -11
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 10cce63c16d71075b39d7d4b3134fc97687dd359
         | 
| 4 | 
            +
              data.tar.gz: f8273a32c925bf4c2791e946435b89d7271fa71a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 60cb0d5dcaf087c7bc4996306c11b1775eab501cac9f1434fc77dcc9019eaf453f4a41303c802f9dea1f02f21237769b8e32191da5525c2caa5e632cbdc4e856
         | 
| 7 | 
            +
              data.tar.gz: 79591c97aa1841f941cb4298524269286282b50f7510da8a154d784e4ddcf8afabc2bd8430a05d82f54886fa7a4e6f324a3377b557898f1d2f77c797ea095bee
         | 
    
        data/bower.json
    CHANGED
    
    
| @@ -23,6 +23,7 @@ function MissingSequenceError(message) { | |
| 23 23 | 
             
             */
         | 
| 24 24 | 
             
            ModelDefinition = function (model, config) {
         | 
| 25 25 | 
             
              var sequences = {};
         | 
| 26 | 
            +
              var traits = {};
         | 
| 26 27 | 
             
              var defaultAttributes = {};
         | 
| 27 28 | 
             
              var namedModels = {};
         | 
| 28 29 | 
             
              var modelId = 1;
         | 
| @@ -69,12 +70,17 @@ ModelDefinition = function (model, config) { | |
| 69 70 |  | 
| 70 71 | 
             
               @param {String} name fixture name
         | 
| 71 72 | 
             
               @param {Object} opts attributes to override
         | 
| 73 | 
            +
               @param {String} traits array of traits
         | 
| 72 74 | 
             
               @returns {Object} json
         | 
| 73 75 | 
             
               */
         | 
| 74 | 
            -
              this.build = function (name, opts) {
         | 
| 76 | 
            +
              this.build = function (name, opts, traitArgs) {
         | 
| 77 | 
            +
                var traitsObj = {}
         | 
| 78 | 
            +
                traitArgs.forEach(function(trait) {
         | 
| 79 | 
            +
                  $.extend(traitsObj, traits[trait]);
         | 
| 80 | 
            +
                })
         | 
| 75 81 | 
             
                var modelAttributes = namedModels[name] || {};
         | 
| 76 | 
            -
                // merge default, modelAttributes and opts to get the rough fixture
         | 
| 77 | 
            -
                var fixture = $.extend({}, defaultAttributes, modelAttributes, opts);
         | 
| 82 | 
            +
                // merge default, modelAttributes, traits and opts to get the rough fixture
         | 
| 83 | 
            +
                var fixture = $.extend({}, defaultAttributes, modelAttributes, traitsObj, opts);
         | 
| 78 84 | 
             
                // deal with attributes that are functions or objects
         | 
| 79 85 | 
             
                for (attribute in fixture) {
         | 
| 80 86 | 
             
                  if (Ember.typeOf(fixture[attribute]) == 'function') {
         | 
| @@ -98,13 +104,14 @@ ModelDefinition = function (model, config) { | |
| 98 104 |  | 
| 99 105 | 
             
               @param {String} name model name or named model type
         | 
| 100 106 | 
             
               @param {Integer} number of fixtures to build
         | 
| 107 | 
            +
               @param {Array} array of traits to build with
         | 
| 101 108 | 
             
               @param {Object} opts attribute options
         | 
| 102 109 | 
             
               @returns array of fixtures
         | 
| 103 110 | 
             
               */
         | 
| 104 | 
            -
              this.buildList = function (name, number, opts) {
         | 
| 111 | 
            +
              this.buildList = function (name, number, traits, opts) {
         | 
| 105 112 | 
             
                var arr = [];
         | 
| 106 113 | 
             
                for (var i = 0; i < number; i++) {
         | 
| 107 | 
            -
                  arr.push(this.build(name, opts))
         | 
| 114 | 
            +
                  arr.push(this.build(name, opts, traits))
         | 
| 108 115 | 
             
                }
         | 
| 109 116 | 
             
                return arr;
         | 
| 110 117 | 
             
              }
         | 
| @@ -124,13 +131,25 @@ ModelDefinition = function (model, config) { | |
| 124 131 | 
             
                defaultAttributes = object;
         | 
| 125 132 | 
             
              }
         | 
| 126 133 |  | 
| 134 | 
            +
              var parseTraits = function (object) {
         | 
| 135 | 
            +
                if (!object) {
         | 
| 136 | 
            +
                  return
         | 
| 137 | 
            +
                }
         | 
| 138 | 
            +
            //    for (trait in object) {
         | 
| 139 | 
            +
            //      var trait = object[trait];
         | 
| 140 | 
            +
            //      if (Ember.typeOf(trait) == 'function') {}
         | 
| 141 | 
            +
            //      object[trait] = new Trait(trait);
         | 
| 142 | 
            +
            //    }
         | 
| 143 | 
            +
                traits = object;
         | 
| 144 | 
            +
              }
         | 
| 145 | 
            +
             | 
| 127 146 | 
             
              var parseSequences = function (object) {
         | 
| 128 147 | 
             
                if (!object) {
         | 
| 129 148 | 
             
                  return
         | 
| 130 149 | 
             
                }
         | 
| 131 150 | 
             
                for (sequenceName in object) {
         | 
| 132 151 | 
             
                  var sequenceFn = object[sequenceName];
         | 
| 133 | 
            -
                  if ( | 
| 152 | 
            +
                  if (Ember.typeOf(sequenceFn) != 'function') {
         | 
| 134 153 | 
             
                    throw new Error('Problem with [' + sequenceName + '] sequence definition. Sequences must be functions')
         | 
| 135 154 | 
             
                  }
         | 
| 136 155 | 
             
                  object[sequenceName] = new Sequence(sequenceFn);
         | 
| @@ -142,6 +161,9 @@ ModelDefinition = function (model, config) { | |
| 142 161 | 
             
                parseSequences(config.sequences);
         | 
| 143 162 | 
             
                delete config.sequences;
         | 
| 144 163 |  | 
| 164 | 
            +
                parseTraits(config.traits);
         | 
| 165 | 
            +
                delete config.traits;
         | 
| 166 | 
            +
             | 
| 145 167 | 
             
                parseDefault(config.default);
         | 
| 146 168 | 
             
                delete config.default;
         | 
| 147 169 |  | 
| @@ -293,18 +315,32 @@ FactoryGuy = { | |
| 293 315 | 
             
               Build fixtures for model or specific fixture name. For example:
         | 
| 294 316 |  | 
| 295 317 | 
             
               FactoryGuy.build('user') for User model
         | 
| 296 | 
            -
               FactoryGuy.build('bob') for  | 
| 318 | 
            +
               FactoryGuy.build('bob') for a 'bob' User
         | 
| 319 | 
            +
               FactoryGuy.build('bob', 'dude') for a 'bob' User with dude traits
         | 
| 320 | 
            +
               FactoryGuy.build('bob', 'dude', 'funny') for a 'bob' User with dude and funny traits
         | 
| 321 | 
            +
               FactoryGuy.build('bob', 'dude', name: 'wombat') for a 'bob' User with dude trait and custom attribute name of 'wombat'
         | 
| 297 322 |  | 
| 298 323 | 
             
               @param {String} name Fixture name
         | 
| 324 | 
            +
               @param {String} trait trait name ( can be more than one )
         | 
| 299 325 | 
             
               @param {Object} opts Options that will override default fixture values
         | 
| 300 326 | 
             
               @returns {Object} json fixture
         | 
| 301 327 | 
             
               */
         | 
| 302 | 
            -
              build: function ( | 
| 328 | 
            +
              build: function () {
         | 
| 329 | 
            +
                var args = Array.prototype.slice.call(arguments);
         | 
| 330 | 
            +
                var opts = {}
         | 
| 331 | 
            +
                var name = args.shift();
         | 
| 332 | 
            +
                if (!name) {
         | 
| 333 | 
            +
                  throw new Error("Build needs a factory name to build");
         | 
| 334 | 
            +
                }
         | 
| 335 | 
            +
                if (Ember.typeOf(args[args.length-1]) == 'object') {
         | 
| 336 | 
            +
                  opts  = args.pop();
         | 
| 337 | 
            +
                }
         | 
| 338 | 
            +
                var traits = args; // whatever is left are traits
         | 
| 303 339 | 
             
                var definition = this.lookupDefinitionForFixtureName(name);
         | 
| 304 340 | 
             
                if (!definition) {
         | 
| 305 341 | 
             
                  throw new Error("Can't find that factory named [" + name + "]");
         | 
| 306 342 | 
             
                }
         | 
| 307 | 
            -
                return definition.build(name, opts);
         | 
| 343 | 
            +
                return definition.build(name, opts, traits);
         | 
| 308 344 | 
             
              },
         | 
| 309 345 |  | 
| 310 346 | 
             
              /**
         | 
| @@ -315,15 +351,28 @@ FactoryGuy = { | |
| 315 351 |  | 
| 316 352 | 
             
               @param {String} name fixture name
         | 
| 317 353 | 
             
               @param {Number} number number of fixtures to create
         | 
| 354 | 
            +
               @param {String} trait (one or more)
         | 
| 318 355 | 
             
               @param {Object} opts options that will override default fixture values
         | 
| 319 356 | 
             
               @returns {Array} list of fixtures
         | 
| 320 357 | 
             
               */
         | 
| 321 | 
            -
              buildList: function ( | 
| 358 | 
            +
              buildList: function () {
         | 
| 359 | 
            +
                var args = Array.prototype.slice.call(arguments);
         | 
| 360 | 
            +
                var name = args.shift();
         | 
| 361 | 
            +
                var number = args.shift();
         | 
| 362 | 
            +
                if (!name || !number) {
         | 
| 363 | 
            +
                  throw new Error("buildList needs a name and a number ( at least ) to build with");
         | 
| 364 | 
            +
                }
         | 
| 365 | 
            +
                var opts = {}
         | 
| 366 | 
            +
                if (Ember.typeOf(args[args.length-1]) == 'object') {
         | 
| 367 | 
            +
                  opts  = args.pop();
         | 
| 368 | 
            +
                }
         | 
| 369 | 
            +
                var traits = args; // whatever is left are traits
         | 
| 370 | 
            +
                console.log(name, number, traits+'', opts)
         | 
| 322 371 | 
             
                var definition = this.lookupDefinitionForFixtureName(name);
         | 
| 323 372 | 
             
                if (!definition) {
         | 
| 324 373 | 
             
                  throw new Error("Can't find that factory named [" + name + "]");
         | 
| 325 374 | 
             
                }
         | 
| 326 | 
            -
                return definition.buildList(name, number, opts);
         | 
| 375 | 
            +
                return definition.buildList(name, number, traits, opts);
         | 
| 327 376 | 
             
              },
         | 
| 328 377 |  | 
| 329 378 | 
             
              /**
         | 
| @@ -1 +1 @@ | |
| 1 | 
            -
            Sequence=function(fn){var index=1;this.next=function(){return fn.call(this,index++)};this.reset=function(){index=1}};function MissingSequenceError(message){this.toString=function(){return message}}ModelDefinition=function(model,config){var sequences={};var defaultAttributes={};var namedModels={};var modelId=1;this.model=model;this.matchesName=function(name){return model==name||namedModels[name]};this.merge=function(config){};this.generate=function(name,sequenceFn){if(sequenceFn){if(!sequences[name]){sequences[name]=new Sequence(sequenceFn)}}var sequence=sequences[name];if(!sequence){throw new MissingSequenceError("Can not find that sequence named ["+sequenceName+"] in '"+model+"' definition")}return sequence.next()};this.build=function(name,opts){var modelAttributes=namedModels[name]||{};var fixture=$.extend({},defaultAttributes,modelAttributes,opts);for(attribute in fixture){if(Ember.typeOf(fixture[attribute])=="function"){fixture[attribute]=fixture[attribute].call(this,fixture)}else if(Ember.typeOf(fixture[attribute])=="object"){fixture[attribute]=FactoryGuy.build(attribute,fixture[attribute])}}if(!fixture.id){fixture.id=modelId++}return fixture};this.buildList=function(name,number,opts){var arr=[];for(var i=0;i<number;i++){arr.push(this.build(name,opts))}return arr};this.reset=function(){modelId=1;for(name in sequences){sequences[name].reset()}};var parseDefault=function(object){if(!object){return}defaultAttributes=object};var parseSequences=function(object){if(!object){return}for(sequenceName in object){var sequenceFn=object[sequenceName];if(typeof sequenceFn!="function"){throw new Error("Problem with ["+sequenceName+"] sequence definition. Sequences must be functions")}object[sequenceName]=new Sequence(sequenceFn)}sequences=object};var parseConfig=function(config){parseSequences(config.sequences);delete config.sequences;parseDefault(config.default);delete config.default;namedModels=config};parseConfig(config)};FactoryGuy={modelDefinitions:{},define:function(model,config){if(this.modelDefinitions[model]){this.modelDefinitions[model].merge(config)}else{this.modelDefinitions[model]=new ModelDefinition(model,config)}},generate:function(nameOrFunction){var sortaRandomName=Math.floor((1+Math.random())*65536).toString(16)+Date.now();return function(){if(Em.typeOf(nameOrFunction)=="function"){return this.generate(sortaRandomName,nameOrFunction)}else{return this.generate(nameOrFunction)}}},association:function(fixtureName,opts){return function(){return FactoryGuy.build(fixtureName,opts)}},lookupModelForFixtureName:function(name){var definition=this.lookupDefinitionForFixtureName(name);if(definition){return definition.model}},lookupDefinitionForFixtureName:function(name){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];if(definition.matchesName(name)){return definition}}},build:function(name,opts){var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.build(name,opts)},buildList:function(name,number,opts){var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.buildList(name,number,opts)},resetModels:function(store){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];definition.reset();try{var modelType=store.modelFor(definition.model);if(store.usingFixtureAdapter()){modelType.FIXTURES=[]}store.unloadAll(modelType)}catch(e){}}},pushFixture:function(modelClass,fixture){if(!modelClass["FIXTURES"]){modelClass["FIXTURES"]=[]}modelClass["FIXTURES"].push(fixture);return fixture},clear:function(opts){if(!opts){this.modelDefinitions={}}}};DS.Store.reopen({usingFixtureAdapter:function(){var adapter=this.adapterFor("application");return adapter instanceof DS.FixtureAdapter},makeFixture:function(name,options){var store=this;var modelName=FactoryGuy.lookupModelForFixtureName(name);var fixture=FactoryGuy.build(name,options);var modelType=store.modelFor(modelName);if(this.usingFixtureAdapter()){this.setAssociationsForFixtureAdapter(modelType,modelName,fixture);return FactoryGuy.pushFixture(modelType,fixture)}else{var store=this;var model;Em.run(function(){store.findEmbeddedBelongsToAssociationsForRESTAdapter(modelType,fixture);if(fixture.type){modelName=fixture.type.underscore();modelType=store.modelFor(modelName)}model=store.push(modelName,fixture);store.setAssociationsForRESTAdapter(modelType,modelName,model)});return model}},makeList:function(name,number,options){var arr=[];for(var i=0;i<number;i++){arr.push(this.makeFixture(name,options))}return arr},setAssociationsForFixtureAdapter:function(modelType,modelName,fixture){var self=this;var adapter=this.adapterFor("application");Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){if(fixture[relationship.key]){fixture[relationship.key].forEach(function(id){var hasManyfixtures=adapter.fixturesForType(relationship.type);var fixture=adapter.findFixtureById(hasManyfixtures,id);fixture[modelName]=fixture.id})}}if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(belongsToRecord){if(typeof belongsToRecord=="object"){FactoryGuy.pushFixture(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord.id}var hasManyName=self.findHasManyRelationshipNameForFixtureAdapter(relationship.type,relationship.parentType);var belongsToFixtures=adapter.fixturesForType(relationship.type);var belongsTofixture=adapter.findFixtureById(belongsToFixtures,fixture[relationship.key]);if(!belongsTofixture[hasManyName]){belongsTofixture[hasManyName]=[]}belongsTofixture[hasManyName].push(fixture.id)}}})},findEmbeddedBelongsToAssociationsForRESTAdapter:function(modelType,fixture){var store=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(Ember.typeOf(belongsToRecord)=="object"){belongsToRecord=store.push(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord}}})},setAssociationsForRESTAdapter:function(modelType,modelName,model){var self=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){var children=model.get(name)||[];children.forEach(function(child){var belongsToName=self.findRelationshipName("belongsTo",child.constructor,model);var hasManyName=self.findRelationshipName("hasMany",child.constructor,model);var inverseName=relationship.options&&relationship.options.inverse;if(belongsToName){child.set(belongsToName||inverseName,model)}else if(hasManyName){relation=child.get(hasManyName||inverseName)||[];relation.pushObject(model)}})}if(relationship.kind=="belongsTo"){var belongsToRecord=model.get(name);if(belongsToRecord){var setAssociations=function(){var hasManyName=self.findRelationshipName("hasMany",belongsToRecord.constructor,model);if(hasManyName){belongsToRecord.get(hasManyName).addObject(model);return}var oneToOneName=self.findRelationshipName("belongsTo",belongsToRecord.constructor,model);if(oneToOneName&&!(belongsToRecord.constructor==model.constructor)){belongsToRecord.set(oneToOneName,model)}};if(belongsToRecord.then){belongsToRecord.then(function(record){belongsToRecord=record;setAssociations()})}else{setAssociations()}}}})},findRelationshipName:function(kind,belongToModelType,childModel){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind==kind&&childModel instanceof relationship.type){relationshipName=relationship.key}});return relationshipName},findHasManyRelationshipNameForFixtureAdapter:function(belongToModelType,childModelType){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"&&childModelType==relationship.type){relationshipName=relationship.key}});return relationshipName},pushPayload:function(type,payload){if(this.usingFixtureAdapter()){var model=this.modelFor(modelName);FactoryGuy.pushFixture(model,payload)}else{this._super(type,payload)}}});DS.FixtureAdapter.reopen({createRecord:function(store,type,record){var promise=this._super(store,type,record);promise.then(function(){Em.RSVP.Promise.resolve(Ember.get(type,"relationshipNames")).then(function(relationShips){if(relationShips.belongsTo){relationShips.belongsTo.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);Ember.RSVP.resolve(belongsToRecord.get(hasManyName)).then(function(relationship){relationship.addObject(record)})}})})}if(relationShips.hasMany){relationShips.hasMany.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord&&belongsToRecord.get("length")>0){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);belongsToRecord.forEach(function(child){child.get(hasManyName).addObject(record)})}})})}})});return promise}});FactoryGuyTestMixin=Em.Mixin.create({setup:function(app){this.set("container",app.__container__);return this},useFixtureAdapter:function(app){app.ApplicationAdapter=DS.FixtureAdapter;this.getStore().adapterFor("application").simulateRemoteResponse=false},usingActiveModelSerializer:function(type){var store=this.getStore();var type=store.modelFor(type);var serializer=store.serializerFor(type.typeKey);return serializer instanceof DS.ActiveModelSerializer},find:function(type,id){return this.getStore().find(type,id)},make:function(name,opts){return this.getStore().makeFixture(name,opts)},getStore:function(){return this.get("container").lookup("store:main")},pushPayload:function(type,hash){return this.getStore().pushPayload(type,hash)},pushRecord:function(type,hash){return this.getStore().push(type,hash)},stubEndpointForHttpRequest:function(url,json,options){options=options||{};var request={url:url,dataType:"json",responseText:json,type:options.type||"GET",status:options.status||200};if(options.data){request.data=options.data}$.mockjax(request)},buildAjaxHttpResponse:function(name,opts){var fixture=FactoryGuy.build(name,opts);var modelName=FactoryGuy.lookupModelForFixtureName(name);if(this.usingActiveModelSerializer(modelName)){this.toSnakeCase(fixture)}var hash={};hash[modelName]=fixture;return hash},toSnakeCase:function(fixture){for(key in fixture){if(key!=Em.String.decamelize(key)){var value=fixture[key];delete fixture[key];fixture[Em.String.decamelize(key)]=value}}},handleFind:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var id=responseJson[modelName].id;var url="/"+Em.String.pluralize(modelName)+"/"+id;this.stubEndpointForHttpRequest(url,responseJson,{type:"GET",status:status||200});return responseJson},handleCreate:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var url="/"+Em.String.pluralize(modelName);this.stubEndpointForHttpRequest(url,responseJson,{type:"POST",status:status||200});return responseJson},handleUpdate:function(root,id,status){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"PUT",status:status||200})},handleDelete:function(root,id,status){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"DELETE",status:status||200})},teardown:function(){FactoryGuy.resetModels(this.getStore())}});
         | 
| 1 | 
            +
            Sequence=function(fn){var index=1;this.next=function(){return fn.call(this,index++)};this.reset=function(){index=1}};function MissingSequenceError(message){this.toString=function(){return message}}ModelDefinition=function(model,config){var sequences={};var traits={};var defaultAttributes={};var namedModels={};var modelId=1;this.model=model;this.matchesName=function(name){return model==name||namedModels[name]};this.merge=function(config){};this.generate=function(name,sequenceFn){if(sequenceFn){if(!sequences[name]){sequences[name]=new Sequence(sequenceFn)}}var sequence=sequences[name];if(!sequence){throw new MissingSequenceError("Can not find that sequence named ["+sequenceName+"] in '"+model+"' definition")}return sequence.next()};this.build=function(name,opts,traitArgs){var traitsObj={};traitArgs.forEach(function(trait){$.extend(traitsObj,traits[trait])});var modelAttributes=namedModels[name]||{};var fixture=$.extend({},defaultAttributes,modelAttributes,traitsObj,opts);for(attribute in fixture){if(Ember.typeOf(fixture[attribute])=="function"){fixture[attribute]=fixture[attribute].call(this,fixture)}else if(Ember.typeOf(fixture[attribute])=="object"){fixture[attribute]=FactoryGuy.build(attribute,fixture[attribute])}}if(!fixture.id){fixture.id=modelId++}return fixture};this.buildList=function(name,number,traits,opts){var arr=[];for(var i=0;i<number;i++){arr.push(this.build(name,opts,traits))}return arr};this.reset=function(){modelId=1;for(name in sequences){sequences[name].reset()}};var parseDefault=function(object){if(!object){return}defaultAttributes=object};var parseTraits=function(object){if(!object){return}traits=object};var parseSequences=function(object){if(!object){return}for(sequenceName in object){var sequenceFn=object[sequenceName];if(Ember.typeOf(sequenceFn)!="function"){throw new Error("Problem with ["+sequenceName+"] sequence definition. Sequences must be functions")}object[sequenceName]=new Sequence(sequenceFn)}sequences=object};var parseConfig=function(config){parseSequences(config.sequences);delete config.sequences;parseTraits(config.traits);delete config.traits;parseDefault(config.default);delete config.default;namedModels=config};parseConfig(config)};FactoryGuy={modelDefinitions:{},define:function(model,config){if(this.modelDefinitions[model]){this.modelDefinitions[model].merge(config)}else{this.modelDefinitions[model]=new ModelDefinition(model,config)}},generate:function(nameOrFunction){var sortaRandomName=Math.floor((1+Math.random())*65536).toString(16)+Date.now();return function(){if(Em.typeOf(nameOrFunction)=="function"){return this.generate(sortaRandomName,nameOrFunction)}else{return this.generate(nameOrFunction)}}},association:function(fixtureName,opts){return function(){return FactoryGuy.build(fixtureName,opts)}},lookupModelForFixtureName:function(name){var definition=this.lookupDefinitionForFixtureName(name);if(definition){return definition.model}},lookupDefinitionForFixtureName:function(name){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];if(definition.matchesName(name)){return definition}}},build:function(){var args=Array.prototype.slice.call(arguments);var opts={};var name=args.shift();if(!name){throw new Error("Build needs a factory name to build")}if(Ember.typeOf(args[args.length-1])=="object"){opts=args.pop()}var traits=args;var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.build(name,opts,traits)},buildList:function(){var args=Array.prototype.slice.call(arguments);var name=args.shift();var number=args.shift();if(!name||!number){throw new Error("buildList needs a name and a number ( at least ) to build with")}var opts={};if(Ember.typeOf(args[args.length-1])=="object"){opts=args.pop()}var traits=args;console.log(name,number,traits+"",opts);var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.buildList(name,number,traits,opts)},resetModels:function(store){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];definition.reset();try{var modelType=store.modelFor(definition.model);if(store.usingFixtureAdapter()){modelType.FIXTURES=[]}store.unloadAll(modelType)}catch(e){}}},pushFixture:function(modelClass,fixture){if(!modelClass["FIXTURES"]){modelClass["FIXTURES"]=[]}modelClass["FIXTURES"].push(fixture);return fixture},clear:function(opts){if(!opts){this.modelDefinitions={}}}};DS.Store.reopen({usingFixtureAdapter:function(){var adapter=this.adapterFor("application");return adapter instanceof DS.FixtureAdapter},makeFixture:function(name,options){var store=this;var modelName=FactoryGuy.lookupModelForFixtureName(name);var fixture=FactoryGuy.build(name,options);var modelType=store.modelFor(modelName);if(this.usingFixtureAdapter()){this.setAssociationsForFixtureAdapter(modelType,modelName,fixture);return FactoryGuy.pushFixture(modelType,fixture)}else{var store=this;var model;Em.run(function(){store.findEmbeddedBelongsToAssociationsForRESTAdapter(modelType,fixture);if(fixture.type){modelName=fixture.type.underscore();modelType=store.modelFor(modelName)}model=store.push(modelName,fixture);store.setAssociationsForRESTAdapter(modelType,modelName,model)});return model}},makeList:function(name,number,options){var arr=[];for(var i=0;i<number;i++){arr.push(this.makeFixture(name,options))}return arr},setAssociationsForFixtureAdapter:function(modelType,modelName,fixture){var self=this;var adapter=this.adapterFor("application");Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){if(fixture[relationship.key]){fixture[relationship.key].forEach(function(id){var hasManyfixtures=adapter.fixturesForType(relationship.type);var fixture=adapter.findFixtureById(hasManyfixtures,id);fixture[modelName]=fixture.id})}}if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(belongsToRecord){if(typeof belongsToRecord=="object"){FactoryGuy.pushFixture(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord.id}var hasManyName=self.findHasManyRelationshipNameForFixtureAdapter(relationship.type,relationship.parentType);var belongsToFixtures=adapter.fixturesForType(relationship.type);var belongsTofixture=adapter.findFixtureById(belongsToFixtures,fixture[relationship.key]);if(!belongsTofixture[hasManyName]){belongsTofixture[hasManyName]=[]}belongsTofixture[hasManyName].push(fixture.id)}}})},findEmbeddedBelongsToAssociationsForRESTAdapter:function(modelType,fixture){var store=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(Ember.typeOf(belongsToRecord)=="object"){belongsToRecord=store.push(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord}}})},setAssociationsForRESTAdapter:function(modelType,modelName,model){var self=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){var children=model.get(name)||[];children.forEach(function(child){var belongsToName=self.findRelationshipName("belongsTo",child.constructor,model);var hasManyName=self.findRelationshipName("hasMany",child.constructor,model);var inverseName=relationship.options&&relationship.options.inverse;if(belongsToName){child.set(belongsToName||inverseName,model)}else if(hasManyName){relation=child.get(hasManyName||inverseName)||[];relation.pushObject(model)}})}if(relationship.kind=="belongsTo"){var belongsToRecord=model.get(name);if(belongsToRecord){var setAssociations=function(){var hasManyName=self.findRelationshipName("hasMany",belongsToRecord.constructor,model);if(hasManyName){belongsToRecord.get(hasManyName).addObject(model);return}var oneToOneName=self.findRelationshipName("belongsTo",belongsToRecord.constructor,model);if(oneToOneName&&!(belongsToRecord.constructor==model.constructor)){belongsToRecord.set(oneToOneName,model)}};if(belongsToRecord.then){belongsToRecord.then(function(record){belongsToRecord=record;setAssociations()})}else{setAssociations()}}}})},findRelationshipName:function(kind,belongToModelType,childModel){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind==kind&&childModel instanceof relationship.type){relationshipName=relationship.key}});return relationshipName},findHasManyRelationshipNameForFixtureAdapter:function(belongToModelType,childModelType){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"&&childModelType==relationship.type){relationshipName=relationship.key}});return relationshipName},pushPayload:function(type,payload){if(this.usingFixtureAdapter()){var model=this.modelFor(modelName);FactoryGuy.pushFixture(model,payload)}else{this._super(type,payload)}}});DS.FixtureAdapter.reopen({createRecord:function(store,type,record){var promise=this._super(store,type,record);promise.then(function(){Em.RSVP.Promise.resolve(Ember.get(type,"relationshipNames")).then(function(relationShips){if(relationShips.belongsTo){relationShips.belongsTo.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);Ember.RSVP.resolve(belongsToRecord.get(hasManyName)).then(function(relationship){relationship.addObject(record)})}})})}if(relationShips.hasMany){relationShips.hasMany.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord&&belongsToRecord.get("length")>0){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);belongsToRecord.forEach(function(child){child.get(hasManyName).addObject(record)})}})})}})});return promise}});FactoryGuyTestMixin=Em.Mixin.create({setup:function(app){this.set("container",app.__container__);return this},useFixtureAdapter:function(app){app.ApplicationAdapter=DS.FixtureAdapter;this.getStore().adapterFor("application").simulateRemoteResponse=false},usingActiveModelSerializer:function(type){var store=this.getStore();var type=store.modelFor(type);var serializer=store.serializerFor(type.typeKey);return serializer instanceof DS.ActiveModelSerializer},find:function(type,id){return this.getStore().find(type,id)},make:function(name,opts){return this.getStore().makeFixture(name,opts)},getStore:function(){return this.get("container").lookup("store:main")},pushPayload:function(type,hash){return this.getStore().pushPayload(type,hash)},pushRecord:function(type,hash){return this.getStore().push(type,hash)},stubEndpointForHttpRequest:function(url,json,options){options=options||{};var request={url:url,dataType:"json",responseText:json,type:options.type||"GET",status:options.status||200};if(options.data){request.data=options.data}$.mockjax(request)},buildAjaxHttpResponse:function(name,opts){var fixture=FactoryGuy.build(name,opts);var modelName=FactoryGuy.lookupModelForFixtureName(name);if(this.usingActiveModelSerializer(modelName)){this.toSnakeCase(fixture)}var hash={};hash[modelName]=fixture;return hash},toSnakeCase:function(fixture){for(key in fixture){if(key!=Em.String.decamelize(key)){var value=fixture[key];delete fixture[key];fixture[Em.String.decamelize(key)]=value}}},handleFind:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var id=responseJson[modelName].id;var url="/"+Em.String.pluralize(modelName)+"/"+id;this.stubEndpointForHttpRequest(url,responseJson,{type:"GET",status:status||200});return responseJson},handleCreate:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var url="/"+Em.String.pluralize(modelName);this.stubEndpointForHttpRequest(url,responseJson,{type:"POST",status:status||200});return responseJson},handleUpdate:function(root,id,status){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"PUT",status:status||200})},handleDelete:function(root,id,status){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"DELETE",status:status||200})},teardown:function(){FactoryGuy.resetModels(this.getStore())}});
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 2 2 | 
             
            Gem::Specification.new do |s|
         | 
| 3 3 | 
             
              s.name        = "ember-data-factory-guy"
         | 
| 4 | 
            -
              s.version     = "0. | 
| 4 | 
            +
              s.version     = "0.5.0"
         | 
| 5 5 | 
             
              s.platform    = Gem::Platform::RUBY
         | 
| 6 6 | 
             
              s.authors     = ["Daniel Sudol", "Alex Opak"]
         | 
| 7 7 | 
             
              s.email       = ["dansudol@yahoo.com", "opak.alexandr@gmail.com"]
         | 
    
        data/package.json
    CHANGED
    
    
    
        data/src/factory_guy.js
    CHANGED
    
    | @@ -140,18 +140,32 @@ FactoryGuy = { | |
| 140 140 | 
             
               Build fixtures for model or specific fixture name. For example:
         | 
| 141 141 |  | 
| 142 142 | 
             
               FactoryGuy.build('user') for User model
         | 
| 143 | 
            -
               FactoryGuy.build('bob') for  | 
| 143 | 
            +
               FactoryGuy.build('bob') for a 'bob' User
         | 
| 144 | 
            +
               FactoryGuy.build('bob', 'dude') for a 'bob' User with dude traits
         | 
| 145 | 
            +
               FactoryGuy.build('bob', 'dude', 'funny') for a 'bob' User with dude and funny traits
         | 
| 146 | 
            +
               FactoryGuy.build('bob', 'dude', name: 'wombat') for a 'bob' User with dude trait and custom attribute name of 'wombat'
         | 
| 144 147 |  | 
| 145 148 | 
             
               @param {String} name Fixture name
         | 
| 149 | 
            +
               @param {String} trait trait name ( can be more than one )
         | 
| 146 150 | 
             
               @param {Object} opts Options that will override default fixture values
         | 
| 147 151 | 
             
               @returns {Object} json fixture
         | 
| 148 152 | 
             
               */
         | 
| 149 | 
            -
              build: function ( | 
| 153 | 
            +
              build: function () {
         | 
| 154 | 
            +
                var args = Array.prototype.slice.call(arguments);
         | 
| 155 | 
            +
                var opts = {}
         | 
| 156 | 
            +
                var name = args.shift();
         | 
| 157 | 
            +
                if (!name) {
         | 
| 158 | 
            +
                  throw new Error("Build needs a factory name to build");
         | 
| 159 | 
            +
                }
         | 
| 160 | 
            +
                if (Ember.typeOf(args[args.length-1]) == 'object') {
         | 
| 161 | 
            +
                  opts  = args.pop();
         | 
| 162 | 
            +
                }
         | 
| 163 | 
            +
                var traits = args; // whatever is left are traits
         | 
| 150 164 | 
             
                var definition = this.lookupDefinitionForFixtureName(name);
         | 
| 151 165 | 
             
                if (!definition) {
         | 
| 152 166 | 
             
                  throw new Error("Can't find that factory named [" + name + "]");
         | 
| 153 167 | 
             
                }
         | 
| 154 | 
            -
                return definition.build(name, opts);
         | 
| 168 | 
            +
                return definition.build(name, opts, traits);
         | 
| 155 169 | 
             
              },
         | 
| 156 170 |  | 
| 157 171 | 
             
              /**
         | 
| @@ -162,15 +176,28 @@ FactoryGuy = { | |
| 162 176 |  | 
| 163 177 | 
             
               @param {String} name fixture name
         | 
| 164 178 | 
             
               @param {Number} number number of fixtures to create
         | 
| 179 | 
            +
               @param {String} trait (one or more)
         | 
| 165 180 | 
             
               @param {Object} opts options that will override default fixture values
         | 
| 166 181 | 
             
               @returns {Array} list of fixtures
         | 
| 167 182 | 
             
               */
         | 
| 168 | 
            -
              buildList: function ( | 
| 183 | 
            +
              buildList: function () {
         | 
| 184 | 
            +
                var args = Array.prototype.slice.call(arguments);
         | 
| 185 | 
            +
                var name = args.shift();
         | 
| 186 | 
            +
                var number = args.shift();
         | 
| 187 | 
            +
                if (!name || !number) {
         | 
| 188 | 
            +
                  throw new Error("buildList needs a name and a number ( at least ) to build with");
         | 
| 189 | 
            +
                }
         | 
| 190 | 
            +
                var opts = {}
         | 
| 191 | 
            +
                if (Ember.typeOf(args[args.length-1]) == 'object') {
         | 
| 192 | 
            +
                  opts  = args.pop();
         | 
| 193 | 
            +
                }
         | 
| 194 | 
            +
                var traits = args; // whatever is left are traits
         | 
| 195 | 
            +
                console.log(name, number, traits+'', opts)
         | 
| 169 196 | 
             
                var definition = this.lookupDefinitionForFixtureName(name);
         | 
| 170 197 | 
             
                if (!definition) {
         | 
| 171 198 | 
             
                  throw new Error("Can't find that factory named [" + name + "]");
         | 
| 172 199 | 
             
                }
         | 
| 173 | 
            -
                return definition.buildList(name, number, opts);
         | 
| 200 | 
            +
                return definition.buildList(name, number, traits, opts);
         | 
| 174 201 | 
             
              },
         | 
| 175 202 |  | 
| 176 203 | 
             
              /**
         | 
    
        data/src/model_definition.js
    CHANGED
    
    | @@ -7,6 +7,7 @@ | |
| 7 7 | 
             
             */
         | 
| 8 8 | 
             
            ModelDefinition = function (model, config) {
         | 
| 9 9 | 
             
              var sequences = {};
         | 
| 10 | 
            +
              var traits = {};
         | 
| 10 11 | 
             
              var defaultAttributes = {};
         | 
| 11 12 | 
             
              var namedModels = {};
         | 
| 12 13 | 
             
              var modelId = 1;
         | 
| @@ -53,12 +54,17 @@ ModelDefinition = function (model, config) { | |
| 53 54 |  | 
| 54 55 | 
             
               @param {String} name fixture name
         | 
| 55 56 | 
             
               @param {Object} opts attributes to override
         | 
| 57 | 
            +
               @param {String} traits array of traits
         | 
| 56 58 | 
             
               @returns {Object} json
         | 
| 57 59 | 
             
               */
         | 
| 58 | 
            -
              this.build = function (name, opts) {
         | 
| 60 | 
            +
              this.build = function (name, opts, traitArgs) {
         | 
| 61 | 
            +
                var traitsObj = {}
         | 
| 62 | 
            +
                traitArgs.forEach(function(trait) {
         | 
| 63 | 
            +
                  $.extend(traitsObj, traits[trait]);
         | 
| 64 | 
            +
                })
         | 
| 59 65 | 
             
                var modelAttributes = namedModels[name] || {};
         | 
| 60 | 
            -
                // merge default, modelAttributes and opts to get the rough fixture
         | 
| 61 | 
            -
                var fixture = $.extend({}, defaultAttributes, modelAttributes, opts);
         | 
| 66 | 
            +
                // merge default, modelAttributes, traits and opts to get the rough fixture
         | 
| 67 | 
            +
                var fixture = $.extend({}, defaultAttributes, modelAttributes, traitsObj, opts);
         | 
| 62 68 | 
             
                // deal with attributes that are functions or objects
         | 
| 63 69 | 
             
                for (attribute in fixture) {
         | 
| 64 70 | 
             
                  if (Ember.typeOf(fixture[attribute]) == 'function') {
         | 
| @@ -82,13 +88,14 @@ ModelDefinition = function (model, config) { | |
| 82 88 |  | 
| 83 89 | 
             
               @param {String} name model name or named model type
         | 
| 84 90 | 
             
               @param {Integer} number of fixtures to build
         | 
| 91 | 
            +
               @param {Array} array of traits to build with
         | 
| 85 92 | 
             
               @param {Object} opts attribute options
         | 
| 86 93 | 
             
               @returns array of fixtures
         | 
| 87 94 | 
             
               */
         | 
| 88 | 
            -
              this.buildList = function (name, number, opts) {
         | 
| 95 | 
            +
              this.buildList = function (name, number, traits, opts) {
         | 
| 89 96 | 
             
                var arr = [];
         | 
| 90 97 | 
             
                for (var i = 0; i < number; i++) {
         | 
| 91 | 
            -
                  arr.push(this.build(name, opts))
         | 
| 98 | 
            +
                  arr.push(this.build(name, opts, traits));
         | 
| 92 99 | 
             
                }
         | 
| 93 100 | 
             
                return arr;
         | 
| 94 101 | 
             
              }
         | 
| @@ -108,13 +115,25 @@ ModelDefinition = function (model, config) { | |
| 108 115 | 
             
                defaultAttributes = object;
         | 
| 109 116 | 
             
              }
         | 
| 110 117 |  | 
| 118 | 
            +
              var parseTraits = function (object) {
         | 
| 119 | 
            +
                if (!object) {
         | 
| 120 | 
            +
                  return
         | 
| 121 | 
            +
                }
         | 
| 122 | 
            +
            //    for (trait in object) {
         | 
| 123 | 
            +
            //      var trait = object[trait];
         | 
| 124 | 
            +
            //      if (Ember.typeOf(trait) == 'function') {}
         | 
| 125 | 
            +
            //      object[trait] = new Trait(trait);
         | 
| 126 | 
            +
            //    }
         | 
| 127 | 
            +
                traits = object;
         | 
| 128 | 
            +
              }
         | 
| 129 | 
            +
             | 
| 111 130 | 
             
              var parseSequences = function (object) {
         | 
| 112 131 | 
             
                if (!object) {
         | 
| 113 132 | 
             
                  return
         | 
| 114 133 | 
             
                }
         | 
| 115 134 | 
             
                for (sequenceName in object) {
         | 
| 116 135 | 
             
                  var sequenceFn = object[sequenceName];
         | 
| 117 | 
            -
                  if ( | 
| 136 | 
            +
                  if (Ember.typeOf(sequenceFn) != 'function') {
         | 
| 118 137 | 
             
                    throw new Error('Problem with [' + sequenceName + '] sequence definition. Sequences must be functions')
         | 
| 119 138 | 
             
                  }
         | 
| 120 139 | 
             
                  object[sequenceName] = new Sequence(sequenceFn);
         | 
| @@ -126,6 +145,9 @@ ModelDefinition = function (model, config) { | |
| 126 145 | 
             
                parseSequences(config.sequences);
         | 
| 127 146 | 
             
                delete config.sequences;
         | 
| 128 147 |  | 
| 148 | 
            +
                parseTraits(config.traits);
         | 
| 149 | 
            +
                delete config.traits;
         | 
| 150 | 
            +
             | 
| 129 151 | 
             
                parseDefault(config.default);
         | 
| 130 152 | 
             
                delete config.default;
         | 
| 131 153 |  | 
    
        data/tests/factory_guy_test.js
    CHANGED
    
    | @@ -100,6 +100,30 @@ test("Using associations in attribute definition", function() { | |
| 100 100 | 
             
            });
         | 
| 101 101 |  | 
| 102 102 |  | 
| 103 | 
            +
            test("#build with traits", function() {
         | 
| 104 | 
            +
              var json = FactoryGuy.build('project', 'big');
         | 
| 105 | 
            +
              deepEqual(json, {id: 1, title: 'Big Project'}, 'trait with model attributes');
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              var json = FactoryGuy.build('project', 'with_user');
         | 
| 108 | 
            +
              deepEqual(json, {id: 2, title: 'Project1', user: {id: 1, name: 'User1'}}, 'trait with belongsTo attributes');
         | 
| 109 | 
            +
             | 
| 110 | 
            +
              var json = FactoryGuy.build('project', 'big', 'with_user');
         | 
| 111 | 
            +
              deepEqual(json, {id: 3, title: 'Big Project', user: {id: 2, name: 'User1'}}, 'more than one trait used together');
         | 
| 112 | 
            +
             | 
| 113 | 
            +
              var json = FactoryGuy.build('project', 'big', 'with_user', {title: 'Crazy Project'});
         | 
| 114 | 
            +
              deepEqual(json, {id: 4, title: 'Crazy Project', user: {id: 3, name: 'User1'}}, 'more than one trait used together with custom attributes');
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              var json = FactoryGuy.build('project', 'big', 'with_dude');
         | 
| 117 | 
            +
              deepEqual(json, {id: 5, title: 'Big Project', user: {id: 4, name: 'Dude'}}, 'trait with custom belongsTo association object');
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              var json = FactoryGuy.build('project', 'with_admin');
         | 
| 120 | 
            +
              deepEqual(json, {id: 6, title: 'Project2', user: {id: 5, name: 'Admin'}}, 'trait with attribute using FactoryGuy.association method');
         | 
| 121 | 
            +
             | 
| 122 | 
            +
              var json = FactoryGuy.build('project', 'with_title_sequence');
         | 
| 123 | 
            +
              deepEqual(json, {id: 7, title: 'Project3'}, 'trait with attribute using sequence');
         | 
| 124 | 
            +
            });
         | 
| 125 | 
            +
             | 
| 126 | 
            +
             | 
| 103 127 | 
             
            test("#build creates default json for model", function() {
         | 
| 104 128 | 
             
              var json = FactoryGuy.build('user');
         | 
| 105 129 | 
             
              deepEqual(json, {id: 1, name: 'User1'});
         | 
| @@ -138,6 +162,15 @@ test("#buildList creates list of fixtures", function() { | |
| 138 162 | 
             
              var userList = FactoryGuy.buildList('user', 2);
         | 
| 139 163 | 
             
              deepEqual(userList[0], {id: 1, name: 'User1'});
         | 
| 140 164 | 
             
              deepEqual(userList[1], {id: 2, name: 'User1'});
         | 
| 165 | 
            +
             | 
| 166 | 
            +
              var userList = FactoryGuy.buildList('user', 1, {name: 'Crazy'});
         | 
| 167 | 
            +
              deepEqual(userList[0], {id: 3, name: 'Crazy'},'using custom attributes');
         | 
| 168 | 
            +
             | 
| 169 | 
            +
              var projectList = FactoryGuy.buildList('project', 1, 'big');
         | 
| 170 | 
            +
              deepEqual(projectList[0], {id: 1, title: 'Big Project'}, 'using traits');
         | 
| 171 | 
            +
             | 
| 172 | 
            +
              var projectList = FactoryGuy.buildList('project', 1, 'big', {title: 'Really Big'});
         | 
| 173 | 
            +
              deepEqual(projectList[0], {id: 2, title: 'Really Big'}, 'using traits and custom attributes');
         | 
| 141 174 | 
             
            });
         | 
| 142 175 |  | 
| 143 176 |  | 
| @@ -2,6 +2,13 @@ FactoryGuy.define('project', { | |
| 2 2 | 
             
              sequences: {
         | 
| 3 3 | 
             
                title: function(num) {return 'Project' + num}
         | 
| 4 4 | 
             
              },
         | 
| 5 | 
            +
              traits: {
         | 
| 6 | 
            +
                big: { title: 'Big Project' },
         | 
| 7 | 
            +
                with_title_sequence: { title: FactoryGuy.generate('title') },
         | 
| 8 | 
            +
                with_user: { user: {} },
         | 
| 9 | 
            +
                with_dude: { user: {name: 'Dude'} },
         | 
| 10 | 
            +
                with_admin: { user: FactoryGuy.association('admin') }
         | 
| 11 | 
            +
              },
         | 
| 5 12 | 
             
              default: {
         | 
| 6 13 | 
             
                title: FactoryGuy.generate('title')
         | 
| 7 14 | 
             
              },
         | 
    
        data/tests/test_setup.js
    CHANGED
    
    | @@ -29,6 +29,13 @@ FactoryGuy.define('project', { | |
| 29 29 | 
             
              sequences: {
         | 
| 30 30 | 
             
                title: function(num) {return 'Project' + num}
         | 
| 31 31 | 
             
              },
         | 
| 32 | 
            +
              traits: {
         | 
| 33 | 
            +
                big: { title: 'Big Project' },
         | 
| 34 | 
            +
                with_title_sequence: { title: FactoryGuy.generate('title') },
         | 
| 35 | 
            +
                with_user: { user: {} },
         | 
| 36 | 
            +
                with_dude: { user: {name: 'Dude'} },
         | 
| 37 | 
            +
                with_admin: { user: FactoryGuy.association('admin') }
         | 
| 38 | 
            +
              },
         | 
| 32 39 | 
             
              default: {
         | 
| 33 40 | 
             
                title: FactoryGuy.generate('title')
         | 
| 34 41 | 
             
              },
         | 
| @@ -23,6 +23,7 @@ function MissingSequenceError(message) { | |
| 23 23 | 
             
             */
         | 
| 24 24 | 
             
            ModelDefinition = function (model, config) {
         | 
| 25 25 | 
             
              var sequences = {};
         | 
| 26 | 
            +
              var traits = {};
         | 
| 26 27 | 
             
              var defaultAttributes = {};
         | 
| 27 28 | 
             
              var namedModels = {};
         | 
| 28 29 | 
             
              var modelId = 1;
         | 
| @@ -69,12 +70,17 @@ ModelDefinition = function (model, config) { | |
| 69 70 |  | 
| 70 71 | 
             
               @param {String} name fixture name
         | 
| 71 72 | 
             
               @param {Object} opts attributes to override
         | 
| 73 | 
            +
               @param {String} traits array of traits
         | 
| 72 74 | 
             
               @returns {Object} json
         | 
| 73 75 | 
             
               */
         | 
| 74 | 
            -
              this.build = function (name, opts) {
         | 
| 76 | 
            +
              this.build = function (name, opts, traitArgs) {
         | 
| 77 | 
            +
                var traitsObj = {}
         | 
| 78 | 
            +
                traitArgs.forEach(function(trait) {
         | 
| 79 | 
            +
                  $.extend(traitsObj, traits[trait]);
         | 
| 80 | 
            +
                })
         | 
| 75 81 | 
             
                var modelAttributes = namedModels[name] || {};
         | 
| 76 | 
            -
                // merge default, modelAttributes and opts to get the rough fixture
         | 
| 77 | 
            -
                var fixture = $.extend({}, defaultAttributes, modelAttributes, opts);
         | 
| 82 | 
            +
                // merge default, modelAttributes, traits and opts to get the rough fixture
         | 
| 83 | 
            +
                var fixture = $.extend({}, defaultAttributes, modelAttributes, traitsObj, opts);
         | 
| 78 84 | 
             
                // deal with attributes that are functions or objects
         | 
| 79 85 | 
             
                for (attribute in fixture) {
         | 
| 80 86 | 
             
                  if (Ember.typeOf(fixture[attribute]) == 'function') {
         | 
| @@ -98,13 +104,14 @@ ModelDefinition = function (model, config) { | |
| 98 104 |  | 
| 99 105 | 
             
               @param {String} name model name or named model type
         | 
| 100 106 | 
             
               @param {Integer} number of fixtures to build
         | 
| 107 | 
            +
               @param {Array} array of traits to build with
         | 
| 101 108 | 
             
               @param {Object} opts attribute options
         | 
| 102 109 | 
             
               @returns array of fixtures
         | 
| 103 110 | 
             
               */
         | 
| 104 | 
            -
              this.buildList = function (name, number, opts) {
         | 
| 111 | 
            +
              this.buildList = function (name, number, traits, opts) {
         | 
| 105 112 | 
             
                var arr = [];
         | 
| 106 113 | 
             
                for (var i = 0; i < number; i++) {
         | 
| 107 | 
            -
                  arr.push(this.build(name, opts))
         | 
| 114 | 
            +
                  arr.push(this.build(name, opts, traits))
         | 
| 108 115 | 
             
                }
         | 
| 109 116 | 
             
                return arr;
         | 
| 110 117 | 
             
              }
         | 
| @@ -124,13 +131,25 @@ ModelDefinition = function (model, config) { | |
| 124 131 | 
             
                defaultAttributes = object;
         | 
| 125 132 | 
             
              }
         | 
| 126 133 |  | 
| 134 | 
            +
              var parseTraits = function (object) {
         | 
| 135 | 
            +
                if (!object) {
         | 
| 136 | 
            +
                  return
         | 
| 137 | 
            +
                }
         | 
| 138 | 
            +
            //    for (trait in object) {
         | 
| 139 | 
            +
            //      var trait = object[trait];
         | 
| 140 | 
            +
            //      if (Ember.typeOf(trait) == 'function') {}
         | 
| 141 | 
            +
            //      object[trait] = new Trait(trait);
         | 
| 142 | 
            +
            //    }
         | 
| 143 | 
            +
                traits = object;
         | 
| 144 | 
            +
              }
         | 
| 145 | 
            +
             | 
| 127 146 | 
             
              var parseSequences = function (object) {
         | 
| 128 147 | 
             
                if (!object) {
         | 
| 129 148 | 
             
                  return
         | 
| 130 149 | 
             
                }
         | 
| 131 150 | 
             
                for (sequenceName in object) {
         | 
| 132 151 | 
             
                  var sequenceFn = object[sequenceName];
         | 
| 133 | 
            -
                  if ( | 
| 152 | 
            +
                  if (Ember.typeOf(sequenceFn) != 'function') {
         | 
| 134 153 | 
             
                    throw new Error('Problem with [' + sequenceName + '] sequence definition. Sequences must be functions')
         | 
| 135 154 | 
             
                  }
         | 
| 136 155 | 
             
                  object[sequenceName] = new Sequence(sequenceFn);
         | 
| @@ -142,6 +161,9 @@ ModelDefinition = function (model, config) { | |
| 142 161 | 
             
                parseSequences(config.sequences);
         | 
| 143 162 | 
             
                delete config.sequences;
         | 
| 144 163 |  | 
| 164 | 
            +
                parseTraits(config.traits);
         | 
| 165 | 
            +
                delete config.traits;
         | 
| 166 | 
            +
             | 
| 145 167 | 
             
                parseDefault(config.default);
         | 
| 146 168 | 
             
                delete config.default;
         | 
| 147 169 |  | 
| @@ -293,18 +315,32 @@ FactoryGuy = { | |
| 293 315 | 
             
               Build fixtures for model or specific fixture name. For example:
         | 
| 294 316 |  | 
| 295 317 | 
             
               FactoryGuy.build('user') for User model
         | 
| 296 | 
            -
               FactoryGuy.build('bob') for  | 
| 318 | 
            +
               FactoryGuy.build('bob') for a 'bob' User
         | 
| 319 | 
            +
               FactoryGuy.build('bob', 'dude') for a 'bob' User with dude traits
         | 
| 320 | 
            +
               FactoryGuy.build('bob', 'dude', 'funny') for a 'bob' User with dude and funny traits
         | 
| 321 | 
            +
               FactoryGuy.build('bob', 'dude', name: 'wombat') for a 'bob' User with dude trait and custom attribute name of 'wombat'
         | 
| 297 322 |  | 
| 298 323 | 
             
               @param {String} name Fixture name
         | 
| 324 | 
            +
               @param {String} trait trait name ( can be more than one )
         | 
| 299 325 | 
             
               @param {Object} opts Options that will override default fixture values
         | 
| 300 326 | 
             
               @returns {Object} json fixture
         | 
| 301 327 | 
             
               */
         | 
| 302 | 
            -
              build: function ( | 
| 328 | 
            +
              build: function () {
         | 
| 329 | 
            +
                var args = Array.prototype.slice.call(arguments);
         | 
| 330 | 
            +
                var opts = {}
         | 
| 331 | 
            +
                var name = args.shift();
         | 
| 332 | 
            +
                if (!name) {
         | 
| 333 | 
            +
                  throw new Error("Build needs a factory name to build");
         | 
| 334 | 
            +
                }
         | 
| 335 | 
            +
                if (Ember.typeOf(args[args.length-1]) == 'object') {
         | 
| 336 | 
            +
                  opts  = args.pop();
         | 
| 337 | 
            +
                }
         | 
| 338 | 
            +
                var traits = args; // whatever is left are traits
         | 
| 303 339 | 
             
                var definition = this.lookupDefinitionForFixtureName(name);
         | 
| 304 340 | 
             
                if (!definition) {
         | 
| 305 341 | 
             
                  throw new Error("Can't find that factory named [" + name + "]");
         | 
| 306 342 | 
             
                }
         | 
| 307 | 
            -
                return definition.build(name, opts);
         | 
| 343 | 
            +
                return definition.build(name, opts, traits);
         | 
| 308 344 | 
             
              },
         | 
| 309 345 |  | 
| 310 346 | 
             
              /**
         | 
| @@ -315,15 +351,28 @@ FactoryGuy = { | |
| 315 351 |  | 
| 316 352 | 
             
               @param {String} name fixture name
         | 
| 317 353 | 
             
               @param {Number} number number of fixtures to create
         | 
| 354 | 
            +
               @param {String} trait (one or more)
         | 
| 318 355 | 
             
               @param {Object} opts options that will override default fixture values
         | 
| 319 356 | 
             
               @returns {Array} list of fixtures
         | 
| 320 357 | 
             
               */
         | 
| 321 | 
            -
              buildList: function ( | 
| 358 | 
            +
              buildList: function () {
         | 
| 359 | 
            +
                var args = Array.prototype.slice.call(arguments);
         | 
| 360 | 
            +
                var name = args.shift();
         | 
| 361 | 
            +
                var number = args.shift();
         | 
| 362 | 
            +
                if (!name || !number) {
         | 
| 363 | 
            +
                  throw new Error("buildList needs a name and a number ( at least ) to build with");
         | 
| 364 | 
            +
                }
         | 
| 365 | 
            +
                var opts = {}
         | 
| 366 | 
            +
                if (Ember.typeOf(args[args.length-1]) == 'object') {
         | 
| 367 | 
            +
                  opts  = args.pop();
         | 
| 368 | 
            +
                }
         | 
| 369 | 
            +
                var traits = args; // whatever is left are traits
         | 
| 370 | 
            +
                console.log(name, number, traits+'', opts)
         | 
| 322 371 | 
             
                var definition = this.lookupDefinitionForFixtureName(name);
         | 
| 323 372 | 
             
                if (!definition) {
         | 
| 324 373 | 
             
                  throw new Error("Can't find that factory named [" + name + "]");
         | 
| 325 374 | 
             
                }
         | 
| 326 | 
            -
                return definition.buildList(name, number, opts);
         | 
| 375 | 
            +
                return definition.buildList(name, number, traits, opts);
         | 
| 327 376 | 
             
              },
         | 
| 328 377 |  | 
| 329 378 | 
             
              /**
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ember-data-factory-guy
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Daniel Sudol
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2014- | 
| 12 | 
            +
            date: 2014-08-01 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies: []
         | 
| 14 14 | 
             
            description: Easily create Fixtures for Ember Data
         | 
| 15 15 | 
             
            email:
         |