Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interfaces #25

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
/tags
/target
\#*\#
/.cljs_node_repl
3 changes: 2 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@

:dependencies
[[pretty "1.0.0"]
[potemkin "0.4.5"]]
[potemkin "0.4.5"]
[org.clojure/clojurescript "1.10.520" :scope "provided"]]

:aot [methodical.interface methodical.impl.standard]

Expand Down
13 changes: 6 additions & 7 deletions src/methodical/impl/cache/simple.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
"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 [potemkin.types :as p.types]
[pretty.core :refer [PrettyPrintable]])
(:require [pretty.core :refer [PrettyPrintable]])
(:import methodical.interface.Cache))

(p.types/deftype+ SimpleCache [atomm]
(deftype SimpleCache [atomm]
PrettyPrintable
(pretty [_]
'(simple-cache))

Cache
(cached-method [_ dispatch-value]
(cachedMethod [_ dispatch-value]
(get @atomm dispatch-value))

(cache-method! [_ dispatch-value method]
(cacheMethodBang [_ dispatch-value method]
(swap! atomm assoc dispatch-value method))

(clear-cache! [this]
(clearCacheBang [this]
(reset! atomm {})
this)

(empty-copy [this]
(emptyCopy [this]
(SimpleCache. (atom {}))))
17 changes: 8 additions & 9 deletions src/methodical/impl/cache/watching.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
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 :refer [PrettyPrintable]])
(:import java.lang.ref.WeakReference
methodical.interface.Cache))

(declare add-watches remove-watches)

(p.types/deftype+ WatchingCache [^Cache cache watch-key refs]
(deftype WatchingCache [^Cache cache watch-key refs]
PrettyPrintable
(pretty [_]
(concat ['watching-cache cache 'watching] refs))
Expand All @@ -29,18 +28,18 @@
(remove-watches this))

Cache
(cached-method [_ dispatch-value]
(.cached-method cache dispatch-value))
(cachedMethod [_ dispatch-value]
(.cachedMethod cache dispatch-value))

(cache-method! [this dispatch-value method]
(.cache-method! cache dispatch-value method)
(cacheMethodBang [this dispatch-value method]
(.cacheMethodBang cache dispatch-value method)
this)

(clear-cache! [this]
(.clear-cache! cache)
(clearCacheBang [this]
(.clearCacheBang cache)
this)

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

(defn- cache-watch-fn [cache]
Expand Down
11 changes: 5 additions & 6 deletions src/methodical/impl/combo/clojure.clj
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
(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 [potemkin.types :as p.types]
[pretty.core :refer [PrettyPrintable]])
(:require [pretty.core :refer [PrettyPrintable]])
(:import methodical.interface.MethodCombination))

(p.types/deftype+ ClojureMethodCombination []
(deftype ClojureMethodCombination []
PrettyPrintable
(pretty [_]
'(clojure-method-combination))
Expand All @@ -15,13 +14,13 @@
(instance? ClojureMethodCombination another))

MethodCombination
(allowed-qualifiers [_]
(allowedQualifiers [_]
#{nil}) ; only primary methods

(combine-methods [_ [primary-method] aux-methods]
(combineMethods [_ [primary-method] aux-methods]
(when (seq aux-methods)
(throw (UnsupportedOperationException. "Clojure-style multimethods do not support auxiliary methods.")))
primary-method)

(transform-fn-tail [_ _ fn-tail]
(transformFnTail [_ _ fn-tail]
fn-tail))
9 changes: 4 additions & 5 deletions src/methodical/impl/combo/clos.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
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]
[potemkin.types :as p.types]
[pretty.core :refer [PrettyPrintable]])
(:import methodical.interface.MethodCombination))

Expand Down Expand Up @@ -53,7 +52,7 @@
result)]
(comp apply-afters combined-method))))

(p.types/deftype+ CLOSStandardMethodCombination []
(deftype CLOSStandardMethodCombination []
PrettyPrintable
(pretty [_]
'(clos-method-combination))
Expand All @@ -63,14 +62,14 @@
(instance? CLOSStandardMethodCombination another))

MethodCombination
(allowed-qualifiers [_]
(allowedQualifiers [_]
#{nil :before :after :around})

(combine-methods [_ primary-methods {:keys [before after around]}]
(combineMethods [_ primary-methods {:keys [before after around]}]
(some-> (combo.common/combine-primary-methods primary-methods)
(apply-befores before)
(apply-afters after)
(combo.common/apply-around-methods around)))

(transform-fn-tail [_ qualifier fn-tail]
(transformFnTail [_ qualifier fn-tail]
(combo.common/add-implicit-next-method-args qualifier fn-tail)))
9 changes: 4 additions & 5 deletions src/methodical/impl/combo/operator.clj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
...)"
(:refer-clojure :exclude [methods])
(:require [methodical.impl.combo.common :as combo.common]
[potemkin.types :as p.types]
[pretty.core :refer [PrettyPrintable]])
(:import methodical.interface.MethodCombination))

Expand Down Expand Up @@ -152,7 +151,7 @@

;;;; ### `OperatorMethodCombination`

(p.types/deftype+ OperatorMethodCombination [operator-name]
(deftype OperatorMethodCombination [operator-name]
PrettyPrintable
(pretty [_]
(list 'operator-method-combination operator-name))
Expand All @@ -163,15 +162,15 @@
(= operator-name (.operator-name ^OperatorMethodCombination another))))

MethodCombination
(allowed-qualifiers [_]
(allowedQualifiers [_]
#{nil :around})

(combine-methods [_ primary-methods {:keys [around]}]
(combineMethods [_ primary-methods {:keys [around]}]
(when (seq primary-methods)
(-> ((operator operator-name) primary-methods)
(combo.common/apply-around-methods around))))

(transform-fn-tail [_ qualifier fn-tail]
(transformFnTail [_ qualifier fn-tail]
(if (= qualifier :around)
(combo.common/add-implicit-next-method-args qualifier fn-tail)
fn-tail)))
Expand Down
10 changes: 4 additions & 6 deletions src/methodical/impl/combo/threaded.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
(ns methodical.impl.combo.threaded
(:refer-clojure :exclude [methods])
(:require [methodical.impl.combo.common :as combo.common]
[potemkin.types :as p.types]
[pretty.core :refer [PrettyPrintable]])
(:import methodical.interface.MethodCombination))

Expand Down Expand Up @@ -70,25 +69,24 @@
(apply method (conj butlast* last*)))]))))


(p.types/deftype+ ThreadingMethodCombination [threading-type]
(deftype ThreadingMethodCombination [threading-type]
PrettyPrintable
(pretty [_]
(list 'threading-method-combination threading-type))

MethodCombination
Object
(equals [_ another]
(and (instance? ThreadingMethodCombination another)
(= threading-type (.threading-type ^ThreadingMethodCombination another))))

MethodCombination
(allowed-qualifiers [_]
(allowedQualifiers [_]
#{nil :before :after :around})

(combine-methods [_ primary-methods aux-methods]
(combineMethods [_ primary-methods aux-methods]
(combine-with-threader (threading-invoker threading-type) primary-methods aux-methods))

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

(defn threading-method-combination
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
(ns methodical.impl.dispatcher.common
"Utility functions for implementing Dispatchers.")
"Utility functions for implementing Dispatchers."
#?(:cljs
(:require
[goog.string :refer [format]])))

#?(:cljs (def ^:private IllegalStateException js/Error))

(defn add-preference
"Add a method preference to `prefs` for dispatch value `x` over `y`. Used to implement `prefer-method`."
Expand Down
25 changes: 12 additions & 13 deletions src/methodical/impl/dispatcher/everything.clj
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
(ns methodical.impl.dispatcher.everything
(:require [methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.interface :as i]
[potemkin.types :as p.types]
[pretty.core :refer [PrettyPrintable]])
(:import methodical.interface.Dispatcher))

(p.types/deftype+ EverythingDispatcher [hierarchy-var prefs]
(deftype EverythingDispatcher [hierarchy-var prefs]
PrettyPrintable
(pretty [_]
(cons
Expand All @@ -26,31 +25,31 @@
(= prefs (.prefs another))))))

Dispatcher
(dispatch-value [_] nil)
(dispatch-value [_ a] nil)
(dispatch-value [_ a b] nil)
(dispatch-value [_ a b c] nil)
(dispatch-value [_ a b c d] nil)
(dispatch-value [_ a b c d more] nil)

(matching-primary-methods [_ method-table _]
(dispatchValue [_] nil)
(dispatchValue [_ a] nil)
(dispatchValue [_ a b] nil)
(dispatchValue [_ a b c] nil)
(dispatchValue [_ a b c d] nil)
(dispatchValue [_ a b c d more] nil)

(matchingPrimaryMethods [_ method-table _]
(let [primary-methods (i/primary-methods method-table)
comparitor (dispatcher.common/domination-comparitor (var-get hierarchy-var) prefs ::no-dispatch-value)]
(map second (sort-by first comparitor primary-methods))))

(matching-aux-methods [_ method-table _]
(matchingAuxMethods [_ method-table _]
(let [aux-methods (i/aux-methods method-table)
comparitor (dispatcher.common/domination-comparitor (var-get hierarchy-var) prefs ::no-dispatch-value)]
(into {} (for [[qualifier dispatch-value->methods] aux-methods]
[qualifier (mapcat second (sort-by first comparitor dispatch-value->methods))]))))

(default-dispatch-value [_]
(defaultDispatchValue [_]
nil)

(prefers [_]
prefs)

(prefer-method [this x y]
(preferMethod [this x y]
(let [new-prefs (dispatcher.common/add-preference (partial isa? (var-get hierarchy-var)) prefs x y)]
(if (= prefs new-prefs)
this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
(:refer-clojure :exclude [prefers prefer-method])
(:require [methodical.impl.dispatcher.common :as dispatcher.common]
[methodical.interface :as i]
[potemkin.types :as p.types]
[pretty.core :refer [PrettyPrintable]])
(:import methodical.interface.Dispatcher))
#?(:clj [pretty.core :refer [PrettyPrintable]])
#?(:cljs [methodical.interface :refer [Dispatcher]])
#?(:cljs [goog.string :refer [format]]))
#?(:clj (:import methodical.interface.Dispatcher)))

#?(:cljs (def ^:private IllegalArgumentException js/Error))

(defn- matching-primary-pairs-excluding-default
"Return a sequence of pairs of `[dispatch-value method]` for all applicable dispatch values, excluding the default
Expand Down Expand Up @@ -87,20 +90,23 @@
:when (seq pairs)]
[qualifier (map second pairs)])))

(deftype StandardDispatcher [dispatch-fn hierarchy-var default-value prefs]
#?@(:clj
[PrettyPrintable
(pretty [_]
(concat ['standard-dispatcher dispatch-fn]
(when (not= hierarchy-var #'clojure.core/global-hierarchy)
[:hierarchy hierarchy-var])
(when (not= default-value :default)
[:default-value default-value])
(when (seq prefs)
[:prefers prefs])))])

(p.types/deftype+ StandardDispatcher [dispatch-fn hierarchy-var default-value prefs]
PrettyPrintable
(pretty [_]
(concat ['standard-dispatcher dispatch-fn]
(when (not= hierarchy-var #'clojure.core/global-hierarchy)
[:hierarchy hierarchy-var])
(when (not= default-value :default)
[:default-value default-value])
(when (seq prefs)
[:prefers prefs])))
#?(:clj Object
:cljs IEquiv)
;; todo: hashcode

Object
(equals [_ another]
(#?(:clj equals, :cljs -equiv) [_ another]
(and
(instance? StandardDispatcher another)
(let [^StandardDispatcher another another]
Expand All @@ -110,27 +116,29 @@
(= default-value (.default-value another))
(= prefs (.prefs another))))))

Dispatcher
(dispatch-value [_] (dispatch-fn))
(dispatch-value [_ a] (dispatch-fn a))
(dispatch-value [_ a b] (dispatch-fn a b))
(dispatch-value [_ a b c] (dispatch-fn a b c))
(dispatch-value [_ a b c d] (dispatch-fn a b c d))
(dispatch-value [_ a b c d more] (apply dispatch-fn a b c d more))
#?(:clj Dispatcher :cljs Object)
(dispatchValue [_] (dispatch-fn))
(dispatchValue [_ a] (dispatch-fn a))
(dispatchValue [_ a b] (dispatch-fn a b))
(dispatchValue [_ a b c] (dispatch-fn a b c))
(dispatchValue [_ a b c d] (dispatch-fn a b c d))
(dispatchValue [_ a b c d more] (apply dispatch-fn a b c d more))

(matching-primary-methods [_ method-table dispatch-value]
(matchingPrimaryMethods [_ method-table dispatch-value]
(matching-primary-methods (var-get hierarchy-var) prefs default-value method-table dispatch-value))

(matching-aux-methods [_ method-table dispatch-value]
(matchingAuxMethods [_ method-table dispatch-value]
(matching-aux-methods (var-get hierarchy-var) prefs default-value method-table dispatch-value))

(default-dispatch-value [_]
(defaultDispatchValue [_]
default-value)

(prefers [_]
prefs)

(prefer-method [this x y]
(preferMethod [this x y]
;; var-get is not implemented in cljs
;; https://github.com/camsaul/methodical/issues/29
(let [new-prefs (dispatcher.common/add-preference (partial isa? (var-get hierarchy-var)) prefs x y)]
(if (= prefs new-prefs)
this
Expand Down
Loading