Last active
December 18, 2016 06:22
-
-
Save h3h/5953a0657f0040fe66ce098fc7e0c247 to your computer and use it in GitHub Desktop.
Evolving Elm Validation Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (onInput) | |
import List | |
import Regex exposing (regex) | |
main = | |
Html.beginnerProgram | |
{ model = model | |
, view = view | |
, update = update | |
} | |
-- MODEL | |
type alias Model = | |
{ name : String | |
, age : String | |
, password : String | |
, passwordAgain : String | |
} | |
model : Model | |
model = | |
Model "" "" "" "" | |
-- UPDATE | |
type Msg | |
= Name String | |
| Age String | |
| Password String | |
| PasswordAgain String | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
Name name -> | |
{ model | name = name } | |
Age age -> | |
{ model | age = age } | |
Password password -> | |
{ model | password = password } | |
PasswordAgain password -> | |
{ model | passwordAgain = password } | |
-- VIEW | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ input [ type_ "text", placeholder "Name", onInput Name ] [] | |
, input [ type_ "text", placeholder "Age", onInput Age ] [] | |
, input [ type_ "password", placeholder "Password", onInput Password ] [] | |
, input [ type_ "password", placeholder "Re-enter Password", onInput PasswordAgain ] [] | |
, viewValidation model | |
] | |
viewValidation : Model -> Html msg | |
viewValidation model = | |
let | |
errors = List.filterMap (\fn -> fn model) modelValidations | |
in | |
if List.isEmpty errors then | |
div [ style [("color", "green")] ] [ text "Great password!" ] | |
else | |
ul [ style [("color", "red")] ] (List.map (\msg -> li [] [ text (msg) ]) errors) | |
modelValidations = | |
[ validatePasswordsMatch | |
, validatePasswordLength | |
, validatePasswordChars | |
, validateAge | |
] | |
validatePasswordChars : Model -> Maybe String | |
validatePasswordChars {password} = | |
if not (Regex.contains (regex "[a-z]") password) || | |
not (Regex.contains (regex "[A-Z]") password) || | |
not (Regex.contains (regex "[0-9]") password) then | |
Just "Your password must contain lowercase and uppercase letters and a number." | |
else | |
Nothing | |
validatePasswordLength : Model -> Maybe String | |
validatePasswordLength {password} = | |
if String.length password < 8 then | |
Just "Your password must be at least 8 characters long." | |
else | |
Nothing | |
validatePasswordsMatch : Model -> Maybe String | |
validatePasswordsMatch {password, passwordAgain} = | |
if password /= passwordAgain then | |
Just "Your passwords don't match." | |
else | |
Nothing | |
validateAge : Model -> Maybe String | |
validateAge {age} = | |
if not (Regex.contains (regex "^[0-9]+$") age) then | |
Just "Your age must be a positive integer number." | |
else | |
Nothing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main exposing (..) | |
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (onInput) | |
import List | |
import Regex | |
main = | |
Html.beginnerProgram | |
{ model = model | |
, view = view | |
, update = update | |
} | |
-- MODEL | |
type alias Model = | |
{ name : String | |
, age : String | |
, password : String | |
, passwordAgain : String | |
} | |
model : Model | |
model = | |
Model "" "" "" "" | |
-- UPDATE | |
type Msg | |
= Name String | |
| Age String | |
| Password String | |
| PasswordAgain String | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
Name name -> | |
{ model | name = name } | |
Age age -> | |
{ model | age = age } | |
Password password -> | |
{ model | password = password } | |
PasswordAgain password -> | |
{ model | passwordAgain = password } | |
-- VIEW | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ input [ type_ "text", placeholder "Name", onInput Name ] [] | |
, input [ type_ "text", placeholder "Age", onInput Age ] [] | |
, input [ type_ "password", placeholder "Password", onInput Password ] [] | |
, input [ type_ "password", placeholder "Re-enter Password", onInput PasswordAgain ] [] | |
, viewValidation model | |
] | |
viewValidation : Model -> Html msg | |
viewValidation model = | |
let | |
errors : List String | |
errors = | |
List.filterMap (\fn -> fn model) modelValidations | |
in | |
if List.isEmpty errors then | |
div [ style [ ( "color", "green" ) ] ] [ text "Great password!" ] | |
else | |
ul [ style [ ( "color", "red" ) ] ] (List.map (\msg -> li [] [ text (msg) ]) errors) | |
modelValidations = | |
[ validatePasswordsMatch | |
, validatePasswordLength | |
, validatePasswordChars | |
, validateAge | |
] | |
validatePasswordChars : Model -> Maybe String | |
validatePasswordChars { password } = | |
if | |
List.any (\pattern -> not <| Regex.contains (Regex.regex pattern) password) | |
[ "[a-z]" | |
, "[A-Z]" | |
, "[0-9]" | |
] | |
then | |
Just "Your password must contain lowercase and uppercase letters and a number." | |
else | |
Nothing | |
validatePasswordLength : Model -> Maybe String | |
validatePasswordLength { password } = | |
if String.length password < 8 then | |
Just "Your password must be at least 8 characters long." | |
else | |
Nothing | |
validatePasswordsMatch : Model -> Maybe String | |
validatePasswordsMatch { password, passwordAgain } = | |
if password /= passwordAgain then | |
Just "Your passwords don't match." | |
else | |
Nothing | |
validateAge : Model -> Maybe String | |
validateAge { age } = | |
if not (Regex.contains (Regex.regex "^[0-9]+$") age) then | |
Just "Your age must be a positive integer number." | |
else | |
Nothing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main exposing (..) | |
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (onInput) | |
import List | |
import Regex | |
main : Program Never Model Msg | |
main = | |
Html.beginnerProgram | |
{ model = model | |
, view = view | |
, update = update | |
} | |
-- MODEL | |
type alias Model = | |
{ name : String | |
, age : String | |
, password : String | |
, passwordAgain : String | |
} | |
model : Model | |
model = | |
Model "" "" "" "" | |
-- UPDATE | |
type Msg | |
= Name String | |
| Age String | |
| Password String | |
| PasswordAgain String | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
Name name -> | |
{ model | name = name } | |
Age age -> | |
{ model | age = age } | |
Password password -> | |
{ model | password = password } | |
PasswordAgain passwordAgain -> | |
{ model | passwordAgain = passwordAgain } | |
-- VIEW | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ input [ type_ "text", placeholder "Name", onInput Name ] [] | |
, input [ type_ "text", placeholder "Age", onInput Age ] [] | |
, input [ type_ "password", placeholder "Password", onInput Password ] [] | |
, input [ type_ "password", placeholder "Re-enter Password", onInput PasswordAgain ] [] | |
, viewValidation model | |
] | |
viewValidation : Model -> Html msg | |
viewValidation model = | |
let | |
errors : List String | |
errors = | |
List.filterMap (\fn -> fn model) modelValidations | |
in | |
if List.isEmpty errors then | |
div [ style [ ( "color", "green" ) ] ] [ text "Great password!" ] | |
else | |
ul [ style [ ( "color", "red" ) ] ] (List.map (\msg -> li [] [ text (msg) ]) errors) | |
modelValidations : List (Model -> Maybe String) | |
modelValidations = | |
[ modelValidator | |
( (\{ password, passwordAgain } -> password /= passwordAgain) | |
, "Your passwords don't match." | |
) | |
, modelValidator | |
( (\{ password } -> String.length password < 8) | |
, "Your password must be at least 8 characters long." | |
) | |
, modelValidator | |
( validatePasswordChars | |
, "Your password must contain lowercase and uppercase letters and a number." | |
) | |
, modelValidator | |
( (\{ age } -> not <| simpleRegexMatches "^[0-9]+$" age) | |
, "Your age must be a positive integer number." | |
) | |
] | |
modelValidator : ( Model -> Bool, String ) -> (Model -> Maybe String) | |
modelValidator ( fnValidator, errorMsg ) = | |
(\model -> | |
if fnValidator model then | |
Just errorMsg | |
else | |
Nothing | |
) | |
simpleRegexMatches : String -> String -> Bool | |
simpleRegexMatches pattern string = | |
Regex.contains (Regex.regex pattern) string | |
validatePasswordChars : Model -> Bool | |
validatePasswordChars { password } = | |
List.any | |
(\pattern -> not <| simpleRegexMatches pattern password) | |
[ "[a-z]" | |
, "[A-Z]" | |
, "[0-9]" | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 01.elm 2016-12-18 00:19:28.000000000 -0600 | |
+++ 02.elm 2016-12-18 00:19:28.000000000 -0600 | |
@@ -1,8 +1,10 @@ | |
+module Main exposing (..) | |
+ | |
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (onInput) | |
import List | |
-import Regex exposing (regex) | |
+import Regex | |
main = | |
@@ -71,16 +73,20 @@ | |
, viewValidation model | |
] | |
+ | |
viewValidation : Model -> Html msg | |
viewValidation model = | |
let | |
- errors = List.filterMap (\fn -> fn model) modelValidations | |
+ errors : List String | |
+ errors = | |
+ List.filterMap (\fn -> fn model) modelValidations | |
in | |
if List.isEmpty errors then | |
div [ style [("color", "green")] ] [ text "Great password!" ] | |
else | |
ul [ style [("color", "red")] ] (List.map (\msg -> li [] [ text (msg) ]) errors) | |
+ | |
modelValidations = | |
[ validatePasswordsMatch | |
, validatePasswordLength | |
@@ -88,15 +94,21 @@ | |
, validateAge | |
] | |
+ | |
validatePasswordChars : Model -> Maybe String | |
validatePasswordChars {password} = | |
- if not (Regex.contains (regex "[a-z]") password) || | |
- not (Regex.contains (regex "[A-Z]") password) || | |
- not (Regex.contains (regex "[0-9]") password) then | |
+ if | |
+ List.any (\pattern -> not <| Regex.contains (Regex.regex pattern) password) | |
+ [ "[a-z]" | |
+ , "[A-Z]" | |
+ , "[0-9]" | |
+ ] | |
+ then | |
Just "Your password must contain lowercase and uppercase letters and a number." | |
else | |
Nothing | |
+ | |
validatePasswordLength : Model -> Maybe String | |
validatePasswordLength {password} = | |
if String.length password < 8 then | |
@@ -104,6 +116,7 @@ | |
else | |
Nothing | |
+ | |
validatePasswordsMatch : Model -> Maybe String | |
validatePasswordsMatch {password, passwordAgain} = | |
if password /= passwordAgain then | |
@@ -111,9 +124,10 @@ | |
else | |
Nothing | |
+ | |
validateAge : Model -> Maybe String | |
validateAge {age} = | |
- if not (Regex.contains (regex "^[0-9]+$") age) then | |
+ if not (Regex.contains (Regex.regex "^[0-9]+$") age) then | |
Just "Your age must be a positive integer number." | |
else | |
Nothing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 02.elm 2016-12-18 00:19:28.000000000 -0600 | |
+++ 03.elm 2016-12-18 00:19:28.000000000 -0600 | |
@@ -7,6 +7,7 @@ | |
import Regex | |
+main : Program Never Model Msg | |
main = | |
Html.beginnerProgram | |
{ model = model | |
@@ -55,8 +56,8 @@ | |
Password password -> | |
{ model | password = password } | |
- PasswordAgain password -> | |
- { model | passwordAgain = password } | |
+ PasswordAgain passwordAgain -> | |
+ { model | passwordAgain = passwordAgain } | |
@@ -87,47 +88,47 @@ | |
ul [ style [ ( "color", "red" ) ] ] (List.map (\msg -> li [] [ text (msg) ]) errors) | |
+modelValidations : List (Model -> Maybe String) | |
modelValidations = | |
- [ validatePasswordsMatch | |
- , validatePasswordLength | |
- , validatePasswordChars | |
- , validateAge | |
+ [ modelValidator | |
+ ( (\{ password, passwordAgain } -> password /= passwordAgain) | |
+ , "Your passwords don't match." | |
+ ) | |
+ , modelValidator | |
+ ( (\{ password } -> String.length password < 8) | |
+ , "Your password must be at least 8 characters long." | |
+ ) | |
+ , modelValidator | |
+ ( validatePasswordChars | |
+ , "Your password must contain lowercase and uppercase letters and a number." | |
+ ) | |
+ , modelValidator | |
+ ( (\{ age } -> not <| simpleRegexMatches "^[0-9]+$" age) | |
+ , "Your age must be a positive integer number." | |
+ ) | |
] | |
-validatePasswordChars : Model -> Maybe String | |
-validatePasswordChars { password } = | |
- if | |
- List.any (\pattern -> not <| Regex.contains (Regex.regex pattern) password) | |
- [ "[a-z]" | |
- , "[A-Z]" | |
- , "[0-9]" | |
- ] | |
- then | |
- Just "Your password must contain lowercase and uppercase letters and a number." | |
- else | |
- Nothing | |
- | |
- | |
-validatePasswordLength : Model -> Maybe String | |
-validatePasswordLength { password } = | |
- if String.length password < 8 then | |
- Just "Your password must be at least 8 characters long." | |
+modelValidator : ( Model -> Bool, String ) -> (Model -> Maybe String) | |
+modelValidator ( fnValidator, errorMsg ) = | |
+ (\model -> | |
+ if fnValidator model then | |
+ Just errorMsg | |
else | |
Nothing | |
+ ) | |
-validatePasswordsMatch : Model -> Maybe String | |
-validatePasswordsMatch { password, passwordAgain } = | |
- if password /= passwordAgain then | |
- Just "Your passwords don't match." | |
- else | |
- Nothing | |
+simpleRegexMatches : String -> String -> Bool | |
+simpleRegexMatches pattern string = | |
+ Regex.contains (Regex.regex pattern) string | |
-validateAge : Model -> Maybe String | |
-validateAge { age } = | |
- if not (Regex.contains (Regex.regex "^[0-9]+$") age) then | |
- Just "Your age must be a positive integer number." | |
- else | |
- Nothing | |
+validatePasswordChars : Model -> Bool | |
+validatePasswordChars { password } = | |
+ List.any | |
+ (\pattern -> not <| simpleRegexMatches pattern password) | |
+ [ "[a-z]" | |
+ , "[A-Z]" | |
+ , "[0-9]" | |
+ ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment