From 080b231ceb51ca8ce995d46492833d9b5530162b Mon Sep 17 00:00:00 2001 From: Arnout Roemers Date: Fri, 24 Jul 2020 20:39:58 +0200 Subject: [PATCH] Skip redefinition of defstate when active --- CHANGELOG.md | 7 +++++++ README.md | 2 ++ project.clj | 2 +- src/redelay/core.clj | 20 +++++++++++++++----- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a79b7d..a7a2228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## 1.0.3 + +### Added + +- Trying to redefine an active (i.e. realized) `defstate` is skipped and yields a warning. + + ## 1.0.2 ### Fixed diff --git a/README.md b/README.md index 67129a3..0100530 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,8 @@ Therefore the above can also be written as follows: ``` Users of [mount](https://github.com/tolitius/mount) or [mount-lite](https://github.com/aroemers/mount-lite) will recognize above syntax. +Trying to redefine a `defstate` which is active (i.e. realized) is skipped. + The `defstate` macro fully supports metadata on the name, a docstring and an attribute map. Note that this metadata is set on the var. If you want metadata on a State, you can use **a `:meta` expression** in the body of the `state` macro, or use Clojure's `with-meta` on it. diff --git a/project.clj b/project.clj index 0a5a6f5..1555b11 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject functionalbytes/redelay "1.0.2" +(defproject functionalbytes/redelay "1.0.3" :description "Clojure library for first class lifecycle-managed state." :url "https://github.com/aroemers/redelay" :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" diff --git a/src/redelay/core.clj b/src/redelay/core.clj index d4421ee..a5f3048 100644 --- a/src/redelay/core.clj +++ b/src/redelay/core.clj @@ -87,9 +87,15 @@ (recur qualifiers (rest exprs) qualifier (update qualified qualifier (fnil conj []) expr)))) qualified))) +(declare state?) + +(defn- skip-defstate? [ns name] + (let [state (some-> (ns-resolve ns name) deref)] + (and (state? state) (realized? state)))) + ;;; Public API -(defn state* +(defn state* "Low-level function to create a State object. All keys are optional. The `:start-fn` value must be a 0-arity function. The `:stop-fn` value must be a 1-arity function. The `:meta` value must be a map." @@ -131,12 +137,16 @@ "Create a State object, using the optional :start, :stop and :meta expressions, and bind it to a var with the given name in the current namespace. Supports metadata on the name, a docstring and an - attribute map." + attribute map. Trying to redefine an active (i.e. realized) defstate + is skipped." {:arglists '([name doc-string? attr-map? body])} [name & exprs] - (let [[name exprs] (name-with-exprs name exprs)] - `(def ~name - (state ~@exprs :name ~(symbol (str *ns*) (str name)))))) + (if (skip-defstate? *ns* name) + (binding [*out* *err*] + (println "WARNING: skipping redefinition of active defstate" name)) + (let [[name exprs] (name-with-exprs name exprs)] + `(def ~name + (state ~@exprs :name ~(symbol (str *ns*) (str name))))))) ;;; Default management.