Skip to content

Commit

Permalink
Support datafying multifns (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
camsaul authored Sep 9, 2022
1 parent f0cb498 commit 818f8b4
Show file tree
Hide file tree
Showing 21 changed files with 330 additions and 101 deletions.
3 changes: 2 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
;; clojure -X:dev:test
:test
{:exec-fn methodical.test-runner/run-tests
:exec-args {:only ["test"]}}
:exec-args {:only ["test"]}
:jvm-opts ["-Dinhumane.test.output=true"]}

;; clj -X:dev:cloverage
:cloverage
Expand Down
5 changes: 4 additions & 1 deletion dev/user.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
(ns user
(:require
[environ.core :as env]
[humane-are.core :as humane-are]
[pjstadig.humane-test-output :as humane-test-output]))

(humane-test-output/activate!)
(when-not (get env/env :inhumane-test-output)
(humane-test-output/activate!))

(humane-are/install!)
19 changes: 13 additions & 6 deletions src/methodical/impl/cache/simple.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
"A basic, dumb cache. `SimpleCache` stores cached methods in a simple map of dispatch-value -> effective method; it
offers no facilities to deduplicate identical methods for the same dispatch value. This behaves similarly to the
caching mechanism in vanilla Clojure."
(:require methodical.interface
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import methodical.interface.Cache))
(:require
[clojure.core.protocols :as clojure.protocols]
[methodical.interface]
[pretty.core :as pretty])
(:import
(methodical.interface Cache)))

(set! *warn-on-reflection* true)

(comment methodical.interface/keep-me)

(p.types/deftype+ SimpleCache [atomm]
(deftype SimpleCache [atomm]
pretty/PrettyPrintable
(pretty [_]
'(simple-cache))
Expand All @@ -28,4 +30,9 @@
this)

(empty-copy [_]
(SimpleCache. (atom {}))))
(SimpleCache. (atom {})))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)
:cache @atomm}))
23 changes: 16 additions & 7 deletions src/methodical/impl/cache/watching.clj
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@
potentially large method maps; they also automatically clear out their watches when they are garbage collected and
finalized (which, of course, may actually be never -- but worst-case is that some unneeded calls to `clear-cache!`
get made)."
(:require [methodical.interface :as i]
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import java.lang.ref.WeakReference
methodical.interface.Cache))
(:require
[clojure.core.protocols :as clojure.protocols]
[clojure.datafy :as datafy]
[methodical.interface :as i]
[pretty.core :as pretty])
(:import
(java.lang.ref WeakReference)
(methodical.interface Cache)))

(set! *warn-on-reflection* true)

(declare add-watches remove-watches)

(p.types/deftype+ WatchingCache [^Cache cache watch-key refs]
(deftype WatchingCache [^Cache cache watch-key refs]
pretty/PrettyPrintable
(pretty [_]
(concat ['watching-cache cache 'watching] refs))
Expand All @@ -43,7 +46,13 @@
this)

(empty-copy [_]
(add-watches (i/empty-copy cache) refs)))
(add-watches (i/empty-copy cache) refs))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)
:cache (datafy/datafy cache)
:refs refs}))

(defn- cache-watch-fn [cache]
(let [cache-weak-ref (WeakReference. cache)]
Expand Down
20 changes: 13 additions & 7 deletions src/methodical/impl/combo/clojure.clj
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
(ns methodical.impl.combo.clojure
"Simple method combination strategy that mimics the way vanilla Clojure multimethods combine methods; that is, to say,
not at all. Like vanilla Clojure multimethods, this method combination only supports primary methods."
(:require methodical.interface
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import methodical.interface.MethodCombination))
(:require
[clojure.core.protocols :as clojure.protocols]
[methodical.interface]
[pretty.core :as pretty])
(:import
(methodical.interface MethodCombination)))

(set! *warn-on-reflection* true)

(comment methodical.interface/keep-me)

(p.types/deftype+ ClojureMethodCombination []
(deftype ClojureMethodCombination []
pretty/PrettyPrintable
(pretty [_]
'(clojure-method-combination))
Expand All @@ -28,5 +30,9 @@
(throw (UnsupportedOperationException. "Clojure-style multimethods do not support auxiliary methods.")))
primary-method)

(transform-fn-tail [_ _ fn-tail]
fn-tail))
(transform-fn-tail [_this _qualifier fn-tail]
fn-tail)

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)}))
20 changes: 13 additions & 7 deletions src/methodical/impl/combo/clos.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
Supports `:before`, `:after`, and `:around` auxiliary methods. The values returned by `:before` and `:after` methods
are ignored. Primary methods and around methods get an implicit `next-method` arg (see Methodical dox for more on
what this means)."
(:require [methodical.impl.combo.common :as combo.common]
methodical.interface
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import methodical.interface.MethodCombination))
(:require
[clojure.core.protocols :as clojure.protocols]
[methodical.impl.combo.common :as combo.common]
[methodical.interface]
[pretty.core :as pretty])
(:import
(methodical.interface MethodCombination)))

(set! *warn-on-reflection* true)

Expand Down Expand Up @@ -58,7 +60,7 @@
result)]
(comp apply-after-fns combined-method))))

(p.types/deftype+ CLOSStandardMethodCombination []
(deftype CLOSStandardMethodCombination []
pretty/PrettyPrintable
(pretty [_]
'(clos-method-combination))
Expand All @@ -78,4 +80,8 @@
(combo.common/apply-around-methods around)))

(transform-fn-tail [_ qualifier fn-tail]
(combo.common/add-implicit-next-method-args qualifier fn-tail)))
(combo.common/add-implicit-next-method-args qualifier fn-tail))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)}))
11 changes: 8 additions & 3 deletions src/methodical/impl/combo/operator.clj
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@
...)"
(:refer-clojure :exclude [methods])
(:require
[clojure.core.protocols :as clojure.protocols]
[clojure.spec.alpha :as s]
[methodical.impl.combo.common :as combo.common]
[methodical.interface]
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import
(methodical.interface MethodCombination)))
Expand Down Expand Up @@ -168,7 +168,7 @@

;;;; ### `OperatorMethodCombination`

(p.types/deftype+ OperatorMethodCombination [operator-name]
(deftype OperatorMethodCombination [operator-name]
pretty/PrettyPrintable
(pretty [_]
(list 'operator-method-combination operator-name))
Expand All @@ -190,7 +190,12 @@
(transform-fn-tail [_ qualifier fn-tail]
(if (= qualifier :around)
(combo.common/add-implicit-next-method-args qualifier fn-tail)
fn-tail)))
fn-tail))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)
:operator operator-name}))

(defn operator-method-combination
"Create a new method combination using the operator named by `operator-name`, a keyword name of one of the
Expand Down
21 changes: 14 additions & 7 deletions src/methodical/impl/combo/threaded.clj
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
(ns methodical.impl.combo.threaded
(:refer-clojure :exclude [methods])
(:require [methodical.impl.combo.common :as combo.common]
methodical.interface
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import methodical.interface.MethodCombination))
(:require
[clojure.core.protocols :as clojure.protocols]
[methodical.impl.combo.common :as combo.common]
[methodical.interface]
[pretty.core :as pretty])
(:import
(methodical.interface MethodCombination)))

(set! *warn-on-reflection* true)

Expand Down Expand Up @@ -76,7 +78,7 @@
(apply method (conj butlast* last*)))]))))


(p.types/deftype+ ThreadingMethodCombination [threading-type]
(deftype ThreadingMethodCombination [threading-type]
pretty/PrettyPrintable
(pretty [_]
(list 'threading-method-combination threading-type))
Expand All @@ -95,7 +97,12 @@
(combine-with-threader (threading-invoker threading-type) primary-methods aux-methods))

(transform-fn-tail [_ qualifier fn-tail]
(combo.common/add-implicit-next-method-args qualifier fn-tail)))
(combo.common/add-implicit-next-method-args qualifier fn-tail))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)
:threading-type threading-type}))

(defn threading-method-combination
"Create a new `ThreadingMethodCombination` using the keyword `threading-type` strategy, e.g. `:thread-first` or
Expand Down
24 changes: 16 additions & 8 deletions src/methodical/impl/dispatcher/everything.clj
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
(ns methodical.impl.dispatcher.everything
(:refer-clojure :exclude [methods])
(:require [methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.interface :as i]
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import methodical.interface.Dispatcher))
(:require
[clojure.core.protocols :as clojure.protocols]
[methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.interface :as i]
[pretty.core :as pretty])
(:import
(methodical.interface Dispatcher)))

(set! *warn-on-reflection* true)

(p.types/deftype+ EverythingDispatcher [hierarchy-var prefs]
(deftype EverythingDispatcher [hierarchy-var prefs]
pretty/PrettyPrintable
(pretty [_]
(cons
Expand Down Expand Up @@ -47,7 +49,7 @@
comparatorr (dispatcher.common/domination-comparator (deref hierarchy-var) prefs)]
(into {} (for [[qualifier dispatch-value->methods] aux-methods]
[qualifier (for [[dispatch-value methods] (sort-by first comparatorr dispatch-value->methods)
method methods]
method methods]
(vary-meta method assoc :dispatch-value dispatch-value))]))))

(default-dispatch-value [_]
Expand All @@ -60,4 +62,10 @@
(EverythingDispatcher. hierarchy-var new-prefs))

(dominates? [_ x y]
(dispatcher.common/dominates? (deref hierarchy-var) prefs x y)))
(dispatcher.common/dominates? (deref hierarchy-var) prefs x y))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)
:hierarchy hierarchy-var
:prefs prefs}))
26 changes: 18 additions & 8 deletions src/methodical/impl/dispatcher/multi_default.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
"A single-hierarchy dispatcher similar to the standard dispatcher, with one big improvement: when dispatching on
multiple values, it supports default methods that specialize on some args and use the default for others. (e.g.
`[String :default]`"
(:require [methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.impl.dispatcher.standard :as dispatcher.standard]
[methodical.interface :as i]
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import methodical.interface.Dispatcher))
(:require
[clojure.core.protocols :as clojure.protocols]
[methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.impl.dispatcher.standard :as dispatcher.standard]
[methodical.interface :as i]
[pretty.core :as pretty])
(:import
(methodical.interface Dispatcher)))

(set! *warn-on-reflection* true)

Expand Down Expand Up @@ -127,7 +129,7 @@
(into {} (for [[qualifier] (i/aux-methods method-table)]
[qualifier (matching-aux-methods* qualifier opts)])))

(p.types/deftype+ MultiDefaultDispatcher [dispatch-fn hierarchy-var default-value prefs]
(deftype MultiDefaultDispatcher [dispatch-fn hierarchy-var default-value prefs]
pretty/PrettyPrintable
(pretty [_]
(concat ['multi-default-dispatcher dispatch-fn]
Expand Down Expand Up @@ -183,4 +185,12 @@
(MultiDefaultDispatcher. dispatch-fn hierarchy-var default-value new-prefs))

(dominates? [_ x y]
(dispatcher.common/dominates? (deref hierarchy-var) prefs default-value x y)))
(dispatcher.common/dominates? (deref hierarchy-var) prefs default-value x y))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)
:dispatch-fn dispatch-fn
:default-value default-value
:hierarchy hierarchy-var
:prefs prefs}))
24 changes: 17 additions & 7 deletions src/methodical/impl/dispatcher/standard.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
"A single-hierarchy dispatcher that behaves similarly to the way multimethod dispatch is done by vanilla Clojure
multimethods, but with added support for auxiliary methods."
(:refer-clojure :exclude [prefers methods])
(:require [methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.interface :as i]
[potemkin.types :as p.types]
[pretty.core :as pretty])
(:import methodical.interface.Dispatcher))
(:require
[clojure.core.protocols :as clojure.protocols]
[methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.interface :as i]
[pretty.core :as pretty])
(:import
(methodical.interface Dispatcher)))

(set! *warn-on-reflection* true)

Expand Down Expand Up @@ -97,7 +99,7 @@
[qualifier (for [[dispatch-value method] pairs]
(vary-meta method assoc :dispatch-value dispatch-value))])))

(p.types/deftype+ StandardDispatcher [dispatch-fn hierarchy-var default-value prefs]
(deftype StandardDispatcher [dispatch-fn hierarchy-var default-value prefs]
pretty/PrettyPrintable
(pretty [_]
(concat ['standard-dispatcher dispatch-fn]
Expand Down Expand Up @@ -153,4 +155,12 @@
(StandardDispatcher. dispatch-fn hierarchy-var default-value new-prefs))

(dominates? [_ x y]
(dispatcher.common/dominates? (deref hierarchy-var) prefs default-value x y)))
(dispatcher.common/dominates? (deref hierarchy-var) prefs default-value x y))

clojure.protocols/Datafiable
(datafy [this]
{:class (class this)
:dispatch-fn dispatch-fn
:default-value default-value
:hierarchy hierarchy-var
:prefs prefs}))
Loading

0 comments on commit 818f8b4

Please sign in to comment.