packages feed

path-pieces 0.0.0 → 0.2.1

raw patch · 5 files changed

Files

+ ChangeLog.md view
@@ -0,0 +1,7 @@+## 0.2.0++* Make `PathMultiPiece` instance for lists based on `PathPiece` [Yesod issue #932](https://github.com/yesodweb/yesod/issues/932)++## 0.1.5++Added more integral instances, and check bounds on them [#5](https://github.com/yesodweb/path-pieces/pull/5).
+ README.md view
@@ -0,0 +1,6 @@+## path-pieces++Defines two typeclasses used for converting Haskell data types to and from route pieces.+Used in Yesod to automatically marshall data in the request path.++see http://www.yesodweb.com/ for more information.
Web/PathPieces.hs view
@@ -1,55 +1,167 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, OverloadedStrings #-} module Web.PathPieces-    ( SinglePiece (..)-    , MultiPiece (..)+    ( PathPiece (..)+    , PathMultiPiece (..)+    , readFromPathPiece+    , showToPathPiece+    -- * Deprecated+    , toSinglePiece+    , toMultiPiece+    , fromSinglePiece+    , fromMultiPiece     ) where -import Data.Int (Int64)+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64) import qualified Data.Text as S import qualified Data.Text.Lazy as L import qualified Data.Text.Read+import Data.Time (Day)+import Control.Exception (assert)+import Text.Read (readMaybe) -class SinglePiece s where-    fromSinglePiece :: S.Text -> Maybe s-    toSinglePiece :: s -> S.Text-instance SinglePiece String where-    fromSinglePiece s = if S.null s then Nothing else Just (S.unpack s)-    toSinglePiece = S.pack-instance SinglePiece S.Text where-    fromSinglePiece s = if S.null s then Nothing else Just s-    toSinglePiece = id-instance SinglePiece L.Text where-    fromSinglePiece s = if S.null s then Nothing else Just (L.fromChunks [s])-    toSinglePiece = S.concat . L.toChunks-instance SinglePiece Integer where-    fromSinglePiece s =-        case Data.Text.Read.decimal s of-            Right (i, _) -> Just i-            Left _ -> Nothing-    toSinglePiece = S.pack . show-instance SinglePiece Int where-    fromSinglePiece s =-        case Data.Text.Read.decimal s of-            Right (i, _) -> Just i-            Left _ -> Nothing-    toSinglePiece = S.pack . show-instance SinglePiece Int64 where-    fromSinglePiece s =-        case Data.Text.Read.decimal s of-            Right (i, _) -> Just i-            Left _ -> Nothing-    toSinglePiece = S.pack . show+class PathPiece s where+    fromPathPiece :: S.Text -> Maybe s+    toPathPiece :: s -> S.Text -class MultiPiece s where-    fromMultiPiece :: [S.Text] -> Maybe s-    toMultiPiece :: s -> [S.Text]-instance MultiPiece [String] where-    fromMultiPiece = Just . map S.unpack-    toMultiPiece = map S.pack-instance MultiPiece [S.Text] where-    fromMultiPiece = Just-    toMultiPiece = id-instance MultiPiece [L.Text] where-    fromMultiPiece = Just . map (L.fromChunks . return)-    toMultiPiece = map $ S.concat . L.toChunks+instance PathPiece () where+    fromPathPiece t = if t == "_" then Just () else Nothing+    toPathPiece () = "_"++instance PathPiece String where+    fromPathPiece = Just . S.unpack+    toPathPiece = S.pack++instance PathPiece S.Text where+    fromPathPiece = Just+    toPathPiece = id++instance PathPiece L.Text where+    fromPathPiece = Just . L.fromChunks . return+    toPathPiece = S.concat . L.toChunks++parseIntegral :: (Integral a, Bounded a, Ord a) => S.Text -> Maybe a+parseIntegral s = n+    where+    n = case Data.Text.Read.signed Data.Text.Read.decimal s of+        Right (i, "") | i <= top && i >= bot -> Just (fromInteger i)+        _ -> Nothing+    Just witness = n+    top = toInteger (maxBound `asTypeOf` witness)+    bot = toInteger (minBound `asTypeOf` witness)++instance PathPiece Integer where+    fromPathPiece s =+        case Data.Text.Read.signed Data.Text.Read.decimal s of+            Right (i, "") -> Just i+            _ -> Nothing+    toPathPiece = S.pack . show++instance PathPiece Int where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Int8 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Int16 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Int32 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Int64 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Word where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Word8 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Word16 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Word32 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Word64 where+    fromPathPiece = parseIntegral+    toPathPiece = S.pack . show++instance PathPiece Bool where+    fromPathPiece t =+        case filter (null . snd) $ reads $ S.unpack t of+            (a, s):_ -> assert (null s) (Just a)+            _        -> Nothing+    toPathPiece = S.pack . show++instance PathPiece Day where+    fromPathPiece t =+        case reads $ S.unpack t of+            [(a,"")] -> Just a+            _ -> Nothing+    toPathPiece = S.pack . show++instance (PathPiece a) => PathPiece (Maybe a) where+    fromPathPiece s = case S.stripPrefix "Just " s of+        Just r -> Just `fmap` fromPathPiece r+        _ -> case s of+            "Nothing" -> Just Nothing+            _ -> Nothing+    toPathPiece m = case m of+        Just s -> "Just " `S.append` toPathPiece s+        _ -> "Nothing"++class PathMultiPiece s where+    fromPathMultiPiece :: [S.Text] -> Maybe s+    toPathMultiPiece :: s -> [S.Text]++instance PathPiece a => PathMultiPiece [a] where+    fromPathMultiPiece = mapM fromPathPiece+    toPathMultiPiece = map toPathPiece++-- | A function for helping generate free 'PathPiece'+--   instances for enumeration data types +--   that have derived 'Read' and 'Show' instances.+--   Intended to be used like this:+--+--   > data MyData = Foo | Bar | Baz+--   >   deriving (Read,Show)+--   > instance PathPiece MyData where+--   >   fromPathPiece = readFromPathPiece+--   >   toPathPiece = showToPathPiece+--+--  Since 0.2.1. +readFromPathPiece :: Read s => S.Text -> Maybe s+readFromPathPiece = readMaybe . S.unpack++-- | See the documentation for 'readFromPathPiece'.+--+--  Since 0.2.1. +showToPathPiece :: Show s => s -> S.Text+showToPathPiece = S.pack . show++{-# DEPRECATED toSinglePiece "Use toPathPiece instead of toSinglePiece" #-}+toSinglePiece :: PathPiece p => p -> S.Text+toSinglePiece = toPathPiece++{-# DEPRECATED fromSinglePiece "Use fromPathPiece instead of fromSinglePiece" #-}+fromSinglePiece :: PathPiece p => S.Text -> Maybe p+fromSinglePiece = fromPathPiece++{-# DEPRECATED toMultiPiece "Use toPathMultiPiece instead of toMultiPiece" #-}+toMultiPiece :: PathMultiPiece ps => ps -> [S.Text]+toMultiPiece = toPathMultiPiece++{-# DEPRECATED fromMultiPiece "Use fromPathMultiPiece instead of fromMultiPiece" #-}+fromMultiPiece :: PathMultiPiece ps => [S.Text] -> Maybe ps+fromMultiPiece = fromPathMultiPiece
path-pieces.cabal view
@@ -1,22 +1,39 @@ name:            path-pieces-version:         0.0.0+version:         0.2.1 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com> maintainer:      Michael Snoyman <michael@snoyman.com> synopsis:        Components of paths.+description:    Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/path-pieces>. category:        Web, Yesod stability:       unstable-cabal-version:   >= 1.6+cabal-version:   >= 1.8 build-type:      Simple-homepage:        http://github.com/snoyberg/path-pieces+extra-source-files:+  test/main.hs+  ChangeLog.md+  README.md  library     build-depends:   base             >= 4       && < 5-                   , text             >= 0.5     && < 0.12+                   , text             >= 0.5+                   , time     exposed-modules: Web.PathPieces     ghc-options:     -Wall +test-suite test+    type:          exitcode-stdio-1.0+    main-is:       main.hs+    hs-source-dirs: test+    ghc-options:   -Wall+    build-depends:   HUnit+                   , hspec >= 1.3+                   , base >= 4 && < 5+                   , QuickCheck+                   , path-pieces+                   , text+ source-repository head   type:     git-  location: git://github.com/snoyberg/path-pieces.git+  location: https://github.com/yesodweb/path-pieces
+ test/main.hs view
@@ -0,0 +1,82 @@+{-# Language ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Main where++import Test.Hspec+import Test.Hspec.QuickCheck(prop)+import Test.QuickCheck++import Web.PathPieces+import qualified Data.Text as T+import Data.Maybe (fromJust)++-- import FileLocation (debug)++instance Arbitrary T.Text where+  arbitrary = fmap T.pack arbitrary+++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "PathPiece" $ do+    prop "toPathPiece <=> fromPathPiece String" $ \(p::String) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> null p+        Just pConverted -> p == pConverted++    prop "toPathPiece <=> fromPathPiece Text" $ \(p::T.Text) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> T.null p+        Just pConverted -> p == pConverted++    prop "toPathPiece <=> fromPathPiece Int" $ \(p::Int) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> False+        Just pConverted -> p == pConverted++    prop "toPathPiece <=> fromPathPiece Bool" $ \(p::Bool) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> False+        Just pConverted -> p == pConverted++    prop "toPathPiece <=> fromPathPiece Maybe String" $ \(p::Maybe String) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> False+        Just pConverted -> p == pConverted++  describe "PathMultiPiece" $ do+    prop "toPathMultiPiece <=> fromPathMultiPiece String" $ \(p::[String]) ->+      p == (fromJust . fromPathMultiPiece . toPathMultiPiece) p++    prop "toPathMultiPiece <=> fromPathMultiPiece Text" $ \(p::[T.Text]) ->+      p == (fromJust . fromPathMultiPiece . toPathMultiPiece) p+++  describe "SinglePiece" $ do+    prop "toPathPiece <=> fromPathPiece String" $ \(p::String) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> null p+        Just pConverted -> p == pConverted++    prop "toPathPiece <=> fromPathPiece Text" $ \(p::T.Text) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> T.null p+        Just pConverted -> p == pConverted++    prop "toPathPiece <=> fromPathPiece Int" $ \(p::Int) ->+      case (fromPathPiece . toPathPiece) p of+        Nothing -> p < 0+        Just pConverted -> p == pConverted++  describe "MultiPiece" $ do+    prop "toPathMultiPiece <=> fromPathMultiPiece String" $ \(p::[String]) ->+      p == (fromJust . fromPathMultiPiece . toPathMultiPiece) p++    prop "toPathMultiPiece <=> fromPathMultiPiece Text" $ \(p::[T.Text]) ->+      p == (fromJust . fromPathMultiPiece . toPathMultiPiece) p++  it "bad ints are rejected" $ fromPathPiece (T.pack "123hello")+    `shouldBe` (Nothing :: Maybe Int)