08 septembre 2011

Underscore + JSONSelect = XPath for JSON ?

XML est largement utilisé pour formater, stocker, échanger des informations structurées. Et malgré l’étendu de ses capacités, il n'en reste pas moins qu'un support. Et en tant que support JSON n'a rien à envier à XML. N'importe quelle information peut-être stocker avec JSON. Par contre l'écosystème XML est riche et on peut facilement transformer, valider, émietter nos données, ce qui semble moins évident avec JSON. Mais qui dit JSON dit Javascript et l'écosystème Javascript est également très riche et il permet de faire aussi bien voir mieux que XML dans certain domaine. Voici une technique pour picorer de l'information comme on le ferai avec XPath sur du XML mais sur un objet JSON.

JSONSelect

JSONSelect permet de picorer dans un objet javascript à l'aide de sélecteur CSS. Exemple :
#!/usr/bin/env node

var jsel = require('JSONSelect');
var doc = {
	"id": "0001",
	"type": "donut",
	"name": "Cake",
	"ppu": 0.55,
	"batters":
		{
			"batter":
				[
					{ "id": "1000", "type": "None" },
					{ "id": "1001", "type": "Regular" },
					{ "id": "1002", "type": "Chocolate" },
					{ "id": "1003", "type": "Blueberry" },
					{ "id": "1004", "type": "Devil's Food" }
				]
		},
	"topping":
		[
			{ "id": "5001", "type": "None" },
			{ "id": "5002", "type": "Glazed" },
			{ "id": "5005", "type": "Sugar" },
			{ "id": "5007", "type": "Powdered Sugar" },
			{ "id": "5006", "type": "Chocolate with Sprinkles" },
			{ "id": "5003", "type": "Chocolate" },
			{ "id": "5004", "type": "Maple" }
		]
};

console.log(jsel.match('.name', doc));
// [ 'Cake' ]
console.log(jsel.match('number', doc));
// [ 0.55 ]
console.log(jsel.match('.batter .type', doc));
// [ 'Regular', 'Chocolate', 'Blueberry', 'Devil\'s Food' ]
console.log(jsel.match('.type ~ .id:val("5005")', doc));
// [ '5005' ]
console.log(jsel.match('.type:val("None") ~ .id', doc));
// [ '1000', '5001' ]



Underscore

Underscore fournit ~ 60 fonctions orientées programmation fonctionnelle.
Et partie elles, une trentaine simplifient grandement la manipulation et le traitement des listes et des tableaux. Exemple :
#!/usr/bin/env node

var _ = require('underscore');

var arr = ["1000", "1001", "1002", "1003", "1004"];
console.log(_.first(arr));
// [ '1000' ]
console.log(_.without(arr, "1000"));
// [ '1001', '1002', '1003', '1004' ]
console.log(_(arr).chain().without(arr, "1000").first().value());
// 1001
console.log(_.map(arr, function(value) {
			return '#'+value ;
}));
// [ '#1000', '#1001', '#1002', '#1003', '#1004' ]
console.log(_(arr).chain().map(function(value) { 
			return value.substr(1, 2);
	}).uniq().first().value());
// 00


JSONSelect & Underscore

JSONSelect permet de récupérer des listes d'objet ou des tableaux de valeur, Underscore permet de manipuler des listes et des tableaux.
Coupler les deux offre donc un outil extrêmement puissant pour aller piocher et trier de l'information. Exemple :
#!/usr/bin/env node

var jsel = require('JSONSelect'),
	_ = require('underscore');

//  Underscore + JSONSelect
_.mixin({
		jsel : function(doc, sel) {
			return jsel.match(sel, doc)
		}
});

var data = [
	{ name:'Africa', type:'continent'},
	{ name:'Egypt', type:'country' },
	{ name:'Kenya', type:'country'},
	{ name:'Nairobi', type:'city' },
	{ name:'Mombasa', type:'city' },
	{ name:'Sudan', type:'country'},
	{ name:'Khartoum', type:'city' },
	{ name:'Asia', type:'continent'},
	{ name:'China', type:'country' },
	{ name:'India', type:'country' },
	{ name:'Russia', type:'country' },
	{ name:'Mongolia', type:'country' },
	{ name:'Australia', type:'continent'},
	{ name:'Commonwealth of Australia', type:'country'},
	{ name:'Europe', type:'continent'},
	{ name:'Germany', type:'country' },
	{ name:'France', type:'country' },
	{ name:'Spain', type:'country' },
	{ name:'Italy', type:'country' },
	{ name:'North America', type:'continent'},
	{ name:'Mexico', type:'country'},
	{ name:'Mexico City', type:'city'},
	{ name:'Guadalajara', type:'city'},
	{ name:'Canada', type:'country'},
	{ name:'Ottawa', type:'city'},
	{ name:'Toronto', type:'city'},
	{ name:'United States of America', type:'country' },
	{ name:'South America', type:'continent'},
	{ name:'Brazil', type:'country'},
	{ name:'Argentina', type:'country'}
];

