Last active
August 29, 2015 14:08
-
-
Save mattdeboard/ae6ec3f2a5335bcb7939 to your computer and use it in GitHub Desktop.
Toying with protocols in CoffeeScript
This file contains hidden or 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
cloneState = (state, phase = 'current') -> | |
### | |
Returns a copy of a particular phase (i.e. either current or initial) | |
of the atom state. | |
Of course this assumes everything in the value is serializable to | |
JSON :) | |
### | |
JSON.parse(JSON.stringify(state[phase])) | |
class ISwap | |
@__swap: (fn, args...) -> | |
curr_state = cloneState @__state | |
@__state['last'] = curr_state | |
args.splice 0, 0, curr_state | |
@__state['current'] = fn.apply(fn, args) | |
@ | |
class IDeref | |
@__deref: -> | |
cloneState @__state | |
class IReset | |
@__reset: (new_val = null) -> | |
new_state = cloneState @__state, 'initial' | |
if new_val? | |
new_state = new_val | |
@__state['current'] = new_state | |
@ | |
class Atom | |
### | |
Naive/toy implementation of a ClojureScript-style Atom. | |
Supports dereferencing, swapping and resetting of the value via | |
Clojure-style protocols | |
### | |
__state: | |
initial: null | |
current: null | |
@protocols: | |
swap: ISwap.__swap | |
deref: IDeref.__deref | |
reset: IReset.__reset | |
constructor: (state = null) -> | |
@__state['current'] = state | |
@__state['initial'] = state | |
# Completely arbitrary decision here on my part to patch in methods in | |
# this manner. Could easily just do like | |
# swap: -> ISwap.__swap.call @ | |
# Probably better to just do it that way, but I'm just "exploring the space". | |
for proto, func of Atom.protocols | |
@[proto] = func.bind @ | |
exports.atom = (state) -> | |
### | |
Create a new atom encapsulating the values in 'state'. | |
### | |
new Atom(state) | |
exports.deref = (_atom) -> | |
### | |
Return a copy of the current state of the atom. Modifications to the | |
value returned will not update the state of the atom. Use 'swap' for | |
that. | |
### | |
if _atom instanceof Atom | |
_atom.deref() | |
exports.swap = (_atom, fn, args...) -> | |
### | |
Transform the current state of the atom by calling 'fn' with arguments | |
'args'. | |
### | |
if _atom instanceof Atom | |
_atom.swap fn, args | |
exports.reset = (_atom, new_val) -> | |
### | |
Set the value of atom without regard to its current value. If | |
'new_val' is not provided, then resets value of atom to its | |
initial value. | |
### | |
if _atom instanceof Atom | |
_atom.reset new_val | |
### | |
Example: | |
Adds a new key to 'app_state'. | |
Obviously this requires some knowledge of the shape of the app state in the | |
atom. | |
### | |
app_state = atom | |
foo: "bar" | |
baz: "qux" | |
_func_for_swap = (state_val) -> | |
# 'state_val' will be the value of a dereferenced atom. | |
if state_val instanceof Object | |
state_val['quux'] = 'quuux' | |
return state_val | |
else | |
throw "Invalid type for this operation." | |
# Look at the current state | |
console.log deref(app_state) | |
# Modify the atom state | |
swap app_state, _func_for_swap | |
# Should have 'quux' key now | |
console.log deref(app_state) | |
# Set it back to its original value | |
reset app_state | |
# Should match initial state | |
console.log deref(app_state) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment