Skip to content

Commit ad78a2b

Browse files
committed
dynamic var for xapi version
1 parent 6e06f85 commit ad78a2b

4 files changed

Lines changed: 162 additions & 33 deletions

File tree

src/xapi_schema/spec.cljc

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
MailToIRIRegEx
88
UuidRegEx
99
TimestampRegEx
10+
TimestampRegEx200
1011
xAPIVersionRegEx
12+
xAPIVersionRegEx200
1113
DurationRegEx
14+
DurationRegEx200
1215
Sha1RegEx
1316
Sha2RegEx]]
1417
[clojure.spec.alpha :as s #?@(:cljs [:include-macros true])]
@@ -22,6 +25,10 @@
2225
"When true, coerce 0.95 context activities to conform."
2326
true)
2427

28+
(def ^:dynamic *xapi-version*
29+
"xAPI Statement Version to Conform"
30+
"1.0.3")
31+
2532
;; Utils
2633

2734
(def double-conformer
@@ -234,7 +241,11 @@
234241
[timestamp]
235242
(letfn [(parse-int [s] #?(:clj (Integer/parseInt s) :cljs (js/parseInt s)))]
236243
(let [[ts year month day _hour _min _sec _sec-frac _offset]
237-
(re-matches TimestampRegEx timestamp)
244+
(re-matches
245+
(case *xapi-version*
246+
"1.0.3" TimestampRegEx
247+
"2.0.0" TimestampRegEx200)
248+
timestamp)
238249
month-int (when month (parse-int month))
239250
year-int (when year (parse-int year))
240251
day-int (when day (parse-int day))]
@@ -269,7 +280,11 @@
269280
(s/def ::duration
270281
(s/with-gen
271282
(s/and string?
272-
(partial re-matches DurationRegEx))
283+
#(re-matches
284+
(case *xapi-version*
285+
"1.0.3" DurationRegEx
286+
"2.0.0" DurationRegEx200)
287+
%))
273288
#(sgen/fmap (fn [[h m s]]
274289
(#?(:clj format
275290
:cljs gstring/format) "PT%dH%sM%dS" h m s))
@@ -280,8 +295,12 @@
280295
(s/def ::version
281296
(s/with-gen
282297
(s/and string?
283-
(partial re-matches xAPIVersionRegEx))
284-
#(sgen/return "2.0.0")))
298+
#(re-matches
299+
(case *xapi-version*
300+
"1.0.3" xAPIVersionRegEx
301+
"2.0.0" xAPIVersionRegEx200)
302+
%))
303+
#(sgen/return *xapi-version*)))
285304

286305
(s/def ::sha2
287306
(s/with-gen
@@ -1015,31 +1034,62 @@
10151034
(s/every ::context-group
10161035
:into []))
10171036

1037+
;; multispec for dynamic params
1038+
(defmulti context-version (fn [_] *xapi-version*))
1039+
1040+
(defmethod context-version "1.0.3" [_]
1041+
(conform-ns
1042+
"context"
1043+
(s/and
1044+
(s/keys :opt [:context/registration
1045+
:context/instructor
1046+
:context/team
1047+
:context/contextActivities
1048+
:context/revision
1049+
:context/platform
1050+
:context/language
1051+
:context/statement
1052+
:context/extensions])
1053+
(restrict-keys :context/registration
1054+
:context/instructor
1055+
:context/team
1056+
:context/contextActivities
1057+
:context/revision
1058+
:context/platform
1059+
:context/language
1060+
:context/statement
1061+
:context/extensions))))
1062+
1063+
(defmethod context-version "2.0.0" [_]
1064+
(conform-ns
1065+
"context"
1066+
(s/and
1067+
(s/keys :opt [:context/registration
1068+
:context/instructor
1069+
:context/team
1070+
:context/contextActivities
1071+
:context/revision
1072+
:context/platform
1073+
:context/language
1074+
:context/statement
1075+
:context/extensions
1076+
:context/contextAgents
1077+
:context/contextGroups])
1078+
(restrict-keys :context/registration
1079+
:context/instructor
1080+
:context/team
1081+
:context/contextActivities
1082+
:context/revision
1083+
:context/platform
1084+
:context/language
1085+
:context/statement
1086+
:context/extensions
1087+
:context/contextAgents
1088+
:context/contextGroups))))
1089+
10181090
(s/def ::context
1019-
(conform-ns "context"
1020-
(s/and
1021-
(s/keys :opt [:context/registration
1022-
:context/instructor
1023-
:context/team
1024-
:context/contextActivities
1025-
:context/revision
1026-
:context/platform
1027-
:context/language
1028-
:context/statement
1029-
:context/extensions
1030-
:context/contextAgents
1031-
:context/contextGroups])
1032-
(restrict-keys :context/registration
1033-
:context/instructor
1034-
:context/team
1035-
:context/contextActivities
1036-
:context/revision
1037-
:context/platform
1038-
:context/language
1039-
:context/statement
1040-
:context/extensions
1041-
:context/contextAgents
1042-
:context/contextGroups))))
1091+
(s/multi-spec context-version (fn [gen-val _]
1092+
gen-val) ))
10431093

10441094
;; Attachments
10451095

src/xapi_schema/spec/regex.cljc

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
;; Time
118118
time (str "(?:" hour ":" min ":" sec sec-frac "?" ")")
119119
date (str "(?:" year "-" month "-" day ")")]
120-
(str date "[T\\s]" time)))
120+
(str date "T" time)))
121121

