packages feed

route-generator (empty) → 0.1

raw patch · 5 files changed

+219/−0 lines, 5 filesdep +attoparsecdep +basedep +textsetup-changed

Dependencies added: attoparsec, base, text, yesod-routes

Files

+ COPYING view
@@ -0,0 +1,13 @@+Copyright © 2012, Stephen Paul Weber <singpolyma.net>++Permission to use, copy, modify, and/or distribute this software for any+purpose with or without fee is hereby granted, provided that the above+copyright notice and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ README view
@@ -0,0 +1,30 @@+Most of the defacto Haskell web routing libraries are either linear+in complexity, or require lots of extra extensions, like Template+Haskell.++Luckily, yesod-routes has Yesod.Routes.Dispatch, which is a very clean,+efficient, and extension-free router.  Writing routes out in code can,+however, be quite verbose.  This utility is a code generator to produce+routes compatible with Yesod.Routes.Dispatch from a nice input format.++Example:++> GET /       => home+> GET /post/: => showPost+> PUT /*      => updateSomething++> ./routeGenerator routes.txt SomeModule++Will generate routes that map the correct HTTP verb (which you should+pass as a prepended "path segment" to your Dispatch) and path to+functions imported from the module specified in the second parameter.++A colon matches any path segment, and passes the matched segment+through to the specified function, passing each match segment in order.+The expected type of the segment is inferred from the type of the+function.  If the segment cannot be parsed as that type, the path does+not match.  Parsing is done with Web.PathPieces.fromPathPiece.++An asterisk at the end of the path causes rhHasMulti to be set to True,+meaning that any path segments after what has been specified will be+allowed.
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple++main = defaultMain
+ route-generator.cabal view
@@ -0,0 +1,62 @@+name:            route-generator+version:         0.1+cabal-version:   >= 1.8+license:         OtherLicense+license-file:    COPYING+category:        Utility+copyright:       © 2012 Stephen Paul Weber+author:          Stephen Paul Weber <singpolyma@singpolyma.net>+maintainer:      Stephen Paul Weber <singpolyma@singpolyma.net>+stability:       experimental+tested-with:     GHC == 7.0.3+synopsis:        Utility to generate routes for use with yesod-routes+homepage:        http://github.com/singpolyma/route-generator+bug-reports:     http://github.com/singpolyma/route-generator/issues+build-type:      Simple+description:+        Most of the defacto Haskell web routing libraries are either linear+        in complexity, or require lots of extra extensions, like Template+        Haskell.+        .+        Luckily, yesod-routes has Yesod.Routes.Dispatch, which is a very clean,+        efficient, and extension-free router.  Writing routes out in code can,+        however, be quite verbose.  This utility is a code generator to produce+        routes compatible with Yesod.Routes.Dispatch from a nice input format.+        .+        Example:+        .+        > GET /       => home+        > GET /post/: => showPost+        > PUT /*      => updateSomething+        .+        > ./routeGenerator routes.txt SomeModule+        .+        Will generate routes that map the correct HTTP verb (which you should+        pass as a prepended "path segment" to your Dispatch) and path to+        functions imported from the module specified in the second parameter.+        .+        A colon matches any path segment, and passes the matched segment+        through to the specified function, passing each match segment in order.+        The expected type of the segment is inferred from the type of the+        function.  If the segment cannot be parsed as that type, the path does+        not match.  Parsing is done with Web.PathPieces.fromPathPiece.+        .+        An asterisk at the end of the path causes rhHasMulti to be set to True,+        meaning that any path segments after what has been specified will be+        allowed.++extra-source-files:+        README++executable routeGenerator+        main-is: routeGenerator.hs++        build-depends:+                base == 4.*,+                text >= 0.7,+                attoparsec >= 0.10.0.0,+                yesod-routes++source-repository head+        type:     git+        location: git://github.com/route-generator/BitBrawl.git
+ routeGenerator.hs view
@@ -0,0 +1,111 @@+module Main where++import System.Environment (getArgs)+import System.IO (hPutStrLn, stderr)+import Data.List (intercalate)+import Data.Char (isUpper, isSpace)+import Data.Maybe (catMaybes, isJust)+import Yesod.Routes.Dispatch (Piece(Static, Dynamic))++import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Data.Attoparsec.Text+import Control.Applicative++data Route = Route {+		method :: Text,+		pieces :: [Piece],+		multi  :: Bool,+		target :: Text+	}+	deriving (Show)++instance Show Piece where+	show Dynamic = "Dynamic"+	show (Static s) = "Static (pack " ++ show (T.unpack s) ++ ")"++emitRoutes :: [Route] -> IO ()+emitRoutes rs = do+	-- We want to be polymorphic in the parameter to route, so just let+	-- the inference engine do it all+	-- putStrLn "routes :: [Route a]"+	putStrLn "routes = ["+	putStrLn $ intercalate ",\n" $ map showRoute rs+	putStrLn "\t]"+	where+	showRoute r =+		"\t\tRoute {\n" +++		"\t\t\trhPieces = " +++		show (Static (method r) : pieces r) +++		",\n" ++++		"\t\t\trhHasMulti = " +++		show (multi r) +++		",\n" ++++		"\t\t\trhDispatch = (\\(" +++		piecesPattern (pieces r) +++		") -> (return " +++		T.unpack (target r) +++		")" +++		piecesAp (pieces r) +++		")\n" ++++		"\t\t}"++	piecesAp pieces = concat $ fst $ foldr (\p (ps,c) -> case p of+			Dynamic -> ((" `ap` (fromPathPiece val" ++ show c ++ ")"):ps, c+1)+			Static _ -> (ps, c)+		) ([],0::Int) pieces++	piecesPattern pieces = intercalate ":" $ ("_":) $ fst $+		foldr (\p (ps,c) -> case p of+			Dynamic -> (("val" ++ show c):ps, c+1)+			Static _ -> ("_":ps, c)+		) (["_"],0::Int) pieces++parser :: Parser [Route]+parser = many1 $ do+	skipSpace+	m <- method+	skipSpace+	p <- pieces+	multi <- fmap isJust $ option Nothing (fmap Just (char '*'))+	skipSpace+	_ <- char '='+	_ <- char '>'+	skipSpace+	t <- target+	skipWhile (\x -> isSpace x && not (isEndOfLine x))+	endOfLine+	return $ Route m p multi t+	where+	target = takeWhile1 (not . isSpace)+	method = takeWhile1 isUpper+	pieces = fmap catMaybes $ many1 $ do+		_ <- char '/'+		option Nothing (fmap Just piece)+	piece = dynamic <|> static+	static = fmap Static (takeWhile1 (\x -> x /= '/' && x /= '*' && not (isSpace x)))+	dynamic = char ':' >> return Dynamic++main :: IO ()+main = do+	args <- getArgs+	case args of+		[input, mod] -> do+			Right routes <- fmap (parseOnly parser) $ T.readFile input++			putStrLn "module Routes where"+			putStrLn ""+			putStrLn $ "import " ++ mod+			putStrLn "import Control.Monad (ap)"+			putStrLn "import Data.Text (pack)"+			putStrLn "import Web.PathPieces (fromPathPiece)"+			putStrLn "import Yesod.Routes.Dispatch (Route(..), Piece(Static, Dynamic))"+			putStrLn ""+			emitRoutes routes+		_ ->+			hPutStrLn stderr "Usage: ./routeGenerator <input file> <implementation module>"