git.iko.soy/typeable/inflections-hs
on master help sign in
Parser tests and fixes
commit4d3bb48d7bac7f9d81254d028da74a8213f79833 authormrkkrp <markkarpov@opmbx.org> dateWed 21 Dec 2016, 18:49 (10 years ago) parent477a36d
6 files changed+89−22
CHANGELOG.md+7 Text/Inflections/Parse/CamelCase.hs+1 Text/Inflections/Parse/SnakeCase.hs+10−20 Text/Inflections/Types.hs+3 test/Text/Inflections/Parse/CamelCaseSpec.hs+40−1 test/Text/Inflections/Parse/SnakeCaseSpec.hs+28−1
CHANGELOG.md+7
@@ -9,6 +9,13 @@
99
1010* Renamed `defaultMap` to `defaultTransliterations`.
1111
12+* Words now can contain digits (recognized by all parsers).
13+
14+* `parseSnakeCase` now is not confused when a word happens to have prefix
15+ coinciding with an acronym. This is harder to fix for `parseCamelCase`
16+ because acronym may contain capital letters, so old behavior is preserved
17+ for `parseCamelCase` for now.
18+
1219* `parseCamelCase` and `parseSnakeCase` take any instance of `Foldable` as a
1320 collection of acronyms, not just lists.
1421
Text/Inflections/Parse/CamelCase.hs+1
@@ -28,6 +28,7 @@ import qualified Data.Text as T
2828import Prelude hiding (Word)
2929#else
3030import Data.Foldable
31+import Prelude hiding (elem)
3132#endif
3233
3334-- | Parse a CamelCase string.
Text/Inflections/Parse/SnakeCase.hs+10−20
@@ -27,6 +27,7 @@ import qualified Data.Text as T
2727import Prelude hiding (Word)
2828#else
2929import Data.Foldable
30+import Prelude hiding (elem)
3031#endif
3132
3233-- | Parse a snake_case string.
@@ -48,25 +49,14 @@ parseSnakeCase acronyms = parse (parser acronyms) ""
4849parser :: (Foldable f, Functor f)
4950 => f (Word 'Acronym)
5051 -> Parser [SomeWord]
51−parser acronyms = ((a <|> n) `sepBy` char '_') <* eof
52− where
53− n = SomeWord <$> word
54− a = SomeWord <$> acronym acronyms
52+parser acronyms = (pWord acronyms `sepBy` char '_') <* eof
5553
56−acronym :: (Foldable f, Functor f)
54+pWord :: (Foldable f, Functor f)
5755 => f (Word 'Acronym)
58− -> Parser (Word 'Acronym)
59−acronym acronyms = do
60− x <- T.pack <$> choice (string . T.unpack . unWord <$> acronyms)
61− case mkAcronym x of
62− Nothing -> empty -- cannot happen if the system is sound
63− Just acr -> return acr
64−{-# INLINE acronym #-}
65−
66−word :: Parser (Word 'Normal)
67−word = do
68− x <- T.pack <$> (some lowerChar <|> some digitChar)
69− case mkWord x of
70− Nothing -> empty -- cannot happen if the system is sound
71− Just wrd -> return wrd
72−{-# INLINE word #-}
56+ -> Parser SomeWord
57+pWord acronyms = do
58+ let acs = unWord <$> acronyms
59+ r <- T.pack <$> some alphaNumChar
60+ if r `elem` acs
61+ then maybe empty (return . SomeWord) (mkAcronym r)
62+ else maybe empty (return . SomeWord) (mkWord r)
Text/Inflections/Types.hs+3
@@ -106,6 +106,9 @@ data SomeWord where
106106instance Show SomeWord where
107107 show (SomeWord w) = show w
108108
109+instance Eq SomeWord where
110+ x == y = unSomeWord id x == unSomeWord id y
111+
109112-- | Extract 'Text' from 'SomeWord' and apply given function only if the
110113-- word inside wasn't an acronym.
111114--
test/Text/Inflections/Parse/CamelCaseSpec.hs+40−1
@@ -1,8 +1,47 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
13module Text.Inflections.Parse.CamelCaseSpec
24 ( spec )
35where
46
57import Test.Hspec
8+import Test.Hspec.Megaparsec
9+import Text.Inflections
610
711spec :: Spec
8−spec = return ()
12+spec =
13+ describe "parseCamelCase" $ do
14+ context "when given no acronyms" $ do
15+ context "when first word is capitalized" $
16+ it "parses CamelCase correctly" $ do
17+ r <- mapM (fmap SomeWord . mkWord) ["One","Two","Three"]
18+ parseCamelCase [] "OneTwoThree" `shouldParse` r
19+ context "when first word is not capitalized" $
20+ it "parses camelCase correctly" $ do
21+ r <- mapM (fmap SomeWord . mkWord) ["one","Two","Three"]
22+ parseCamelCase [] "oneTwoThree" `shouldParse` r
23+ context "when there are digits in the words" $
24+ it "parses CamelCase correctly" $ do
25+ r <- mapM (fmap SomeWord . mkWord) ["one1two","Three3"]
26+ parseCamelCase [] "one1twoThree3" `shouldParse` r
27+ context "when given some acronyms" $ do
28+ context "when first word is capitalized" $
29+ it "parses CamelCase correctly" $ do
30+ a <- mkAcronym "BOO"
31+ r <- mapM (fmap SomeWord . mkWord) ["One","BOO","One"]
32+ parseCamelCase [a] "OneBOOOne" `shouldParse` r
33+ context "when first word is not capitalized" $
34+ it "parses camelCase correctly" $ do
35+ a <- mkAcronym "BOO"
36+ r <- mapM (fmap SomeWord . mkWord) ["one","Two","BOO"]
37+ parseCamelCase [a] "oneTwoBOO" `shouldParse` r
38+ context "when there are digits in the words" $
39+ it "parses CamelCase correctly" $ do
40+ a <- mkAcronym "BOO"
41+ r <- mapM (fmap SomeWord . mkWord) ["one1two","Three3"]
42+ parseCamelCase [a] "one1twoThree3" `shouldParse` r
43+ context "when a word has a suffix coinciding with a acronym" $
44+ it "is still parsed correctly as a normala word" $ do
45+ a <- mkAcronym "boo"
46+ r <- mapM (fmap SomeWord . mkWord) ["fooboo","Bar"]
47+ parseCamelCase [a] "foobooBar" `shouldParse` r
test/Text/Inflections/Parse/SnakeCaseSpec.hs+28−1
@@ -1,8 +1,35 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
13module Text.Inflections.Parse.SnakeCaseSpec
24 ( spec )
35where
46
57import Test.Hspec
8+import Test.Hspec.Megaparsec
9+import Text.Inflections
610
711spec :: Spec
8−spec = return ()
12+spec =
13+ describe "parseSnakeCase" $ do
14+ context "when given no acronyms" $ do
15+ it "parses snake_case correctly" $ do
16+ r <- mapM (fmap SomeWord . mkWord) ["OneTwo","Three"]
17+ parseSnakeCase [] "OneTwo_Three" `shouldParse` r
18+ it "handles digits in the words correctly" $ do
19+ r <- mapM (fmap SomeWord . mkWord) ["one4a","two00"]
20+ parseSnakeCase [] "one4a_two00" `shouldParse` r
21+ context "when given some acronyms" $ do
22+ it "parses snake_case correctly" $ do
23+ a <- mkAcronym "BOO"
24+ r <- mapM (fmap SomeWord . mkWord) ["BOO","one","one"]
25+ parseSnakeCase [a] "BOO_one_one" `shouldParse` r
26+ context "when acronym happens to be a prefix of other word" $
27+ it "parses the word correctly" $ do
28+ a <- mkAcronym "BOO"
29+ r <- mapM (fmap SomeWord . mkWord) ["one","BOOtwo"]
30+ parseSnakeCase [a] "one_BOOtwo" `shouldParse` r
31+ context "when acronym happens to be a suffix of other word" $
32+ it "parses the word correctly" $ do
33+ a <- mkAcronym "BOO"
34+ r <- mapM (fmap SomeWord . mkWord) ["oneBOO","two"]
35+ parseSnakeCase [a] "oneBOO_two" `shouldParse` r