on master help sign in
Merge pull request #11 from haskell-servant/pr5

Matrix params

commit8c6f327c0d5c0b60687bddca0a3ff136973a7cc6 authorJulian Arni <jkarni@gmail.com> dateWed 8 Apr 2015, 12:28 (12 years ago) parent84f8f81ad900cd
6 files changed+106−33
.gitignore+17 CHANGELOG.md+1 servant-jquery.cabal+4−4 src/Servant/JQuery.hs+3−2 src/Servant/JQuery/Internal.hs+81−26 test/Servant/JQuerySpec.hs−1
.gitignorenew file+17
@@ -0,0 +1,17 @@
1+dist
2+cabal-dev
3+*.o
4+*.hi
5+*.chi
6+*.chs.h
7+*.dyn_o
8+*.dyn_hi
9+.virtualenv
10+.hpc
11+.hsenv
12+.cabal-sandbox/
13+cabal.sandbox.config
14+cabal.config
15+*.prof
16+*.aux
17+*.hp
CHANGELOG.md+1
@@ -2,6 +2,7 @@
22---
33* Extend `HeaderArg` to support more advanced HTTP header handling (https://github.com/haskell-servant/servant-jquery/pull/6)
44* Support content-type aware combinators (but require that endpoints support JSON)
5+* Add support for Matrix params (https://github.com/haskell-servant/servant-jquery/pull/11)
56
670.2.2
78-----
servant-jquery.cabal+4−4
@@ -34,7 +34,7 @@ library
3434 build-depends: base >=4.5 && <5
3535 , charset
3636 , lens >= 4
37− , servant >= 0.2.1
37+ , servant >= 0.2.2
3838 , text
3939 hs-source-dirs: src
4040 default-language: Haskell2010
@@ -54,9 +54,9 @@ executable counter
5454 aeson
5555 , base
5656 , filepath
57− , servant >= 0.2.1
58− , servant-server >= 0.2.1
59− , servant-jquery >= 0.2.1
57+ , servant >= 0.2.2
58+ , servant-server >= 0.2.3
59+ , servant-jquery >= 0.2.2
6060 , stm
6161 , transformers
6262 , warp
src/Servant/JQuery.hs+3−2
@@ -46,7 +46,7 @@ generateJS req = "\n" <>
4646 ++ body
4747 ++ map (toValidFunctionName . (<>) "header" . headerArgName) hs
4848 ++ ["onSuccess", "onError"]
49−
49+
5050 captures = map captureArg
5151 . filter isCapture
5252 $ req ^. reqUrl.path
@@ -76,7 +76,8 @@ generateJS req = "\n" <>
7676
7777 fname = req ^. funcName
7878 method = req ^. reqMethod
79− url = "'"
79+ url = if url' == "'" then "'/'" else url'
80+ url' = "'"
8081 ++ urlArgs
8182 ++ queryArgs
8283
src/Servant/JQuery/Internal.hs+81−26
@@ -24,29 +24,12 @@ import Servant.API
2424
2525type Arg = String
2626
27−data Segment = Static String -- ^ a static path segment. like "/foo"
28− | Cap Arg -- ^ a capture. like "/:userid"
27+data Segment = Segment { _segment :: SegmentType, _matrix :: [MatrixArg] }
2928 deriving (Eq, Show)
3029
31−
32−isCapture :: Segment -> Bool
33−isCapture (Cap _) = True
34−isCapture _ = False
35−
36−captureArg :: Segment -> Arg
37−captureArg (Cap s) = s
38−captureArg _ = error "captureArg called on non capture"
39−
40−jsSegments :: [Segment] -> String
41−jsSegments [] = "/'"
42−jsSegments [x] = "/" ++ segmentToStr x False
43−jsSegments (x:xs) = "/" ++ segmentToStr x True ++ jsSegments xs
44−
45−segmentToStr :: Segment -> Bool -> String
46−segmentToStr (Static s) notTheEnd =
47− if notTheEnd then s else s ++ "'"
48−segmentToStr (Cap s) notTheEnd =
49− "' + encodeURIComponent(" ++ s ++ if notTheEnd then ") + '" else ")"
30+data SegmentType = Static String -- ^ a static path segment. like "/foo"
31+ | Cap Arg -- ^ a capture. like "/:userid"
32+ deriving (Eq, Show)
5033
5134type Path = [Segment]
5235
@@ -113,6 +96,8 @@ toValidFunctionName (x:xs) = [setFirstChar x] <> filter remainder xs
11396 , Set.connectorPunctuation ]
11497toValidFunctionName [] = "_"
11598
99+type MatrixArg = QueryArg
100+
116101data Url = Url
117102 { _path :: Path
118103 , _queryStr :: [QueryArg]
@@ -133,13 +118,52 @@ data AjaxReq = AjaxReq
133118 } deriving (Eq, Show)
134119
135120makeLenses ''QueryArg
121+makeLenses ''Segment
136122makeLenses ''Url
137123makeLenses ''AjaxReq
138124
125+isCapture :: Segment -> Bool
126+isCapture (Segment (Cap _) _) = True
127+isCapture _ = False
128+
129+hasMatrixArgs :: Segment -> Bool
130+hasMatrixArgs (Segment _ (_:_)) = True
131+hasMatrixArgs _ = False
132+
133+hasArgs :: Segment -> Bool
134+hasArgs s = isCapture s || hasMatrixArgs s
135+
136+matrixArgs :: Segment -> [MatrixArg]
137+matrixArgs (Segment _ ms) = ms
138+
139+captureArg :: Segment -> Arg
140+captureArg (Segment (Cap s) _) = s
141+captureArg _ = error "captureArg called on non capture"
142+
143+jsSegments :: [Segment] -> String
144+jsSegments [] = ""
145+jsSegments [x] = "/" ++ segmentToStr x False
146+jsSegments (x:xs) = "/" ++ segmentToStr x True ++ jsSegments xs
147+
148+segmentToStr :: Segment -> Bool -> String
149+segmentToStr (Segment st ms) notTheEnd =
150+ segmentTypeToStr st ++ jsMParams ms ++ if notTheEnd then "" else "'"
151+
152+segmentTypeToStr :: SegmentType -> String
153+segmentTypeToStr (Static s) = s
154+segmentTypeToStr (Cap s) = "' + encodeURIComponent(" ++ s ++ ") + '"
155+
156+jsGParams :: String -> [QueryArg] -> String
157+jsGParams _ [] = ""
158+jsGParams _ [x] = paramToStr x False
159+jsGParams s (x:xs) = paramToStr x True ++ s ++ jsGParams s xs
160+
139161jsParams :: [QueryArg] -> String
140−jsParams [] = ""
141−jsParams [x] = paramToStr x False
142−jsParams (x:xs) = paramToStr x True ++ "&" ++ jsParams xs
162+jsParams = jsGParams "&"
163+
164+jsMParams :: [MatrixArg] -> String
165+jsMParams [] = ""
166+jsMParams xs = ";" ++ jsGParams ";" xs
143167
144168paramToStr :: QueryArg -> Bool -> String
145169paramToStr qarg notTheEnd =
@@ -184,7 +208,7 @@ instance (KnownSymbol sym, HasJQ sublayout)
184208
185209 jqueryFor Proxy req =
186210 jqueryFor (Proxy :: Proxy sublayout) $
187− req & reqUrl.path <>~ [Cap str]
211+ req & reqUrl.path <>~ [Segment (Cap str) []]
188212
189213 where str = symbolVal (Proxy :: Proxy sym)
190214
@@ -256,6 +280,37 @@ instance (KnownSymbol sym, HasJQ sublayout)
256280
257281 where str = symbolVal (Proxy :: Proxy sym)
258282
283+instance (KnownSymbol sym, HasJQ sublayout)
284+ => HasJQ (MatrixParam sym a :> sublayout) where
285+ type JQ (MatrixParam sym a :> sublayout) = JQ sublayout
286+
287+ jqueryFor Proxy req =
288+ jqueryFor (Proxy :: Proxy sublayout) $
289+ req & reqUrl.path._last.matrix <>~ [QueryArg strArg Normal]
290+
291+ where str = symbolVal (Proxy :: Proxy sym)
292+ strArg = str ++ "Value"
293+
294+instance (KnownSymbol sym, HasJQ sublayout)
295+ => HasJQ (MatrixParams sym a :> sublayout) where
296+ type JQ (MatrixParams sym a :> sublayout) = JQ sublayout
297+
298+ jqueryFor Proxy req =
299+ jqueryFor (Proxy :: Proxy sublayout) $
300+ req & reqUrl.path._last.matrix <>~ [QueryArg str List]
301+
302+ where str = symbolVal (Proxy :: Proxy sym)
303+
304+instance (KnownSymbol sym, HasJQ sublayout)
305+ => HasJQ (MatrixFlag sym :> sublayout) where
306+ type JQ (MatrixFlag sym :> sublayout) = JQ sublayout
307+
308+ jqueryFor Proxy req =
309+ jqueryFor (Proxy :: Proxy sublayout) $
310+ req & reqUrl.path._last.matrix <>~ [QueryArg str Flag]
311+
312+ where str = symbolVal (Proxy :: Proxy sym)
313+
259314instance HasJQ Raw where
260315 type JQ Raw = Method -> AjaxReq
261316
@@ -276,7 +331,7 @@ instance (KnownSymbol path, HasJQ sublayout)
276331
277332 jqueryFor Proxy req =
278333 jqueryFor (Proxy :: Proxy sublayout) $
279− req & reqUrl.path <>~ [Static str]
334+ req & reqUrl.path <>~ [Segment (Static str) []]
280335 & funcName %~ (str <>)
281336
282337 where str = map (\c -> if c == '.' then '_' else c) $ symbolVal (Proxy :: Proxy path)
test/Servant/JQuerySpec.hs−1
@@ -13,7 +13,6 @@ import Language.ECMAScript3.Parser (parseFromString)
1313import Test.Hspec
1414
1515import Servant.API
16−import Servant.API.ContentTypes
1716import Servant.JQuery
1817import Servant.JQuerySpec.CustomHeaders
1918