lackey-2.0.0.0: 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