Last active
April 2, 2016 10:40
-
-
Save ohAitch/4f94075fe8f139b25c32ab5f21db3eff to your computer and use it in GitHub Desktop.
The abstraction model of Redux, implemented in 7 lines. Learning project.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## 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