Skip to content

Instantly share code, notes, and snippets.

@ohAitch
Last active April 2, 2016 10:40
Show Gist options
  • Save ohAitch/4f94075fe8f139b25c32ab5f21db3eff to your computer and use it in GitHub Desktop.
Save ohAitch/4f94075fe8f139b25c32ab5f21db3eff to your computer and use it in GitHub Desktop.
The abstraction model of Redux, implemented in 7 lines. Learning project.
## Info ##
# requires jquery, zepto, or such
# live demo at https://jsbin.com/kuyukucoxe/edit?js,output
## shim('react'): render an html string to the page
$ \#mount .remove!
$ \body .append '<div id="mount"/>'
mount = -> $ \#mount .html it
## shim('react-dom'): functionally compose html
dom = (node, props={}, ...kids)->
attrs = [" #k='#v'" for k,v of props]*\,
body = kids * ''
"<#node#attrs>#body</#node>"
for let k in <[div span button]>
dom[k] = (...x)-> dom k, ...x
## shim('redux'): runs a reducer on a piece of data and
# dispatched actions, observable by a subscriber function
createStore = (reducer, data)->
subscriber = -> # warning: unmultiplexed
store =
subscribe: (subscriber:=)
dispatch: (...args)->
data := reducer data, ...args
subscriber data
# Calculator example #
## Create a store that manages the output window ##
{dispatch, subscribe} = createStore (
# The display contains a `res`ult or expression,
# and has a textual `buf`fer.
{res, buf} = {+res, buf:"0"},
# Accepted commands are `num`bers, `op`erations,
# or `run`ning the window contents.
{num, op, run} = {} )->
# Write out an evaluated result.
| run? => {+res, buf: ""+ try eval buf catch}
# Clear buffer if necessary to begin a new expression,
# append numerical symbol.
| num? => {-res, buf: (if res then "" else buf) + num}
# Just append operators.
| op? => {-res, buf: buf + op}
# An unknown state changes are ineffective state change.
| _ => {res, buf}
## Action handler/generator ##
# Maps button symbols to typed actions.
window.calckey = ({innerText:txt})->
# Equals requests the expression be evaluated.
| txt is '=' => dispatch {+run}
# Digits and dot are "numerical", and can begin
# an expression.
| txt is /[0-9.]/ => dispatch num:txt
# The rest(*/+-) are only allowed in infix position.
| _ => dispatch op:txt
## Components ##
let @ = dom
# Every key dispatches an action when clicked
key = (symbol)~>
@button {onclick:'window.calckey(this)'} symbol
# Most of the calculator is composed of rows of keys,
row = (chars)~> @div {} ...[(key ..) for chars]
# which in turn are stacked under the output display.
grid = ({buf}, rows)~> @div {},
(@div {} @span {} buf)
...[(row ..) for rows]
## Setup ##
# Whenever the buffer updates, the grid should be
# rendered with a fixed set of available commands.
subscribe ({buf})->
mount grid {buf},
<[ 123/
456*
789-
0.=+ ]>
## Finally, all state is initialized. ##
dispatch!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment