diff --git a/.travis.yml b/.travis.yml index e1402ac..c5d47fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,6 @@ cache: matrix: include: - - env: CABALVER=1.24 GHCVER=7.6.3 - addons: {apt: {packages: [cabal-install-1.24,ghc-7.6.3], sources: [hvr-ghc]}} - env: CABALVER=1.24 GHCVER=7.8.4 addons: {apt: {packages: [cabal-install-1.24,ghc-7.8.4,],sources: [hvr-ghc]}} - env: CABALVER=1.24 GHCVER=7.10.3 @@ -33,10 +31,6 @@ script: *) cabal configure --enable-tests -v2 -f dev ;; esac - cabal build - - case "$GHCVER" in - "7.6.3") true ;; - *) cabal test --show-details=always ;; - esac - cabal sdist - cabal haddock | grep "100%" | wc -l | grep "13" diff --git a/CHANGELOG.md b/CHANGELOG.md index 26b542d..e268061 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## Inflections 0.4.0.0 + +* Update megaparsec to version 6. + ## Inflections 0.3.0.0 * A more type-safe API forbidding creation of invalid words. diff --git a/Text/Inflections.hs b/Text/Inflections.hs index 4d1a349..04b6c60 100644 --- a/Text/Inflections.hs +++ b/Text/Inflections.hs @@ -117,6 +117,7 @@ where import Control.Monad.Catch (MonadThrow (..)) import Data.Text (Text) +import Data.Void (Void) import Text.Inflections.Camelize (camelize, camelizeCustom) import Text.Inflections.Dasherize (dasherize) import Text.Inflections.Data (Transliterations, defaultTransliterations) @@ -141,7 +142,7 @@ import Prelude hiding (Word) -- -- >>> toUnderscore "FooBarBazz" -- "foo_bar_bazz" -toUnderscore :: Text -> Either (ParseError Char Dec) Text +toUnderscore :: Text -> Either (ParseError Char Void) Text toUnderscore = fmap underscore . parseCamelCase [] -- | Transforms CamelCasedString to snake-cased-string-with-dashes. @@ -150,7 +151,7 @@ toUnderscore = fmap underscore . parseCamelCase [] -- -- >>> toDashed "FooBarBazz" -- "foo-bar-bazz" -toDashed :: Text -> Either (ParseError Char Dec) Text +toDashed :: Text -> Either (ParseError Char Void) Text toDashed = fmap dasherize . parseCamelCase [] -- | Transforms underscored_text to CamelCasedText. If first argument is @@ -166,7 +167,7 @@ toDashed = fmap dasherize . parseCamelCase [] toCamelCased :: Bool -- ^ Capitalize the first character -> Text -- ^ Input - -> Either (ParseError Char Dec) Text -- ^ Output + -> Either (ParseError Char Void) Text -- ^ Output toCamelCased c = fmap (camelizeCustom c) . parseSnakeCase [] -- | Transforms underscored_text to space-separated human-readable text. @@ -185,10 +186,10 @@ toCamelCased c = fmap (camelizeCustom c) . parseSnakeCase [] toHumanized :: Bool -- ^ Capitalize the first character -> Text -- ^ Input - -> Either (ParseError Char Dec) Text -- ^ Output + -> Either (ParseError Char Void) Text -- ^ Output toHumanized c = fmap (humanizeCustom c) . parseSnakeCase [] --- | Lift something of type @'Either' ('ParseError' 'Char' 'Dec') a@ to +-- | Lift something of type @'Either' ('ParseError' 'Char' 'Void') a@ to -- an instance of 'MonadThrow'. Useful when you want to shortcut on parsing -- failures and you're in an instance of 'MonadThrow'. -- @@ -196,6 +197,6 @@ toHumanized c = fmap (humanizeCustom c) . parseSnakeCase [] -- -- /since 0.3.0.0/ -betterThrow :: MonadThrow m => Either (ParseError Char Dec) a -> m a +betterThrow :: MonadThrow m => Either (ParseError Char Void) a -> m a betterThrow (Left err) = throwM (InflectionParsingFailed err) betterThrow (Right x) = return x diff --git a/Text/Inflections/Parse/CamelCase.hs b/Text/Inflections/Parse/CamelCase.hs index 340d93b..baeef76 100644 --- a/Text/Inflections/Parse/CamelCase.hs +++ b/Text/Inflections/Parse/CamelCase.hs @@ -19,9 +19,10 @@ where import Control.Applicative import Data.Text (Text) +import Data.Void (Void) import Text.Inflections.Types import Text.Megaparsec -import Text.Megaparsec.Text +import Text.Megaparsec.Char import qualified Data.Text as T #if MIN_VERSION_base(4,8,0) @@ -31,6 +32,8 @@ import Data.Foldable import Prelude hiding (elem) #endif +type Parser = Parsec Void Text + -- | Parse a CamelCase string. -- -- >>> bar <- mkAcronym "bar" @@ -44,7 +47,7 @@ import Prelude hiding (elem) parseCamelCase :: (Foldable f, Functor f) => f (Word 'Acronym) -- ^ Collection of acronyms -> Text -- ^ Input - -> Either (ParseError Char Dec) [SomeWord] -- ^ Result of parsing + -> Either (ParseError Char Void) [SomeWord] -- ^ Result of parsing parseCamelCase acronyms = parse (parser acronyms) "" parser :: (Foldable f, Functor f) @@ -59,7 +62,7 @@ acronym :: (Foldable f, Functor f) => f (Word 'Acronym) -> Parser (Word 'Acronym) acronym acronyms = do - x <- T.pack <$> choice (string . T.unpack . unWord <$> acronyms) + x <- choice (string . unWord <$> acronyms) case mkAcronym x of Nothing -> empty -- cannot happen if the system is sound Just acr -> return acr diff --git a/Text/Inflections/Parse/SnakeCase.hs b/Text/Inflections/Parse/SnakeCase.hs index 19d6a24..cbd6782 100644 --- a/Text/Inflections/Parse/SnakeCase.hs +++ b/Text/Inflections/Parse/SnakeCase.hs @@ -18,9 +18,10 @@ where import Control.Applicative import Data.Text (Text) +import Data.Void (Void) import Text.Inflections.Types import Text.Megaparsec -import Text.Megaparsec.Text +import Text.Megaparsec.Char import qualified Data.Text as T #if MIN_VERSION_base(4,8,0) @@ -30,6 +31,8 @@ import Data.Foldable import Prelude hiding (elem) #endif +type Parser = Parsec Void Text + -- | Parse a snake_case string. -- -- >>> bar <- mkAcronym "bar" @@ -43,7 +46,7 @@ import Prelude hiding (elem) parseSnakeCase :: (Foldable f, Functor f) => f (Word 'Acronym) -- ^ Collection of acronyms -> Text -- ^ Input - -> Either (ParseError Char Dec) [SomeWord] -- ^ Result of parsing + -> Either (ParseError Char Void) [SomeWord] -- ^ Result of parsing parseSnakeCase acronyms = parse (parser acronyms) "" parser :: (Foldable f, Functor f) diff --git a/Text/Inflections/Types.hs b/Text/Inflections/Types.hs index 06b42f5..b13edba 100644 --- a/Text/Inflections/Types.hs +++ b/Text/Inflections/Types.hs @@ -33,6 +33,7 @@ where import Control.Monad.Catch import Data.Char (isAlphaNum) import Data.Data (Data) +import Data.Void (Void) import Data.Text (Text) import Data.Typeable (Typeable) import GHC.Generics (Generic) @@ -135,7 +136,7 @@ instance Transformable (Word 'Acronym) where -- /since 0.3.0.0/ data InflectionException - = InflectionParsingFailed (ParseError Char Dec) + = InflectionParsingFailed (ParseError Char Void) | InflectionInvalidWord Text | InflectionInvalidAcronym Text deriving (Eq, Show, Typeable, Data, Generic) diff --git a/inflections.cabal b/inflections.cabal index c3a2222..661fd81 100644 --- a/inflections.cabal +++ b/inflections.cabal @@ -1,5 +1,5 @@ name: inflections -version: 0.3.0.0 +version: 0.4.0.0 synopsis: Inflections library for Haskell description: Inflections provides methods for singularization, pluralization, @@ -49,9 +49,12 @@ library ghc-options: -O2 -Wall build-depends: base >= 4.6 && < 5.0 , exceptions >= 0.6 && < 0.9 - , megaparsec >= 5.0 && < 6.0 + , megaparsec >= 6.0 && < 7.0 , text >= 0.2 && < 1.3 , unordered-containers >= 0.2.7 && < 0.3 + if !impl(ghc >= 7.10) + build-depends: void == 0.7.* + default-language: Haskell2010 test-suite test @@ -61,10 +64,17 @@ test-suite test build-depends: inflections , QuickCheck >= 2.7.6 && < 3.0 , base >= 4.6 && < 5.0 + , containers >= 0.5 && < 0.7 , hspec >= 2.0 && < 3.0 - , hspec-megaparsec >= 0.3 && < 0.4 - , megaparsec >= 5.1 && < 6.0 + , hspec-megaparsec >= 1.0 && < 2.0 + , megaparsec , text >= 0.2 && < 1.3 + if !impl(ghc >= 7.10) + build-depends: void == 0.7.* + + if !impl(ghc >= 8.0) + build-depends: semigroups == 0.18.* + if flag(dev) ghc-options: -Wall -Werror else diff --git a/stack.yaml b/stack.yaml index 9085c49..1ec4e2b 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,6 +1,7 @@ +--- resolver: lts-7.13 -packages: -- '.' + extra-deps: -- hspec-megaparsec-0.3.0 -- megaparsec-5.1.2 + - hspec-megaparsec-1.0.0 + - megaparsec-6.0.0 + - parser-combinators-0.1.0 diff --git a/test/Text/InflectionsSpec.hs b/test/Text/InflectionsSpec.hs index 84797ec..4437b4f 100644 --- a/test/Text/InflectionsSpec.hs +++ b/test/Text/InflectionsSpec.hs @@ -1,10 +1,44 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Text.InflectionsSpec (spec) where +import Data.Void import Test.Hspec import Test.QuickCheck import Text.Inflections +import Text.Megaparsec + +import qualified Data.List.NonEmpty as NE +import qualified Data.Set as S + +#if !MIN_VERSION_base(4,8,0) +import Control.Applicative +#endif + +arbitraryParseError :: Gen (ParseError Char Void) +arbitraryParseError = oneof [trivialError, fancyError] + where + trivialError = TrivialError <$> nonEmptyArbitrary <*> maybeErrorItem <*> setErrorItem + fancyError = FancyError <$> nonEmptyArbitrary <*> setErrorFancy + nonEmptyArbitrary = NE.fromList <$> listOf1 arbitrarySourcePos + setErrorFancy = S.fromList <$> listOf arbitraryErrorFancy + maybeErrorItem = oneof [ Just <$> arbitraryErrorItem, return Nothing] + setErrorItem = S.fromList <$> listOf arbitraryErrorItem + +arbitrarySourcePos :: Gen SourcePos +arbitrarySourcePos = SourcePos <$> arbitrary <*> posArbitrary <*> posArbitrary + where + posArbitrary = mkPos <$> ((+1) . abs <$> arbitrary) + +arbitraryErrorFancy :: Gen (ErrorFancy e) +arbitraryErrorFancy = oneof [ ErrorFail <$> arbitrary ] + +arbitraryErrorItem :: (Arbitrary e) => Gen (ErrorItem e) +arbitraryErrorItem = oneof [ tokens_, labels_, return EndOfInput ] + where + tokens_ = Tokens <$> (NE.fromList <$> listOf1 arbitrary) + labels_ = Label <$> (NE.fromList <$> listOf1 arbitrary) spec :: Spec spec = do @@ -38,9 +72,10 @@ spec = do describe "betterThrow" $ do context "when given a parse error" $ it "throws the correct exception" $ - property $ \err -> + property $ forAll arbitraryParseError $ \err -> betterThrow (Left err) `shouldThrow` (== InflectionParsingFailed err) + context "when given a value in Right" $ it "returns the value" $ property $ \x ->