Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

translation examples and readme test

  • Loading branch information...
commit 049e975dd0f1af2bbd62e5309d4934e8bd5b82c0 1 parent 70b8b06
@logaan authored
View
60 README.md
@@ -21,21 +21,22 @@ once the first validation fails. This helps avoid overwhelming your users with
redundant error messages.
```clojure
-(use 'vlad)
+(ns vlad.test.readme
+ (:use vlad))
(def common
(join (present [:name])
(present [:email])))
(def password
- (chain (present [:password]
- (join (length-in 6 128 [:password])
- (match #"[a-zA-Z]" [:password])
- (match #"[0-9]" [:password]))
- (equals-field [:password] [:confirmation]))))
+ (chain (present [:password])
+ (join (length-in 6 128 [:password])
+ (matches #"[a-zA-Z]" [:password])
+ (matches #"[0-9]" [:password]))
+ (equals-field [:password] [:confirmation])))
(def signup
- (join common password)
+ (join common password))
(def update
common)
@@ -44,6 +45,51 @@ redundant error messages.
And of course all these validations could be run over any data. Whether you're
pulling it in from a web service, a database or a csv file somewhere.
+## Translation
+
+Vlad is an exercise in extreme simpicity. This means you can use validations in
+any number of ways. Because errors are not coupled to messages vlad is well
+suited for localisation. Default english translations are provided for your
+convenience.
+
+```clojure
+(def english-field-names
+ {[:name] "Full Name"
+ [:email] "Email Address"
+ [:password] "Password"
+ [:confirmation] "Password Confirmation"})
+
+(-> (validate signup {:password "!"})
+ (assign-name english-field-names)
+ (translate-errors english-translate))
+
+; {[:password] ["Password must be over 6 characters long."
+; "Password must match the pattern [a-zA-Z]."
+; "Password must match the pattern [0-9]."],
+; [:email] ["Email Address is required."],
+; [:name] ["Full Name is required."]}
+
+(def chinese-field-names
+ {[:name] "姓名"
+ [:email] "邮箱"
+ [:password] "密码"
+ [:confirmation] "确认密码"})
+
+(defmulti chinese-translate :type)
+
+(defmethod chinese-translate :vlad.validations/present
+ [{:keys [name]}]
+ (format "%s是必需的。" name))
+
+; Other validation translations go here.
+
+(-> (validate update {:name "Rich"})
+ (assign-name chinese-field-names)
+ (translate-errors chinese-translate))
+
+; {[:email] ["邮箱是必需的。"]}
+```
+
## A simple example
Say you have an application with user accounts and information about users is
View
10 src/vlad.clj
@@ -1,5 +1,5 @@
(ns vlad
- (:require [vlad validations validation_types]
+ (:require [vlad validations validation-types default-errors]
[potemkin :refer :all]))
(import-vars
@@ -13,8 +13,12 @@
equals-value
equals-field
matches]
- [vlad.validation_types
+ [vlad.validation-types
join
chain
predicate
- validate])
+ validate]
+ [vlad.default-errors
+ assign-name
+ english-translate
+ translate-errors])
View
31 src/vlad/default_errors.clj
@@ -1,6 +1,6 @@
;; Validations return a data structure that gives all information about an
;; error. You may find this information does not suit the tastes of your users.
-(ns vlad.default_errors
+(ns vlad.default-errors
(:require [clojure.string :as s]))
(defn assign-name
@@ -10,40 +10,40 @@
[errors selectors-to-names]
(map #(assoc % :name (selectors-to-names (:selector %))) errors))
-(defmulti translate
+(defmulti english-translate
"The translate function simply takes an error and returns a readable version
of it."
:type)
-(defmethod translate :vlad.validations/present
+(defmethod english-translate :vlad.validations/present
[{:keys [name]}]
(format "%s is required." name))
-(defmethod translate :vlad.validations/length-over
+(defmethod english-translate :vlad.validations/length-over
[{:keys [name size]}]
(format "%s must be over %s characters long." name size))
-(defmethod translate :vlad.validations/length-under
+(defmethod english-translate :vlad.validations/length-under
[{:keys [name size]}]
(format "%s must be under %s characters long." name size))
-(defmethod translate :vlad.validations/one-of
+(defmethod english-translate :vlad.validations/one-of
[{:keys [name set]}]
(format "%s must be one of %s." name (s/join ", " set)))
-(defmethod translate :vlad.validations/not-of
+(defmethod english-translate :vlad.validations/not-of
[{:keys [name set]}]
(format "%s must not be one of %s." name (s/join ", " set)))
-(defmethod translate :vlad.validations/equals-value
+(defmethod english-translate :vlad.validations/equals-value
[{:keys [name value]}]
(format "%s must be \"%s\"." name value))
-(defmethod translate :vlad.validations/equals-field
+(defmethod english-translate :vlad.validations/equals-field
[{:keys [first-name second-name]}]
(format "%s must be the same as %s." first-name second-name))
-(defmethod translate :vlad.validations/matches
+(defmethod english-translate :vlad.validations/matches
[{:keys [name pattern]}]
(format "%s must match the pattern %s." name (.toString pattern)))
@@ -59,7 +59,10 @@
:name \"Password\"
:size 8}])
; => {[:password] \"Password must be under 8 characters long.\"}"
- [errors]
- (letfn [(translate-with-selector [error]
- {(:selector error) (translate error)})]
- (apply merge (map translate-with-selector errors))))
+ [errors translate]
+ (reduce (fn [output-map {:keys [selector] :as error}]
+ (let [existing-errors (get output-map selector [])
+ new-errors (conj existing-errors (translate error))]
+ (assoc output-map selector new-errors)))
+ {} errors))
+
View
6 src/vlad/validation_types.clj
@@ -1,5 +1,5 @@
;; Here you will find ways to create, compose and execute validations.
-(ns vlad.validation_types)
+(ns vlad.validation-types)
(defprotocol Validation
"The core of vlad is the `Validation` protocol. It simply requires that your
@@ -30,7 +30,7 @@
([] valid)
([left] left)
([left right] (Join. left right))
- ([left right & rest] (reduce (Join. left right) rest)))
+ ([left right & validations] (reduce #(Join. %1 %2) (Join. left right) validations)))
;; `Chain` can also be using for composing validations. However it will fail
;; fast, only returning the first validation if it fails. If the first
@@ -52,7 +52,7 @@
([] valid)
([left] left)
([left right] (Chain. left right))
- ([left right & rest] (reduce (Chain. left right) rest)))
+ ([left right & validations] (reduce #(Chain. %1 %2) (Chain. left right) validations)) )
;; Predicates are simple functions that take some data and return a boolean
;; value. They're ideal for use as validators and so `Predicate` exists to make
View
2  src/vlad/validations.clj
@@ -1,5 +1,5 @@
(ns vlad.validations
- (:use [vlad.validation_types])
+ (:use [vlad.validation-types])
(:require [clojure.string :as str]))
(defn present
View
6 test/vlad/test/default_errors.clj
@@ -1,7 +1,7 @@
-(ns vlad.test.default_errors
- (:use vlad.default_errors
+(ns vlad.test.default-errors
+ (:use vlad.default-errors
midje.sweet)
- (:require [vlad.validation_types :as vt]
+ (:require [vlad.validation-types :as vt]
[vlad.validations :as v]))
(tabular
View
55 test/vlad/test/readme.clj
@@ -0,0 +1,55 @@
+(ns vlad.test.readme
+ (:use vlad))
+
+(def common
+ (join (present [:name])
+ (present [:email])))
+
+(def password
+ (chain (present [:password])
+ (join (length-in 6 128 [:password])
+ (matches #"[a-zA-Z]" [:password])
+ (matches #"[0-9]" [:password]))
+ (equals-field [:password] [:confirmation])))
+
+(def signup
+ (join common password))
+
+(def update
+ common)
+
+(def english-field-names
+ {[:name] "Full Name"
+ [:email] "Email Address"
+ [:password] "Password"
+ [:confirmation] "Password Confirmation"})
+
+(-> (validate signup {:password "!"})
+ (assign-name english-field-names)
+ (translate-errors english-translate))
+
+; {[:password] ["Password must be over 6 characters long."
+; "Password must match the pattern [a-zA-Z]."
+; "Password must match the pattern [0-9]."],
+; [:email] ["Email Address is required."],
+; [:name] ["Full Name is required."]}
+
+(def chinese-field-names
+ {[:name] "姓名"
+ [:email] "邮箱"
+ [:password] "密码"
+ [:confirmation] "确认密码"})
+
+(defmulti chinese-translate :type)
+
+(defmethod chinese-translate :vlad.validations/present
+ [{:keys [name]}]
+ (format "%s是必需的。" name))
+
+; Other validation translations go here.
+
+(-> (validate update {:name "Rich"})
+ (assign-name chinese-field-names)
+ (translate-errors chinese-translate))
+
+; {[:email] ["邮箱是必需的。"]}
View
4 test/vlad/test/validation_types.clj
@@ -1,5 +1,5 @@
-(ns vlad.test.validation_types
- (:use vlad.validation_types
+(ns vlad.test.validation-types
+ (:use vlad.validation-types
midje.sweet
clojure.test))
View
2  test/vlad/test/validations.clj
@@ -1,6 +1,6 @@
(ns vlad.test.validations
(:use [midje.sweet :only [tabular fact just contains]]
- [vlad validations validation_types]))
+ [vlad validations validation-types]))
(tabular
(fact (validate ?validator {:name "Chris" :confirm_name "Brad"}) => ?errors)
Please sign in to comment.
Something went wrong with that request. Please try again.