Skip to content
πŸ”ͺ Handy object manipulation tools
Branch: master
Clone or download
Latest commit 37c5343 Jun 11, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
dist 0.2.0 Jun 11, 2019
src improved clear functionality Jun 10, 2019
test documenting forDeep Jun 8, 2019
.eslintrc.js moved from old local repo Jun 7, 2019
.gitignore moved from old local repo Jun 7, 2019
.npmignore 0.1.0 Jun 8, 2019
.travis.yml adding TRAVIS Jun 7, 2019
LICENSE Initial commit Jun 7, 2019
README.md updated toc Jun 11, 2019
hobj.svg
package-lock.json |Transerring tests from old repo Jun 7, 2019
package.json 0.2.0 Jun 11, 2019

README.md

Hobj

πŸ”ͺ Handy object manipulation tools

travis npm MIT

Features

  • before/after hooks on each method.
  • get/set/has/delete with nested path support.
  • deep iteration.
  • deep clone.
  • deep merge.
  • Everything while keeping direct access to original js object (no constrains on using Hobj API for every operation).

TOC

Installation

With NPM:

npm install --save hobj

Without:

<script src="https://unpkg.com/lucagez/hobj/dist/hobj.umd.js"></script>

How hooks work

Hobj will provide hooks to execute functions before/after a method is executed. This is done by executing in order:

=> BEFORE queue
=> fulfilled promise executing AFTER queue
=> called METHOD

A micro-task is scheduled thanks to the already fulfilled promise. So, the AFTER queue will always be executed after the called METHOD. Precisely on nextTick.

This will guarantee the order:

  1. BEFORE
  2. METHOD
  3. AFTER

Usage

Init Hobj

You can create a new Hobj instance passing an existing js object.

const Hobj = require('hobj');

const obj = new Hobj();

const obj1 = new Hobj({
  hello: 'world',
});

Store

The object that is mutated thanks to Hobj methods lives in the store property.

const obj = new Hobj(); // Hobj instance

obj.store // {}

The store property can be manipulated exactly like any other js object. NOTE: This means that you don't have to rely only on the Hobj methods to mutate the object.

const test = { hello: 'world' };

const obj = new Hobj();

// Example operation.
obj.store = {
  ...test,
  a: 'b',
};

Paths

Every Hobj method that take a path as argument supports dot-notation.

e.g.

const obj = new Hobj();

obj.store // {}

obj.set('a.b.c', 'd'); // { a: { b: { c: 'd' } } }

Calling a method

For each Hobj method there are two variations:

  • Normal => obj.[method] => ALWAYS executes before/after hooks.
  • Pure => obj.[_method] => Pure method. No hooks.

NOTE: Normal methods can be used also if hooks are not defined.

const obj = new Hobj();

obj.before('set', () => console.log('Setting'));

// NORMAL
obj.set('a.b', 'c'); 

// Setting
// { a: { b: 'c' } }


// PURE => no hooks are invoked
obj._set('d', 'e');

// { a: { b: 'c' }, d: 'e' }

Defining hooks

Hooks can be defined calling on a Hobj instance a before/after method. Passing the method to hook and a function responsible for that particular hook.

const obj = new Hobj();

// Example using an arbitrary method. You can hook every method defined
// in the `METHODS` section.
obj.before('set', () => {
  console.log('Setting 0');
});

// You can hook with how many functions you like.
// They will be executed in insertion order.
obj.before('set', () => {
  console.log('Setting 1');
});

obj.set('a', 'b');

// Setting 0
// Setting 1
// [Actually setting the property]

The same is true for after hook.

const obj = new Hobj();

obj.before('set', () => {
  console.log('Setting');
});

obj.after('set', () => {
  console.log('Success πŸŽ‰');
});

obj.set('a', 'b');

// Setting
// [Actually setting the property]
// Success πŸŽ‰

Every before function will be invoked with the exact same arguments as the invoked method.

const obj = new Hobj();

// Hooked function will be invoked with TWO arguments
// as the `set` method accepts TWO arguments.
obj.before('set', (prop, value) => {
  console.log(`Setting ${prop} equal to ${value}`);
});

obj.set('a', 'b');

// Setting a equal to b
// [Actually setting the property]


// Hooked function will be invoked with ONE argument
// as the `set` method accepts ONE argument.
obj.before('has', (value) => {
  console.log(`Checking if ${value} is in obj`);
});

obj.has('a');

// Checking if a is in obj
// TRUE

