mirror of
https://github.com/typeable/inflections-hs.git
synced 2024-08-15 17:10:21 +03:00
Implement a more type safe API
This commit is contained in:
parent
ab508f1b4f
commit
212d0cb3e7
@ -39,7 +39,7 @@ script:
|
||||
*) cabal test --show-details=always ;;
|
||||
esac
|
||||
- cabal sdist
|
||||
- cabal haddock | grep "100%" | wc -l | grep "14"
|
||||
- cabal haddock | grep "100%" | wc -l | grep "13"
|
||||
|
||||
# after_script:
|
||||
# - cabal install hpc-coveralls
|
||||
|
@ -71,36 +71,26 @@ code or bug reports:
|
||||
-}
|
||||
|
||||
module Text.Inflections
|
||||
( camelize
|
||||
, camelizeCustom
|
||||
|
||||
, dasherize
|
||||
|
||||
, humanize
|
||||
|
||||
, underscore
|
||||
|
||||
, titleize
|
||||
|
||||
, Transliterations
|
||||
, defaultMap
|
||||
|
||||
, parameterize
|
||||
, parameterizeCustom
|
||||
|
||||
, transliterate
|
||||
, transliterateCustom
|
||||
|
||||
, ordinal
|
||||
, ordinalize
|
||||
|
||||
, parseSnakeCase
|
||||
, parseCamelCase
|
||||
( camelize
|
||||
, camelizeCustom
|
||||
, dasherize
|
||||
, humanize
|
||||
, underscore
|
||||
, titleize
|
||||
, Transliterations
|
||||
, defaultMap
|
||||
, parameterize
|
||||
, parameterizeCustom
|
||||
, transliterate
|
||||
, transliterateCustom
|
||||
, ordinal
|
||||
, ordinalize
|
||||
, parseSnakeCase
|
||||
, parseCamelCase
|
||||
-- * Often used combinators
|
||||
, toUnderscore
|
||||
, toDashed
|
||||
, toCamelCased
|
||||
)
|
||||
, toUnderscore
|
||||
, toDashed
|
||||
, toCamelCased )
|
||||
where
|
||||
|
||||
import Control.Monad (liftM)
|
||||
@ -114,9 +104,9 @@ import Text.Inflections.Ordinal (ordinal, ordinalize)
|
||||
import Text.Inflections.Parameterize (parameterize, parameterizeCustom)
|
||||
import Text.Inflections.Parse.CamelCase (parseCamelCase)
|
||||
import Text.Inflections.Parse.SnakeCase (parseSnakeCase)
|
||||
import Text.Inflections.Parse.Types
|
||||
import Text.Inflections.Titleize (titleize)
|
||||
import Text.Inflections.Transliterate (transliterate, transliterateCustom)
|
||||
import Text.Inflections.Types
|
||||
import Text.Inflections.Underscore (underscore)
|
||||
import Text.Megaparsec
|
||||
|
||||
|
@ -18,34 +18,30 @@ module Text.Inflections.Camelize
|
||||
where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Types
|
||||
import Text.Inflections.Types
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#else
|
||||
#if !MIN_VERSION_base(4,8,0)
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
-- |Turns a an input Word List in into CamelCase. Returns the CamelCase String.
|
||||
-- | Turn an input word list in into CamelCase.
|
||||
--
|
||||
-- >>> camelize [ Word "foo", Acronym "bar", Word "bazz" ]
|
||||
-- "FoobarBazz"
|
||||
camelize
|
||||
:: [Word] -- ^ Input Words to separate with underscores
|
||||
-> Text -- ^ The camelized 'Text'
|
||||
:: [SomeWord] -- ^ Input words
|
||||
-> Text -- ^ The camelized 'Text'
|
||||
camelize = camelizeCustom True
|
||||
{-# INLINE camelize #-}
|
||||
|
||||
-- |Turns an input Word List into a CamelCase String.
|
||||
-- | Turn an input word list into a CamelCase String.
|
||||
--
|
||||
-- >>> camelizeCustom False [ Word "foo", Acronym "bar", Word "bazz" ]
|
||||
-- "foobarBazz"
|
||||
camelizeCustom
|
||||
:: Bool -- ^ Whether to capitalize the first character in the output String
|
||||
-> [Word] -- ^ The input Words
|
||||
-> Text -- ^ The camelized 'Text'
|
||||
:: Bool -- ^ Whether to capitalize the first character in the output String
|
||||
-> [SomeWord] -- ^ The input Words
|
||||
-> Text -- ^ The camelized 'Text'
|
||||
camelizeCustom _ [] = ""
|
||||
camelizeCustom c (x:xs) = T.concat $
|
||||
mapWord (if c then T.toTitle else T.toLower) x : (mapWord T.toTitle <$> xs)
|
||||
{-# INLINE camelizeCustom #-}
|
||||
unSomeWord (if c then T.toTitle else T.toLower) x : (unSomeWord T.toTitle <$> xs)
|
||||
|
@ -9,25 +9,24 @@
|
||||
--
|
||||
-- Conversion to dasherized phrases.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Text.Inflections.Dasherize ( dasherize ) where
|
||||
module Text.Inflections.Dasherize
|
||||
( dasherize )
|
||||
where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Types
|
||||
import Text.Inflections.Types
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#endif
|
||||
|
||||
-- | Replaces underscores in a snake_cased string with dashes (hyphens).
|
||||
--
|
||||
-- >>> dasherize [ Word "foo", Acronym "bar", Word "bazz" ]
|
||||
-- >>> foo <- SomeWord <$> mkWord "foo"
|
||||
-- >>> bar <- SomeWord <$> mkAcronym "bar"
|
||||
-- >>> bazz <- SomeWord <$> mkWord "bazz"
|
||||
-- >>> dasherize [foo,bar,bazz]
|
||||
-- "foo-bar-bazz"
|
||||
dasherize
|
||||
:: [Word] -- ^ Input Words to separate with dashes
|
||||
-> Text -- ^ The dasherized String
|
||||
dasherize = T.intercalate "-" . fmap (mapWord T.toLower)
|
||||
{-# INLINE dasherize #-}
|
||||
:: [SomeWord] -- ^ Input Words to separate with dashes
|
||||
-> Text -- ^ The dasherized String
|
||||
dasherize = T.intercalate "-" . fmap (unSomeWord T.toLower)
|
||||
|
@ -17,12 +17,10 @@ module Text.Inflections.Humanize
|
||||
where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Types
|
||||
import Text.Inflections.Types
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#else
|
||||
#if !MIN_VERSION_base(4,8,0)
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
@ -30,13 +28,15 @@ import Control.Applicative
|
||||
-- 'Text.Inflections.Titleize.titleize', this is meant for creating pretty
|
||||
-- output.
|
||||
--
|
||||
-- >>> humanize [ Word "foo", Acronym "bar", Word "bazz" ]
|
||||
-- >>> humanize [Word "foo", Acronym "bar", Word "bazz"]
|
||||
-- "Foo bar bazz"
|
||||
--
|
||||
-- Note that as of version 0.3.0.0 @Word@ and @Acronym@ constructors are
|
||||
-- hidden, but you still can construct them with 'mkWord' and 'mkAcronym'.
|
||||
humanize
|
||||
:: [Word] -- ^ List of Words, first of which will be capitalized
|
||||
-> Text -- ^ The humanized output
|
||||
:: [SomeWord] -- ^ List of Words, first of which will be capitalized
|
||||
-> Text -- ^ The humanized output
|
||||
humanize xs' =
|
||||
case mapWord (T.replace "_" " ") <$> xs' of
|
||||
case unSomeWord (T.replace "_" " ") <$> xs' of
|
||||
[] -> ""
|
||||
(x:xs) -> T.unwords $ T.toTitle x : (T.toLower <$> xs)
|
||||
{-# INLINE humanize #-}
|
||||
|
@ -1,32 +0,0 @@
|
||||
-- |
|
||||
-- Module : Text.Inflections.Parse.Acronym
|
||||
-- Copyright : © 2016 Justin Leitgeb
|
||||
-- License : MIT
|
||||
--
|
||||
-- Maintainer : Justin Leitgeb <justin@stackbuilders.com>
|
||||
-- Stability : experimental
|
||||
-- Portability : portable
|
||||
--
|
||||
-- Parser for acronyms.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
|
||||
module Text.Inflections.Parse.Acronym
|
||||
( acronym )
|
||||
where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Types
|
||||
import Text.Megaparsec
|
||||
import Text.Megaparsec.Text
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#endif
|
||||
|
||||
-- | Parser that accepts a 'Text' from given collection and turns it into
|
||||
-- an 'Acronym'.
|
||||
acronym :: [Text] -> Parser Word
|
||||
acronym = fmap (Acronym . T.pack) . choice . fmap (string . T.unpack)
|
||||
{-# INLINE acronym #-}
|
@ -10,26 +10,25 @@
|
||||
-- Parser for camel case “symbols”.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Text.Inflections.Parse.CamelCase
|
||||
( parseCamelCase )
|
||||
where
|
||||
|
||||
import Control.Applicative
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Acronym (acronym)
|
||||
import Text.Inflections.Parse.Types (Word(..))
|
||||
import Text.Inflections.Types
|
||||
import Text.Megaparsec
|
||||
import Text.Megaparsec.Text
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#else
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
-- |Parse a CamelCase string.
|
||||
-- | Parse a CamelCase string.
|
||||
--
|
||||
-- >>> parseCamelCase ["Bar"] "FooBarBazz"
|
||||
-- Right [Word "Foo",Acronym "Bar",Word "Bazz"]
|
||||
@ -37,20 +36,32 @@ import Control.Applicative
|
||||
-- Left "(unknown)" (line 1, column 4):
|
||||
-- unexpected '_'
|
||||
parseCamelCase
|
||||
:: [Text] -- ^ Collection of acronyms
|
||||
-> Text -- ^ Input
|
||||
-> Either (ParseError Char Dec) [Word] -- ^ Result of parsing
|
||||
:: [Word 'Acronym] -- ^ Collection of acronyms
|
||||
-> Text -- ^ Input
|
||||
-> Either (ParseError Char Dec) [SomeWord] -- ^ Result of parsing
|
||||
parseCamelCase acronyms = parse (parser acronyms) ""
|
||||
|
||||
parser
|
||||
:: [Text] -- ^ Collection of acronyms
|
||||
-> Parser [Word] -- ^ CamelCase parser
|
||||
parser acronyms = many (acronym acronyms <|> word) <* eof
|
||||
{-# INLINE parser #-}
|
||||
:: [Word 'Acronym] -- ^ Collection of acronyms
|
||||
-> Parser [SomeWord] -- ^ CamelCase parser
|
||||
parser acronyms = many (a <|> n) <* eof
|
||||
where
|
||||
n = SomeWord <$> word
|
||||
a = SomeWord <$> acronym acronyms
|
||||
|
||||
word :: Parser Word
|
||||
acronym :: [Word 'Acronym] -> Parser (Word 'Acronym)
|
||||
acronym acronyms = do
|
||||
x <- T.pack <$> choice (string . T.unpack . unWord <$> acronyms)
|
||||
case mkAcronym x of
|
||||
Nothing -> empty -- cannot happen if the system is sound
|
||||
Just acr -> return acr
|
||||
{-# INLINE acronym #-}
|
||||
|
||||
word :: Parser (Word 'Normal)
|
||||
word = do
|
||||
firstChar <- upperChar <|> lowerChar
|
||||
restChars <- many $ lowerChar <|> digitChar
|
||||
return . Word . T.pack $ firstChar : restChars
|
||||
case (mkWord . T.pack) (firstChar : restChars) of
|
||||
Nothing -> empty -- cannot happen if the system is sound
|
||||
Just wrd -> return wrd
|
||||
{-# INLINE word #-}
|
||||
|
@ -9,47 +9,59 @@
|
||||
--
|
||||
-- Parser for snake case “symbols”.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
|
||||
module Text.Inflections.Parse.SnakeCase
|
||||
( parseSnakeCase )
|
||||
where
|
||||
|
||||
import Control.Applicative
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Acronym (acronym)
|
||||
import Text.Inflections.Parse.Types (Word(..))
|
||||
import Text.Inflections.Types
|
||||
import Text.Megaparsec
|
||||
import Text.Megaparsec.Text
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#else
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
-- |Parses a snake_case string.
|
||||
-- | Parse a snake_case string.
|
||||
--
|
||||
-- >>> parseSnakeCase ["bar"] "foo_bar_bazz"
|
||||
-- >>> bar <- mkAcronym "bar"
|
||||
-- >>> parseSnakeCase [bar] "foo_bar_bazz"
|
||||
-- Right [Word "foo",Acronym "bar",Word "bazz"]
|
||||
--
|
||||
-- >>> parseSnakeCase [] "fooBarBazz"
|
||||
-- Left "(unknown)" (line 1, column 4):
|
||||
-- unexpected 'B'
|
||||
parseSnakeCase
|
||||
:: [Text] -- ^ Collection of acronyms
|
||||
:: [Word 'Acronym] -- ^ Collection of acronyms
|
||||
-> Text -- ^ Input
|
||||
-> Either (ParseError Char Dec) [Word] -- ^ Result of parsing
|
||||
-> Either (ParseError Char Dec) [SomeWord] -- ^ Result of parsing
|
||||
parseSnakeCase acronyms = parse (parser acronyms) ""
|
||||
|
||||
parser
|
||||
:: [Text]
|
||||
-> Parser [Word]
|
||||
parser acronyms = do
|
||||
ws <- (acronym acronyms <|> word) `sepBy` char '_'
|
||||
eof
|
||||
return ws
|
||||
{-# INLINE parser #-}
|
||||
:: [Word 'Acronym]
|
||||
-> Parser [SomeWord]
|
||||
parser acronyms = ((a <|> n) `sepBy` char '_') <* eof
|
||||
where
|
||||
n = SomeWord <$> word
|
||||
a = SomeWord <$> acronym acronyms
|
||||
|
||||
word :: Parser Word
|
||||
word = Word . T.pack <$> (some lowerChar <|> some digitChar)
|
||||
acronym :: [Word 'Acronym] -> Parser (Word 'Acronym)
|
||||
acronym acronyms = do
|
||||
x <- T.pack <$> choice (string . T.unpack . unWord <$> acronyms)
|
||||
case mkAcronym x of
|
||||
Nothing -> empty -- cannot happen if the system is sound
|
||||
Just acr -> return acr
|
||||
{-# INLINE acronym #-}
|
||||
|
||||
word :: Parser (Word 'Normal)
|
||||
word = do
|
||||
x <- T.pack <$> (some lowerChar <|> some digitChar)
|
||||
case mkWord x of
|
||||
Nothing -> empty -- cannot happen if the system is sound
|
||||
Just wrd -> return wrd
|
||||
{-# INLINE word #-}
|
||||
|
@ -1,54 +0,0 @@
|
||||
-- |
|
||||
-- Module : Text.Inflections.Parse.Types
|
||||
-- Copyright : © 2016 Justin Leitgeb
|
||||
-- License : MIT
|
||||
--
|
||||
-- Maintainer : Justin Leitgeb <justin@stackbuilders.com>
|
||||
-- Stability : experimental
|
||||
-- Portability : portable
|
||||
--
|
||||
-- Types used in the library.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
|
||||
module Text.Inflections.Parse.Types
|
||||
( Word (..) -- FIXME we should not export the constructor
|
||||
, unWord
|
||||
, mapWord
|
||||
, InflectionException (..) )
|
||||
where
|
||||
|
||||
import Control.Monad.Catch (Exception)
|
||||
import Data.Text (Text)
|
||||
import Data.Typeable (Typeable)
|
||||
import Text.Megaparsec
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#endif
|
||||
|
||||
-- | A 'String' that should be kept whole through applied inflections
|
||||
data Word
|
||||
= Word Text -- ^ A word that may be transformed by inflection
|
||||
| Acronym Text -- ^ A word that may not be transformed by inflections
|
||||
deriving (Show, Eq)
|
||||
|
||||
-- | Get a 'Text' value from 'Word'.
|
||||
unWord :: Word -> Text
|
||||
unWord (Word s) = s
|
||||
unWord (Acronym s) = s
|
||||
{-# INLINE unWord #-}
|
||||
|
||||
-- | Apply 'Text' transforming function to a 'Word' unless it's a 'Acronym'.
|
||||
mapWord :: (Text -> Text) -> Word -> Text
|
||||
mapWord f (Word s) = f s
|
||||
mapWord _ (Acronym s) = s
|
||||
{-# INLINE mapWord #-}
|
||||
|
||||
-- | The exceptions that is thrown when parsing of input fails.
|
||||
|
||||
data InflectionException = InflectionParsingFailed (ParseError Char Dec)
|
||||
deriving (Eq, Show, Typeable)
|
||||
|
||||
instance Exception InflectionException
|
@ -9,26 +9,19 @@
|
||||
--
|
||||
-- Conversion to titleized phrases.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
|
||||
module Text.Inflections.Titleize
|
||||
( titleize )
|
||||
where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Types
|
||||
import Text.Inflections.Types
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#endif
|
||||
|
||||
-- | Capitalize all the Words in the input list.
|
||||
--
|
||||
-- >>> titleize [ Word "foo", Acronym "bar", Word "bazz" ]
|
||||
-- "Foo bar Bazz"
|
||||
titleize
|
||||
:: [Word] -- ^ List of Words, first of which will be capitalized
|
||||
-> Text -- ^ The titleized String
|
||||
titleize = T.unwords . fmap (mapWord T.toTitle)
|
||||
{-# INLINE titleize #-}
|
||||
:: [SomeWord] -- ^ List of Words, first of which will be capitalized
|
||||
-> Text -- ^ The titleized String
|
||||
titleize = T.unwords . fmap (unSomeWord T.toTitle)
|
||||
|
122
Text/Inflections/Types.hs
Normal file
122
Text/Inflections/Types.hs
Normal file
@ -0,0 +1,122 @@
|
||||
-- |
|
||||
-- Module : Text.Inflections.Types
|
||||
-- Copyright : © 2016 Justin Leitgeb
|
||||
-- License : MIT
|
||||
--
|
||||
-- Maintainer : Justin Leitgeb <justin@stackbuilders.com>
|
||||
-- Stability : experimental
|
||||
-- Portability : portable
|
||||
--
|
||||
-- Types used in the library. Usually you don't need to import this module
|
||||
-- and "Text.Inflections" should be enough.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE KindSignatures #-}
|
||||
|
||||
module Text.Inflections.Types
|
||||
( Word
|
||||
, WordType (..)
|
||||
, mkWord
|
||||
, mkAcronym
|
||||
, unWord
|
||||
, SomeWord (..)
|
||||
, unSomeWord
|
||||
, InflectionException (..) )
|
||||
where
|
||||
|
||||
import Control.Monad.Catch
|
||||
import Data.Char (isSpace)
|
||||
import Data.Data (Data)
|
||||
import Data.Text (Text)
|
||||
import Data.Typeable (Typeable)
|
||||
import GHC.Generics (Generic)
|
||||
import Text.Megaparsec
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#endif
|
||||
|
||||
-- | Create a word from given 'Text'. The input should not contain spaces or
|
||||
-- 'InflectionInvalidWord' will be thrown.
|
||||
|
||||
mkWord :: MonadThrow m => Text -> m (Word 'Normal)
|
||||
mkWord txt =
|
||||
if T.any isSpace txt
|
||||
then throwM (InflectionInvalidWord txt)
|
||||
else return (Word txt)
|
||||
|
||||
-- | Create an acronym from given 'Text'. The input should not contain
|
||||
-- spaces or 'InflectionInvalidAcronym' will be thrown. Acronym is different
|
||||
-- from normal word by that it may not be transformed by inflections.
|
||||
|
||||
mkAcronym :: MonadThrow m => Text -> m (Word 'Acronym)
|
||||
mkAcronym txt =
|
||||
if T.any isSpace txt
|
||||
then throwM (InflectionInvalidAcronym txt)
|
||||
else return (Word txt)
|
||||
|
||||
-- | A 'Text' value that should be kept whole through applied inflections.
|
||||
data Word (t :: WordType) = Word Text
|
||||
deriving (Eq, Ord, Show)
|
||||
|
||||
instance Show (Word 'Normal) where
|
||||
show (Word x) = "Word " ++ show x
|
||||
|
||||
instance Show (Word 'Acronym) where
|
||||
show (Word x) = "Acronym " ++ show x
|
||||
|
||||
-- | A type-level tag for words.
|
||||
|
||||
data WordType = Normal | Acronym
|
||||
|
||||
-- | Get a 'Text' value from 'Word'.
|
||||
unWord :: Word t -> Text
|
||||
unWord (Word s) = s
|
||||
|
||||
-- | An existential wrapper that allows to keep words and acronyms in single
|
||||
-- list for example. The only thing that receiver of 'SomeWord' can do is to
|
||||
-- apply 'unWord' on it, of course. This is faciliated by 'unSomeWord'.
|
||||
|
||||
data SomeWord where
|
||||
SomeWord :: Transformable (Word t) => Word t -> SomeWord
|
||||
-- NOTE The constraint is only needed because GHC is not smart enough
|
||||
-- (yet?) to figure out that t cannot be anything other than Normal and
|
||||
-- Acronym and thus all cases are already covered by the instances
|
||||
-- provided below.
|
||||
|
||||
instance Show SomeWord where
|
||||
show (SomeWord w) = show w
|
||||
|
||||
-- | Extract 'Text' from 'SomeWord' and apply given function only if the
|
||||
-- word inside wasn't an acronym.
|
||||
|
||||
unSomeWord :: (Text -> Text) -> SomeWord -> Text
|
||||
unSomeWord f (SomeWord w) = transform f w
|
||||
|
||||
-- | Non public stuff.
|
||||
|
||||
class Transformable a where
|
||||
transform :: (Text -> Text) -> a -> Text
|
||||
|
||||
instance Transformable (Word 'Normal) where
|
||||
transform f = f . unWord
|
||||
|
||||
instance Transformable (Word 'Acronym) where
|
||||
transform _ = unWord
|
||||
|
||||
-- | The exceptions that is thrown when parsing of input fails.
|
||||
|
||||
data InflectionException
|
||||
= InflectionParsingFailed (ParseError Char Dec)
|
||||
| InflectionInvalidWord Text
|
||||
| InflectionInvalidAcronym Text
|
||||
deriving (Eq, Show, Typeable, Data, Generic)
|
||||
|
||||
instance Exception InflectionException
|
@ -9,7 +9,6 @@
|
||||
--
|
||||
-- Conversion to phrases separated by underscores.
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Text.Inflections.Underscore
|
||||
@ -17,19 +16,14 @@ module Text.Inflections.Underscore
|
||||
where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Text.Inflections.Parse.Types
|
||||
import Text.Inflections.Types
|
||||
import qualified Data.Text as T
|
||||
|
||||
#if MIN_VERSION_base(4,8,0)
|
||||
import Prelude hiding (Word)
|
||||
#endif
|
||||
|
||||
-- |Turns a CamelCase string into an underscore_separated 'Text'.
|
||||
--
|
||||
-- >>> underscore [ Word "foo", Acronym "bar", Word "bazz" ]
|
||||
-- "foo_bar_bazz"
|
||||
underscore
|
||||
:: [Word] -- ^ Input Words to separate with underscores
|
||||
-> Text -- ^ The underscored String
|
||||
underscore = T.intercalate "_" . fmap (mapWord T.toLower)
|
||||
{-# INLINE underscore #-}
|
||||
:: [SomeWord] -- ^ Input Words to separate with underscores
|
||||
-> Text -- ^ The underscored String
|
||||
underscore = T.intercalate "_" . fmap (unSomeWord T.toLower)
|
||||
|
@ -29,7 +29,7 @@ flag dev
|
||||
|
||||
library
|
||||
exposed-modules: Text.Inflections
|
||||
, Text.Inflections.Parse.Types
|
||||
, Text.Inflections.Types
|
||||
|
||||
other-modules: Text.Inflections.Data
|
||||
, Text.Inflections.Camelize
|
||||
@ -37,7 +37,6 @@ library
|
||||
, Text.Inflections.Humanize
|
||||
, Text.Inflections.Ordinal
|
||||
, Text.Inflections.Parameterize
|
||||
, Text.Inflections.Parse.Acronym
|
||||
, Text.Inflections.Parse.CamelCase
|
||||
, Text.Inflections.Parse.SnakeCase
|
||||
, Text.Inflections.Titleize
|
||||
|
@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Text.Inflections.DasherizeSpec
|
||||
@ -7,9 +8,15 @@ where
|
||||
import Test.Hspec
|
||||
|
||||
import Text.Inflections (dasherize)
|
||||
import Text.Inflections.Parse.Types (Word (..))
|
||||
import Text.Inflections.Types
|
||||
|
||||
#if !MIN_VERSION_base(4,8,0)
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
spec :: Spec
|
||||
spec = describe "dasherize" $
|
||||
it "dasherizes a collection of words sentence" $
|
||||
dasherize [Word "foo", Word "bar"] `shouldBe` "foo-bar"
|
||||
it "dasherizes a collection of words sentence" $ do
|
||||
foo <- SomeWord <$> mkWord "foo"
|
||||
bar <- SomeWord <$> mkWord "bar"
|
||||
dasherize [foo,bar] `shouldBe` "foo-bar"
|
||||
|
@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Text.Inflections.HumanizeSpec (spec) where
|
||||
@ -5,13 +6,22 @@ module Text.Inflections.HumanizeSpec (spec) where
|
||||
import Test.Hspec
|
||||
|
||||
import Text.Inflections (humanize)
|
||||
import Text.Inflections.Parse.Types (Word(..))
|
||||
import Text.Inflections.Types
|
||||
|
||||
#if !MIN_VERSION_base(4,8,0)
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
spec :: Spec
|
||||
spec = describe "humazine" $ do
|
||||
it "converts snake case to a human-readable string" $
|
||||
humanize [Word "employee", Word "salary"] `shouldBe` "Employee salary"
|
||||
it "turns underscores into spaces" $
|
||||
humanize [Word "employee", Word "has_salary"] `shouldBe` "Employee has salary"
|
||||
it "capitalizes the first word of a sentence" $
|
||||
humanize [Word "underground"] `shouldBe` "Underground"
|
||||
it "converts snake case to a human-readable string" $ do
|
||||
employee <- SomeWord <$> mkWord "employee"
|
||||
salary <- SomeWord <$> mkWord "salary"
|
||||
humanize [employee,salary] `shouldBe` "Employee salary"
|
||||
it "turns underscores into spaces" $ do
|
||||
employee <- SomeWord <$> mkWord "employee"
|
||||
hasSalary <- SomeWord <$> mkWord "has_salary"
|
||||
humanize [employee, hasSalary] `shouldBe` "Employee has salary"
|
||||
it "capitalizes the first word of a sentence" $ do
|
||||
underground <- SomeWord <$> mkWord "underground"
|
||||
humanize [underground] `shouldBe` "Underground"
|
||||
|
@ -1,15 +1,22 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Text.Inflections.TitleizeSpec (spec) where
|
||||
|
||||
import Test.Hspec
|
||||
|
||||
import Text.Inflections (titleize)
|
||||
import Text.Inflections.Parse.Types (Word(..))
|
||||
import Text.Inflections.Types
|
||||
|
||||
#if !MIN_VERSION_base(4,8,0)
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
spec :: Spec
|
||||
spec = describe "titleize" $ do
|
||||
it "converts two words to title case" $
|
||||
titleize [Word "Employee", Word "Salary"] `shouldBe` "Employee Salary"
|
||||
it "converts one word to title case" $
|
||||
titleize [Word "underground"] `shouldBe` "Underground"
|
||||
it "converts two words to title case" $ do
|
||||
employee <- SomeWord <$> mkWord "Employee"
|
||||
salary <- SomeWord <$> mkWord "Salary"
|
||||
titleize [employee,salary] `shouldBe` "Employee Salary"
|
||||
it "converts one word to title case" $ do
|
||||
underground <- SomeWord <$> mkWord "underground"
|
||||
titleize [underground] `shouldBe` "Underground"
|
||||
|
@ -1,12 +1,19 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Text.Inflections.UnderscoreSpec (spec) where
|
||||
|
||||
import Test.Hspec
|
||||
import Text.Inflections (underscore)
|
||||
import Text.Inflections.Parse.Types (Word(..))
|
||||
import Text.Inflections.Types
|
||||
|
||||
#if !MIN_VERSION_base(4,8,0)
|
||||
import Control.Applicative
|
||||
#endif
|
||||
|
||||
spec :: Spec
|
||||
spec = describe "underscore" $
|
||||
it "converts a word list to snake case" $
|
||||
underscore [Word "test", Word "this"] `shouldBe` "test_this"
|
||||
it "converts a word list to snake case" $ do
|
||||
test <- SomeWord <$> mkWord "test"
|
||||
this <- SomeWord <$> mkWord "this"
|
||||
underscore [test, this] `shouldBe` "test_this"
|
||||
|
Loading…
Reference in New Issue
Block a user