Unable to use Mongoose Object Methods from non-Mongoose Object - javascript

Suppose we have a Mongoose object Foo.js.
var mongoose = require('mongoose');
var Bar = require('/path/to/bar');
var Foo = mongoose.Schema({});
Foo.statics.hello = function() {
console.log('hello from foo');
};
Foo.statics.useBar = function() {
Bar.hello();
};
module.exports = mongoose.model('Foo', Foo);
As well as a regular javascript object Bar.js.
var Foo = require('/path/to/foo');
var Bar = function() {};
Bar.hello = function() {
console.log('hello from bar');
};
Bar.useFoo = function() {
Foo.hello();
};
module.exports = Bar;
If we wanted to call methods in Bar from Foo, everything would be fine. Yet, if we wanted to call methods in Foo from Bar, we would receive an error.
app.use('/test', function(req, res, next) {
var Foo = require('/path/to/foo');
var Bar = require('/path/to/bar');
Foo.hello();
Bar.hello();
Foo.useBar();
Bar.useFoo();
});
The above yields:
hello from foo
hello from bar
hello from bar
TypeError: Foo.hello is not a function
Why does this happen?
Additionally, how do I create an object Bar that can call methods from Foo, but at the same time is not meant to be - and cannot be - persisted into mongodb?

The problem you are experiencing is circular/cyclic dependencies in node.js. It gives you an empty object.
If you change Bar.js like this:
var Bar = function() {};
module.exports = Bar;
var Foo = require('/path/to/foo');
Bar.hello = function() {
console.log('hello from bar');
};
Bar.useFoo = function() {
Foo.hello();
};
and then swap the order in app.use to
var Bar = require('/path/to/bar');
var Foo = require('/path/to/foo');
it works for me.
Look at this answer for more information: How to deal with cyclic dependencies in Node.js

Related

How to mock a function defined with this keyword using sinon?

I have a function foo
var foo = function(){
this.doRandomStuff = function(callback){
//do Something
callback(false);
}
}
var bar = function(){
var fooInstance = new foo();
fooInstance.doRandomStuff(function(val){
//do Something with val
})
}
I want to write test for bar function and I am using mocha and sinon for this.
describe("Foo Test",function(){
it("testing foo",function(done){
var instance = new foo();
sinon.stub(instance,'doRandomStuff').callsArgWith(0,true); // This Doesn't work
sinon.stub(foo,'doRandomStuff').callsArgWith(0,true); // This also Doesn't work
bar();
done();
})
});
I get below Exception :
TypeError: Cannot stub non-existent own property doRandomStuff
Alternative approach to make it more testable is module approach as below:
foo.js
function doRandomStuff(callback) {
callback(false);
}
module.exports = {
doRandomStuff
}
bar.js
const foo = require('./foo');
module.exports = function() {
foo.doRandomStuff(function(val) {
console.log('test val', val); // for testing purpose
})
}
test.js
const sinon = require('sinon');
const foo = require('./foo');
const bar = require('./bar');
describe('Foo Test', function() {
it("testing foo",function(done){
sinon.stub(foo, 'doRandomStuff').callsArgWith(0,true);
bar(); // output: "test val true"
done();
});
});

Module pattern: setting module-wide arrays

