Last active
May 27, 2023 05:58
-
-
Save jaidetree/adefdc48a98b3fceed105ac190e444aa to your computer and use it in GitHub Desktop.
Fennel state machine
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
;; Usage example | |
(local my-fsm | |
(fsm.defmachine | |
{:name :test-fsm | |
:state {:idle {} | |
:pending {:url (p.and | |
p.str? | |
p.url?) | |
:started-at p.number?} | |
:fulfilled {:response {:data p.assoc-table?} | |
:data p.assoc-table? | |
:completed-at p.number?} | |
:failed {:failed-at p.number?}} | |
:context {:request (p.or p.nil? {:url p.url?}) | |
:error (p.or p.nil? p.error?)} | |
:actions {:fetch [{:url p.url}] | |
:resolve [{:response p.assoc-table?}] | |
:reject [{:error p.error?}]}})) | |
(fsm.transition | |
my-fsm | |
{:on [:fetch] | |
:when [:idle :fulfilled :failed] | |
:do | |
(fn [{: state : ctx : cancel-effect &as machine} {: url &as action}] | |
{:state {:is :pending | |
:url url | |
:started-at (now)} | |
:context (merge ctx {:request {:url url}}) | |
;; Pretend the fetch function exists and is async but the code below it | |
;; is called after it completes | |
:effect (fn [{: dispatch}] | |
(let [request (fetch url) | |
response request.response] | |
(if response.error | |
(dispatch {:type :reject :error response.error}) | |
(dispatch {:type :resolve :response response})) | |
(fn destroy [] | |
(request:abort))))})}) | |
(fsm.transition | |
my-fsm | |
{:on [:resolve] | |
:when [:pending] | |
:do | |
(fn [{: state : ctx : cancelEffect &as machine} {: response :as}] | |
{:state {:is :fulfilled | |
:response response | |
:data response.data | |
:completed-at (now)} | |
:context (dissoc ctx :error)})}) | |
(fsm.transition | |
my-fsm | |
{:on [:reject] | |
:when [:pending] | |
:do | |
(fn [{: state : ctx : cancelEffect &as machine} {:error err &as action}] | |
{:state {:is :failed | |
:failed-at (now)} | |
:context (merge ctx {:error err})})}) | |
;; ...More transitions if desired... | |
;; Creating an instance | |
(local a-request-fsm (fsm.new my-fsm {:state {:is :idle} | |
:context {}})) | |
(print a-request-fsm.state) | |
;; => {:state {:is :idle} :context {}} | |
(a-request-fsm.dispatch {:type :fetch :url "https://example.com"}) | |
(print a-request-fsm.state) | |
;; => {:state {:is :pending} | |
;; :context {:request {:url "https://example.com"}})) | |
;; :cancel-effect #<function: 0xaabbcc>} | |
;; About 200ms later... | |
(print a-request-fsm.state)) | |
;; => {:state {:is :fulfilled | |
;; :response #<table: 0xaabbcc> | |
;; :data #<table: 0xddeeff>} | |
;; :context {:request {:url "https://example.com"}}} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment