Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
dsc committed Aug 7, 2012
0 parents commit ed801a9
Show file tree
Hide file tree
Showing 7 changed files with 392 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .gitignore
@@ -0,0 +1,29 @@
# git-ls-files --others --exclude-from=.git/info/exclude
*~

# OSX
.VolumeIcon.icns
.fseventsd
.Spotlight-V100
.Trashes
.DS_Store
._*
Icon?

# Node
node_modules/
node_modules/*
npm-debug.log
test/*.log
test/fixtures/*.json
test/fixtures/logs/*.log
lib-cov/
*.sass-cache
.cache/
.tmp/

build/
dist/
var/
log/
tmp/
97 changes: 97 additions & 0 deletions README.md
@@ -0,0 +1,97 @@
# underscore.kv

Key-value pairs serialization (aka, `www-form-encoding`) of objects for [Underscore.js][underscore].


## Usage

For usage in [node.js][node], install it via [npm][npm]: `npm install underscore.kv`.

You can use `underscore.kv` as a stand-alone library, though it depends on Underscore.
Most people mix it into the Underscore namespace, which gains you the chaining wrappers.

```js
// standalone
var _kv = require('underscore.kv');

// mixin
var _ = require('underscore');
_.mixin require('underscore.kv');
```


## API

### _.**toKV**(*object*[, *item_delim*='&'[, *kv_delim*='=']])

Transforms an object to a string of URL-encoded KV-pairs (aka "www-form-encoding").
You may optionally override the delimiter inserted between items (`&` by default),
or the delimiter inserted between keys and values (`=`).

Note:
- All values end up as a string, implying all type information is lost.
- Both keys and values are URL-encoded once.

```js
_.toKV({ "foo":"bar", "feh":1, "lol":true })
// --> "foo=bar&feh=1&lol=true"
```


### _.**fromKV**(*string*[, *item_delim*=`'&'`[, *kv_delim*=`'='`]])

Restores an object from a string of URL-encoded KV-pairs (aka "www-form-encoding").
You may optionally override the delimiter inserted between items (`&` by default),
or the delimiter inserted between keys and values (`=`).

Note:
- All resulting values will be strings as all type information is lost.
- Both keys and values will be URL-decoded once.

```js
_.fromKV("foo=bar&feh=1&lol=true")
// --> { "foo":"bar", "feh":"1", "lol":"true" }
```


### _.**collapseObject**(*source*[, *target*=`{}`[, *prefix*=`''`]])

Copies and flattens a tree of sub-objects into namespaced keys on the target object.

```js
_.collapseObject({ "foo":{ "bar":1 } })
// --> { "foo.bar":1 }
```


### _.**uncollapseObject**(*source*[, *target*=`{}`])

Inverse of `_.collapseObject()` — copies all keys onto the target object,
expanding any dot-namespaced keys found.

```js
_.uncollapseObject({ "foo.bar":1 })
// --> { "foo":{ "bar":1 } }
```



## Feedback

Find a bug or want to contribute? Open a ticket (or fork the source!) on [github][project].
You're also welcome to send me email at [dsc@less.ly][dsc_email].

--

`underscore.kv` was written by [David Schoonover][dsc]; it is open-source software and freely available under the [MIT License][mit_license].



[project]: http://github.com/dsc/underscore.kv "underscore.kv on GitHub"
[dsc]: https://github.com/dsc/ "David Schoonover"
[dsc_email]: mailto:dsc+underscore.kv@less.ly?subject=underscore.kv "dsc@less.ly"
[mit_license]: http://dsc.mit-license.org/ "MIT License"

[node]: http://nodejs.org/ "node.js"
[npm]: http://npmjs.org/ "npm"
[underscore]: http://underscorejs.org "Underscore.js"
1 change: 1 addition & 0 deletions index.js
@@ -0,0 +1 @@
module.exports = require('./underscore.kv');
21 changes: 21 additions & 0 deletions package.co
@@ -0,0 +1,21 @@
name : 'underscore.kv'
version : '0.1.0'
description : 'Key-value pairs serialization (aka "www-form-encoding") of objects for Underscore.js'
homepage : 'https://github.com/dsc/underscore.kv'
keywords : <[ underscore kv key value pairs serialization util server client browser ]>
author : 'David Schoonover <dsc@less.ly> (http://less.ly)'

main : "./underscore.kv"

dependencies :
'underscore' : '== 1.3.x'
'underscore.nested' : '== 0.1.x'
devDependencies :
'coco' : '== 0.7.x'
# 'expresso' : '== 0.9.2'

# scripts : test:'expresso'
repository : type:'git', url:'https://github.com/dsc/underscore.kv.git'
bugs : url:'https://github.com/dsc/underscore.kv/issues'

license : 'MIT'
35 changes: 35 additions & 0 deletions package.json
@@ -0,0 +1,35 @@
{
"name": "underscore.kv",
"version": "0.1.0",
"description": "Key-value pairs serialization (aka \"www-form-encoding\") of objects for Underscore.js",
"homepage": "https://github.com/dsc/underscore.kv",
"keywords": [
"underscore",
"kv",
"key",
"value",
"pairs",
"serialization",
"util",
"server",
"client",
"browser"
],
"author": "David Schoonover <dsc@less.ly> (http://less.ly)",
"main": "./underscore.kv",
"dependencies": {
"underscore": "== 1.3.x",
"underscore.nested": "== 0.1.x"
},
"devDependencies": {
"coco": "== 0.7.x"
},
"repository": {
"type": "git",
"url": "https://github.com/dsc/underscore.kv.git"
},
"bugs": {
"url": "https://github.com/dsc/underscore.kv/issues"
},
"license": "MIT"
}
97 changes: 97 additions & 0 deletions underscore.kv.co
@@ -0,0 +1,97 @@
_ = require 'underscore'
_nest = require 'underscore.nested'


/**
* @namespace Functions for key-value pairs serialization (aka, www-form-encoding) of objects
*/
_kv = do

/**
* Transforms an object to a string of URL-encoded KV-pairs (aka "www-form-encoding").
*
* Note:
* - All values end up as a string, implying all type information is lost.
* - Both keys and values are URL-encoded once.
*
* @param {Object} object The object to be serialized.
* @param {String} [item_delim='&'] String delimiting each pair.
* @param {String} [kv_delim='='] String delimiting key from value.
* @returns {String} Serialized and encoded KV-pairs.
*/
toKV: (object, item_delim='&', kv_delim='=') ->
_.reduce do
object
(acc, v, k) ->
acc.push encodeURIComponent(k) + kv_delim + encodeURIComponent(v) if k
acc
[]
.join item_delim

/**
* Restores an object from a string of URL-encoded KV-pairs (aka "www-form-encoding").
*
* Note:
* - All resulting values will be strings as all type information is lost.
* - Both keys and values will be URL-decoded once.
*
* @param {String} string String of serialized KV-pairs.
* @param {String} [item_delim='&'] String delimiting each pair.
* @param {String} [kv_delim='='] String delimiting key from value.
* @returns {Object} Deserialized object containing the KV-pairs.
*/
fromKV: (string, item_delim='&', kv_delim='=') ->
_.reduce do
string.split item_delim
(acc, pair) ->
idx = pair.indexOf kv_delim
if idx is not -1
[k, v] = [pair.slice(0, idx), pair.slice(idx+1)]
else
[k, v] = [pair, '']
acc[ decodeURIComponent k ] = decodeURIComponent v if k
acc
{}

/**
* Copies and flattens a tree of sub-objects into namespaced keys on the target object, such
* that `{ "foo":{ "bar":1 } }` becomes `{ "foo.bar":1 }`.
*
* @param {Object} source Object to collapse.
* @param {Object} [target={}] Target of the collapsed keys.
* @param {String} [prefix=''] Prefix applied to copied keys.
* @returns {Object} The collapsed object.
*/
collapseObject: (source, target={}, prefix='') ->
prefix += '.' if prefix
_.each source, (v, k) ->
if _nest.isPlainObject v
_kv.collapseObject v, parent, prefix+k
else
parent[prefix+k] = v
parent

/**
* Inverse of `_.collapseObject()` -- copies all keys onto the target object, expanding any
* dot-namespaced keys found, such that `{ "foo.bar":1 }` becomes `{ "foo":{ "bar":1 }}`.
*
* @param {Object} source Collapsed source object.
* @param {Object} [target={}] Target of the uncollapsed keys.
* @returns {Object} The uncollapsed object -- either `target` or a new object.
*/
uncollapseObject: (source, target={}) ->
_.reduce do
source
(acc, v, k) ->
_nest.setNested acc, k, v, {+ensure}
acc
target


