Giter Site home page Giter Site logo

pull-stream-model's Introduction

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')
    })
)

pull-stream-model's People

Contributors

nichoth avatar

Stargazers

Andrejs Agejevs avatar Diego avatar Martín Acosta avatar Mikey avatar Jake Burden avatar

Watchers

James Cloos avatar  avatar  avatar

pull-stream-model's Issues

event utils

How to check event interfaces? view (readable) vs model (writable)

We want to be able to map the model state into different formats — something easier for the view or different for a different view. How do tests work in this factoring?

Don't use nextTick in effects

Can we do #3 but without making everything async? It works, but it's not good for rendering UI in a browser. The async stuff causes it to re-render when it shouldn't.

better interface for multiple subscribers

var model = Model({
  effects: {},
  update: {},
  init: { foo: 'bar' }  // initial state
})

S(
  someSource,
  model.effects(),
  model.update(),  // emit the init state right away
  someSink
)

S(
  model.update.listen()  // source starting with the most recent value
  sink
)

Don't `filter` in the effects

This is unnecessary. The more conventional fp pattern would be to return Maybe.Nothing, which is S.empty() for us.

request stream

A stream for an http request. It is the normal request stream start, op, resolve, but add a method onEnd(function (err, resp) {})

Use case
Need to dispatch additional messages at different levels in the model hierarchy.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.