Package Exports
- jinang
- jinang/Directory
- jinang/JsonFile
- jinang/PoC
- jinang/Progress
- jinang/absorb
- jinang/cloneObject
- jinang/defineError
- jinang/forInObject
- jinang/jointString
- jinang/modifyUrl
- jinang/ott
- jinang/papply
- jinang/parseOptions
- jinang/safeClone
- jinang/sleep
- jinang/split
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (jinang) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
jinang
Collection of Node.js / ECMAScript Mini Modules
The name jinang is abbreviation of "Jin-Nang", which in chinese means a magic box. The modules in jinang are independent for each other, and are for different usage.
jinang is an incubator. Successful sub modules may be encouraged to be published as independent NPM packages.
Table of contents
Links
Get Started
// Modules are independent for each other and are suggested to be required independently.
const defineError = require('jinang/defineError');
const MyError = defineError('MyError', Error, function(message) {
this.code = 'SOMETHING_IS_WRONG';
this.message = message;
});
// ...
throw new MyError('Helo word!');
API
All sub-modules in jinang are independent from each other. Use require('jinang/<subModuleName>')
to require the sub-modules.
For your convenience, avaiable modules included in jinang are listed here,
- absorb
- cloneObject
- currying
- defineError
- Directory
- forInObject
- jointString
- JsonFile
- modifyUrl
- ordinal
- ott
- papply
- parseOptions
- PoC
- Progress
- promiseRejectionAutoHandle
- safeClone
- sleep
- split
absorb
- number absorb( Array foo, Array bar )
cloneObject
Object cloneObject( object source )
Object cloneObject( object source, Array keynames )
Item of keynames may be string or RegExp instance. If item is a string, key in source which strictly equals to the keyname will be cloned. However, if it is a RegExp instance, all keys in source will be iterated and those matched will be cloned.Object cloneObject( object source, Function mapper )
The mapper SHOULD be a function who accepts two arguments(key, value)
and return an array[ newKey, newValue ]
.
currying
Transform a normal function to a curried one.
- curried Function currying( Function fn, number paramsLength )
const currying = require('jinang/currying');
function plus(a, b, c) {
return a + b + c;
}
// Create a curried function.
// 3 means that the original function plus() should be invoked with 3 arguments.
var curriedPlus = currying(plus, 3);
// Curried function accepts one and only one argument.
// It may return a new curried function, or the result returned by the original function.
curriedPlus(1); // RETURN a new function.
curriedPlus(1)(2); // RETURN a new function.
curriedPlus(1)(2)(3); // RETURN 6.
ATTENTION: Although Currying and Partial Application are mutually related, they are DIFFERENT. If you wanna create a new function which is based on an existing function and with some arguments predefined, use papply.
Read more about currying:
- WIKIPEDIA.org, Currying
- WIKIPEDIA.org, Lambda calculus
defineError
- Function defineError( string ErrorName, Function ParentErrorClass, Function constructor )
E.g.
// Modules are independent for each other and are suggested to be required independently.
const defineError = require('jinang/defineError');
const MyError = defineError('MyError', Error, function(message) {
this.code = 'SOMETHING_IS_WRONG';
this.message = message;
});
// ...
throw new MyError('Helo word!');
Directory
- class Directory( string homepath )
- void <instance>.append ( string filename, string | Buffer data )
- ReadStream <instance>.createReadStream ( string filename [, object options ] )
- WriteStream <instance>.createWriteStream ( string filename [, object options ] )
- boolean <instance>.exists ( string filename )
- void <instance>.mkdir ( string pathname )
- number <instance>.open ( string pathname, string flags )
- void <instance>.read ( string filename, string | Buffer encoding )
- string <instance>.resolve( string filename )
- void <instance>.rmfr ( string filename )
- void <instance>.write ( string filename, string | Buffer data )
forInObject
- void forInObject( object foo, Function iterator )
Function iterator SHOULD accept two arguments.
E.g.
const forInObject = require('jinang/forInObject');
forInObject({ name: 'YounGoat' }, (name, value) {
console.log(name);
console.log(value);
});
jointString
- string jointString( string joint, string str_1, string str_2, ...)
Concatenate strings with joint. If the end of the front string or the beginning of the rear one equals to joint, it will be trimmed before being concatenated.
E.g.
const jointString = require('jinang/jointString');
jointString('/', 'a/', '/b');
jointString('/', 'a' , '/b');
jointString('/', 'a/', 'b');
jointString('/', 'a' , 'b');
// All return 'a/b'.
JsonFile
- class JsonFile( string pathname )
- object <instance>.json
Handle to read/write JSON data. - void <instance>.save()
- void <instance>.remove()
modifyUrl
- string modifyUrl( string urlname, Object options )
- string modifyUrl.pathname( string urlname, string pathname, char flag )
- string modifyUrl.protocol( string urlname, string protocol )
- string modifyUrl.query( string urlname, string|Object query, char flag )
ordinal
Acquire the ordinal form of a natural number, e.g. 1st for 1, 22nd for 22.
const ordinal = require('jinang/ordinal');
ordinal(1);
// RETURN 1st
ordinal(101);
// RETURN 101st
ordinal.suffix(22);
// RETURN nd
ordinal(0);
// throws Error
string ordinal(number | string n) throws
Return the ordinal form of a natural number.
If n is not a natural number, an Error will be thrown.string oridnal.suffix(number | string n) throws
Return only the ordinal suffix.
If n is not a natural number, an Error will be thrown.
ott
ott is abbreviation of Once, Twice, Thrice.
const ott = require('jinang/ott');
let n = 0;
function fn() {
return n++;
};
let fn3 = ott(fn, 3);
fn3(); // n == 1; RETURN 0
fn3(); // n == 2; RETURN 1
fn3(); // n == 3; RETURN 2
// n will not change more by fn3
fn3(); // n == 3
fn3(); // n == 3
fn3.runtimes(); // RETURN 5
- Function ott(Function fn, number n)
- Function ott(Function fn, number n, any returnOnExceeding)
- Symbol ott.FIRST
- Symbol ott.LAST
- Function ott.once(Function fn)
- Function ott.twice(Function fn)
- Function ott.thrice(Function fn)
ott()
returns a wrapper of the provided function. When the returned function has been invoked for n times, what it returns on next calls depends on the parameter returnOnExceeding:
- If
ott.FIRST
used, it will return what it firstly returned. - If
ott.LAST
used, it will return what it returned on n-th call. - Otherwise, it will return just returnOnExceeding.
papply
Word "papply" is abbreviation of Partial Application, which means to apply a function to some of its arguments and return a new function with fewer parameters.
papply offers three styles:
Function papply(Function fn, any leading_argument, ...)
Create a new function based on fn with leading arguments predefined by any number of leading_argument.Function papply.tail(Function fn, any tailing_argument, ...)
Create a new function based on fn with tailing arguments predefined by any number of tailing_argument. The last tailing_argument will also be the last argument finally passed into fn.Function papply.position(Function fn, [ number position, any value ] positioned_argument, ...)
Create a new function based on fn with some position(s) of argument list predefined by any number of positioned_argument.
The final arguments passed into fn will be the shortest list which contains all positioned arguments and real arguments. Sometimes the final arguments will be tailed with one or moreundefined
.
If position is 0 or positive integer, it indicates the position from left (starts with 0). Otherwise, if position is negative integer, it indicates the position from right (starts with -1).
const papply = require('jinang/papply');
// -- papply --
// Suppose a function with three parameters.
function add(a, b, c) {
return a + b + c;
}
// Run partial application and return a new function.
const add2 = papply(add, 2);
add2(3, 4); // RETURN 2 + 3 + 4
const add2_3 = papply(add, 2, 3);
add2_3(4); // RETURN 2 + 3 + 4
// -- papply.tail --
function minus(a, b, c) {
return a - b*1 - c*2;
}
const minus2 = papply.tail(minus, 2);
minus2(9, 3); // RETURN 9 - 3 - 2*2 = 2
const minus2_3 = papply.tail(minus, 2, 3);
minus2_3(9); // RETURN 9 - 2 - 3*2 = 1
// -- papply.position --
function join() {
let args = Array.from(arguments);
let chars = args.map(n => typeof n == 'undefined' ? '-' : n);
return chars.join('');
}
const join_z = papply.position(join, [ -1, 'z' ]);
join_z('a');
Read more about partial application:
- WIKIPEDIA.org, Partial application
- Curry or Partial Application? The Difference Between Partial Application and Curry
- StackOverflow.com, What is the difference between currying and partial application?
- 2ality.com, Currying versus partial application (with JavaScript code)
parseOptions
To normalise options argument.
const parseOptions = requrie('jinang/parseOptions');
const options = {
Domain: 'www.example.com',
Port: 8080,
path: '/index.html',
};
const def = {
// Whether the property names of *options* are case sensitive.
// DEFAULT false
caseSensitive: false,
// Whether the property names of returned (parsed) object may keep the case
// as what column names look like, even *def.caseSensitive* is false.
// DEFAULT false
keepNameCase: false,
// If set true, properties not explicitly declared will be ignored.
// DEFAULT false
explicit: true,
// Declare properties in *options*.
columns: [
'port',
{ name: 'Hostname', alias: 'domain' }
],
};
const po = parseOptions(options, def);
// RETURN {
// Hostname: 'www.example.com',
// port: 8080
// }
parseOptions is an easy way to make your function paramemters more friendly.
function formatUrl(options) {
const optionsDef = {
caseSensitive: false,
explicit: true,
// Property *columns* of definition may be an array or object.
columns: [
// Use object to define/declare a column.
{ name: 'protocol', default: 'http' },
{ name: 'query', alias: [ 'querystring', 'queries' ] },
// Use description string to define/declare a column.
'hostname required alias(domain, domainName)',
// Only column name is also OK.
'port',
'path',
'search',
'hash'
]
};
options = parseOptions(options, optionsDef);
// ...
}
A column definition may be an object with following properties:
- name string
- alias string | string[]
- default any OPTIONAL
- parser Function OPTIONAL
- required boolean DEFAULT
false
PoC
PoC means Promise or Callback. It may be invoked in an asychronuous function to create an return an instance of Promise
or to invoke the callback
function if passed.
const PoC = require('jinang/PoC');
function asyncDemo(params, callback) {
return PoC((done) => {
// ...
done(error, data);
}, callback);
};
asyncDemo(params)
.then((data) => { /* ... */ })
.catch((error) => { /* ... */ })
;
// When callback passed, PoC will return void.
asyncDemo(params, (error, data) => { /* ... */ });
Progress
const Progress = require('jinang/Progress');
const progress = new Progress();
// Progress inherits class events.EventEmitter.
progress.on('error', function(ex) {
// ...
});
progress.emit('error', ex);
// Progress may send/change its signal via homonymous methods.
progress.on('signal', function(signal) {
// ...
});
progress.abort();
class Progress
number Progress.SIGABRT
number Progress.SIGHUP
number Progress.SIGINT
number Progress.SIGKILL
number Progress.SIGQUIT
number Progress.SIGTERM
void <instance>.raise(number signal )
void <instance>.signal(number signal, Function catcher)
void <instance>.abort()
Send signal SIGABRT to progress and emit a signal event.void <instance>.hangup()
Send signal SIGHUP to progress and emit a signal event.void <instance>.interrupt()
Send signal SIGINT to progress and emit a signal event.void <instance>.kill()
Send signal SIGKILL to progress and emit a signal event.void <instance>.quit()
Send signal SIGQUIT to progress and emit a signal event.void <instance>.terminate()
Send signal SIGTERM to progress and emit a signal event.
promiseRejectionAutoHandle
By default, an instance of Promise
without .catch(onReject)
will throw an exception while it is rejected. promiseRejectionAutoHandle will catch the exception automatically in such situations.
const handler = (err) => console.log(err);
require('jinang/promiseRejectionAutoHandle')(handler);
// The *handler* is not required
new Promise((resolve, reject) => { /* ... */ })
.then(data => {
/* ... */
})
;
Read unit test code for more examples.
safeClone
safeClone is deep and partial clone method. The skeleton of the original argument will be kept and the primitive items or properties will be copied, while the complex values will be ignored. Whatever you do with the returned value, the original will not be affected.
const safeClone = require('jinang/safeClone');
const foo = {
a: undefined,
b: null,
c: 1, // number
d: 'foobar', // string
e: true, // boolean
f: function() {}, // function
g: [ , , 2, ], // Array
}
let bar = safeClone(foo);
bar.a === undefined;
bar.b === null;
bar.c === 1;
bar.d === 'foobar';
bar.e === true;
bar.hasOwnProperty('f') === false;
bar.g.length === 3;
// The original will not change when the cloned changed.
bar.g.pop();
foo.g.length === 3;
Read unit test code for more examples.
sleep
Make current process to "sleep" for a while.
const sleep = require('jinang/sleep');
// Block the current process for 2000 milliseconds (2 seconds).
sleep(2000);
In co(function*() { /* ... */ })
code block, sleep.promise()
is recommended because it is more precise.
const sleep = require('jinang/sleep');
const co = require('co');
co(function*() {
yield sleep.promise(2000);
});
split
Split string in different ways.
Array split(string s, string | RegExp seperator)
The first parameter is the string to be split.
seperator may be a string or a regular expression object.Array split(string s, string | RegExp seperator, string | Array delimiter)
Substring enbraced by SAME delimiter will not be split. Each delimiter SHOULD be a character (1-length string).Array split(string s, string | RegExp seperator, string | Array delimiter, string escaper)
const split = require('jinang/split');
split('foo bar baz', ' ');
// RETURN: [ "foo", "bar", "baz" ]
split('foo==bar==baz', '==');
// RETURN: [ "foo", "bar", "baz" ]
split('foo "bar baz"', ' ', '"');
// RETURN: [ "foo", "bar baz" ]
split('foo "bar\\"baz"', ' ', '"');
// RETURN: [ "foo", "bar\\"baz" ]
Read unit test code for more examples.
Why jinang
jinang is an incubator for creatives which will make programming with Node.js much easier.