if module?
module.exports = _kv
else if exports?
exports import _kv
else if window?
window.UnderscoreKV = _kv

112 changes: 112 additions & 0 deletions underscore.kv.js
@@ -0,0 +1,112 @@
var _, _nest, _kv;
_ = require('underscore');
_nest = require('underscore.nested');
/**
* @namespace Functions for key-value pairs serialization (aka, www-form-encoding) of objects
*/
_kv = {
/**
* Transforms an object to a string of URL-encoded KV-pairs (aka "www-form-encoding").
*
* Note:
* - All values end up as a string, implying all type information is lost.
* - Both keys and values are URL-encoded once.
*
* @param {Object} object The object to be serialized.
* @param {String} [item_delim='&'] String delimiting each pair.
* @param {String} [kv_delim='='] String delimiting key from value.
* @returns {String} Serialized and encoded KV-pairs.
*/
toKV: function(object, item_delim, kv_delim){
item_delim == null && (item_delim = '&');
kv_delim == null && (kv_delim = '=');
return _.reduce(object, function(acc, v, k){
if (k) {
acc.push(encodeURIComponent(k) + kv_delim + encodeURIComponent(v));
}
return acc;
}, []).join(item_delim);
}
/**
* Restores an object from a string of URL-encoded KV-pairs (aka "www-form-encoding").
*
* Note:
* - All resulting values will be strings as all type information is lost.
* - Both keys and values will be URL-decoded once.
*
* @param {String} string String of serialized KV-pairs.
* @param {String} [item_delim='&'] String delimiting each pair.
* @param {String} [kv_delim='='] String delimiting key from value.
* @returns {Object} Deserialized object containing the KV-pairs.
*/,
fromKV: function(string, item_delim, kv_delim){
item_delim == null && (item_delim = '&');
kv_delim == null && (kv_delim = '=');
return _.reduce(string.split(item_delim), function(acc, pair){
var idx, k, v, __ref;
idx = pair.indexOf(kv_delim);
if (idx !== -1) {
__ref = [pair.slice(0, idx), pair.slice(idx + 1)], k = __ref[0], v = __ref[1];
} else {
__ref = [pair, ''], k = __ref[0], v = __ref[1];
}
if (k) {
acc[decodeURIComponent(k)] = decodeURIComponent(v);
}
return acc;
}, {});
}
/**
* Copies and flattens a tree of sub-objects into namespaced keys on the target object, such
* that `{ "foo":{ "bar":1 } }` becomes `{ "foo.bar":1 }`.
*
* @param {Object} source Object to collapse.
* @param {Object} [target={}] Target of the collapsed keys.
* @param {String} [prefix=''] Prefix applied to copied keys.
* @returns {Object} The collapsed object.
*/,
collapseObject: function(source, target, prefix){
target == null && (target = {});
prefix == null && (prefix = '');
if (prefix) {
prefix += '.';
}
_.each(source, function(v, k){
if (_nest.isPlainObject(v)) {
return _kv.collapseObject(v, parent, prefix + k);
} else {
return parent[prefix + k] = v;
}
});
return parent;
}
/**
* Inverse of `_.collapseObject()` -- copies all keys onto the target object, expanding any
* dot-namespaced keys found, such that `{ "foo.bar":1 }` becomes `{ "foo":{ "bar":1 }}`.
*
* @param {Object} source Collapsed source object.
* @param {Object} [target={}] Target of the uncollapsed keys.
* @returns {Object} The uncollapsed object -- either `target` or a new object.
*/,
uncollapseObject: function(source, target){
target == null && (target = {});
return _.reduce(source, function(acc, v, k){
_nest.setNested(acc, k, v, {
ensure: true
});
return acc;
}, target);
}
};
if (typeof module != 'undefined' && module !== null) {
module.exports = _kv;
} else if (typeof exports != 'undefined' && exports !== null) {
__import(exports, _kv);
} else if (typeof window != 'undefined' && window !== null) {
window.UnderscoreKV = _kv;
}
function __import(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}

0 comments on commit ed801a9

Please sign in to comment.