I am trying to figure out how to put an object to a function and return that
object with its original values.
It's part from my "framework"...
Here an simplified example:
var _objectToFunction = function (obj) {
var F = function () { }
F.prototype = obj
return F
}
var myclass = {
a:"abc",
print: function(){
console.log("i am a func")
},
config: {
path: "c:/bla"
}
}
var fo = _objectToFunction(myclass)
var of = new fo()
of.config.path = "c:/ofpath"
of.z = "zzz"
of.a ="aaa"
console.log(of)
var fo2 = _objectToFunction(myclass)
var of2 = new fo2()
console.log(of2.z)
console.log(of2.a)
console.log(of2.config.path)
The output from console.log(of2.config.path) should "c:/bla", but is "c:/ofpath".
How can I do this right?
You may want to add a constructor (a function that is called, when an instance was created):
var _objectToFunction = function (obj) {
var F = function (...values) {
if( this.constructor) this.constructor(...values);
}
F.prototype = obj
return F
}
So you can create a new config Object for each instance:
var myclass = {
constructor:function(addconf){
this.config=Object.create(this.config);
if(addconf) Object.assign(this.config,addconf);
},
a:"abc",
print: function(){
console.log("i am a func")
},
config: {
path: "c:/bla"
}
}
Now it behaves as wanted.
var parent=_objectToFunction(myclass);
var instance=new parent({ path:"changed"});
Or with standard object funcs:
var instance=Object.create(myclass);
instance.constructor({path:"changed"});
I can't get toBeCalled() working in my Jade test script.
I get the following error msg when run the Jade test:
Error: toBeCalled() should be used on a mock function or a jasmine spy
I have a call to jest.unmock('../fooey') so not sure why I'm getting the error ?
fooey.js
var foo = function(phrase) {
return bar(phrase);
}
var bar = function(greeting) {
console.log(greeting + " Watz up?");
}
foo("Hi Bob!");
module.exports.foo = foo;
module.exports.bar = bar;
fooey-test.js:
jest.unmock('../fooey'); // unmock to use the actual implementation.
describe('fooey()', () => {
const foo = require('../fooey').foo;
const bar = require('../fooey').bar;
it('bar() is called.', () => {
foo("Hi Bob!");
expect(bar).toBeCalled();
});
});
I got it working with both a mock of bar() and also using spyOn()...
fooey.js
var Fooey = function() {
// var self = this;
this.foo = function(phrase) {
// var result = self.bar(phrase);
var result = this.bar(phrase);
return result;
// return "Junky."
};
this.bar = function(greeting) {
var result = greeting + " Watz up?"
console.log(result);
return result;
};
};
module.exports = Fooey;
fooey-test.js
jest.unmock('../fooey'); // unmock to use the actual implementation.
describe('fooey()', () => {
const Fooey = require('../fooey');
const fooey = new Fooey();
it('mock: bar() is called.', () => {
var myFooey = {
foo: fooey.foo,
bar: jest.genMockFunction()
};
myFooey.foo("Hello");
expect(myFooey.bar).toBeCalledWith("Hello");
});
it('bar() is called with "Hi Bob!".', () => {
spyOn(fooey, 'bar');
fooey.foo("Hi Bob!");
expect(fooey.bar).toHaveBeenCalledWith("Hi Bob!");
});
});
I have the following code:
var Promise = require('bluebird');
Promise.longStackTraces();
var path = require('path');
var fs = Promise.promisifyAll(require('fs-extra'));
var clone = require('nodegit').Clone.clone;
var tar = require('tar-fs');
var zlib = require('zlib');
var gzip = zlib.createGzip();
var globAsync = Promise.promisify(require('glob'));
module.exports = Archive;
function Archive(pkg) {
var self = this;
var tmp_dir_name = '.tmp';
var code_dir_name = 'code';
var files_dir_name = 'files';
var output_dir_name = 'archives';
var coverall_docs_dir_name = 'coverall_documents';
// the archive's name (no extension):
self.name = pkg.name;
self.recipient_name = pkg.recipient_name;
// path to letter.tex:
self.tex_letter_path = path.resolve(pkg.files.letter);
// path to resume.tex:
self.tex_resume_path = path.resolve(pkg.files.resume);
// path to merged.pdf (letter.pdf + resume.pdf):
self.pdf_package_path = path.resolve(pkg.compiled_files.package);
// temp dir where the archive is assembled:
self.tmp_path = path.resolve(tmp_dir_name, pkg.name);
// path to final archive:
self.output_path = path.resolve(output_dir_name, self.name + '.tar.gz');
// where to copy files to be added to the archive:
self.files_path = path.resolve(tmp_dir_name, self.name, files_dir_name);
// where the tex files are within the archive:
self.coverall_docs_path = path.resolve(self.files_path, code_dir_name, coverall_docs_dir_name);
}
Archive.prototype.make = Promise.method(function() {
var self = this;
return self._prepareFilesDir()
.then(self._copyFiles.bind(self))
.then(self._writeArchive.bind(self))
.then(self._delTmpDir.bind(self));
});
// ********************************
// * Private functions
// ********************************
Archive.prototype._prepareFilesDir = function() {
var self = this;
return fs.emptyDirAsync(self.tmp_path);
};
Archive.prototype._copyFiles = function() {
var self = this;
var sources = {
tex_letter_path: path.resolve(self.tex_letter_path, '..'),
tex_resume_path: path.resolve(self.tex_resume_path, '..'),
tex_letter_shared_path: path.resolve(self.tex_letter_path, '../../shared'),
pdf_package_path: self.pdf_package_path
};
var destinations = {
letter_path: path.resolve(self.coverall_docs_path, 'coverletters', self.recipient_name.toLowerCase()),
resume_path: path.resolve(self.coverall_docs_path, 'resume'),
letter_shared_path: path.resolve(self.coverall_docs_path, 'coverletters/shared'),
pdf_package_path: path.resolve(self.files_path, 'pdf', self.recipient_name.toLowerCase() + '.pdf'),
coverall_repo_path: path.resolve(self.files_path, 'code/coverall')
};
var filters = {
tex: function(filename) {
var contains_dot = /\./gm;
var hidden = /\/\./gm;
var cls_or_tex_file = /\.(cls|tex)$/gm;
var is_a_dir = !contains_dot.test(filename);
var is_not_hidden = (contains_dot.test(filename) && !hidden.test(filename));
var is_cls_or_tex = cls_or_tex_file.test(filename);
// it doesn't contain a dot or it isn't a hidden file or it is a cls/tex file
var is_allowed = is_a_dir || is_not_hidden || is_cls_or_tex;
return is_allowed;
},
pdf: /[^\.].*\.pdf/
};
var copyLetter = function() {
return fs.copyAsync(sources.tex_letter_path, destinations.letter_path, { filter: filters.tex });
};
function copyShared() {
return fs.copyAsync(sources.tex_letter_shared_path, destinations.letter_shared_path, { filter: filters.tex });
}
function copyResume() {
return fs.copyAsync(sources.tex_resume_path, destinations.resume_path, { filter: filters.tex });
}
function copyPdf() {
return fs.copyAsync(sources.pdf_package_path, destinations.pdf_package_path, { filter: filters.pdf });
}
function copyJs() {
return clone('https://github.com/coaxial/coverall.git', destinations.coverall_repo_path);
}
return Promise.all([
copyLetter(),
copyShared(),
copyResume(),
copyPdf(),
copyJs()
]);
};
Archive.prototype._writeArchive = function() {
var self = this;
var archive_dir_path = path.resolve(self.output_path, '..');
var tarPromise = function() {
return new Promise(function(resolve, reject) {
tar.pack(self.files_path)
.pipe(gzip)
.pipe(fs.createWriteStream(self.output_path))
.on('error', reject)
.on('finish', resolve);
});
};
return fs.ensureDirAsync(archive_dir_path)
.then(tarPromise);
};
Archive.prototype._delTmpDir = function() {
var self = this;
return fs.removeAsync(self.tmp_path);
};
and I am testing it with:
/*eslint-env mocha */
var chai = require('chai');
var chaiAsPromised = require("chai-as-promised");
var expect = chai.expect;
var Promise = require('bluebird');
Promise.longStackTraces();
var Archive = require('../lib/archive');
var path = require('path');
var fs = Promise.promisifyAll(require('fs-extra'));
var globAsync = Promise.promisify(require('glob'));
var tar = require('tar-fs');
var zlib = Promise.promisifyAll(require('zlib'));
var _ = require('lodash');
chai.use(chaiAsPromised);
describe.only('Archive', function() {
var pkg;
beforeEach(function() {
pkg = {
name: 'test_0790feebb1',
recipient_name: 'Test',
files: {
letter: '../coverall_documents/coverletters/test/letter.tex',
resume: '../coverall_documents/resume/resume.tex'
},
compiled_files: {
package: '../coverall_documents/coverletters/test/test.pdf'
}
};
});
// after(function() {
// return Promise.all([
// 'archives/test*',
// 'test/.tmp'
// ].map(function(glob_pattern) {
// return globAsync(glob_pattern)
// .each(function(filename) {
// // make every file writeable so the git packfiles can be removed
// return fs.chmodAsync(filename, '755')
// .then(function() { fs.removeAsync(filename); });
// })
// }));
// });
describe('#make', function() {
it('creates an archive', function() {
var modified_pkg = _.cloneDeep(pkg);
modified_pkg.name = 'test_0000000001';
var archive_location = path.resolve('archives', modified_pkg.name + '.tar.gz');
var test_archive = new Archive(modified_pkg);
return test_archive.make()
.then(function() { return fs.statAsync(archive_location); })
.then(function(file) { return expect(file).to.exist; })
.catch(function(e) { return expect(e).to.not.exist; });
});
it('creates a gzip compressed archive', function() {
var modified_pkg = _.cloneDeep(pkg);
modified_pkg.name = 'test_0000000002';
var archive_location = path.resolve('archives', modified_pkg.name + '.tar.gz');
var test_archive = new Archive(modified_pkg);
// inspired from https://github.com/mafintosh/gunzip-maybe/blob/master/index.js#L6-L11
var isGzipped = function(data) {
var GZIP_MAGIC_BYTES = [0x1f, 0x8b];
var DEFLATE_COMPRESSION_METHOD = 0x08;
var buffer = data[1];
if (buffer[0] !== GZIP_MAGIC_BYTES[0] && buffer[1] !== GZIP_MAGIC_BYTES[1]) return false;
if (buffer[2] !== DEFLATE_COMPRESSION_METHOD) return false;
return true;
};
return test_archive.make()
.then(function() { return fs.openAsync(archive_location, 'r'); })
.then(function(fd) {
var buffer = new Buffer(10);
var buffer_offset = 0;
var buffer_length = 10;
var file_position = 0;
return fs.readAsync(fd, buffer, buffer_offset, buffer_length, file_position);
})
.then(function(data) { console.log('data', data); return data; })
.then(function(data) { return expect(isGzipped(data)).to.be.true; })
});
it('has the correct directory structure', function() {
var modified_pkg = _.cloneDeep(pkg);
modified_pkg.name = 'test_0000000003';
var archive_location = path.resolve('archives', modified_pkg.name + '.tar.gz');
var test_archive = new Archive(modified_pkg);
var tmp_extract_path = path.resolve('test/.tmp');
var tarPromise = function(archive_path) {
return new Promise(function(resolve, reject) {
fs.createReadStream(archive_path)
.pipe(zlib.Unzip())
.pipe(tar.extract(tmp_extract_path))
.on('error', reject)
.on('finish', resolve);
})
};
var verifyDir = function() {
return Promise.all([
'code',
'pdf',
'code/coverall',
'code/coverall_documents',
'code/coverall_documents/coverletters',
'code/coverall_documents/coverletters/test',
'code/coverall_documents/coverletters/shared',
'code/coverall_documents/resume',
'code/coverall_documents/coverletters'
].map(function(subpath) {
return expect(fs.statAsync(path.resolve(tmp_extract_path, subpath)))
.to.be.fulfilled;
}))
};
return test_archive.make()
.then(function() { return tarPromise(archive_location); })
.then(function() { return verifyDir(); });
});
it('removes the temporary dir', function() {
var modified_pkg = _.cloneDeep(pkg);
modified_pkg.name = 'test_0000000004';
var archive_location = path.resolve('archives', modified_pkg.name + '.tar.gz');
var test_archive = new Archive(modified_pkg);
var tmp_dir = path.resolve('.tmp');
return test_archive.make()
.then(function() { return expect(fs.statAsync(tmp_dir)).to.be.rejected; });
});
});
});
Which results in:
$ mocha test
Archive
#make
✓ creates an archive (644ms)
1) creates a gzip compressed archive
2) has the correct directory structure
3) removes the temporary dir
1 passing (2s)
3 failing
1) Archive #make creates a gzip compressed archive:
Uncaught Error: write after end
at writeAfterEnd (_stream_writable.js:167:12)
at Gzip.Writable.write (_stream_writable.js:214:5)
at ondata (node_modules/tar-fs/node_modules/tar-stream/node_modules/readable-stream/lib/_stream_readable.js:574:20)
at readableAddChunk (node_modules/tar-fs/node_modules/tar-stream/node_modules/readable-stream/lib/_stream_readable.js:198:16)
at Readable.push (node_modules/tar-fs/node_modules/tar-stream/node_modules/readable-stream/lib/_stream_readable.js:162:10)
at Pack._encode (node_modules/tar-fs/node_modules/tar-stream/pack.js:154:17)
at Pack.entry (node_modules/tar-fs/node_modules/tar-stream/pack.js:100:10)
at onstat (node_modules/tar-fs/index.js:108:19)
at node_modules/tar-fs/index.js:40:9
at FSReqWrap.oncomplete (fs.js:95:15)
2) Archive #make has the correct directory structure:
AssertionError: expected false to be true
at Context.<anonymous> (test/archive_spec.js:96:10)
3) Archive #make removes the temporary dir:
Uncaught Error: write after end
at writeAfterEnd (_stream_writable.js:167:12)
at Gzip.Writable.write (_stream_writable.js:214:5)
at ondata (node_modules/tar-fs/node_modules/tar-stream/node_modules/readable-stream/lib/_stream_readable.js:574:20)
at readableAddChunk (node_modules/tar-fs/node_modules/tar-stream/node_modules/readable-stream/lib/_stream_readable.js:198:16)
at Readable.push (node_modules/tar-fs/node_modules/tar-stream/node_modules/readable-stream/lib/_stream_readable.js:162:10)
at Pack._encode (node_modules/tar-fs/node_modules/tar-stream/pack.js:154:17)
at Pack.entry (node_modules/tar-fs/node_modules/tar-stream/pack.js:100:10)
at onstat (node_modules/tar-fs/index.js:108:19)
at node_modules/tar-fs/index.js:40:9
at FSReqWrap.oncomplete (fs.js:95:15)
I suspected a race condition so I commented out the after block to see if it would make any difference but it doesn't.
I do not understand what the Uncaught Error: write after end is about nor why the stacktrace is unusable, even though I am using Promise.longStackTraces(). What is causing this error?
My tests look overly complicated for what they are doing and I am repeating code several times when instantiating the different test_archive objects. How could I refactor them?
You're trying to re-use the same gzip instance, which won't work. This also explains why the first test works just fine.
So move your var gzip = zlib.createGzip(); line to right inside your Archive.prototype._writeArchive function.
Is it possible to name a method dynamically?
Let us say:
Class.prototype[name] = function(param) {
console.log(name, param)
}
So if I do:
// will return `hello there`
class.hello('there')
// will return `hey there`
class.hey('there')
Is this possible to do?
I'm using the library zerorpc.
They have a syntax of
client.invoke("iter", 10, 20, 2, function(error, res, more) {
So I want to create a class to wrap their function so I can do something like:
client.iter(10,20,2 function(...
This is how I tried:
var zerorpc = require('zerorpc')
var util = require('util')
var EventEmitter = require('events').EventEmitter
var RPC = function () {
if (!(this instanceof RPC)) return new RPC()
this.rpc = new zerorpc.Client()
}
util.inherits(RPC, EventEmitter)
module.exports = RPC()
RPC.prototype.connect = function(config) {
this.con = this.rpc.connect('tcp://' + config.host + ':' + config.port)
}
// this is the idea
RPC.prototype[name] = function(params) {
this.rpc.invoke(name, params[0], params[1], params[2], function(error, res, more) { // ...
}
Saw this on gitbub gist.
Are you looking for proxies?
var obj = Proxy.create({
get: function(target, value) {
return function() {
console.log('called ' + value)
}
}
});
obj.hello(); // "called hello"
obj.world(); // "called world"
You have to use --harmony_proxies option to enable proxies in node.
I want to be able to assign default values to variables when I'm using prototyping for object creation.
When I try to assign default values to the variables they are always 'undefined'.
I have tried to find the answer but all the possible solutions I have tried dont work.
My questions are:
why do a variable that have I have initiated with a value has the value 'undefined'
how do I solve my problem?
(function() {
EmployeeNS = {};
EmployeeNS.Employee = function() {
var _firstName;
var _lastName;
var _employeeID = 'Unassigned';
}
EmployeeNS.Employee.prototype.setFirstName = function(fName) { this._firstName = fName; };
EmployeeNS.Employee.prototype.getFirstName = function() { return this._firstName; };
EmployeeNS.Employee.prototype.setLastName = function(lName) { this._lastName = lName; };
EmployeeNS.Employee.prototype.getLastName = function() { return this._lastName; };
EmployeeNS.Employee.prototype.setEmployeeID = function(employeeID) { this._employeeID = employeeID; };
EmployeeNS.Employee.prototype.getEmployeeID = function() { return this._employeeID; };
EmployeeNS.Worker = function() {
var _department;
}
EmployeeNS.Worker.prototype = new EmployeeNS.Employee();
EmployeeNS.Worker.prototype.constructor = Worker;
EmployeeNS.Worker.prototype.setDepartment = function(department) { this._department = department; };
EmployeeNS.Worker.prototype.getDepartment = function() { return this._department; };
})();
function createWorker() {
var x = new EmployeeNS.Worker();
x.setFirstName("John");
x.setLastName("Doe");
x.setDepartment("Transport");
var message = x.getFirstName()
+ " "
+ x.getLastName()
+ " (Department: "
+ x.getDepartment()
+ " / EmployeeID: "
+ x.getEmployeeID()
+ ")";
alert(message);
}
Thanks
you can simply make it to work by changing like this,
EmployeeNS.Employee = function() {
this._firstName;
this._lastName;
this._employeeID = 'Unassigned';
}
Try out this way , you can make those variables truly private by wrapping Employee ,
(function() {
EmployeeNS = {};
(function() {
var _firstName;
var _lastName;
var _employeeID = 'Unassigned';
EmployeeNS.Employee = function() {
}
EmployeeNS.Employee.prototype.setFirstName = function(fName) { _firstName = fName; };
EmployeeNS.Employee.prototype.getFirstName = function() { return _firstName; };
EmployeeNS.Employee.prototype.setLastName = function(lName) { _lastName = lName; };
EmployeeNS.Employee.prototype.getLastName = function() { return _lastName; };
EmployeeNS.Employee.prototype.setEmployeeID = function(employeeID) { _employeeID = employeeID; };
EmployeeNS.Employee.prototype.getEmployeeID = function() { return _employeeID; };
})();
(function() {
var _department;
EmployeeNS.Worker = function() {
}
EmployeeNS.Worker.prototype = new EmployeeNS.Employee();
EmployeeNS.Worker.prototype.constructor = Worker;
EmployeeNS.Worker.prototype.setDepartment = function(department) { _department = department; };
EmployeeNS.Worker.prototype.getDepartment = function() { return _department; };
})();
})();
Here is the jsfiddle
If you want instance properties, do it like this:
(function() {
EmployeeNS = {};
EmployeeNS.Employee = function () {
this._firstName = null;
this._lastName = null;
this._employeeID = 'Unassigned';
};
EmployeeNS.Employee.prototype.setFirstName = function(fName) {
this._firstName = fName;
};
})();