-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
updated readme and examples for the new interface changes
- Loading branch information
James Halliday
committed
Feb 18, 2011
1 parent
c89ae4b
commit aa2d4f3
Showing
5 changed files
with
170 additions
and
178 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,147 +1,182 @@ | ||
Description | ||
=========== | ||
Traverse and transform objects by visiting every node on a recursive walk. | ||
traverse | ||
======== | ||
|
||
Installation | ||
============ | ||
Traverse and transform objects by visiting every node on a recursive walk. | ||
|
||
Using npm: | ||
npm install traverse | ||
examples | ||
======== | ||
|
||
Or check out the repository and link your development copy: | ||
git clone http://github.com/substack/js-traverse.git | ||
cd js-traverse | ||
npm link . | ||
transform negative numbers in-place | ||
----------------------------------- | ||
|
||
You can test traverse with "expresso":http://github.com/visionmedia/expresso | ||
(`npm install expresso`): | ||
js-traverse $ expresso | ||
negative.js | ||
var Traverse = require('traverse'); | ||
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; | ||
|
||
100% wahoo, your stuff is not broken! | ||
Traverse(obj).forEach(function (x) { | ||
if (x < 0) this.update(x + 128); | ||
}); | ||
|
||
console.dir(obj); | ||
|
||
Examples | ||
======== | ||
|
||
These examples use node.js, but the module should work without it. | ||
output | ||
[ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ] | ||
|
||
Collect Leaf Nodes | ||
collect leaf nodes | ||
------------------ | ||
var sys = require('sys'); | ||
|
||
leaves.js | ||
var Traverse = require('traverse'); | ||
|
||
var acc = []; | ||
Traverse({ | ||
|
||
var obj = { | ||
a : [1,2,3], | ||
b : 4, | ||
c : [5,6], | ||
d : { e : [7,8], f : 9 } | ||
}).forEach(function (x) { | ||
d : { e : [7,8], f : 9 }, | ||
}; | ||
|
||
var leaves = Traverse(obj).reduce(function (acc, x) { | ||
if (this.isLeaf) acc.push(x); | ||
}); | ||
sys.puts(acc.join(' ')); | ||
|
||
/* Output: | ||
1 2 3 4 5 6 7 8 9 | ||
*/ | ||
return acc; | ||
}, []); | ||
|
||
Replace Negative Numbers | ||
------------------------ | ||
var sys = require('sys'); | ||
var Traverse = require('traverse'); | ||
|
||
var numbers = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; | ||
var fixed = Traverse.map(numbers, function (x) { | ||
if (typeof x == 'number' && x < 0) this.update(x + 128); | ||
}); | ||
sys.puts(sys.inspect(fixed)); | ||
|
||
/* Output: | ||
[ 5, 6, 124, [ 7, 8, 125, 1 ], { f: 10, g: 114 } ] | ||
*/ | ||
|
||
Scrub and Collect Functions | ||
--------------------------- | ||
|
||
Suppose you have a complex data structure that you want to send to another | ||
process with JSON over a network socket. If the data structure has references to | ||
functions in it, JSON will convert functions inside Arrays to null and ignore | ||
keys that map to functions inside Objects. | ||
|
||
> JSON.stringify([ 7, 8, function () {}, 9, { b : 4, c : function () {} } ]) | ||
'[7,8,null,9,{"b":4}]' | ||
|
||
If these nested functions are important, it'd be nice if they could be collected | ||
and replaced with some placeholder value that JSON can encapsulate. This sort of | ||
transform and collection might be useful for | ||
[an asynchronous remote method invocation library | ||
](http://github.com/substack/dnode), for instance. | ||
|
||
This example scrubs functions out of an arbitrary data structure so that the | ||
structure may be JSON-ified. The functions are also collected for some other | ||
use. | ||
|
||
var sys = require('sys'); | ||
var Traverse = require('traverse'); | ||
|
||
var id = 54; | ||
var callbacks = {}; | ||
var obj = { moo : function () {}, foo : [2,3,4, function () {}] }; | ||
|
||
var scrubbed = Traverse.map(obj, function (x) { | ||
if (typeof x == 'function') { | ||
callbacks[id] = { id : id, f : x, path : this.path }; | ||
this.update('[Function]'); | ||
id++; | ||
} | ||
}); | ||
|
||
sys.puts(JSON.stringify(scrubbed)); | ||
sys.puts(sys.inspect(callbacks)); | ||
|
||
/* Output: | ||
{"moo":"[Function]","foo":[2,3,4,"[Function]"]} | ||
{ '54': { id: 54, f: [Function], path: [ 'moo' ] } | ||
, '55': { id: 55, f: [Function], path: [ 'foo', '3' ] } | ||
} | ||
*/ | ||
|
||
Hash Transforms | ||
=============== | ||
output | ||
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] | ||
|
||
There's also a hash lib in this distribution with tons of useful functions to | ||
operate on hashes: | ||
context | ||
======= | ||
|
||
map, forEach, filter, reduce, some, update, merge, tap, valuesAt, extract, | ||
items, keys, values, clone, copy | ||
Each method that takes a callback has a context (its `this` object) with these | ||
attributes: | ||
|
||
These work mostly like their array counterparts where available except they get | ||
an extra second argument, key. | ||
node | ||
---- | ||
|
||
Other functions like tap, valuesAt, merge, and update work like their ruby | ||
counterparts. | ||
The present node on the recursive walk | ||
|
||
The extract function creates a hash with only the supplied keys in it. | ||
path | ||
---- | ||
|
||
The clone property makes a deep copy with Traversable.clone() and the copy | ||
property makes a shallow copy. | ||
An array of string keys from the root to the present node | ||
|
||
The items property is the hash with the Hash() wrapper peeled away. | ||
parent | ||
------ | ||
|
||
The context of the node's parent. | ||
This is `undefined` for the root node. | ||
|
||
key | ||
--- | ||
|
||
The name of the key of the present node in its parent. | ||
This is `undefined` for the root node. | ||
|
||
> var Hash = require('traverse/hash') | ||
> Hash({ a : 1, b : 2 }).map(function (v) { return v + 1 }).items | ||
{ a: 2, b: 3 } | ||
|
||
To do the same thing without chaining: | ||
isRoot, notRoot | ||
--------------- | ||
|
||
Whether the present node is the root node | ||
|
||
isLeaf, notLeaf | ||
--------------- | ||
|
||
Whether or not the present node is a leaf node (has no children) | ||
|
||
level | ||
----- | ||
|
||
Depth of the node within the traversal | ||
|
||
> Hash.map({ a : 1, b : 2 }, function (v) { return v + 1 }) | ||
{ a: 2, b: 3 } | ||
circular | ||
-------- | ||
|
||
The 'this' context of the function calls is the same object that the chained | ||
functions return, so you can make nested chains. | ||
If the node equals one of its parents, the `circular` attribute is set to the | ||
context of that parent and the traversal progresses no deeper. | ||
|
||
update(value) | ||
------------- | ||
|
||
Set a new value for the present node. | ||
|
||
before(fn) | ||
---------- | ||
|
||
Call this function before any of the children are traversed. | ||
|
||
after(fn) | ||
--------- | ||
|
||
Call this function after any of the children are traversed. | ||
|
||
pre(fn) | ||
------- | ||
|
||
Call this function before each of the children are traversed. | ||
|
||
post(fn) | ||
-------- | ||
|
||
Call this function after each of the children are traversed. | ||
|
||
methods | ||
======= | ||
|
||
.map(fn) | ||
-------- | ||
|
||
Execute `fn` for each node in the object and return a new object with the | ||
results of the walk. To update nodes in the result use `this.update(value)`. | ||
|
||
.forEach(fn) | ||
------------ | ||
|
||
Execute `fn` for each node in the object but unlike `.map()`, when | ||
`this.update()` is called it updates the object in-place. | ||
|
||
.reduce(fn, acc) | ||
---------------- | ||
|
||
For each node in the object, perform a | ||
[left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function)) | ||
with the return value of `fn(acc, node)`. | ||
|
||
If `acc` isn't specified, `acc` is set to the root object for the first step | ||
and the root element is skipped. | ||
|
||
.paths() | ||
-------- | ||
|
||
Return an `Array` of every possible non-cyclic path in the object. | ||
Paths are `Array`s of string keys. | ||
|
||
.nodes() | ||
-------- | ||
|
||
Return an `Array` of every node in the object. | ||
|
||
.clone() | ||
-------- | ||
|
||
Create a deep clone of the object. | ||
|
||
installation | ||
============ | ||
|
||
Using npm: | ||
npm install traverse | ||
|
||
Or check out the repository and link your development copy: | ||
git clone http://github.com/substack/js-traverse.git | ||
cd js-traverse | ||
npm link . | ||
|
||
You can test traverse with "expresso":http://github.com/visionmedia/expresso | ||
(`npm install expresso`): | ||
js-traverse $ expresso | ||
|
||
100% wahoo, your stuff is not broken! | ||
|
||
hash transforms | ||
=============== | ||
|
||
See also [creationix's pattern/hash](http://github.com/creationix/pattern), | ||
which does a similar thing except with hash inputs and array outputs. | ||
This library formerly had a hash transformation component. It has been | ||
[moved to the hashish package](https://github.com/substack/node-hashish). |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,16 @@ | ||
#!/usr/bin/env node | ||
var sys = require('sys'); | ||
var Traverse = require('traverse'); | ||
|
||
var id = 54; | ||
var callbacks = {}; | ||
var obj = { moo : function () {}, foo : [2,3,4, function () {}] }; | ||
|
||
var scrubbed = Traverse(obj).modify(function (x) { | ||
if (x instanceof Function) { | ||
var scrubbed = Traverse(obj).map(function (x) { | ||
if (typeof x === 'function') { | ||
callbacks[id] = { id : id, f : x, path : this.path }; | ||
this.update('[Function]'); | ||
id++; | ||
} | ||
}).get(); | ||
}); | ||
|
||
sys.puts(JSON.stringify(scrubbed)); | ||
sys.puts(sys.inspect(callbacks)); | ||
|
||
/* Output: | ||
{"moo":"[Function]","foo":[2,3,4,"[Function]"]} | ||
{ '54': { id: 54, f: [Function], path: [ 'moo' ] } | ||
, '55': { id: 55, f: [Function], path: [ 'foo', '3' ] } | ||
} | ||
*/ | ||
console.dir(scrubbed); | ||
console.dir(callbacks); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,15 @@ | ||
#!/usr/bin/env node | ||
var sys = require('sys'); | ||
var Traverse = require('traverse'); | ||
|
||
var acc = []; | ||
Traverse({ | ||
var obj = { | ||
a : [1,2,3], | ||
b : 4, | ||
c : [5,6], | ||
d : { e : [7,8], f : 9 } | ||
}).forEach(function (x) { | ||
d : { e : [7,8], f : 9 }, | ||
}; | ||
|
||
var leaves = Traverse(obj).reduce(function (acc, x) { | ||
if (this.isLeaf) acc.push(x); | ||
}); | ||
sys.puts(acc.join(' ')); | ||
return acc; | ||
}, []); | ||
|
||
/* Output: | ||
1 2 3 4 5 6 7 8 9 | ||
*/ | ||
console.dir(leaves); |
Oops, something went wrong.