122122
(def TimestampRegEx ; RFC 3339
123123
(let [;; Time
@@ -144,8 +144,55 @@
144144
dur-week)]
145145
(re-pattern (str "^P(?:" duration ")|P(?:" (base-timestamp) ")$"))))
146146

147+
(defn- base-timestamp-200 []
148+
(let [;; Date
149+
year "(\\d{4})"
150+
month "(0[1-9]|1[0-2])"
151+
day "(0[1-9]|[12]\\d|3[01])" ; ignore month/leap year constraints
152+
;; Time
153+
hour "([01]\\d|2[0-3])"
154+
min "([0-5]\\d)"
155+
sec "([0-5]\\d|60)" ; leap seconds
156+
sec-frac "(\\.\\d+)"
157+
;; Time
158+
time (str "(?:" hour ":" min ":" sec sec-frac "?" ")")
159+
date (str "(?:" year "-" month "-" day ")")]
160+
(str date "[T\\s]" time)))
161+
162+
(def TimestampRegEx200 ; RFC 3339
163+
(let [;; Time
164+
hour "(?:[01]\\d|2[0-3])"
165+
min "(?:[0-5]\\d)"
166+
;; Offset
167+
lookahead "(?!-00:00)"
168+
num-offset (str "(?:[+-]" hour ":" min ")")
169+
time-offset (str "(Z|" lookahead num-offset ")")]
170+
(re-pattern (str "^" (base-timestamp-200) time-offset "$"))))
171+
172+
(def DurationRegEx200 ; ISO 8601 Durations
173+
(let [dy "(?:\\d+Y|\\d+\\.\\d+Y$)"
174+
dm "(?:\\d+M|\\d+\\.\\d+M$)"
175+
dw "(?:\\d+W|\\d+\\.\\d+W$)"
176+
dd "(?:\\d+D|\\d+\\.\\d+D$)"
177+
dh "(?:\\d+H|\\d+\\.\\d+H$)"
178+
ds "(?:\\d+S|\\d+\\.\\d+S$)"
179+
dur-date (str "(?:" dd "|" dm dd "?" "|" dy dm "?" dd "?" ")")
180+
dur-time (str "(?:" ds "|" dm ds "?" "|" dh dm "?" ds "?" ")")
181+
dur-week (str "(?:" dw ")")
182+
duration (str "(?:" dur-date "(?:T" dur-time ")?" ")" "|"
183+
"(?:T" dur-time ")" "|"
184+
dur-week)]
185+
(re-pattern (str "^P(?:" duration ")|P(?:" (base-timestamp-200) ")$"))))
186+
187+
147188
;; Based on http://www.regexr.com/39s32
148189
(def xAPIVersionRegEx
190+
(let [suf-part "[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*"
191+
suffix (str "(\\.[0-9]+(?:-" suf-part ")?(?:\\+" suf-part ")?)?")
192+
ver-str (str "^1\\.0" suffix "$")]
193+
(re-pattern ver-str)))
194+
195+
(def xAPIVersionRegEx200
149196
(let [suf-part "[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*"
150197
suffix (str "(\\.[0-9]+(?:-" suf-part ")?(?:\\+" suf-part ")?)?")
151198
ver-str (str "^(1\\.0" suffix ")|(2\\.0\\.0)$")]

test/xapi_schema/spec/regex_test.cljc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
MailToIRIRegEx
1010
UuidRegEx
1111
TimestampRegEx
12+
TimestampRegEx200
1213
xAPIVersionRegEx
14+
xAPIVersionRegEx200
1315
DurationRegEx
1416
Base64RegEx
1517
Sha1RegEx
@@ -147,7 +149,7 @@
147149
;; negative offset
148150
(is (not (re-matches TimestampRegEx "2008-09-15T15:53:00.601-00:00"))))
149151
(testing "matches valid but terrible stamps in rfc3339 OUTSIDE of 8601"
150-
(is (re-matches TimestampRegEx "2015-05-13 15:16:00Z"))))
152+
(is (re-matches TimestampRegEx200 "2015-05-13 15:16:00Z"))))
151153

