web-inv-route 0.1.2.3 → 0.1.3.0
raw patch · 18 files changed
+57/−22 lines, 18 files
Files
- Web/Route/Invertible/Map/Bool.hs +0/−2
- Web/Route/Invertible/Map/Const.hs +0/−2
- Web/Route/Invertible/Map/Custom.hs +0/−1
- Web/Route/Invertible/Map/Default.hs +0/−1
- Web/Route/Invertible/Map/Monoid.hs +0/−1
- Web/Route/Invertible/Map/MonoidHash.hs +0/−1
- Web/Route/Invertible/Map/Placeholder.hs +0/−1
- Web/Route/Invertible/Map/Query.hs +0/−1
- Web/Route/Invertible/Map/Route.hs +0/−1
- Web/Route/Invertible/Map/Sequence.hs +0/−1
- Web/Route/Invertible/Monoid/Exactly.hs +0/−1
- Web/Route/Invertible/Monoid/Prioritized.hs +0/−2
- Web/Route/Invertible/Path.hs +0/−1
- Web/Route/Invertible/Render.hs +43/−0
- Web/Route/Invertible/Result.hs +0/−1
- Web/Route/Invertible/Sequence.hs +0/−1
- test/Main.hs +12/−3
- web-inv-route.cabal +2/−1
Web/Route/Invertible/Map/Bool.hs view
@@ -7,8 +7,6 @@ , lookupBool ) where -import Data.Semigroup (Semigroup((<>)))- -- |A trivial, flat representation of a 'Bool'-keyed map. -- Value existance (but not the values themselves) is strict. data BoolMap v = BoolMap
Web/Route/Invertible/Map/Const.hs view
@@ -12,8 +12,6 @@ , flattenConstDefaultMap ) where -import Data.Semigroup (Semigroup((<>)))- import Web.Route.Invertible.Map.Default -- |A monoid map where every key (additionally) maps to the same constant value, parameterized over the type of the map.
Web/Route/Invertible/Map/Custom.hs view
@@ -6,7 +6,6 @@ ) where import Data.Maybe (mapMaybe)-import Data.Semigroup (Semigroup) import Text.Show.Functions () newtype CustomMap q a b = CustomMap [(q -> Maybe a, b)]
Web/Route/Invertible/Map/Default.hs view
@@ -10,7 +10,6 @@ ) where import Control.Applicative ((<|>))-import Data.Semigroup (Semigroup((<>))) -- |A map that also provides a default value, for when a key is not found in the underlying map, parameterized over the type of the map. data DefaultMap m v = DefaultMap
Web/Route/Invertible/Map/Monoid.hs view
@@ -12,7 +12,6 @@ import Data.Foldable (fold) import qualified Data.Map.Strict as M-import Data.Semigroup (Semigroup((<>))) -- |A specialized version of 'M.Map'. newtype MonoidMap k a = MonoidMap { monoidMap :: M.Map k a }
Web/Route/Invertible/Map/MonoidHash.hs view
@@ -13,7 +13,6 @@ import Data.Foldable (fold) import Data.Hashable (Hashable) import qualified Data.HashMap.Strict as M-import Data.Semigroup (Semigroup((<>))) -- |A specialized version of 'M.HashMap'. newtype MonoidHashMap k a = MonoidHashMap { monoidHashMap :: M.HashMap k a }
Web/Route/Invertible/Map/Placeholder.hs view
@@ -18,7 +18,6 @@ import Data.Dynamic (Dynamic) import qualified Data.HashMap.Strict as HM import qualified Data.Map.Strict as M-import Data.Semigroup (Semigroup((<>))) import Web.Route.Invertible.String import Web.Route.Invertible.Placeholder
Web/Route/Invertible/Map/Query.hs view
@@ -8,7 +8,6 @@ ) where import qualified Data.HashMap.Lazy as HM-import Data.Semigroup (Semigroup((<>))) import Web.Route.Invertible.Placeholder import Web.Route.Invertible.Map.Placeholder
Web/Route/Invertible/Map/Route.hs view
@@ -20,7 +20,6 @@ import Data.Dynamic (Dynamic, toDyn) import qualified Data.HashMap.Strict as HM import qualified Data.Map.Strict as Map-import Data.Semigroup (Semigroup((<>))) import Web.Route.Invertible.String import Web.Route.Invertible.Sequence
Web/Route/Invertible/Map/Sequence.hs view
@@ -33,7 +33,6 @@ import Control.Invertible.Monoidal.Free import Control.Monad (MonadPlus(..)) import Control.Monad.Trans.State (evalState)-import Data.Semigroup (Semigroup((<>))) import Web.Route.Invertible.String import Web.Route.Invertible.Placeholder
Web/Route/Invertible/Monoid/Exactly.hs view
@@ -11,7 +11,6 @@ import Control.Applicative (Alternative(..)) import Control.Monad (MonadPlus(..))-import Data.Semigroup (Semigroup((<>))) -- |A 'Maybe'-like monoid that only allows one value, overflowing into 'Conflict' when more than one 'Exactly' are combined (with '<|>' or 'Data.Monoid.<>', which thus function identically). data Exactly a
Web/Route/Invertible/Monoid/Prioritized.hs view
@@ -4,8 +4,6 @@ ( Prioritized(..) ) where -import Data.Semigroup (Semigroup((<>)))- -- |A trival monoid allowing each item to be given a priority when combining. data Prioritized a = Prioritized { priority :: !Int -- ^ The priority this value, where larger numeric values have higher priority and take precedence over lower priorities.
Web/Route/Invertible/Path.hs view
@@ -19,7 +19,6 @@ import Control.Invertible.Monoidal import qualified Data.ByteString.Builder as B-import Data.Monoid ((<>)) import qualified Data.Invertible as I import Data.String (IsString(..)) import qualified Data.Text as T
+ Web/Route/Invertible/Render.hs view
@@ -0,0 +1,43 @@+-- |Render requests in various ways+module Web.Route.Invertible.Render+ ( renderRequestBuilder+ , renderUrlRequestBuilder+ , renderHamletUrl+ ) where++import Control.Arrow (second)+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Builder as B+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import Network.HTTP.Types.URI (Query, encodePathSegments, renderQueryBuilder, simpleQueryToQuery, queryTextToQuery)++import Web.Route.Invertible.Request+import Web.Route.Invertible.Query+import Web.Route.Invertible.Route++-- |This renders a request along with additional query parameters as @[//host][/path][?query]@.+-- Each component is included only if it's specified by the route.+renderRequestBuilder :: Request -> Query -> B.Builder+renderRequestBuilder r q =+ bh (requestHost r)+ <> bp (requestPath r)+ <> renderQueryBuilder True ((simpleQueryToQuery $ paramsQuerySimple $ requestQuery r) ++ q)+ where+ bh [] = mempty+ bh [x] = sl <> sl <> B.byteString x+ bh (x:l) = bh l <> B.char8 '.' <> B.byteString x+ bp [] = sl+ bp p = encodePathSegments p+ sl = B.char8 '/'++-- |This renders a request along with additional query parameters as @scheme:[//host][/path][?query]@.+-- It's roughly equivalent to rendering the 'Web.Route.Invertible.URI.requestURI'.+renderUrlRequestBuilder :: Request -> Query -> B.Builder+renderUrlRequestBuilder r q =+ B.string8 (if requestSecure r then "https:" else "http:") <> renderRequestBuilder r q++-- |A 'Text.Hamlet.Render' function, suitable for passing to a @'Text.Hamlet.HtmlUrl' (RouteAction a b, a)@ template.+renderHamletUrl :: (RouteAction a b, a) -> [(T.Text, T.Text)] -> T.Text+renderHamletUrl (r, a) q = TE.decodeUtf8 $ BSL.toStrict $ B.toLazyByteString+ $ renderRequestBuilder (requestActionRoute r a) $ queryTextToQuery $ map (second Just) q
Web/Route/Invertible/Result.hs view
@@ -5,7 +5,6 @@ ) where import qualified Data.ByteString.Char8 as BSC-import Data.Semigroup (Semigroup((<>))) import Data.Typeable (Typeable) import Network.HTTP.Types.Header (ResponseHeaders, hAllow) import Network.HTTP.Types.Status (Status, notFound404, methodNotAllowed405, internalServerError500)
Web/Route/Invertible/Sequence.hs view
@@ -27,7 +27,6 @@ import Control.Invertible.Monoidal import Control.Invertible.Monoidal.Free import Control.Monad (MonadPlus, mzero, guard)-import Control.Monad.Fail (MonadFail) import qualified Data.Invertible as I import Data.String (IsString(..))
test/Main.hs view
@@ -1,13 +1,16 @@ {-# LANGUAGE OverloadedStrings #-} module Main (main) where -import Data.Maybe (fromJust)-import Network.URI (parseURI)-import System.Exit (exitSuccess, exitFailure)+import qualified Data.ByteString.Lazy as BS+import qualified Data.ByteString.Builder as BSB+import Data.Maybe (fromJust)+import Network.URI (parseURI)+import System.Exit (exitSuccess, exitFailure) import qualified Test.HUnit as U import Web.Route.Invertible import Web.Route.Invertible.URI+import Web.Route.Invertible.Render getThing :: RouteAction Int String getThing = routeMethod GET *< routePath ("thing" *< parameter) `RouteAction` \i ->@@ -62,17 +65,23 @@ req :: RouteAction r a -> r -> (Method, String) req a = fmap show . routeActionURI a +ren :: RouteAction r a -> r -> BS.ByteString+ren r a = BSB.toLazyByteString $ renderUrlRequestBuilder (requestActionRoute r a) []+ tests :: U.Test tests = U.test [ rte GET "http:/thing/0" U.~?= RouteResult "get thing0" , rte GET "http:/thing/-3?type=x" U.~?= RouteResult "get thing-3:x" , req getThingQ (98, '=') U.~?= (GET, "http:/thing/98?type=%3D")+ , ren getThingQ (98, '=') U.~?= "http:/thing/98?type=%3D" , rte PUT "http:/thing/09" U.~?= RouteResult "put thing9" , req postThing "foo" U.~?= (POST, "http:/thing/foo")+ , ren postThing "foo" U.~?= "http:/thing/foo" , rte OPTIONS "http:/thing/xxx" U.~?= AllowedMethods [POST] , rte PUT "http:/thing/0/sub/12/34" U.~?= RouteResult "thing0 sub 12 34" , rte GET "http:/things/0/12/34" U.~?= RouteResult "ignore thing0" , req ignoredThing (-3) U.~?= (GET, "http:/things/-3/ign")+ , ren ignoredThing (-3) U.~?= "http:/things/-3/ign" , rte POST "http://foo.com/foo" U.~?= AllowedMethods [GET] , rte POST "http:/foo" U.~?= RouteNotFound ]
web-inv-route.cabal view
@@ -1,5 +1,5 @@ name: web-inv-route-version: 0.1.2.3+version: 0.1.3.0 synopsis: Composable, reversible, efficient web routing using invertible invariants and bijections description: Utilities to route HTTP requests, mainly focused on path components. Routes are specified using bijections and invariant functors, allowing run-time composition (routes can be distributed across modules), reverse and forward routing derived from the same specification, and O(log n) lookups.@@ -46,6 +46,7 @@ Web.Route.Invertible Web.Route.Invertible.Common Web.Route.Invertible.Internal+ Web.Route.Invertible.Render other-modules: Web.Route.Invertible.String Web.Route.Invertible.Parameter