lackey-2.0.0.4: source/library/Lackey.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module Lackey
( rubyForAPI,
)
where
import qualified Data.Char as Char
import Data.Function ((&))
import qualified Data.Maybe as Maybe
import qualified Data.Proxy as Proxy
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Servant.Foreign as Servant
type Language = Servant.NoTypes
languageProxy :: Proxy.Proxy Language
languageProxy = Proxy.Proxy
type Request = Servant.NoContent
requestProxy :: Proxy.Proxy Request
requestProxy = Proxy.Proxy
renderRequests :: [Servant.Req Request] -> Text.Text
renderRequests requests = requests & fmap renderRequest & Text.intercalate ";"
functionName :: Servant.Req Request -> Text.Text
functionName request = request & Servant._reqFuncName & Servant.snakeCase
hasBody :: Servant.Req Request -> Bool
hasBody request = case Servant._reqBody request of
Nothing -> False
Just _ -> True
bodyArgument :: Text.Text
bodyArgument = "body"
underscore :: Text.Text -> Text.Text
underscore text =
text & Text.toLower & Text.map (\c -> if Char.isAlphaNum c then c else '_')
getHeaders :: Servant.Req Request -> [Text.Text]
getHeaders request =
request
& Servant._reqHeaders
& Maybe.mapMaybe
( \h -> case h of
Servant.HeaderArg x -> Just x
Servant.ReplaceHeaderArg _ _ -> Nothing
)
& fmap (Servant.unPathSegment . Servant._argName)
getURLPieces :: Servant.Req Request -> [Either Text.Text Text.Text]
getURLPieces request =
let url = request & Servant._reqUrl
path =
url
& Servant._path
& Maybe.mapMaybe
( ( \segment -> case segment of
Servant.Static _ -> Nothing
Servant.Cap arg -> Just arg
)
. Servant.unSegment
)
& fmap (Servant.unPathSegment . Servant._argName)
query =
url
& Servant._queryStr
& fmap
(Servant.unPathSegment . Servant._argName . Servant._queryArgName)
in fmap Left path <> fmap Right query
functionArguments :: Servant.Req Request -> Text.Text
functionArguments request =
Text.concat
[ "(",
[ [Just "excon"],
request
& getURLPieces
& fmap
( \piece -> Just $ case piece of
Left capture -> underscore capture
Right param -> underscore param <> ": nil"
),
request & getHeaders & fmap (Just . (<> ": nil") . underscore),
[if hasBody request then Just bodyArgument else Nothing]
]
& concat
& Maybe.catMaybes
& Text.intercalate ",",
")"
]
requestMethod :: Servant.Req Request -> Text.Text
requestMethod request =
request & Servant._reqMethod & Text.decodeUtf8 & Text.toLower & Text.cons ':'
requestPath :: Servant.Req Request -> Text.Text
requestPath request =
let path =
request
& Servant._reqUrl
& Servant._path
& fmap
( ( \x -> case x of
Servant.Static y -> Servant.unPathSegment y
Servant.Cap y ->
let z =
y & Servant._argName & Servant.unPathSegment & underscore
in "#{" <> z <> "}"
)
. Servant.unSegment
)
& Text.intercalate "/"
query =
request
& Servant._reqUrl
& Servant._queryStr
& fmap
( (\x -> x <> "=#{" <> underscore x <> "}")
. Servant.unPathSegment
. Servant._argName
. Servant._queryArgName
)
& Text.intercalate "&"
url = "/" <> path <> (if Text.null query then "" else "?" <> query)
in "\"" <> url <> "\""
requestHeaders :: Servant.Req Request -> Text.Text
requestHeaders request =
[ ["{"],
request & getHeaders & fmap (\x -> "\"" <> x <> "\"=>" <> underscore x),
["}"]
]
& concat
& Text.concat
requestBody :: Servant.Req Request -> Text.Text
requestBody request = if hasBody request then bodyArgument else "nil"
functionBody :: Servant.Req Request -> Text.Text
functionBody request =
Text.concat
[ "excon.request(",
":method=>",
requestMethod request,
",",
":path=>",
requestPath request,
",",
":headers=>",
requestHeaders request,
",",
":body=>",
requestBody request,
")"
]
renderRequest :: Servant.Req Request -> Text.Text
renderRequest request =
Text.concat
[ "def ",
functionName request,
functionArguments request,
functionBody request,
"end"
]
requestsForAPI ::
( Servant.HasForeign Language Request api,
Servant.GenerateList Request (Servant.Foreign Request api)
) =>
Proxy.Proxy api ->
[Servant.Req Request]
requestsForAPI api = api & Servant.listFromAPI languageProxy requestProxy
rubyForAPI ::
( Servant.HasForeign Language Request api,
Servant.GenerateList Request (Servant.Foreign Request api)
) =>
Proxy.Proxy api ->
Text.Text
rubyForAPI api = api & requestsForAPI & renderRequests