console.log(_(data).chain().jsel('.type').uniq().value());
// [ 'continent', 'country', 'city' ]
console.log(_(data).chain().jsel('.type:val("city") ~ .name').sortBy(function(value) { 
			return value.charCodeAt(0)
	}).value());
// [ 'Guadalajara', 'Khartoum', 'Mombasa', 'Mexico City', 'Nairobi', 'Ottawa', 'Toronto' ]


06 septembre 2011

Installer NodeJS dans son HOMEDIR avec STOW

Il y a quelque temps déjà, j'avais présenté l'utilitaire stow. Mais avec les distributions Linux récentes cet utilitaire avait peu d’intérêt tant l'usage d'apt-get install suffisait la majorité du temps. Mais voilà, avec NodeJS, on ne peut pas attendre que la dernière version soit packagée pour l'utiliser. Il faut donc l'installer soit même, et si il existe plusieurs méthodes, aucune ne permet de changer de version de nodejs en un fragment de seconde. Démonstration !

STOW

Stow permet de recréer une arborescence système à l'aide de liens symboliques. Ces liens pointent sur un répertoire isolé et ils sont générés automatiquement à l'aide d'une simple commande.


Pré requis système

Pour installer et compiler NodeJS, il faut vérifier que les paquets g++ et libssl-dev sont installés.

#!/bin/sh

sudo apt-get install g++ libssl-dev


Installation de STOW

#!/bin/sh

# CHOOSE THE VERSION YOU WANT 
export STOW_VERSION=1.3.3

mkdir ~/local/stow
mkdir -p ~/local/src
mkdir ~/local/bin
mkdir ~/local/info
mkdir ~/local/etc
mkdir ~/local/include
mkdir ~/local/share
mkdir ~/local/share/man
mkdir ~/local/lib
mkdir ~/local/man
mkdir ~/local/man/man1
mkdir ~/local/man/man2
mkdir ~/local/man/man3
mkdir ~/local/man/man4
mkdir ~/local/man/man5
mkdir ~/local/man/man6
mkdir ~/local/man/man7
mkdir ~/local/man/man8

cd ~/local/src
curl http://ftp.gnu.org/gnu/stow/stow-${STOW_VERSION}.tar.gz | tar -xzf -

cd stow-${STOW_VERSION}
./configure --prefix=~/local/stow/stow-${STOW_VERSION}

make
make install

cd ~/local/stow/
./stow-1.3.3/bin/stow stow-1.3.3

echo "export PATH=\$HOME/local/bin:\${PATH:=}" >> ~/.profile
echo "export MANPATH=\$HOME/local/man:\${MANPATH:=}" >> ~/.profile
echo "export LD_LIBRARY_PATH=\$HOME/local/lib:\${LD_LIBRARY_PATH:=}" >> ~/.profile

export PATH=$HOME/local/bin:${PATH:=}
export MANPATH=$HOME/local/man:${MANPATH:=}
export LD_LIBRARY_PATH=$HOME/local/lib:${LD_LIBRARY_PATH:=}


NodeJS

NodeJS doit être compilé manuellement pour bénéficier des dernières versions. On va donc compiler et installer chaque version dans un répertoire spécifique.


Installation de NodeJS pour STOW

#!/bin/sh

# CHOOSE THE VERSION YOU WANT 
export NODEJS_VERSION=0.6.1

mkdir -p ~/local/lib/node_modules
cd ~/local/src

curl http://nodejs.org/dist/v${NODEJS_VERSION}/node-v${NODEJS_VERSION}.tar.gz | tar -xzf -
cd ~/local/src/node-v${NODEJS_VERSION}

./configure --prefix=~/local/stow/node-${NODEJS_VERSION}
make
make install

# Careful, check if stow is installed
cd ~/local/stow
stow node-${NODEJS_VERSION}

echo "export NODE_PATH=\$HOME/local:\$HOME/local/lib/node_modules" >> ~/.profile
export NODE_PATH=$HOME/local:$HOME/local/lib/node_modules


Changer de version facilement

Maintenant tester une nouveau version de NodeJS est très simple :

$ node -v
v0.4.11
$ cd ~/local/stow
$ stow -D node-0.4.11
$ stow node-0.6.1
$ node -v
v0.6.1