Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

added callback style functions for attributes

  • Loading branch information...
commit 9bf86ff2988af3eeb8a2ba5b5ea60cb1e3b2375a 1 parent 10b1567
Gregor Melhorn gregormelhorn authored
26 README.md
Source Rendered
@@ -23,7 +23,7 @@ To begin, we need to define our Factory. We do this with the Factory.define met
23 23 "created_at": function(){
24 24 return new Date();
25 25 }
26   - })
  26 + });
27 27 ```
28 28
29 29 In the example above, we've created the "profile" Factory for the class Profile with our default attributes.
@@ -31,9 +31,29 @@ In the example above, we've created the "profile" Factory for the class Profile
31 31 The "created_at" attribute will be filled dynamically by evaluating the function at object build time. This is useful to dynamically fill attributes with a name generator, e.g. https://github.com/marak/Faker.js/
32 32
33 33
34   -*build(factory, [attributes])*
  34 +*build(factory, [attributes], [callback])*
35 35
36   -Builds an instance of the factory, overriding the factory with the attributes hash if passed.
  36 +Builds an instance of the factory, overriding the factory with the attributes hash if passed.
  37 +
  38 +If a callback is passed, it is possible to use callback functions for building attributes. The callback is detected by checking if the attribute function will accept arguments. Here is an example that will create
  39 +BlogEntry for a Comment object and set the foreign key accordingly.
  40 +
  41 +```js
  42 + var Factory = require('factory-worker');
  43 +
  44 + Factory.define("comment", Comment, {
  45 + "text": "Comment text",
  46 + "blogEntry": function(callback){
  47 + Factory.create("BlogEntry", function(err, entry){
  48 + callback(err, entry._id);
  49 + });
  50 + }
  51 + });
  52 +
  53 + Factory.build("comment", {text: "some other comment text"}, function(err, comment){
  54 + console.log(err, comment);
  55 + });
  56 +```
37 57
38 58 *create(factory, [attributes], callback)*
39 59
75 index.js
... ... @@ -1,4 +1,5 @@
1 1 var Hash = require('hashish');
  2 +var Seq = require('seq');
2 3
3 4 module.exports = {
4 5 patterns: {},
@@ -8,32 +9,76 @@ module.exports = {
8 9 attributes: def
9 10 }
10 11 },
11   - build: function(model, data) {
  12 + build: function(model, data, callback) {
  13 + if (typeof(data) == 'function'){
  14 + callback = data;
  15 + data = {}
  16 + }
  17 +
12 18 if (data === undefined) {
13 19 data = {}
14 20 }
15 21
16 22 var attributes = this.patterns[model].attributes
17 23 var values = Hash.merge(attributes, data);
18   - values = Hash.map(values, function(value, key){
19   - if (typeof(value) == 'function'){
20   - return value.call(data);
21   - } else {
22   - return value;
23   - }
24   - });
25   - var obj = new(this.patterns[model].class)(values);
26   - return obj;
  24 + // no callback given so use direct style
  25 + if (callback === undefined){
  26 + values = Hash.map(values, function(value, key){
  27 + if (typeof(value) == 'function'){
  28 + if (value.length > 0){
  29 + throw('you need to pass a callback to the build function - setter for attribute "' + key + '" is asynchronous');
  30 + } else {
  31 + return value.call();
  32 + }
  33 + } else {
  34 + return value;
  35 + }
  36 + });
  37 + var obj = new(this.patterns[model].class)(values);
  38 + return obj;
  39 + } else {
  40 + // callback given, convert everything to function style
  41 + callbacks = []
  42 + Hash.forEach(values, function(value, key){
  43 + if (typeof(value) == 'function'){
  44 + if (value.length == 0){
  45 + callbacks.push({key: key, cbk: function(cbk){
  46 + return cbk(null, value.call());
  47 + }});
  48 + } else {
  49 + callbacks.push({key: key, cbk: value});
  50 + }
  51 + } else {
  52 + callbacks.push({key: key, cbk: function(cbk){
  53 + return cbk(null, value);
  54 + }});
  55 + }
  56 + });
  57 + Seq(callbacks)
  58 + .parEach(function(value){
  59 + value.cbk(this.into(value.key));
  60 + })
  61 + .seq(function(){
  62 + var obj = new(module.exports.patterns[model].class)(this.vars);
  63 + callback(null, obj);
  64 + })
  65 + .catch(function(err){
  66 + callback(err);
  67 + });
  68 + }
27 69 },
28 70 create: function(model, data, callback) {
29 71 if (typeof(data) == 'function') {
30 72 callback = data;
31   - data = {}
  73 + data = {};
32 74 }
33 75
34   - var obj = this.build(model, data)
35   - obj.save(function(error) {
36   - callback(error, obj)
37   - })
  76 + this.build(model, data, function(err, obj){
  77 + if (err)
  78 + throw(err);
  79 + obj.save(function(error) {
  80 + callback(error, obj);
  81 + })
  82 + });
38 83 }
39 84 }
1  package.json
@@ -17,6 +17,7 @@
17 17 },
18 18 "dependencies": {
19 19 "hashish": ">=0.0.3"
  20 + , "seq": ">= 0.3.5"
20 21 },
21 22 "devDependencies": {
22 23 "jessie": ">=0.3.7"
57 spec/factory_spec.js
@@ -4,17 +4,23 @@ describe('Factory#define', function() {
4 4 return "dynamic";
5 5 }
6 6
  7 + callback_function = function(callback){
  8 + return callback(null, 'called');
  9 + }
  10 +
7 11 Factory.define('test', TestModel, {
8 12 name: 'Test Model',
9 13 real: false,
10   - dynamic: dynamic_function})
  14 + dynamic: dynamic_function,
  15 + called: callback_function})
11 16
12 17 expect(Factory.patterns.test).toEqual({
13 18 class: TestModel,
14 19 attributes: {
15 20 name: 'Test Model',
16 21 real: false,
17   - dynamic: dynamic_function
  22 + dynamic: dynamic_function,
  23 + called: callback_function
18 24 }
19 25 })
20 26 })
@@ -32,19 +38,46 @@ describe('Factory#build', function() {
32 38 })
33 39
34 40 it('uses the stored definition to seed attribute values', function() {
35   - object = Factory.build('test')
  41 + var object = Factory.build('test')
36 42 expect(object.name).toEqual('Test Model')
37 43 expect(object.real).toEqual(false)
38 44 expect(object.dynamic).toEqual("dynamic")
39 45 })
40 46
41 47 it('takes an optional parameter to override stores attributes', function() {
42   - object = Factory.build('test', { real: true })
  48 + var object = Factory.build('test', { real: true })
43 49 expect(object.name).toEqual('Test Model')
44 50 expect(object.real).toEqual(true)
45 51 })
46 52 })
47 53
  54 +describe('Factory#build_with_callback', function() {
  55 + beforeEach(function() {
  56 + Factory.define('test_callback', TestModel, {
  57 + called: function(cbk) {
  58 + return cbk(null, 'called');
  59 + }
  60 + })
  61 + })
  62 +
  63 + it('uses the stored definition to seed attribute values', function() {
  64 + var object = null;
  65 + Factory.build('test_callback', function(err, obj){
  66 + object = obj;
  67 + });
  68 + waitsFor(function() { return object != null}, 'object creation failed', 1000);
  69 + runs(function(){
  70 + expect(object.called).toEqual("called");
  71 + });
  72 + })
  73 +
  74 + it("throws an error if no callback is given", function(){
  75 + expect(function(){
  76 + Factory.build('test_callback');
  77 + }).toThrow('you need to pass a callback to the build function - setter for attribute "called" is asynchronous');
  78 + });
  79 +})
  80 +
48 81 describe('Factory#create', function() {
49 82 beforeEach(function() {
50 83 Factory.define('test', TestModel, {
@@ -52,25 +85,23 @@ describe('Factory#create', function() {
52 85 real: false,
53 86 dynamic: function() {
54 87 return "dynamic";
  88 + },
  89 + called: function(cbk) {
  90 + return cbk(null, 'called');
55 91 }
56   - })
57   - })
58   -
59   - it('should call Factory.build, passing the factory name and data', function() {
60   - spyOn(Factory, 'build').andCallThrough()
61   - Factory.create('test', function(error) {})
62   - expect(Factory.build).toHaveBeenCalledWith('test', {})
  92 + })
63 93 })
64 94
65   - it('can also override attributes like Factory#build', function() {
  95 + it('should override attributes like Factory#build', function() {
66 96 var object;
67   - Factory.create('test', { name: function(){return 'Test Object';}, dynamic: "another value" }, function(e, o) {
  97 + Factory.create('test', { name: function(){return 'Test Object';}, dynamic: "another value", called: function(cbk){return cbk(null, 'new value');} }, function(e, o) {
68 98 object = o;
69 99 })
70 100 waitsFor(function() { return object != null}, 'object creation failed', 1000);
71 101 runs(function() {
72 102 expect(object.name).toEqual('Test Object');
73 103 expect(object.dynamic).toEqual('another value');
  104 + expect(object.called).toEqual('new value');
74 105 })
75 106 })
76 107 })
1  spec/spec_helper.js
@@ -3,6 +3,7 @@ TestModel = function TestModel(attributes) {
3 3 this.name = attributes.name;
4 4 this.real = attributes.real;
5 5 this.dynamic = attributes.dynamic;
  6 + this.called = attributes.called;
6 7 }
7 8 TestModel.prototype.save = function(callback) {
8 9 callback(null)

0 comments on commit 9bf86ff

Please sign in to comment.
Something went wrong with that request. Please try again.