module Lackey (rubyForAPI) where
import qualified Data.Char as Char
import Data.Function ((&))
import qualified Data.Maybe as Maybe
import Data.Monoid ((<>))
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 & map 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) &
map Servant._argName &
map Servant.unPathSegment
getURLPieces :: Servant.Req Request -> [Either Text.Text Text.Text]
getURLPieces request =
let url = request & Servant._reqUrl
path =
url & Servant._path & map Servant.unSegment &
Maybe.mapMaybe
(\segment ->
case segment of
Servant.Static _ -> Nothing
Servant.Cap arg -> Just arg) &
map Servant._argName &
map Servant.unPathSegment
query =
url & Servant._queryStr & map Servant._queryArgName &
map Servant._argName &
map Servant.unPathSegment
in map Left path ++ map Right query
functionArguments :: Servant.Req Request -> Text.Text
functionArguments request =
Text.concat
[ "("
, [ [Just "excon"]
, request & getURLPieces &
map
(\piece ->
case piece of
Left capture -> underscore capture
Right param -> underscore param <> ": nil") &
map Just
, request & getHeaders & map underscore & map (<> ": nil") & map Just
, [ 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 & map Servant.unSegment &
map
(\x ->
case x of
Servant.Static y -> Servant.unPathSegment y
Servant.Cap y ->
let z =
y & Servant._argName &
Servant.unPathSegment &
underscore
in "#{" <> z <> "}") &
Text.intercalate "/"
query =
request & Servant._reqUrl & Servant._queryStr &
map Servant._queryArgName &
map Servant._argName &
map Servant.unPathSegment &
map
(\x ->
x <> "=#{" <> underscore x <> "}") &
Text.intercalate "&"
url =
"/" <> path <>
(if Text.null query
then ""
else "?" <> query)
in "\"" <> url <> "\""
requestHeaders :: Servant.Req Request -> Text.Text
requestHeaders request =
[ ["{"]
, request & getHeaders &
map
(\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