Skip to content

Instantly share code, notes, and snippets.

@vano468
Created April 12, 2016 07:42
Show Gist options
  • Save vano468/a28b5fead1e3b2d5c28292b738057b4e to your computer and use it in GitHub Desktop.
Save vano468/a28b5fead1e3b2d5c28292b738057b4e to your computer and use it in GitHub Desktop.
data Error = ParsingError | IncompleteDataError | IncorrectDataError String
deriving (Show, Eq)
data Person = Person { firstName :: String, lastName :: String, age :: Int }
deriving (Show, Eq)
parsePerson :: String -> Either Error Person
parsePerson = validatePerson . buildPerson (Right $ Person "" "" (-1)) . parse where
trim = unwords . words
parse = map (map trim . splitOn "=") . splitOn "\n"
isNumber = (== 0) . length . dropWhile isDigit
buildPerson result [] = result
buildPerson error@(Left _) _ = error
buildPerson (Right person) (x:xs) = buildPerson (addAttribute person x) xs
addAttribute person ("firstName":[value])
= Right person { firstName = value }
addAttribute person ("lastName":[value])
= Right person { lastName = value }
addAttribute person ("age":[value])
| isNumber value = Right person { age = read value :: Int }
| otherwise = Left $ IncorrectDataError value
addAttribute person attribute
| length (filter (/= "") attribute) /= 2 = Left ParsingError
| otherwise = Right person
validatePerson person@(Right (Person fName lName age))
| fName == "" || lName == "" || age == (-1) = Left IncompleteDataError
| otherwise = person
validatePerson error = error
parsePersonSpecs = [
(1, "firstName = John\nlastName = Connor\nage = 30", Right (Person {firstName = "John", lastName = "Connor", age = 30})),
(2, "firstName = John Smith\nlastName = Connor\nage = 30\nasde=as11", Right (Person {firstName = "John Smith", lastName = "Connor", age = 30})),
(3, "firstName=Barbarian\nlastName=Conn On\nage=30", Right (Person {firstName = "Barbarian", lastName = "Conn On", age = 30})),
(4, "firstName=Barbarian\nlastName=Conn On\nage=30\ng dsfsd", Left ParsingError),
(5, "firstName=Barbarian\nlastName=Conn On\nage=30\ng dsfsd\n drrr", Left ParsingError),
(6, "firstName=Barbarian\nlastName=Conn On", Left IncompleteDataError),
(7, " firstName = John\nlastName = Connor\nage = 2f8 ", Left (IncorrectDataError "2f8")),
(8, "firstName = John Smith\nlastName = Connor\nage = 3d0\nasde=", Left ParsingError)
]
runSpecs [] _ = []
runSpecs (x:xs) f = runSpec x : runSpecs xs f where
runSpec (id,input,expected) = (id, f input == expected)
runSpecById [] _ _ = Left "spec not found"
runSpecById ((specId,input,expected):xs) f id
| specId == id = Right $ (("expected",expected),("actual",f input),("passed", f input == expected))
| otherwise = runSpecById xs f id
runParsePersonSpecs = runSpecs parsePersonSpecs parsePerson
runParsePersonSpec = runSpecById parsePersonSpecs parsePerson
parsePerson' = (buildPerson (Right $ Person "" "" 0)) .
(checkAttrsPresence ["firstName", "lastName", "age"] []) .
(validateData []) . parse where
trim = unwords . words
parse = map (filter (/= "") . map trim . splitOn "=") . splitOn "\n"
isNumber = (== 0) . length . dropWhile isDigit
validateData acc [] = Right acc
validateData acc (x:xs)
| length x /= 2 = Left ParsingError
| otherwise = validateData (x:acc) xs
checkAttrsPresence _ _ error@(Left _) = error
checkAttrsPresence attrs filtered (Right [])
| length attrs > 0 = Left IncompleteDataError
| otherwise = Right filtered
checkAttrsPresence attrs filtered (Right (x:xs))
= checkAttrsPresence (filter (/= head x) attrs)
(x:filtered) (Right xs)
buildPerson _ _ = Right [1]
buildPerson error@(Left _) _ = error
buildPerson person (Right []) = person
buildPerson (Right person) (Right (x:xs))
= buildPerson (addAttribute person x) (Right xs)
addAttribute person ("age":[value])
| isNumber value = Right person { age = read value :: Int }
| otherwise = Left $ IncorrectDataError value
addAttribute person (attr:[value])
| attr == "firstName" = Right person { firstName = value }
| attr == "lastName" = Right person { lastName = value }
| otherwise = Right person
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment