JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 4
  • Score
    100M100P100Q41971F
  • License ISC

A state machine with pull stream interface

Package Exports

  • pull-stream-model
  • pull-stream-model/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (pull-stream-model) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

pull stream model

Trying ways to model application state

This creates a state machine from an object where the keys describe event types. An update object is used to create a scan function that handles changing the app state in response to events. It looks like this.

var update = {
    bar: function (state, ev) {
        return state + ev
    },
    start: (state, ev) => state + ' resolving',
    resolve: (state, ev) => state.replace(' resolving', '')
}

Effects is an object used to filter and map events. Since mapping can be asynchronous, this is where you would put any IO, like network requests.

var effects = {
    foo: function (state, msg, ev) {
        return msg.bar(ev + '!!!')
    },
    asyncThing: function (state, msg, ev) {
        // async actions still have a return value -- a new pull stream
        // this gets `join`ed into the main event stream
        return cat([
            S.once(msg.start()),
            async(function (cb) {
                setTimeout(function () {
                    cb(null, msg.resolve())
                }, 100)
            })
        ])
    },
    baz: function (state, msg, ev) {
        // you can filter by returning an empty stream
        return S.empty()
    }
}

These functions get called with a msg argument, which is an object that returns "messages". The messages are just arrays, which means they can be easily serialized.

The functions in update or effects can be nested to any depth, too, and it will be called with the corresponding sub-tree of state.

example

model

var test = require('tape')
var async = require('pull-async')
var cat = require('pull-cat')
var S = require('pull-stream')
var Component = require('../')
var pushable = require('pull-pushable')

function Model () {
    return ''
}
Model.update = {
    bar: function (state, ev) {
        return state + ev
    },
    start: (state, ev) => state + ' resolving',
    resolve: (state, ev) => state.replace(' resolving', '')
}
Model.effects = {
    foo: function (state, msg, ev) {
        return msg.bar(ev + '!!!')
    },
    asyncThing: function (state, msg, ev) {
        return cat([
            S.once(msg.start()),
            async(function (cb) {
                setTimeout(function () {
                    cb(null, msg.resolve())
                }, 100)
            })
        ])
    }
}


test('model', function (t) {
    t.plan(2)
    var model = Component(Model)
    var p = pushable()
    p.push(model.msg.foo('hello'))
    p.push(model.msg.bar(' hi'))
    p.push(model.msg.asyncThing())
    p.end()

    S(
        p,
        // S.through(console.log.bind(console, 'ev')),
        model.effects(),
        model.store,
        S.collect(function (err, res) {
            t.error(err)
            t.deepEqual(res, [
                '',
                'hello!!!',
                'hello!!! hi',
                'hello!!! hi resolving',
                'hello!!! hi'
            ], 'should do the thing')
        })
    )
})

should update

This is for filtering events when you need to know the current and also the last state. It is used in the same role as react's shouldComponentUpdate.

var shouldUpdate = require('pull-stream-model/should-update')

S(
    S.values([1,2,3]),
    // if this is the first event, then `prev` is null
    shouldUpdate(function (prev, next) {
        return prev + next === 3
    }),
    S.collect(function (err, res) {
        t.error(err)
        t.deepEqual(res, [2], 'should filter the stream')
    })
)