Despite having read all the usual tutorials on the Javascript module pattern, there's still something about scoping which I clearly don't understand.
pushing to a module-wide list does what I'd expect it to do. Setting a module-wide list with = doesn't. What am I doing wrong here?
var MODULE = MODULE || {};
MODULE.Submodule = (function(){
var foo = [],
bar = [];
var init = function() {
foo = ['a','b','c']; // This doesn't set MODULE.Submodule.foo
bar.push('a'); // But this works as expected
console.log('foo: ' + MODULE.Submodule.foo); // foo:
console.log('bar: ' + MODULE.Submodule.bar); // bar: a
}
return {
init: init,
foo: foo,
bar: bar
}
}());
MODULE.Submodule.init();
This JSFiddle http://jsfiddle.net/SwBLk/1/ may help explain what's happening:
var MODULE = MODULE || {};
MODULE.Submodule = (function(){
var foo = [],
bar = [];
var init = function() {
console.log(MODULE.Submodule.foo === foo);
foo = ['a','b','c']; // This doesn't set MODULE.Submodule.foo
console.log(MODULE.Submodule.foo === foo);
bar.push('a'); // But this works as expected
console.log('foo: ' + MODULE.Submodule.foo); // foo:
console.log('bar: ' + MODULE.Submodule.bar); // bar: a
}
return {
init: init,
foo: foo,
bar: bar
}
}());
MODULE.Submodule.init();
The first boolean check return TRUE because both objects reference the same object.
The second boolean check returns FALSE because you have replaced foo with a new object and the references don't point to the same underlying object anymore.
You are replacing the foo array with a reference to a new array when you re-assign a new array to it.
When you execute the IIFE, you assign a reference to a very specific version of "foo" on the return statement. That is the reference you then access when you call MODULE.Submodule.foo. When you go in and replace foo = [ "a", ... ], you are replacing the object foo, but not replacing the reference to it in the MODULE.Submodule object.
EDIT: How do you get around this issue?
1) Ideally, you don't replace the entire array, but only clear & re-initialize it on init() call:
MODULE.Submodule = (function(){
var foo = [],
bar = [];
var init = function() {
// Clear our the array if it already contains data (in case your calling "init" more than once)
// This method is documented to be the fastest way to clear out an array, referenced here:
// http://stackoverflow.com/questions/1232040/how-to-empty-an-array-in-javascript
while(foo.length > 0) {
foo.pop();
}
foo.push('a');
foo.push('b');
foo.push('c');
bar.push('a'); // But this works as expected
console.log('foo: ' + MODULE.Submodule.foo); // foo:
console.log('bar: ' + MODULE.Submodule.bar); // bar: a
}
2) Your second option is to use what I'd call "dynamic getters" (working fiddle: http://jsfiddle.net/6zVcP/):
var MODULE = MODULE || {};
MODULE.Submodule = (function(){
var foo = [],
bar = [];
var init = function() {
foo = ['a','b','c']; // This doesn't set MODULE.Submodule.foo
bar.push('a'); // But this works as expected
console.log('foo: ' + MODULE.Submodule.foo()); // foo:
console.log('bar: ' + MODULE.Submodule.bar()); // bar: a
}
var modify = function()
{
foo = [];
foo.push("test");
}
return {
init: init,
modifyArrays: modify,
foo: function() { return foo; },
bar: function() { return bar; }
}
}());
MODULE.Submodule.init();
MODULE.Submodule.modifyArrays();
console.log(MODULE.Submodule.foo());
This allows you to do whatever you want to the foo object while the getter will always return the latest reference.

Callback when 'class' instance is created

var foo = (function(){
var c = function(requests) {
bar();
};
c.prototype = {
bar: bar
};
return c;
})();
var f = new foo();
f.baz(function(){
console.log('new instance of foo created');
});
http://jsfiddle.net/LecJM/
I would like to create a callback function which is called when a new instance of the "class" foo is created. Is this possible? Obviously the code above won't compile, I just want to give you an idea of what I'm trying to achieve.
var Foo = function (createdCallback) {
createdCallback();
return this;
};
var bar = new Foo(function () {
console.log("instance created");
});
Is this what you want to achieve?
Something like this?
var foo = (function(){
var c = function(requests) {
// Initialize your instance
// ...
// Notify
notifyCreated(this);
};
c.prototype = { ... };
var createdCallbacks = [];
c.onCreate = function(callback) {
createdCallbacks.push(callback);
}
function notifyCreated(instance) {
// Note: forEach requires ES5 or a shim
// Just use whatever you want to loop over the array
createdCallbacks.forEach(function(callback) {
callback(instance);
});
}
return c;
})();
// Add callback *before* creating instances
foo.onCreate(function(instance){
console.log('new instance of foo created', instance);
});
// Create an instance
var f = new foo();
Basically, you add a method to foo (and not to foo.prototype) to add a callback. Inside your constructor, you call all registered callbacks (here demonstrated with a separate internal function). To use, you first register a callback and then start creating instances.
EDIT: As requested, with just one callback:
var foo = (function(){
var c = function(requests) {
// Initialize your instance
// ...
// Notify
notifyCreated(this);
};
c.prototype = { ... };
// Use a dummy callback by default
var notifyCreated = function(){};
c.onCreate = function(callback) {
notifyCreated = callback;
}
return c;
})();
Demo
EDIT 2: Heck, if you're only going to need one callback, you might as well get rid of the onCreate function and just expose the callback as a variable. There are a few downsides to this though:
You can't do input checking, for example you can't test if the callback is actually a function before storing it.
Others can trigger the callback externally through foo.onCreate(anInstance).
If those are not problematic (for example if you're not exposing foo anyway), feel free to use this extremely simple snippet:
var foo = (function(){
var c = function(requests) {
// Initialize your instance
// ...
// Trigger callback
c.onCreate(this);
};
c.prototype = { ... };
// Expose callback on "class"
c.onCreate = function(){};
return c;
})();
// Set callback *before* creating instances
foo.onCreate = function(instance){
console.log('new instance of foo created', instance);
};
// Create an instance
var f = new foo();
Demo
Try this
var foo = function() {
this.baz();
};
foo.prototype.baz = function () {
console.log('new instance of foo created');
};
var f = new foo();

How can I share module-private data between 2 files in Node?

I would like to have a module for Node.js that is a directory with several files. I'd like some vars from one file to be accessible from other file, but not from the files external to the module. Is it possible?
So let's suppose the following file structure
` module/
| index.js
| extra.js
` additional.js
In index.js:
var foo = 'some value';
...
// make additional and extra available for the external code
module.exports.additional = require('./additional.js');
module.exports.extra = require('./extra.js');
In extra.js:
// some magic here
var bar = foo; // where foo is foo from index.js
In additional.js:
// some magic here
var qux = foo; // here foo is foo from index.js as well
Additional and Extra are implementing some business logic (independent from each other) but need to share some module-internal service data which should not be exported.
The only solution that I see is to create one more file, service.js and require it from both additional.js and extra.js. Is it correct? Are there any other solutions?
Can you just pass the desired stuff in?
//index.js:
var foo = 'some value';
module.exports.additional = require('./additional.js')(foo);
module.exports.extra = require('./extra.js')(foo);
//extra.js:
module.exports = function(foo){
var extra = {};
// some magic here
var bar = foo; // where foo is foo from index.js
extra.baz = function(req, res, next){};
return extra;
};
//additional.js:
module.exports = function(foo){
var additonal = {};
additional.deadbeef = function(req, res, next){
var qux = foo; // here foo is foo from index.js as well
res.send(200, qux);
};
return additional;
};
Okay, you may be able to do this with the "global" namespace:
//index.js
global.foo = "some value";
and then
//extra.js
var bar = global.foo;
I'd like some vars from one file to be accessible from other file, but not from the files external to the module
Yes, it is possible. You can load that other file into your module and hand it over a privileged function that offers access to specific variables from your module scope, or just hand it over the values themselves:
index.js:
var foo = 'some value';
module.exports.additional = require('./additional.js')(foo);
module.exports.extra = require('./extra.js')(foo);
extra.js:
module.exports = function(foo){
// some magic here
var bar = foo; // foo is the foo from index.js
// instead of assigning the magic to exports, return it
};
additional.js:
module.exports = function(foo){
// some magic here
var qux = foo; // foo is the foo from index.js again
// instead of assigning the magic to exports, return it
};

Call function of app.js from within module in node.js?

Let's say I have the following app.js (obviously very simplified):
var express = require('express'),
app = express.createServer();
// include routes
require('./lib/routes')(app);
// some random function
var foo = function() {
return 'bar';
};
// another random function
var foo2 = function() {
return 'bar2';
};
And then I have the routes module:
module.exports = function(app){
app.get('/some/route', function(req, res){
var fooBar = foo(),
fooBar2 = foo2();
res.end(fooBar + fooBar2);
});
};
This obviously doesn't work since foo and foo2 weren't defined within the module. Is there a way to make this work, or at least a different pattern to better accomplish what this?
Well you can just put these two functions in an object and pass them on the initialization of the routes.js .
var express = require('express'),
app = express.createServer();
// some random function
var foo = function() {
return 'bar';
};
// another random function
var foo2 = function() {
return 'bar2';
};
var fns = {foo : foo, foo2: foo2}
// include routes
require('./lib/routes')(app, fns);
in routes:
module.exports = function(app, fns){
app.get('/some/route', function(req, res){
var fooBar = fns.foo(),
fooBar2 = fns.foo2();
res.end(fooBar + fooBar2);
});
};
This is how would I do it. You can also include them in the app object. Beside passing them in init functions, you can also export those two functions and require them in routes.js.
var express = require('express'),
app = express.createServer();
// some random function
var foo = function() {
return 'bar';
};
// another random function
var foo2 = function() {
return 'bar2';
};
module.exports = {foo : foo, foo2: foo2}
// include routes
require('./lib/routes')(app, fns);
in routes:
module.exports = function(app){
var fns = require('../app.js');
app.get('/some/route', function(req, res){
var fooBar = fns.foo(),
fooBar2 = fns.foo2();
res.end(fooBar + fooBar2);
});
};
But I don't like the idea of it, since it makes circular dependencies. Don't have any good feelings about them.

Categories

Resources