Every after function will be invoked with arguments used on the invoked method PLUS the result of the actual invoked method.

const obj = new Hobj();

// Hooked function will be invoked with TWO arguments
// as the `set` method accepts TWO arguments.
obj.before('set', (prop, value) => {
  console.log(`Setting ${prop} equal to ${value}`);
});

obj.after('set', (prop, value, result) => {
  console.log('The object is now', result);
});

obj.set('a', 'b');

// Setting a equal to b
// [Actually setting the property]
// The object is now { a: 'b' }

METHODS

For each Hobj method there are two variations:

  • Normal => obj.[method] => ALWAYS executes before/after hooks.
  • Pure => obj.[_method] => Pure method. No hooks.

store

Not a method. The object on which the mutations are operated will live inside this property.

obj.store

has / _has

obj.has(path)

Checks if a (nested) path exists in the object.

RETURNS: true/false

param type default required
path string undefined no

get / _get

obj.get(path)

Returns object belonging to a (nested) path.

RETURNS:

  • object if a path is provided
  • undefined if the provided path does not exists
param type default required
path string undefined no

set / _set

obj.set(path, value)

Set property at (nested) path.

RETURNS: store

param type default required
path string undefined no
value any undefined no

delete / _delete

obj.delete(path)

Delete (nested) property.

RETURNS: true/false. Deletion is successful or not.

param type default required
path string undefined no

sub / _sub

obj.sub([path])

Returns a completely new object belonging to a (nested) path.

NOTE: when retrieving a property using get, a reference is returned. Using sub you are creating a totally new instance.

RETURNS:

  • object if a path is provided
  • undefined if the provided path does not exists
  • store (a cloned instance of) if no path is provided
param type default required
path string '' no

for / _for

obj.for([path])(callback)

Iterate each top-level property starting at deep level (path) If no path is provided, the iteration will be at top level.

RETURNS: undefined.

for:

param type default required
path string '' no

callback:

param type
prop string
value any

example:

const obj = new Hobj({
  a: {
    b: 0,
    c: 0,
  },
  d: 0,
});

// No `path` provided => iterating at top level
obj.for()((prop, value) => {
  console.log(prop, value);
});
// a, { b: 0, c: 0 }
// d, 0


// Providing starting `path`
obj.for('a')((prop, value) => {
  console.log(prop, value);
});
// b, 0
// c, 0

forDeep / _forDeep

obj.forDeep([path[, end]])(callback)

Iterate EACH property starting at deep level (path). If no path is provided, the iteration will start at top level. The end (end property) let's you define if you want to iterate over properties that have no descendants or not.

RETURNS: undefined.

for:

param type default required
path string '' no
end boolean true no

callback:

param type
path string
value any

example:

const obj = new Hobj({
  a: {
    b: 0,
    c: 0,
  },
  d: 0,
});

// No `path` provided => starting iteration from top level
obj.forDeep()((path, value) => {
  console.log(path, value);
});
// a.b, 0
// a.c, 0
// d, 0

// specifying iteration on **EACH** property.
obj.forDeep('', false)((path, value) => {
  console.log(path, value);
});
// '', { a: { b: 0, c: 0 }, d: 0 }
// a, { b: 0, c: 0 }
// a.b, 0
// a.c, 0
// d, 0

// Providing starting `path`
obj.forDeep('a')((path, value) => {
  console.log(path, value);
});
// b, 0
// c, 0

size / _size

obj.size([path])

Returns the number of properties at defined deep level. If no path is provided, it will be returned the number of properties at top level.

RETURNS: number

param type default required
path string '' no

sizeDeep / _sizeDeep

obj.sizeDeep([path[, end]])

Returns the number of EVERY property contained in the object at specified deep level. The end param will define if the number should take into account properties that are objects or only end properties.

RETURNS: number

param type default required
path string '' no
end boolean true no

merge / _merge

obj.merge(obj)

(Deeply) merge the provided object with the current store.

RETURNS: store

param type default required
obj object {} no

keys / _keys

obj.keys([path])

Returns an array containing every top-level property at specified deepness.

RETURNS: array

param type default required
path string '' no

entries / _entries

obj.entries([path])

Returns an array with the following structure: [prop, value]. Created at the specified deepness.

RETURNS: array

param type default required
path string '' no

clear / _clear

obj.clear(when, method)

If invoked with no params => initialize store to empty object. If invoked with params => clear queue.

RETURNS: undefined

License

MIT

Author: Luca Gesmundo

You can’t perform that action at this time.