Skip to content
This repository has been archived by the owner on Aug 9, 2018. It is now read-only.

Commit

Permalink
Merge branch 'feature/union-rename' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
calvis committed Sep 18, 2015
2 parents c48be70 + 53ee319 commit bf7b16c
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 68 deletions.
48 changes: 24 additions & 24 deletions src/spark/sparkspec.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
(:require [clojure.core.typed :as t]
[clojure.string :refer [lower-case]]
[clojure.data :as data]
[spark.sparkspec.grammar :refer [parse-spec parse-enum]]
[spark.sparkspec.grammar :refer [parse-spec parse-union]]
[spark.sparkspec.spec :refer :all]
[clojure.string :refer [join]] ;; TODO
[clj-time.core :as time]
Expand Down Expand Up @@ -54,8 +54,8 @@
:else (class o)))

(defmulti get-spec
"If the given item is a Spec/EnumSpec or was defined by a
Spec/EnumSpec, returns the Spec/EnumSpec, otherwise nil."
"If the given item is a Spec/UnionSpec or was defined by a
Spec/UnionSpec, returns the Spec/UnionSpec, otherwise nil."
resolve-fn)

(defmethod get-spec :default [_] nil) ;; TODO
Expand All @@ -74,7 +74,7 @@

(defmulti get-spec-class
"returns the class of the record type representing the given spec name,
or nil (if it is an enum spec, it won't have a corresponding class)"
or nil (if it is an union spec, it won't have a corresponding class)"
identity)

(defmethod get-spec-class :default [_] nil)
Expand Down Expand Up @@ -126,10 +126,10 @@
true)

(defn check-complete!
"checks all fields of a record-sp (not enum),
"checks all fields of a record-sp (not union),
throws exception if required field is missing."
[spec sp]
(do (assert (nil? (:elements spec)) "spec cannot be an enum")
(do (assert (nil? (:elements spec)) "spec cannot be an union")
(doseq [{iname :name :as item} (:items spec)]
(check-component! spec iname (get sp iname)))
sp))
Expand Down Expand Up @@ -314,7 +314,7 @@
(join " "))
"})"))))

