Skip to content

Instantly share code, notes, and snippets.

View axefrog's full-sized avatar

Nathan Ridley axefrog

  • Brisbane, Australia
View GitHub Profile
@axefrog
axefrog / debug.js
Last active January 17, 2017 04:17
Full-featured console-based log/trace debugger for most.js, borrowing ideas from CQRS.
import Immutable from 'immutable';
import formatDate from 'date-fns/format';
import immutableDiff from 'immutablediff';
/* eslint-disable no-underscore-dangle */
var colors = {
0: ['white', '#7fbad8', '#0075b2'],
1: ['white', '#91a0ce', '#24429e'],
2: ['white', '#ab86e0', '#570ec1'],
@axefrog
axefrog / flatScan.js
Last active August 12, 2016 09:43
A multi-pass scan operator for most.js
import {sample} from '@most/sample';
import {proxy as makeProxy} from 'most-proxy';
/**
* FlatScan is a multi-pass accumulation operator. It takes a first-stage
* initiator function and an initial state value, and returns a function that
* takes a stream of values and returns a stream of cumulatively-updated values.
*
* For each input value received from the source stream, the initiator function
* is called with the current accumulated state, the input value, and an
@axefrog
axefrog / dispose.js
Last active July 16, 2016 07:57
A selective, key-based multicast operator for most.js. Some code borrowed/adapted from mostjs/multicast.
export const dispose = disposable => disposable.dispose();
export const emptyDisposable = {
dispose() {}
};
export class DispatchDisposable
{
constructor(source, sink, key) {
this.source = source;
@axefrog
axefrog / limitFlow.js
Last active October 17, 2016 19:44
Flow control limiter for most.js. Unlike `throttle`, which drops events indiscriminately, `limitFlow` retains the most recent event and ensures that it is emitted when the specified period elapses.
// Limit the rate of flow to an event every 250ms:
// const stream$ = other$.thru(limitFlow(250));
export function limitFlow(period) {
return function limitFlow(stream) {
const source = new RateLimitSource(stream.source, period);
return new stream.constructor(source);
};
}
@axefrog
axefrog / intercept.js
Last active May 6, 2016 04:49
A very quick-and-dirty proxy interceptor for introspection of an object's behaviour. Assumes chalk is installed.
import chalk from 'chalk';
function str(val) {
return val ? val.toString().replace(/\s+/g, ' ') : val;
}
let i = 0;
export function intercept(obj, title) {
return new Proxy(obj, {
get(target, name) {
@axefrog
axefrog / conventions.md
Last active April 6, 2016 23:58
A WIP document I'm putting together for Epicycle, my boilerplate framework for building isomorphic web applications using Motorcycle and Most.js.

Conventions, Naming & Best Practices

Though you don't have to follow these conventions, you'll get off to a quicker start if you do, and your code will be more consistent and thus easier to maintain. Many of these conventions are largely an attempt to reuse common ideas and best practices that have been discovered by the Cycle community, and to provide additional abstractions to cover the specialised concerns of an isomorphic web application, and to promote the DRY principle.

Streams

Variables representing streams should be suffixed with $, for example data$. The variable name chosen, or a suffix thereof, should be a suitable name to represent the data emitted. For example, data$ should emit data. Similarly, userAuthData$ is fine for emitting any of userAuthData, authData, or just data. Example: authData$.map(data => ...) or authData$.map(authData => ...)

var frog$ = most.of({ name: 'Hopper' })
@axefrog
axefrog / #upgradeSources.js
Last active April 1, 2016 01:59
An idea I was playing around with for improving the way sources are passed around in Cycle.js. I since discarded the approach after the discussion at https://github.com/cyclejs/core/issues/284
export function upgradeSources(sources) {
const sourceKeys = Array.from(Object.keys(sources));
const cleanSources = sources => sourceKeys
.reduce((acc, key) => (acc[key] = sources[key], acc), {});
function withCustom(baseSources, customSources) {
const cleanedSources = cleanSources(baseSources);
const nextSources = Object.assign({}, cleanedSources, customSources);
return augment(nextSources, cleanedSources);
@axefrog
axefrog / an-imperative-approach.js
Last active April 1, 2016 02:04
An experiment in functional programming for validating and normalizing a variably-structured options argument
function sanitizeOptions(options) {
if(!options) {
options = {}
}
else if(typeof options === `string`) {
options = { scope: options }
}
else if(Array.isArray(options)) {
options = { include: options }
}
@axefrog
axefrog / example-test.js
Last active February 29, 2016 14:05
Utilities for easily running tests against streams of arrays of arrays of streams of streams of... you get the idea. (most.js + mocha + chai)
it('projectStaticsToArrayOfPairStreams() should return an array of streams of key/state objects', () => {
const statics = internals.projectStaticsToArrayOfPairStreams(partitioned.statics);
return deepCapture(statics)
.then(result => {
const expected = [
$([{ key: 'a', state: { x: 1, y: 2 } }, { key: 'a', state: { x: 3, y: 4 } }]),
$([{ key: 'b', state: { x: 5, y: 6 } }, { key: 'b', state: { x: 7, y: 8 } }]),
$([{ key: 'c', state: { } }])
];
assert.deepEqual(expected, result);
@axefrog
axefrog / contextDriver.js
Last active April 1, 2016 01:59
Experiment: Context driver providing a way to recognise the inherit coupling of state with a view, its metadata and children. A context object is built and extended by each nested component as it is emitted to its parent.
export function makeContextDriver(domDriver) {
return function(context$) {
const ctx$ = context$.multicast();
const vtree$ = ctx$.filter(c => c.vtree).map(c => c.vtree);
const state$ = ctx$.filter(c => c.state).map(c => c.state);
const metadata$ = ctx$.filter(c => c.metadata).map(c => c.metadata);
return {
DOM: domDriver(vtree$),
state$,