152154
(deftest xapi-version-regex-test
153155
(testing "matches xAPI 1.0.X versions"
@@ -157,8 +159,8 @@
157159
(re-matches xAPIVersionRegEx "1.0.32-abc.def+ghi.jkl")))
158160
(is (not (re-matches xAPIVersionRegEx "0.9.5"))))
159161
(testing "matches xAPI 2.0.0 version only"
160-
(is (and (re-matches xAPIVersionRegEx "2.0.0")
161-
(not (re-matches xAPIVersionRegEx "2.0.2"))))))
162+
(is (and (re-matches xAPIVersionRegEx200 "2.0.0")
163+
(not (re-matches xAPIVersionRegEx200 "2.0.2"))))))
162164

163165
(deftest duration-regex-test
164166
(testing "matches ISO durations"

test/xapi_schema/spec_test.cljc

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,37 @@
389389
:bad
390390
{"team" {"mbox" "mailto:a@b.com"}}
391391
{"team" {"mbox" "mailto:a@b.com"
392-
"objectType" "Agent"}}))))
392+
"objectType" "Agent"}})))
393+
(testing "xAPI 2.0.0"
394+
(binding [xs/*xapi-version* "2.0.0"]
395+
(testing "contextAgents"
396+
(should-satisfy+
397+
::xs/context
398+
{"contextAgents"
399+
[{:objectType "contextAgent"
400+
:agent {"mbox" "mailto:a@b.com"
401+
"objectType" "Agent"}}]}
402+
:bad
403+
{"contextAgents" [{"mbox" "mailto:a@b.com"
404+
"objectType" "Agent"}]}
405+
{"contextAgents"
406+
[{:objectType "contextGroup"
407+
:group {"mbox" "mailto:a@b.com"
408+
"objectType" "Group"}}]}))
409+
(testing "contextGroups"
410+
(should-satisfy+
411+
::xs/context
412+
{"contextGroups"
413+
[{:objectType "contextGroup"
414+
:group {"mbox" "mailto:a@b.com"
415+
"objectType" "Group"}}]}
416+
:bad
417+
{"contextGroups" [{"mbox" "mailto:a@b.com"
418+
"objectType" "Group"}]}
419+
{"contextGroups"
420+
[{:objectType "contextAgent"
421+
:agent {"mbox" "mailto:a@b.com"
422+
"objectType" "Agent"}}]})))))
393423

394424
(deftest attachment-test
395425
(testing

0 commit comments

Comments
 (0)