(defn spec->enum-type [spec]
(defn spec->union-type [spec]
`(t/U ~@(map #(symbol (str *ns*) (name %)) (:elements spec))))

(defn spec->record-type [spec]
Expand All @@ -334,7 +334,7 @@
:optional ~(into {} opts)))) ;; TODO: aren't there required fields?

(defn spec->type [spec]
(if (:elements spec) (spec->enum-type spec) (spec->record-type spec)))
(if (:elements spec) (spec->union-type spec) (spec->record-type spec)))

(defn- mk-type-alias
"defines an core.typed alias named after the given spec's name"
Expand Down Expand Up @@ -438,22 +438,22 @@
(defmethod get-map-ctor ~(:name spec) [_#] ~fac-sym)
(defmethod get-map-ctor ~(symbol (str "i_" (name (:name spec)))) [_#] ~fac-sym))))

;; when calling get-spec on an enum, try using the extra args to narrow down the spec
;; when calling get-spec on an union, try using the extra args to narrow down the spec
;; i.e. it's not always `spec` being returned if we can do better
(defn- mk-enum-get-spec [spec]
(defn- mk-union-get-spec [spec]
(let [elements (:elements spec)]
`(defmethod get-spec ~(:name spec) [o# & [rest#]]
(if-let [rest-spec# (and rest# (get-spec rest#))]
(if (some #(= (:name rest-spec#) %) [~@elements]) rest-spec#
(throw (ex-info "trying to construct an enum out of spec instance(s) not in enum spec"
(throw (ex-info "trying to construct an union out of spec instance(s) not in union spec"
{:objects (cons o# rest#) :spec ~spec})))
~spec))))

(defn- mk-enum-get-map-ctor [spec]
(defn- mk-union-get-map-ctor [spec]
(let [fac-sym (symbol (str "map->i_" (name (:name spec)) "-fixed"))]
`(do
;; the "map ctor" for an enum means it's arg needs to
;; be a tagged map or a record type of one of the enum's ctors.
;; the "map ctor" for an union means it's arg needs to
;; be a tagged map or a record type of one of the union's ctors.
(defn ~(with-meta fac-sym (assoc (meta fac-sym) :spec-tacular/spec (:name spec))) [o# h#]
(let [subspec-name# (:name (get-spec o#))]
(assert subspec-name#
Expand All @@ -470,7 +470,7 @@
`(do (t/ann ~huh [t/Any ~'-> t/Bool])
(defn ~huh [o#] (instance? ~class-name o#)))))

(defn- mk-enum-huh [spec]
(defn- mk-union-huh [spec]
(let [huh (make-name spec #(str (lower-case %) "?"))]
`(defn ~huh [o#] (contains? ~(:elements spec) (:name (get-spec o#))))))

Expand All @@ -486,32 +486,32 @@
~(mk-get-spec s)
~(mk-get-spec-class s))))

(defmacro defenum [& stx]
(let [s (parse-enum stx)]
(defmacro defunion [& stx]
(let [s (parse-union stx)]
`(do ~(let [spec-name (:name s)
spec-sym (-> s :name name symbol)]
`(def ~(with-meta spec-sym
(assoc (meta spec-sym) :spec-tacular/spec spec-name))
~spec-name))
~(mk-type-alias s)
~(mk-enum-get-map-ctor s)
~(mk-enum-get-spec s)
~(mk-enum-huh s))))
~(mk-union-get-map-ctor s)
~(mk-union-get-spec s)
~(mk-union-huh s))))

(defn inspect-spec
"Produces a json-friendly nested-map representation of a spec.
Nesting depth is bounded by the mask."
[spec-name mask & [resource-prefix-str schema-prefix-str]]
(let [spec (get-spec spec-name)
spec-type (if (:elements spec)
:enum
:union
(if (primitive? spec-name)
:primitive
:record))
resource-kv (when (and resource-prefix-str (= :record spec-type))
{:resource-url (str resource-prefix-str "/"
(lower-case (name spec-name)))})
inspect-kv (when (and schema-prefix-str (#{:record :enum} spec-type))
inspect-kv (when (and schema-prefix-str (#{:record :union} spec-type))
{:schema-url (str schema-prefix-str "/"
(lower-case (name spec-name)))})]
(when mask
Expand All @@ -521,9 +521,9 @@
inspect-kv
resource-kv
(if (map? mask)
(if (= :enum spec-type)
(if (= :union spec-type)
{:expanded true
:enum-elements (->> (:elements spec)
:union-elements (->> (:elements spec)
(map #(inspect-spec % (get mask %) resource-prefix-str schema-prefix-str))
(filter some?))}
(let [items
Expand Down
36 changes: 18 additions & 18 deletions src/spark/sparkspec/datomic.clj
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
the given atomic list of deletions when appropriate."
[db sp mask deletions & [spec]]
(let [spec (or spec (get-spec sp))
[spec mask] (if (:elements spec) ; Need to pick which enum branch to pick in the mask.
[spec mask] (if (:elements spec) ; Need to pick which union branch to pick in the mask.
(let [sub-name (:name (get-spec sp))]
[(get-spec (get-in spec [:elements sub-name]))
(get mask sub-name)])
Expand All @@ -224,7 +224,7 @@
is-many (= cardinality :many)
ival (iname sp)
ival (if (or link? (not (:db-ref ival))) ival (dissoc ival :db-ref))
sub-spec (get-spec type) ; Not necessarily ival's spec: could be an enum.
sub-spec (get-spec type) ; Not necessarily ival's spec: could be an union.
mask (iname mask)
ival-db (iname db-value)
datomic-key (keyword (datomic-ns spec) (name iname))
Expand Down Expand Up @@ -283,7 +283,7 @@
"union (join) taken w.r.t. a lattice of 'specificity' eg -- nil < true < {:item ...}
(recall 'true' means the mask consisting only of the db-ref)
keys are combined and their values are recursively summed.
Enums and Records can be summed the same, as we represent both with maps."
Unions and Records can be summed the same, as we represent both with maps."
([] nil)
([m] m)
([ma mb]
Expand All @@ -307,12 +307,12 @@
(not-empty sp)
true)))
(if (:elements spec)
(let [enum-mask (fn [sp-item]
(let [union-mask (fn [sp-item]
(let [sub-spec-name (:name (get-spec sp-item))]
{sub-spec-name (item-mask sub-spec-name sp-item)}))]
(if (and (coll? sp) (not (map? sp)))
(reduce union-masks (map enum-mask sp)) ; only recover mask from the particular enum types used by the instance
(enum-mask sp)))
(reduce union-masks (map union-mask sp)) ; only recover mask from the particular union types used by the instance
(union-mask sp)))
(let [field-mask
, (fn [sp-item]
(if (= [:db-ref] (keys sp-item))
Expand All @@ -323,7 +323,7 @@
(get sp-item iname))]))
(:items spec)))))]
(if (and (coll? sp) (not (map? sp)))
(reduce union-masks (map field-mask sp)) ; only recover mask from the particular enum types used by the instance
(reduce union-masks (map field-mask sp)) ; only recover mask from the particular union types used by the instance
(field-mask sp))))
true)))

Expand All @@ -346,13 +346,13 @@
true)])
(into {}))))

(t/ann ^:no-check shallow-plus-enums-mask [SpecT -> Mask])
(defn shallow-plus-enums-mask
(t/ann ^:no-check shallow-plus-unions-mask [SpecT -> Mask])
(defn shallow-plus-unions-mask
"Builds a mask-map of the given spec for consumption by
build-transactions. Only lets top-level and is-component fields
through As well, expands toplevel enums and any enum members which
through As well, expands toplevel unions and any union members which
have only primitive fields(intended to catch common cases like
'status' enums where the options have no interesting fields)."
'status' unions where the options have no interesting fields)."
[spec]
(let [is-leaf? (fn [sp-name]
(let [spec (get-spec sp-name)]
Expand All @@ -371,7 +371,7 @@
(let [sub-sp (get-spec typ)]
[iname
(if (:elements sub-sp)
(shallow-plus-enums-mask sub-sp) ;toplevel enums can be leaf-expanded
(shallow-plus-unions-mask sub-sp) ;toplevel unions can be leaf-expanded
true)]))
(into {})))))

Expand All @@ -385,7 +385,7 @@
[sp spec]
(if (:elements spec)
(let [sub-sp (get-spec sp)]
{(:name sub-sp) (new-components-mask sp sub-sp)}) ; only need to specify the actual type for the enum branch.
{(:name sub-sp) (new-components-mask sp sub-sp)}) ; only need to specify the actual type for the union branch.
(if (get-in sp [:db-ref :eid])
true ;treat as a ref, already in db
(if-let [spec (get-spec sp)]
Expand Down Expand Up @@ -617,12 +617,12 @@
(not-empty sp)
true)))
(if (:elements spec)
(let [enum-remove (fn [sp-item]
(let [union-remove (fn [sp-item]
(remove-identity-items (:name (get-spec sp-item))
sp-item))]
(if (and (coll? sp) (not (map? sp)))
(into (empty sp) (map enum-remove sp))
(enum-remove sp)))
(into (empty sp) (map union-remove sp))
(union-remove sp)))
(let [item-remove
, (fn [sp-item]
(reduce
Expand Down Expand Up @@ -842,7 +842,7 @@
:syntax :error)
try-map)]
(when (empty? (get grouped :syntax))
(throw (ex-info "does not conform to any possible enumerated spec"
(throw (ex-info "does not conform to any possible unioned spec"
{:syntax atmap :possible-specs elements
:errors (get grouped :error)})))
(cond
Expand All @@ -864,7 +864,7 @@
spec# ~maybe-spec]
(concat [['~x :spec-tacular/spec spec#]]
(or (get opts# spec#)
(throw (ex-info "does not conform to any possible enumerated spec"
(throw (ex-info "does not conform to any possible unioned spec"
{:computed-spec spec#
:available-specs (keys opts#)})))))
(and (nil? maybe-spec) (nil? (get grouped :error)))
Expand Down
6 changes: 3 additions & 3 deletions src/spark/sparkspec/grammar.clj
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@
:else (throw (ex-info "invalid options" (merge loc {:syntax stx}))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ENUM
;; UNION

(defn parse-enum [stx & [loc]]
(defn parse-union [stx & [loc]]
(let [loc (or loc (merge {:namespace (str *ns*)} (meta stx)))]
(match stx
([name & specs] :seq)
(let [name (keyword name)]
(map->EnumSpec {:name name :elements (into #{} specs)}))
(map->UnionSpec {:name name :elements (into #{} specs)}))
:else (throw (ex-info "expecting name followed by sequence of specs"
(merge loc {:syntax stx}))))))
2 changes: 1 addition & 1 deletion src/spark/sparkspec/spec.clj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
(defrecord Item
[name type precondition required? unique? optional? identity? default-value])

(defrecord EnumSpec [name elements])
(defrecord UnionSpec [name elements])

;;;; There is no existing Java class for a primitive byte array
(def Bytes (class (byte-array [1 2])))
Expand Down
8 changes: 4 additions & 4 deletions test/spark/sparkspec/grammar_test.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns spark.sparkspec.grammar-test
(:use clojure.test)
(:require [spark.sparkspec.grammar :refer [parse-spec parse-enum]]))
(:require [spark.sparkspec.grammar :refer [parse-spec parse-union]]))

(deftest test-valid-syntax
(let [spec (parse-spec '(Link
Expand All @@ -26,8 +26,8 @@
:identity? nil, :default-value nil}])))


(is (= (parse-enum '(Foo :Bar :Baz))
#spark.sparkspec.spec.EnumSpec{:name :Foo, :elements #{:Baz :Bar}})))
(is (= (parse-union '(Foo :Bar :Baz))
#spark.sparkspec.spec.UnionSpec{:name :Foo, :elements #{:Baz :Bar}})))

(deftest test-invalid-syntax
(is (thrown? clojure.lang.ExceptionInfo
Expand All @@ -47,4 +47,4 @@
(parse-spec '(Foo [bar :is-a :Bar] [bar :is-a :Bar]))))

#_(is (thrown? clojure.lang.ExceptionInfo
(parse-enum '(Foo 5)))))
(parse-union '(Foo 5)))))
4 changes: 2 additions & 2 deletions test/spark/sparkspec/test_specs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

(defspec Scm3)

(defenum ScmEnum :Scm2 :Scm3 :Scm)
(defunion ScmEnum :Scm2 :Scm3 :Scm)

(defspec ScmOwnsEnum
(:link
Expand Down Expand Up @@ -55,7 +55,7 @@
(defspec Cat
[name :is-a :string])

(defenum Animal :Dog :Cat)
(defunion Animal :Dog :Cat)

(defspec Birthday
[date :is-a :calendarday])
Loading

0 comments on commit bf7b16c

Please sign in to comment.