Skip to content

Commit c8435d1

Browse files
committed
Merge pull request #8 from cryogenian/decoder-and-list
Decoder and list combinator
2 parents aaa82cc + acfa5f0 commit c8435d1

File tree

5 files changed

+79
-11
lines changed

5 files changed

+79
-11
lines changed

MODULES.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ hashes :: forall e. (String -> String -> Eff e Unit) -> Eff e Unit
2222
matches :: forall e a. Match a -> (Maybe a -> a -> Eff e Unit) -> Eff e Unit
2323
```
2424

25+
Stream of hash changed, callback called when new hash can be matched
26+
First argument of callback is `Just a` when old hash can be matched
27+
and `Nothing` when it can't.
28+
29+
#### `matches'`
30+
31+
``` purescript
32+
matches' :: forall e a. (String -> String) -> Match a -> (Maybe a -> a -> Eff e Unit) -> Eff e Unit
33+
```
34+
2535

2636
#### `matchHash`
2737

@@ -30,6 +40,13 @@ matchHash :: forall a. Match a -> String -> Either String a
3040
```
3141

3242

43+
#### `matchHash'`
44+
45+
``` purescript
46+
matchHash' :: forall a. (String -> String) -> Match a -> String -> Either String a
47+
```
48+
49+
3350

3451
## Module Routing.Hash
3552

@@ -114,6 +131,15 @@ instance matchApplicative :: Applicative Match
114131
```
115132

116133

134+
#### `list`
135+
136+
``` purescript
137+
list :: forall a. Match a -> Match (List a)
138+
```
139+
140+
Matches list of matchers. Useful when argument can easy fail (not `str`)
141+
returns `Match Nil` if no matches
142+
117143
#### `runMatch`
118144

119145
``` purescript
@@ -149,9 +175,11 @@ routes = (pure Routing) <*> (eitherMatch (sortOfString <$> var))
149175
#### `parse`
150176

151177
``` purescript
152-
parse :: String -> Route
178+
parse :: (String -> String) -> String -> Route
153179
```
154180

181+
Parse hash string to `Route` with `decoder` function
182+
applied to every hash part (usually `decodeURIComponent`)
155183

156184

157185
## Module Routing.Types

src/Routing.purs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
module Routing where
1+
module Routing (
2+
hashChanged,
3+
hashes,
4+
matches,
5+
matches',
6+
matchHash,
7+
matchHash'
8+
) where
29

310
import Control.Monad.Eff
411
import Data.Maybe
@@ -8,6 +15,9 @@ import qualified Data.String.Regex as R
815
import Routing.Parser
916
import Routing.Match
1017

18+
19+
foreign import decodeURIComponent :: String -> String
20+
1121
foreign import hashChanged """
1222
function hashChanged(handler) {
1323
return function() {
@@ -28,12 +38,22 @@ hashes cb =
2838
where dropHash h = R.replace (R.regex "^[^#]*#" R.noFlags) "" h
2939

3040

41+
-- | Stream of hash changed, callback called when new hash can be matched
42+
-- | First argument of callback is `Just a` when old hash can be matched
43+
-- | and `Nothing` when it can't.
3144
matches :: forall e a. Match a -> (Maybe a -> a -> Eff e Unit) -> Eff e Unit
32-
matches routing cb = hashes $ \old new ->
33-
let mr = matchHash routing
45+
matches = matches' decodeURIComponent
46+
47+
matches' :: forall e a. (String -> String) ->
48+
Match a -> (Maybe a -> a -> Eff e Unit) -> Eff e Unit
49+
matches' decoder routing cb = hashes $ \old new ->
50+
let mr = matchHash' decoder routing
3451
fst = either (const Nothing) Just $ mr old
3552
in either (const $ pure unit) (cb fst) $ mr new
3653

3754

3855
matchHash :: forall a. Match a -> String -> Either String a
39-
matchHash matcher hash = runMatch matcher $ parse hash
56+
matchHash = matchHash' decodeURIComponent
57+
58+
matchHash' :: forall a. (String -> String) -> Match a -> String -> Either String a
59+
matchHash' decoder matcher hash = runMatch matcher $ parse decoder hash

src/Routing/Match.purs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,22 @@ instance matchApply :: Apply Match where
9696
instance matchApplicative :: Applicative Match where
9797
pure a = Match \r -> pure $ Tuple r a
9898

99+
100+
-- | Matches list of matchers. Useful when argument can easy fail (not `str`)
101+
-- | returns `Match Nil` if no matches
102+
list :: forall a. Match a -> Match (List a)
103+
list (Match r2a) =
104+
Match $ go Nil
105+
where go :: List a -> Route -> V (Free MatchError) (Tuple Route (List a))
106+
go accum r =
107+
runV
108+
(const $ pure (Tuple r (reverse accum)))
109+
(\(Tuple rs a) -> go (Cons a accum) rs)
110+
(r2a r)
111+
112+
113+
114+
99115
-- It groups `Free MatchError` -> [[MatchError]] -map with showMatchError ->
100116
-- [[String]] -fold with semicolon-> [String] -fold with newline-> String
101117
runMatch :: forall a. Match a -> Route -> Either String a

src/Routing/Parser.purs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ tryQuery source@(Path string) = fromMaybe source $ do
2626
Tuple <$> (A.head keyVal) <*> (keyVal A.!! 1)
2727
tryQuery q = q
2828

29-
foreign import decodeURIComponent :: String -> String
3029

31-
parse :: String -> Route
32-
parse hash = tryQuery <$>
30+
-- | Parse hash string to `Route` with `decoder` function
31+
-- | applied to every hash part (usually `decodeURIComponent`)
32+
parse :: (String -> String) -> String -> Route
33+
parse decoder hash = tryQuery <$>
3334
Path <$>
34-
decodeURIComponent <$>
35+
decoder <$>
3536
fromArray (S.split "/" hash)
3637

test/Main.purs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@ import Debug.Trace
55
import Control.Alt
66
import Control.Apply
77
import Debug.Foreign
8-
8+
import Data.List
99

1010
import Routing
1111
import Routing.Match
1212
import Routing.Match.Class
1313

14-
data FooBar = Foo Number | Bar Boolean String
14+
data FooBar = Foo Number | Bar Boolean String | Baz (List Number)
1515

1616
routing :: Match FooBar
1717
routing =
1818
Foo <$> (lit "foo" *> num)
1919
<|>
2020
Bar <$> (lit "bar" *> bool) <*> (param "baz")
21+
<|>
22+
Baz <$> (list num)
23+
2124

2225
main = do
2326
fprint $ matchHash routing "food/asdf"

0 commit comments

Comments
 (0)