packages feed

lackey 0.4.5 → 0.4.6

raw patch · 8 files changed

+300/−301 lines, 8 filesdep +hspecdep −tastydep −tasty-hspecdep ~basedep ~servantdep ~textsetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: hspec

Dependencies removed: tasty, tasty-hspec

Dependency ranges changed: base, servant, text

API changes (from Hackage documentation)

Files

LICENSE.md view
@@ -1,6 +1,6 @@ [The MIT License (MIT)][] -Copyright (c) 2016 Taylor Fausak+Copyright (c) 2017 Taylor Fausak  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in
Setup.hs view
@@ -1,4 +1,4 @@-import qualified Distribution.Simple+import qualified Distribution.Simple as Cabal  main :: IO ()-main = Distribution.Simple.defaultMain+main = Cabal.defaultMain
lackey.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           lackey-version:        0.4.5+version:        0.4.6 synopsis:       Generate Ruby clients from Servant APIs. description:    Lackey generates Ruby clients from Servant APIs. category:       Web@@ -30,25 +30,25 @@       library   ghc-options: -Wall   build-depends:-      base >=4.8 && <4.11-    , servant >=0.8 && <0.12-    , servant-foreign >=0.8 && <0.11-    , text >=1.2 && <1.3+      base >= 4.8 && < 4.11+    , servant >= 0.8 && < 0.13+    , servant-foreign >= 0.8 && < 0.11+    , text >= 1.2 && < 1.3   exposed-modules:       Lackey   default-language: Haskell2010 -test-suite lackey-test-suite+test-suite test   type: exitcode-stdio-1.0   main-is: Main.hs   hs-source-dirs:-      test-suite+      tests   ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N   build-depends:-      base+      base >= 4.8 && < 4.11+    , servant >= 0.8 && < 0.13+    , servant-foreign >= 0.8 && < 0.11+    , text >= 1.2 && < 1.3     , lackey-    , servant-    , tasty >=0.11 && <0.13-    , tasty-hspec >=1.1 && <1.2-    , text+    , hspec >= 2.4.4 && < 2.5   default-language: Haskell2010
library/Lackey.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -module Lackey (rubyForAPI) where+module Lackey+  ( rubyForAPI+  ) where  import qualified Data.Char as Char import Data.Function ((&))@@ -30,157 +32,161 @@  hasBody :: Servant.Req Request -> Bool hasBody request =-    case Servant._reqBody request of-        Nothing -> False-        Just _ -> True+  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 '_')+  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+  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+  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 ","-        , ")"]+  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 ':'+  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 <> "\""+  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+  [ ["{"]+  , 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"+  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-        , ")"]+  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"]+  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 ::+     ( 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 ::+     ( Servant.HasForeign Language Request api+     , Servant.GenerateList Request (Servant.Foreign Request api)+     )+  => Proxy.Proxy api+  -> Text.Text rubyForAPI api = api & requestsForAPI & renderRequests
package.yaml view
@@ -1,37 +1,38 @@+name: lackey+version: 0.4.6+ category: Web description: Lackey generates Ruby clients from Servant APIs. extra-source-files:-- CHANGELOG.md-- LICENSE.md-- package.yaml-- README.md-- stack.yaml-ghc-options: -Wall+  - CHANGELOG.md+  - LICENSE.md+  - package.yaml+  - README.md+  - stack.yaml github: tfausak/lackey-library:-  dependencies:-  - base >=4.8 && <4.11-  - servant >=0.8 && <0.12-  - servant-foreign >=0.8 && <0.11-  - text >=1.2 && <1.3-  source-dirs: library license: MIT maintainer: Taylor Fausak-name: lackey synopsis: Generate Ruby clients from Servant APIs.++dependencies:+  - base >= 4.8 && < 4.11+  - servant >= 0.8 && < 0.13+  - servant-foreign >= 0.8 && < 0.11+  - text >= 1.2 && < 1.3+ghc-options:+  - -Wall++library:+  source-dirs: library+ tests:-  lackey-test-suite:+  test:     dependencies:-    - base-    - lackey-    - servant-    - tasty >=0.11 && <0.13-    - tasty-hspec >=1.1 && <1.2-    - text+      - lackey+      - hspec >= 2.4.4 && < 2.5     ghc-options:-    - -rtsopts-    - -threaded-    - -with-rtsopts=-N-    source-dirs: test-suite+      - -rtsopts+      - -threaded+      - -with-rtsopts=-N+    source-dirs: tests     main: Main.hs-version: '0.4.5'
stack.yaml view
@@ -1,1 +1,1 @@-resolver: lts-8.0+resolver: lts-9.0
− test-suite/Main.hs
@@ -1,141 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeOperators #-}--import Data.Monoid ((<>))-import qualified Data.Proxy as Proxy-import qualified Data.Text as Text-import qualified Lackey-import qualified Servant.API as Servant-import qualified Test.Tasty as Tasty-import Test.Tasty.Hspec--main :: IO ()-main = do-    test <- testSpec "Lackey" spec-    Tasty.defaultMain test--spec :: Spec-spec = parallel $ do-    describe "rubyForAPI" $ do-        it "supports delete requests" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Delete '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "delete" "" "delete" "" "" False--        it "supports get requests" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" "" "get" "" "" False--        it "supports patch requests" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Patch '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "patch" "" "patch" "" "" False--        it "supports post requests" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Post '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "post" "" "post" "" "" False--        it "supports put requests" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Put '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "put" "" "put" "" "" False--        it "supports alternatives" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Get '[Servant.JSON] () Servant.:<|> Servant.Delete '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe` Text.concat-                [ ruby "get" "" "get" "" "" False-                , ";"-                , ruby "delete" "" "delete" "" "" False-                ]--        it "supports captures" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Capture "id" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get_by_id" ",id" "get" "#{id}" "" False--        it "supports query flags" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.QueryFlag "flag" Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",flag: nil" "get" "?flag=#{flag}" "" False--        it "supports query params" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.QueryParam "param" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",param: nil" "get" "?param=#{param}" "" False--        it "supports multiple query params" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.QueryParams "params" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",params: nil" "get" "?params=#{params}" "" False--        it "supports request bodies" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.ReqBody '[Servant.JSON] () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",body" "get" "" "" True--        it "supports request headers" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Header "cookie" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",cookie: nil" "get" "" "\"cookie\"=>cookie" False--        it "supports response headers" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Get '[Servant.JSON] (Servant.Headers '[] ()))-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" "" "get" "" "" False--        it "puts the body param after captures" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Capture "segment" () Servant.:> Servant.ReqBody '[Servant.JSON] () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get_by_segment" ",segment,body" "get" "#{segment}" "" True--        it "puts the body param after query params" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.QueryFlag "flag" Servant.:> Servant.ReqBody '[Servant.JSON] () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",flag: nil,body" "get" "?flag=#{flag}" "" True--        it "sanitizes path segments" $ do-            let api = Proxy.Proxy :: Proxy.Proxy ("A!" Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get_A!" "" "get" "A!" "" False--        it "sanitizes captures" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Capture "A!" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get_by_A!" ",a_" "get" "#{a_}" "" False--        it "sanitizes query flags" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.QueryFlag "A!" Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",a_: nil" "get" "?A!=#{a_}" "" False--        it "sanitizes query params" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.QueryParam "A!" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",a_: nil" "get" "?A!=#{a_}" "" False--        it "sanitizes multiple query params" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.QueryParams "A!" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",a_: nil" "get" "?A!=#{a_}" "" False--        it "sanitizes headers" $ do-            let api = Proxy.Proxy :: Proxy.Proxy (Servant.Header "A!" () Servant.:> Servant.Get '[Servant.JSON] ())-            Lackey.rubyForAPI api `shouldBe`-                ruby "get" ",a_: nil" "get" "" "\"A!\"=>a_" False---- Since every generated function has the same structure, it can be abstracted--- away behind this function.-ruby :: Text.Text -> Text.Text -> Text.Text -> Text.Text -> Text.Text -> Bool -> Text.Text-ruby name params method path headers body = "\-    \def " <> name <> "(excon" <> params <> ")\-      \excon.request(\-        \:method=>:" <> method <> ",\-        \:path=>\"/" <> path <> "\",\-        \:headers=>{" <> headers <> "},\-        \:body=>" <> (if body then "body" else "nil") <> "\-      \)\-    \end\-\"
+ tests/Main.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeOperators #-}++import Data.Proxy+import Data.Text+import Lackey+import Servant.API+import Test.Hspec++main :: IO ()+main = hspec . parallel . describe "Lackey" . describe "rubyForAPI" $ do++  it "supports delete requests" $ do+    let api = Proxy :: Proxy (Delete '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "delete" "" "delete" "" "" False++  it "supports get requests" $ do+    let api = Proxy :: Proxy (Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" "" "get" "" "" False++  it "supports patch requests" $ do+    let api = Proxy :: Proxy (Patch '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "patch" "" "patch" "" "" False++  it "supports post requests" $ do+    let api = Proxy :: Proxy (Post '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "post" "" "post" "" "" False++  it "supports put requests" $ do+    let api = Proxy :: Proxy (Put '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "put" "" "put" "" "" False++  it "supports alternatives" $ do+    let api = Proxy :: Proxy (Get '[JSON] () :<|> Delete '[JSON] ())+    rubyForAPI api `shouldBe` mconcat+      [ ruby "get" "" "get" "" "" False+      , singleton ';'+      , ruby "delete" "" "delete" "" "" False+      ]++  it "supports captures" $ do+    let api = Proxy :: Proxy (Capture "id" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get_by_id" ",id" "get" "#{id}" "" False++  it "supports query flags" $ do+    let api = Proxy :: Proxy (QueryFlag "flag" :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",flag: nil" "get" "?flag=#{flag}" "" False++  it "supports query params" $ do+    let api = Proxy :: Proxy (QueryParam "param" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",param: nil" "get" "?param=#{param}" "" False++  it "supports multiple query params" $ do+    let api = Proxy :: Proxy (QueryParams "params" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",params: nil" "get" "?params=#{params}" "" False++  it "supports request bodies" $ do+    let api = Proxy :: Proxy (ReqBody '[JSON] () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",body" "get" "" "" True++  it "supports request headers" $ do+    let api = Proxy :: Proxy (Header "cookie" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",cookie: nil" "get" "" "\"cookie\"=>cookie" False++  it "supports response headers" $ do+    let api = Proxy :: Proxy (Get '[JSON] (Headers '[] ()))+    rubyForAPI api `shouldBe`+      ruby "get" "" "get" "" "" False++  it "puts the body param after captures" $ do+    let api = Proxy :: Proxy (Capture "segment" () :> ReqBody '[JSON] () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get_by_segment" ",segment,body" "get" "#{segment}" "" True++  it "puts the body param after query params" $ do+    let api = Proxy :: Proxy (QueryFlag "flag" :> ReqBody '[JSON] () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",flag: nil,body" "get" "?flag=#{flag}" "" True++  it "sanitizes path segments" $ do+    let api = Proxy :: Proxy ("A!" :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get_A!" "" "get" "A!" "" False++  it "sanitizes captures" $ do+    let api = Proxy :: Proxy (Capture "A!" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get_by_A!" ",a_" "get" "#{a_}" "" False++  it "sanitizes query flags" $ do+    let api = Proxy :: Proxy (QueryFlag "A!" :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",a_: nil" "get" "?A!=#{a_}" "" False++  it "sanitizes query params" $ do+    let api = Proxy :: Proxy (QueryParam "A!" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",a_: nil" "get" "?A!=#{a_}" "" False++  it "sanitizes multiple query params" $ do+    let api = Proxy :: Proxy (QueryParams "A!" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",a_: nil" "get" "?A!=#{a_}" "" False++  it "sanitizes headers" $ do+    let api = Proxy :: Proxy (Header "A!" () :> Get '[JSON] ())+    rubyForAPI api `shouldBe`+      ruby "get" ",a_: nil" "get" "" "\"A!\"=>a_" False++-- Since every generated function has the same structure, it can be abstracted+-- away behind this function.+ruby :: String -> String -> String -> String -> String -> Bool -> Text+ruby name params method path headers body = pack (mconcat+  [ "def ", name, "(excon", params, ")"+  , "excon.request("+  , ":method=>:", method, ","+  , ":path=>\"/", path, "\","+  , ":headers=>{", headers, "},"+  , ":body=>", if body then "body" else "nil"+  , ")"+  , "end"+  ])