Skip to content

Instantly share code, notes, and snippets.

@PotOfCoffee2Go
Last active October 7, 2018 15:02
Show Gist options
  • Save PotOfCoffee2Go/7433f0b7b5479c57bd8a4f3688e6f8ce to your computer and use it in GitHub Desktop.
Save PotOfCoffee2Go/7433f0b7b5479c57bd8a4f3688e6f8ce to your computer and use it in GitHub Desktop.
Load classes stored in ObservableHq into nodejs
/*
Create empty directory
From command line
* note to self: nvm use 10
npm init -y
npm i fs-extra --save
npm i node-fetch --save
npm i download-cli --save
node node_modules/download-cli/cli.js -e --out notebooks 'https://api.observablehq.com/@potofcoffee2go/01-data-managment-toolbox.tgz'
node node_modules/download-cli/cli.js --out ./ 'https://gist.github.com/PotOfCoffee2Go/7433f0b7b5479c57bd8a4f3688e6f8ce/raw/479f7bc87ed1983408d18483d59c8c96b3ef6a3b/observable-to-nodejs.js'
node observable-to-nodejs.js
*/
'use strict';
const fs = require('fs-extra'),
fetch = require('node-fetch');
/* Load {notebook}.js into Nodejs (CJS)
* Note: requires nodejs >= v10 due to generator functions in notebook
* Changes line 'export default notebook;' to 'module.exports = notebook;'
* leaving the original unmodified so can still be used by the browser
* Returns loaded module
*/
function requireNotebook(notebookPath) {
let es = fs.readFileSync(notebookPath, 'utf8');
let cjs = es.replace(/\nexport default notebook;\n/, 'module.exports = notebook;');
fs.writeFileSync('./notebooks/temp.js', cjs);
let module = require('./notebooks/temp.js');
fs.unlinkSync('./notebooks/temp.js');
return module;
}
/* Get a cell from notebook */
function getCell(cellname, ...args) {
return notebook.modules[0].variables
.find(variable => variable.name === cellname)
.value(...args);
}
const notebook = requireNotebook('./notebooks/01-data-managment-toolbox.js');
// A utilities class defined in notebook 'Util' cell - this cell requires no params
// but... since do not have the browsers 'fetch()' need to use node-fetch
const Util = getCell('Util');
const util = new Util; // instantiate
util.getJson = async(url) => { return await (await fetch(url)).json() }
// Classes in other cells use an object 'cf' as a lookup table
let cf = getCell('cf');
// or could just do a :
//let cf = {};
// Clerk is a base class to the other classes
const Clerk = getCell('Clerk', cf, util);
// Classes that will be instantiated later by our data surrogate class
const
Meta = getCell('Meta', cf, Clerk, util),
Edge = getCell('Edge', cf, Clerk, util),
Feed = getCell('Feed', cf, Clerk, util),
Eyes = getCell('Eyes', cf, Clerk, util);
// Instantiates and use all the classes above
const Surrogate = getCell('Surrogate', cf, Meta, Edge, Feed, Eyes, Clerk);
const surrogate = new Surrogate({ [cf.data]: 'A new surrogate' });
// Watch for when surrogate data updates
async function watchUpdates() {
console.log(`At ${surrogate[cf.meta].updated} ` +
`got ${JSON.stringify({data: surrogate[cf.data]},null,2)}\n`);
await surrogate[cf.eyes].watch(); // Eyes promise resolves when data updated
watchUpdates();
}
watchUpdates();
// Watch for feed href changes
async function watchFeedHref() {
await surrogate[cf.feed].watch(); // Feed promise resolves when href updated
console.log(`--> Feed url changed: ${surrogate[cf.feed].href}\n`);
watchFeedHref();
}
watchFeedHref();
// Go out and get some data off the web
let counter = 0;
setInterval(() => {
surrogate[cf.feed].href = `https://jsonplaceholder.typicode.com/todos/${++counter}`;
surrogate[cf.feed].fetch();
}, 3000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment