git.iko.soy/typeable/servant
on master help sign in
Merge pull request #171 from freezeboy/transform-function-name
dc902e2Alp Mestanogullari
servant-js/examples/www/angular/index.html+2−2
@@ -21,11 +21,11 @@ counterApp.controller('CounterCtrl', ['$scope', '$http', '$interval', function (
21 var publishCounter = function (response) { $scope.counter = response.value; };
21 var publishCounter = function (response) { $scope.counter = response.value; };
22
22
23 $scope.getCounter = function() {
23 $scope.getCounter = function() {
24− getcounter($http)
24+ getCounter($http)
25 .success(publishCounter);
25 .success(publishCounter);
26 }
26 }
27 $scope.incCounter = function() {
27 $scope.incCounter = function() {
28− postcounter($http)
28+ postCounter($http)
29 .success(publishCounter);
29 .success(publishCounter);
30 }
30 }
31
31
servant-js/examples/www/angular/service.html+2−2
@@ -20,11 +20,11 @@ counterApp.controller('CounterCtrl', function ($scope,counterSvc, $interval) {
20 var publishCounter = function (response) { $scope.counter = response.value; };
20 var publishCounter = function (response) { $scope.counter = response.value; };
21
21
22 $scope.getCounter = function() {
22 $scope.getCounter = function() {
23− counterSvc.getcounter()
23+ counterSvc.getCounter()
24 .success(publishCounter);
24 .success(publishCounter);
25 }
25 }
26 $scope.incCounter = function() {
26 $scope.incCounter = function() {
27− counterSvc.postcounter()
27+ counterSvc.postCounter()
28 .success(publishCounter);
28 .success(publishCounter);
29 }
29 }
30
30
servant-js/examples/www/jquery/index.html+3−3
@@ -17,11 +17,11 @@
17<script type="text/javascript">
17<script type="text/javascript">
18$(document).ready(function() {
18$(document).ready(function() {
19 // we get the current value stored by the server when the page is loaded
19 // we get the current value stored by the server when the page is loaded
20− getcounter(updateCounter, alert);
20+ getCounter(updateCounter, alert);
21
21
22 // we update the value every 1sec, in the same way
22 // we update the value every 1sec, in the same way
23 window.setInterval(function() {
23 window.setInterval(function() {
24− getcounter(updateCounter, alert);
24+ getCounter(updateCounter, alert);
25 }, 1000);
25 }, 1000);
26});
26});
27
27
@@ -33,7 +33,7 @@ function updateCounter(response)
33// when the button is clicked, ask the server to increase
33// when the button is clicked, ask the server to increase
34// the value by one
34// the value by one
35$('#inc').click(function() {
35$('#inc').click(function() {
36− postcounter(updateCounter, alert);
36+ postCounter(updateCounter, alert);
37});
37});
38</script>
38</script>
39</body>
39</body>
servant-js/examples/www/vanilla/index.html+3−3
@@ -16,11 +16,11 @@
16<script type="text/javascript">
16<script type="text/javascript">
17window.addEventListener('load', function() {
17window.addEventListener('load', function() {
18 // we get the current value stored by the server when the page is loaded
18 // we get the current value stored by the server when the page is loaded
19− getcounter(updateCounter, alert);
19+ getCounter(updateCounter, alert);
20
20
21 // we update the value every 1sec, in the same way
21 // we update the value every 1sec, in the same way
22 window.setInterval(function() {
22 window.setInterval(function() {
23− getcounter(updateCounter, alert);
23+ getCounter(updateCounter, alert);
24 }, 1000);
24 }, 1000);
25});
25});
26
26
@@ -32,7 +32,7 @@ function updateCounter(response)
32// when the button is clicked, ask the server to increase
32// when the button is clicked, ask the server to increase
33// the value by one
33// the value by one
34document.getElementById('inc').addEventListener('click', function() {
34document.getElementById('inc').addEventListener('click', function() {
35− postcounter(updateCounter, alert);
35+ postCounter(updateCounter, alert);
36});
36});
37</script>
37</script>
38</body>
38</body>
servant-js/src/Servant/JS.hs+5
@@ -79,6 +79,11 @@ module Servant.JS
79 CommonGeneratorOptions(..)
79 CommonGeneratorOptions(..)
80 , defCommonGeneratorOptions
80 , defCommonGeneratorOptions
81
81
82+ , -- * Function renamers
83+ concatCase
84+ , snakeCase
85+ , camelCase
86+
82 , -- * Vanilla Javascript code generation
87 , -- * Vanilla Javascript code generation
83 vanillaJS
88 vanillaJS
84 , vanillaJSWith
89 , vanillaJSWith
servant-js/src/Servant/JS/Angular.hs+1−1
@@ -123,7 +123,7 @@ generateAngularJSWith ngOptions opts req = "\n" <>
123
123
124 fsep = if hasService then ":" else " ="
124 fsep = if hasService then ":" else " ="
125
125
126− fname = namespace <> (functionRenamer opts $ req ^. funcName)
126+ fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
127
127
128 method = req ^. reqMethod
128 method = req ^. reqMethod
129 url = if url' == "'" then "'/'" else url'
129 url = if url' == "'" then "'/'" else url'
servant-js/src/Servant/JS/Internal.hs+32−12
@@ -14,7 +14,7 @@ module Servant.JS.Internal where
14import Control.Applicative
14import Control.Applicative
15#endif
15#endif
16import Control.Lens
16import Control.Lens
17−import Data.Char (toLower)
17+import Data.Char (toLower, toUpper)
18import qualified Data.CharSet as Set
18import qualified Data.CharSet as Set
19import qualified Data.CharSet.Unicode.Category as Set
19import qualified Data.CharSet.Unicode.Category as Set
20import Data.List
20import Data.List
@@ -29,7 +29,7 @@ import Servant.API
29-- customize the output
29-- customize the output
30data CommonGeneratorOptions = CommonGeneratorOptions
30data CommonGeneratorOptions = CommonGeneratorOptions
31 {
31 {
32− functionRenamer :: String -> String -- ^ function transforming function names
32+ functionNameBuilder :: FunctionName -> String -- ^ function generating function names
33 , requestBody :: String -- ^ name used when a user want to send the request body (to let you redefine it)
33 , requestBody :: String -- ^ name used when a user want to send the request body (to let you redefine it)
34 , successCallback :: String -- ^ name of the callback parameter when the request was successful
34 , successCallback :: String -- ^ name of the callback parameter when the request was successful
35 , errorCallback :: String -- ^ name of the callback parameter when the request reported an error
35 , errorCallback :: String -- ^ name of the callback parameter when the request reported an error
@@ -41,7 +41,7 @@ data CommonGeneratorOptions = CommonGeneratorOptions
41--
41--
42-- @
42-- @
43-- > defCommonGeneratorOptions = CommonGeneratorOptions
43-- > defCommonGeneratorOptions = CommonGeneratorOptions
44−-- > { functionRenamer = id
44+-- > { functionNameBuilder = camelCase
45-- > , requestBody = "body"
45-- > , requestBody = "body"
46-- > , successCallback = "onSuccess"
46-- > , successCallback = "onSuccess"
47-- > , errorCallback = "onError"
47-- > , errorCallback = "onError"
@@ -52,13 +52,32 @@ data CommonGeneratorOptions = CommonGeneratorOptions
52defCommonGeneratorOptions :: CommonGeneratorOptions
52defCommonGeneratorOptions :: CommonGeneratorOptions
53defCommonGeneratorOptions = CommonGeneratorOptions
53defCommonGeneratorOptions = CommonGeneratorOptions
54 {
54 {
55− functionRenamer = id
55+ functionNameBuilder = camelCase
56 , requestBody = "body"
56 , requestBody = "body"
57 , successCallback = "onSuccess"
57 , successCallback = "onSuccess"
58 , errorCallback = "onError"
58 , errorCallback = "onError"
59 , moduleName = ""
59 , moduleName = ""
60 , urlPrefix = ""
60 , urlPrefix = ""
61 }
61 }
62+
63+-- | Function name builder that simply concat each part together
64+concatCase :: FunctionName -> String
65+concatCase = concat
66+
67+-- | Function name builder using the snake_case convention.
68+-- each part is separated by a single underscore character.
69+snakeCase :: FunctionName -> String
70+snakeCase = intercalate "_"
71+
72+-- | Function name builder using the CamelCase convention.
73+-- each part begins with an upper case character.
74+camelCase :: FunctionName -> String
75+camelCase [] = ""
76+camelCase (p:ps) = concat $ p : camelCase' ps
77+ where camelCase' [] = []
78+ camelCase' (r:rs) = capitalize r : camelCase' rs
79+ capitalize [] = []
80+ capitalize (x:xs) = toUpper x : xs
62
81
63type Arg = String
82type Arg = String
64
83
@@ -149,7 +168,7 @@ data Url = Url
149defUrl :: Url
168defUrl :: Url
150defUrl = Url [] []
169defUrl = Url [] []
151
170
152−type FunctionName = String
171+type FunctionName = [String]
153type Method = String
172type Method = String
154
173
155data AjaxReq = AjaxReq
174data AjaxReq = AjaxReq
@@ -226,7 +245,7 @@ paramToStr qarg notTheEnd =
226 where name = qarg ^. argName
245 where name = qarg ^. argName
227
246
228defReq :: AjaxReq
247defReq :: AjaxReq
229−defReq = AjaxReq defUrl "GET" [] False ""
248+defReq = AjaxReq defUrl "GET" [] False []
230
249
231type family Elem (a :: *) (ls::[*]) :: Constraint where
250type family Elem (a :: *) (ls::[*]) :: Constraint where
232 Elem a '[] = 'False ~ 'True
251 Elem a '[] = 'False ~ 'True
@@ -252,6 +271,7 @@ instance (KnownSymbol sym, HasJS sublayout)
252 javascriptFor Proxy req =
271 javascriptFor Proxy req =
253 javascriptFor (Proxy :: Proxy sublayout) $
272 javascriptFor (Proxy :: Proxy sublayout) $
254 req & reqUrl.path <>~ [Segment (Cap str) []]
273 req & reqUrl.path <>~ [Segment (Cap str) []]
274+ & funcName %~ (++ ["by", str])
255
275
256 where str = symbolVal (Proxy :: Proxy sym)
276 where str = symbolVal (Proxy :: Proxy sym)
257
277
@@ -259,14 +279,14 @@ instance Elem JSON list => HasJS (Delete list a) where
259 type JS (Delete list a) = AjaxReq
279 type JS (Delete list a) = AjaxReq
260
280
261 javascriptFor Proxy req =
281 javascriptFor Proxy req =
262− req & funcName %~ ("delete" <>)
282+ req & funcName %~ ("delete" :)
263 & reqMethod .~ "DELETE"
283 & reqMethod .~ "DELETE"
264
284
265instance Elem JSON list => HasJS (Get list a) where
285instance Elem JSON list => HasJS (Get list a) where
266 type JS (Get list a) = AjaxReq
286 type JS (Get list a) = AjaxReq
267
287
268 javascriptFor Proxy req =
288 javascriptFor Proxy req =
269− req & funcName %~ ("get" <>)
289+ req & funcName %~ ("get" :)
270 & reqMethod .~ "GET"
290 & reqMethod .~ "GET"
271
291
272instance (KnownSymbol sym, HasJS sublayout)
292instance (KnownSymbol sym, HasJS sublayout)
@@ -283,14 +303,14 @@ instance Elem JSON list => HasJS (Post list a) where
283 type JS (Post list a) = AjaxReq
303 type JS (Post list a) = AjaxReq
284
304
285 javascriptFor Proxy req =
305 javascriptFor Proxy req =
286− req & funcName %~ ("post" <>)
306+ req & funcName %~ ("post" :)
287 & reqMethod .~ "POST"
307 & reqMethod .~ "POST"
288
308
289instance Elem JSON list => HasJS (Put list a) where
309instance Elem JSON list => HasJS (Put list a) where
290 type JS (Put list a) = AjaxReq
310 type JS (Put list a) = AjaxReq
291
311
292 javascriptFor Proxy req =
312 javascriptFor Proxy req =
293− req & funcName %~ ("put" <>)
313+ req & funcName %~ ("put" :)
294 & reqMethod .~ "PUT"
314 & reqMethod .~ "PUT"
295
315
296instance (KnownSymbol sym, HasJS sublayout)
316instance (KnownSymbol sym, HasJS sublayout)
@@ -358,7 +378,7 @@ instance HasJS Raw where
358 type JS Raw = Method -> AjaxReq
378 type JS Raw = Method -> AjaxReq
359
379
360 javascriptFor Proxy req method =
380 javascriptFor Proxy req method =
361− req & funcName %~ ((toLower <$> method) <>)
381+ req & funcName %~ ((toLower <$> method) :)
362 & reqMethod .~ method
382 & reqMethod .~ method
363
383
364instance (Elem JSON list, HasJS sublayout) => HasJS (ReqBody list a :> sublayout) where
384instance (Elem JSON list, HasJS sublayout) => HasJS (ReqBody list a :> sublayout) where
@@ -375,7 +395,7 @@ instance (KnownSymbol path, HasJS sublayout)
375 javascriptFor Proxy req =
395 javascriptFor Proxy req =
376 javascriptFor (Proxy :: Proxy sublayout) $
396 javascriptFor (Proxy :: Proxy sublayout) $
377 req & reqUrl.path <>~ [Segment (Static str) []]
397 req & reqUrl.path <>~ [Segment (Static str) []]
378− & funcName %~ (str <>)
398+ & funcName %~ (++ [str])
379
399
380 where str = map (\c -> if c == '.' then '_' else c) $ symbolVal (Proxy :: Proxy path)
400 where str = map (\c -> if c == '.' then '_' else c) $ symbolVal (Proxy :: Proxy path)
381
401
servant-js/src/Servant/JS/JQuery.hs+1−1
@@ -76,7 +76,7 @@ generateJQueryJSWith opts req = "\n" <>
76 namespace = if null (moduleName opts)
76 namespace = if null (moduleName opts)
77 then "var "
77 then "var "
78 else (moduleName opts) <> "."
78 else (moduleName opts) <> "."
79− fname = namespace <> (functionRenamer opts $ req ^. funcName)
79+ fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
80
80
81 method = req ^. reqMethod
81 method = req ^. reqMethod
82 url = if url' == "'" then "'/'" else url'
82 url = if url' == "'" then "'/'" else url'
servant-js/src/Servant/JS/Vanilla.hs+1−1
@@ -83,7 +83,7 @@ generateVanillaJSWith opts req = "\n" <>
83 namespace = if null (moduleName opts)
83 namespace = if null (moduleName opts)
84 then "var "
84 then "var "
85 else (moduleName opts) <> "."
85 else (moduleName opts) <> "."
86− fname = namespace <> (functionRenamer opts $ req ^. funcName)
86+ fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
87
87
88 method = req ^. reqMethod
88 method = req ^. reqMethod
89 url = if url' == "'" then "'/'" else url'
89 url = if url' == "'" then "'/'" else url'