Skip to content

Instantly share code, notes, and snippets.

@mattdeboard
Last active August 29, 2015 14:08
Show Gist options
  • Save mattdeboard/ae6ec3f2a5335bcb7939 to your computer and use it in GitHub Desktop.
Save mattdeboard/ae6ec3f2a5335bcb7939 to your computer and use it in GitHub Desktop.
Toying with protocols in CoffeeScript
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