diff --git a/CHANGES.md b/CHANGES.md index 078f60e..5d078f2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,10 +1,22 @@ +## v0.3.1 (2015-04-18) + +Various small improvements and bug fixes: + + - log-ex middleware added to core api (it was a mistake that it was missing) + - modest improves to simple example. Better comments, layout, etc. + - the anonymous functions in standard middleware now have meaningful + names, which makes stack traces easier to understand. + - #24 - Fix missing paren in README + - #31 - Fix list formatting in README + - #32 - fix a broken wiki link + - #30 - Fix up the enrich docstring + ## v0.3.0 (2015-04-15) ### Headline - - the middleware `after` and `enrich` now call the supplied function `f` with both `db` and `v` (previously just `db`). Because javascript is so forgiving about function arity, this change is backwards compatible. diff --git a/README.md b/README.md index aeb7fdd..e1b5757 100644 --- a/README.md +++ b/README.md @@ -670,7 +670,7 @@ Let's sketch out the situation described above ... {:name "c" :val 23 :flag "y"}]) (def app-db (reagent/atom {:items L - :sort-by :name}) ;; sorted by the :name attribute + :sort-by :name})) ;; sorted by the :name attribute ``` The subscription-handler might be written: @@ -897,7 +897,7 @@ Collectively, event handlers provide the control logic in a re-frame application An event handler is a pure function of two parameters: 1. current value in `app-db`. Note: that's the map **in** `app-db`, not the atom itself. - 2 an event (represented as a vector) + 2. an event (represented as a vector) It returns the new value which should be reset! into `app-db`. diff --git a/examples/simple/example.html b/examples/simple/example.html index a9b7c39..50b9bd6 100644 --- a/examples/simple/example.html +++ b/examples/simple/example.html @@ -11,7 +11,9 @@ diff --git a/examples/simple/project.clj b/examples/simple/project.clj index c369305..9ee3072 100644 --- a/examples/simple/project.clj +++ b/examples/simple/project.clj @@ -1,10 +1,10 @@ -(defproject simple-re-frame "0.5.0-alpha3" +(defproject simple-re-frame "0.5.0" :dependencies [[org.clojure/clojure "1.6.0"] [org.clojure/clojurescript "0.0-2816"] - [reagent "0.5.0-alpha3"] - [re-frame "0.3.0"] - [figwheel "0.2.3-SNAPSHOT"]] + [reagent "0.5.0"] + [re-frame "0.3.1"] + [figwheel "0.2.6"]] :plugins [[lein-cljsbuild "1.0.4"] [lein-figwheel "0.2.3-SNAPSHOT"]] diff --git a/examples/simple/src/simpleexample/core.cljs b/examples/simple/src/simpleexample/core.cljs index d4cd757..fa58110 100644 --- a/examples/simple/src/simpleexample/core.cljs +++ b/examples/simple/src/simpleexample/core.cljs @@ -3,103 +3,112 @@ (:require [reagent.core :as reagent :refer [atom]] [re-frame.core :refer [register-handler path - register-sub - dispatch + register-sub + dispatch + dispatch-sync subscribe]])) - +;; trigger a dispatch every second (defonce time-updater (js/setInterval #(dispatch [:timer (js/Date.)]) 1000)) -;;; this is the initial state -(defonce initial-state +(def initial-state {:timer (js/Date.) :time-color "#f34"}) -;; Handlers -;------------------------------------------------------------- -;; This handler sets the initial state -(register-handler - ;; the handler is passed a map (not an atom) and must return the new state - ;; of the db - :initialize +;; -- Event Handlers ---------------------------------------------------------- + + +(register-handler ;; setup initial state + :initialize ;; usage: (submit [:initialize]) (fn [db _] - (merge db initial-state))) + (merge db initial-state))) ;; what it returns becomes the new state + -;; This handler changes the color of the displayed time (register-handler - ;;; register-handler can take 3 arguments to allow you to insert middleware - ;;; see https://github.com/Day8/re-frame/wiki/Handler-Middleware - :time-color - (path [:time-color]) + :time-color ;; usage: (submit [:time-color 34562]) + (path [:time-color]) ;; this is middleware (fn - ;; the path handler allows you to get directly to items in the database - ;; return the value you want assoc'd in - [time-color [_ value]] + [time-color [_ value]] ;; path middleware adjusts the first parameter value)) -;; This handler changes the value of the time + (register-handler :timer (fn ;; the first item in the second argument is :timer the second is the ;; new value [db [_ value]] - (assoc db :timer value))) + (assoc db :timer value))) ;; return the new version of db + + +;; -- Subscription Handlers --------------------------------------------------- + -;; add subscriptions to :timer and :time-color (register-sub :timer (fn - [db _] - ;; you need to wrap your subscription code in a reaction - (reaction (:timer @db)))) + [db _] ;; db is the app-db atom + (reaction (:timer @db)))) ;; wrap the compitation in a reaction + (register-sub :time-color (fn [db _] - ;; you need to wrap your subscription code in a reaction (reaction (:time-color @db)))) -(dispatch [:initialize]) +;; -- View Components --------------------------------------------------------- -(defn greeting [message] +(defn greeting + [message] [:h1 message]) -(defn clock [] + +(defn clock + [] (let [time-color (subscribe [:time-color]) timer (subscribe [:timer])] - ;;; wrap your component in a function to use the suscription - (fn [] - ;; note that the initialize call will not be dispatched immediately - ;; as it is an async call - (when @timer - (let [time-str (-> @timer .toTimeString (clojure.string/split " ") first)] - [:div.example-clock - {:style {:color @time-color}} - time-str]))))) -(defn color-input [] + (fn clock-render + [] + (let [time-str (-> @timer + .toTimeString + (clojure.string/split " ") + first) + style {:style {:color @time-color}}] + [:div.example-clock style time-str])))) + + +(defn color-input + [] (let [time-color (subscribe [:time-color])] - ;;; wrap your component in a function to use the suscription - (fn [] - [:div.color-input - "Time color: " - [:input {:type "text" - :value @time-color - :on-change #(dispatch - [:time-color (-> % .-target .-value)])}]]))) -(defn simple-example [] + (fn color-input-render + [] + [:div.color-input + "Time color: " + [:input {:type "text" + :value @time-color + :on-change #(dispatch + [:time-color (-> % .-target .-value)])}]]))) + +(defn simple-example + [] [:div [greeting "Hello world, it is now"] [clock] [color-input]]) -(defn ^:export run [] + +;; -- Entry Point ------------------------------------------------------------- + + +(defn ^:export run + [] + (dispatch-sync [:initialize]) (reagent/render [simple-example] - (js/document.getElementById "app"))) \ No newline at end of file + (js/document.getElementById "app"))) diff --git a/examples/todomvc/project.clj b/examples/todomvc/project.clj index b9c058f..4491b7b 100644 --- a/examples/todomvc/project.clj +++ b/examples/todomvc/project.clj @@ -1,8 +1,8 @@ -(defproject todomvc-re-frame "0.3.0" +(defproject todomvc-re-frame "0.3.1" :dependencies [[org.clojure/clojure "1.6.0"] [org.clojure/clojurescript "0.0-2816"] [reagent "0.5.0"] - [re-frame "0.3.0"] + [re-frame "0.3.1"] [secretary "1.2.1"]] :plugins [[lein-cljsbuild "1.0.4"]] diff --git a/examples/todomvc/src/todomvc/subs.cljs b/examples/todomvc/src/todomvc/subs.cljs index 801a7e1..ba8363e 100644 --- a/examples/todomvc/src/todomvc/subs.cljs +++ b/examples/todomvc/src/todomvc/subs.cljs @@ -7,17 +7,17 @@ (defn filter-fn-for - [showing-kw] - (case showing-kw - :active (complement :done) - :done :done - :all identity)) + [showing-kw] + (case showing-kw + :active (complement :done) + :done :done + :all identity)) (defn completed-count - "return the count of todos for which :done is true" - [todos] - (count (filter :done (vals todos)))) + "return the count of todos for which :done is true" + [todos] + (count (filter :done (vals todos)))) ;; -- Subscription handlers and registration --------------------------------- @@ -25,26 +25,26 @@ (register-sub :todos ;; usage: (subscribe [:todos]) (fn [db _] - (reaction (vals (:todos @db))))) + (reaction (vals (:todos @db))))) (register-sub :visible-todos (fn [db _] - (reaction (let [filter-fn (filter-fn-for (:showing @db)) - todos (vals (:todos @db))] - (filter filter-fn todos))))) + (reaction (let [filter-fn (filter-fn-for (:showing @db)) + todos (vals (:todos @db))] + (filter filter-fn todos))))) (register-sub :completed-count (fn [db _] - (reaction (completed-count (:todos @db))))) + (reaction (completed-count (:todos @db))))) (register-sub :footer-stats (fn [db _] - (reaction - (let [todos (:todos @db) - completed-count (completed-count todos) - active-count (- (count todos) completed-count) - showing (:showing @db)] - [active-count completed-count showing])))) ;; tuple + (reaction + (let [todos (:todos @db) + completed-count (completed-count todos) + active-count (- (count todos) completed-count) + showing (:showing @db)] + [active-count completed-count showing])))) ;; tuple diff --git a/project.clj b/project.clj index e4b4225..47f4890 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject re-frame "0.3.0" +(defproject re-frame "0.3.1" :description "A Clojurescript MVC-like Framework For Writing SPAs Using Regent." :url "https://github.com/Day8/re-frame.git" :license {:name "MIT"} diff --git a/src/re_frame/core.cljs b/src/re_frame/core.cljs index d62c3b7..842380a 100644 --- a/src/re_frame/core.cljs +++ b/src/re_frame/core.cljs @@ -23,14 +23,14 @@ (def enrich middleware/enrich) (def trim-v middleware/trim-v) (def after middleware/after) -; (def log-events middleware/log-events) +(def log-ex middleware/log-ex) ;; -- Convenience API ------- ;; Almost 100% of handlers will be pure, so make it easy to -;; register with "pure" middleware in the correct position. +;; register with "pure" middleware in the correct (left-hand-side) position. (defn register-handler ([id handler] (handlers/register-base id pure handler)) diff --git a/src/re_frame/middleware.cljs b/src/re_frame/middleware.cljs index b349617..0f6d666 100644 --- a/src/re_frame/middleware.cljs +++ b/src/re_frame/middleware.cljs @@ -82,7 +82,7 @@ ....) " [handler] - (fn new-handler + (fn trim-v-handler [db v] (handler db (vec (rest v))))) @@ -140,16 +140,16 @@ complete reassesment of duplication errors and warnings. Eg: that edit update might have introduced a new duplicate or removed one. Same with a todo removal. - And to perform this enrichment, a function has inspect all the todos, + And to perform this enrichment, a function has to inspect all the todos, possibly set flags on each, and set some overall list of duplicates. - And this duplicates checking might be just one check amoung a number. + And this duplication check might just be one check amoung many. \"f\" would need to be both adding and removing the duplicate warnings. By applying \"f\" in middleware, we keep the handlers simple and yet we - ensure this important step is not missed. " + ensure this important step is not missed." [f] (fn middleware [handler] - (fn validate-handler + (fn enrich-handler [db v] (f (handler db v) v))))