packages feed

HostAndPort 0.1.0 → 0.2.0

raw patch · 5 files changed

+141/−31 lines, 5 filesdep +criterionPVP ok

version bump matches the API change (PVP)

Dependencies added: criterion

API changes (from Hackage documentation)

+ Network.HostAndPort: HostName :: a -> ConnectionDetail a
+ Network.HostAndPort: IPv4Address :: a -> ConnectionDetail a
+ Network.HostAndPort: IPv6Address :: a -> ConnectionDetail a
+ Network.HostAndPort: data ConnectionDetail a
+ Network.HostAndPort: detailedHostAndPort :: String -> Either String (RemoteAddr, Maybe String)
+ Network.HostAndPort: instance Eq a => Eq (ConnectionDetail a)
+ Network.HostAndPort: instance Ord a => Ord (ConnectionDetail a)
+ Network.HostAndPort: instance Show a => Show (ConnectionDetail a)
+ Network.HostAndPort: type RemoteAddr = ConnectionDetail String

Files

HostAndPort.cabal view
@@ -1,5 +1,5 @@ name:                HostAndPort-version:             0.1.0+version:             0.2.0 license:             MIT license-file:        LICENSE author:              Slava Bacherikov@@ -10,7 +10,9 @@ category:            Network build-type:          Simple cabal-version:       >=1.10-synopsis:            Parser host and port pairs like localhost:22+tested-with:         GHC == 7.4, GHC == 7.6, GHC == 7.8, GHC == 7.10+extra-source-files:  README.md+synopsis:            Parser for host and port pairs like localhost:22 description:    Simple parser for parsing host and port pairs.@@ -21,13 +23,19 @@   .   Examples:   .-    * localhost-    * localhost:8080-    * 127.0.0.1-    * 127.0.0.1:8080-    * [::1]-    * [::1]:8080+  * localhost+  .+  * localhost:8080+  .+  * 127.0.0.1+  .+  * 127.0.0.1:8080+  .+  * [::1]+  .+  * [::1]:8080 + library   exposed-modules:     Network.HostAndPort   build-depends:       base >=4.5 && <5,@@ -37,7 +45,7 @@   default-language:    Haskell2010  test-suite tests-  default-language:    Haskell2010+  default-language:    Haskell98   type:                exitcode-stdio-1.0   hs-source-dirs:      tests   main-is:             Spec.hs@@ -47,7 +55,7 @@                        hspec  test-suite doctests-  default-language:    Haskell2010+  default-language:    Haskell98   type:                exitcode-stdio-1.0   hs-source-dirs:      tests   main-is:             Doctests.hs@@ -56,6 +64,15 @@                        HostAndPort,                        doctest +benchmark bench-hostandport+  type:                exitcode-stdio-1.0+  hs-source-dirs:      benchmarks+  main-is:             Benchmark.hs+  ghc-options:         -O2 -Wall -fno-warn-name-shadowing+  default-language:    Haskell98+  build-depends:       base >=4.5 && <5,+                       HostAndPort,+                       criterion  source-repository head   type:                git
+ README.md view
@@ -0,0 +1,17 @@+HostAndPort+===========++[![Build Status](https://travis-ci.org/bacher09/hostandport.svg?branch=master)]+(https://travis-ci.org/bacher09/hostandport)+++Simple Haskell library for parsing connection strings that contain+host and port info. For more info see package [documentation][docs].+++License+-------+MIT+++[docs]: https://hackage.haskell.org/package/HostAndPort-0.1.0/docs/Network-HostAndPort.html
+ benchmarks/Benchmark.hs view
@@ -0,0 +1,18 @@+module Main where+import Criterion.Main+import Network.HostAndPort+++main :: IO ()+main = defaultMain [+        bgroup "ipv4" [ bench "127.0.0.1" $ whnf isIPv4Address "127.0.0.1"+                      , bench "bad" $ whnf isIPv4Address "22222.2222.222.22"]+        , bgroup "ipv6" [ bench "::1" $ whnf isIPv6Address "::1"+                        , bench "vinnica.in" $ whnf isIPv6Address "2605:2700:0:2::4713:9eef"+                        , bench "full" $ whnf isIPv6Address "1:2:3:4:5:6:7:8"+                        , bench "with-ipv4" $ whnf isIPv6Address "1:2:3:4:5:6:127.0.0.1"+                        , bench "bad" $ whnf isIPv6Address "2605:2700:0:2::4713:9eef"]+        , bgroup "HostAndPort" [ bench "127.0.0.1" $ nf hostAndPort "127.0.0.1"+                               , bench "localhost:9090" $ nf hostAndPort "localhost:9090"+                               , bench "ipv6-and-port" $ nf hostAndPort "[2605:2700:0:2::4713:9eef]:26000"]+        ]
src/Network/HostAndPort.hs view
@@ -1,17 +1,30 @@-module Network.HostAndPort (-    isIPv4Address,-    isIPv6Address,-    hostAndPort,-    maybeHostAndPort,-    defaultHostAndPort-) where-import Text.Parsec-import Control.Applicative hiding((<|>), many)+module Network.HostAndPort+    ( ConnectionDetail(..)+    , RemoteAddr+    , isIPv4Address+    , isIPv6Address+    , hostAndPort+    , detailedHostAndPort+    , maybeHostAndPort+    , defaultHostAndPort+    ) where++ import Control.Monad import Data.Maybe+import Control.Applicative hiding((<|>), many)+import Control.Arrow (second)+import Text.Parsec  +data ConnectionDetail a = IPv4Address a+                        | IPv6Address a+                        | HostName a+    deriving(Show, Eq, Ord)++ type Parser = Parsec String ()+type RemoteAddr = ConnectionDetail String   countMinMax :: (Stream s m t) => Int -> Int -> ParsecT s u m a -> ParsecT s u m [a]@@ -85,7 +98,7 @@     last2f = try ipv4address <|> consequence [h4s, hexShortNum]     last2 f = if f         then last2f-        else choice [try $ last2f,+        else choice [try last2f,                      try $ consequence [string "::", hexShortNum],                      consequence [hexShortNum, string "::"]] @@ -122,7 +135,7 @@   -- | This function will validate ipv4 address--- and return True if string is valie adress+-- and return True if string is valid adress isIPv4Address :: String -> Bool isIPv4Address = isParsed $ ipv4address <* eof @@ -148,9 +161,13 @@ asciiAlphaNum = satisfy isAsciiAlphaNum  -connectionStr :: Parser (String, Maybe String)-connectionStr = do-    addr <- try ipv6str <|> try ipv4address <|> hostname+connectionStr :: (String -> a) ->+                 (String -> a) ->+                 (String -> a) -> Parser (a, Maybe String)+connectionStr ipv6Fun ipv4Fun hostFun = do+    addr <- try (ipv6Fun <$> ipv6str)+                <|> try (ipv4Fun <$> ipv4address)+                <|> (hostFun <$> hostname)     p <- maybePort     return (addr, p)   where@@ -161,7 +178,30 @@         return ipv6     maybePort = option Nothing $ char ':' >> Just <$> port + -- | This function will parse it's argument and return either+-- `String` (`Left`) in case of error or (`ConnectionDetail String`, Maybe Port)+-- tuple (`Right`).+--+-- Examples:+--+-- >>> detailedHostAndPort "localhost"+-- Right (HostName "localhost",Nothing)+-- >>> detailedHostAndPort "[::1]:3030"+-- Right (IPv6Address "::1",Just "3030")+-- >>> detailedHostAndPort "127.0.0.1:1080"+-- Right (IPv4Address "127.0.0.1",Just "1080")+--+-- /Since/ 0.2+detailedHostAndPort :: String -> Either String (RemoteAddr, Maybe String)+detailedHostAndPort s = case runParser parser () "" s of+    (Right v) -> Right v+    (Left e) -> Left $ show e+  where+    parser = connectionStr IPv6Address IPv4Address HostName <* eof+++-- | This function will parse it's argument and return either -- `String` (`Left`) with info about error or (Host, `Maybe` Port) -- tuple (`Right`). --@@ -172,9 +212,9 @@ -- >>> hostAndPort "[::1]:3030" -- Right ("::1",Just "3030") hostAndPort :: String -> Either String (String, Maybe String)-hostAndPort s = case runParser (connectionStr <* eof) () "" s of+hostAndPort s = case runParser (connectionStr id id id <* eof) () "" s of     (Right v) -> Right v-    (Left e) -> Left $ show $ e+    (Left e) -> Left $ show e   -- | Function will parse argument and return Maybe (Host, Maybe Port)@@ -186,9 +226,7 @@ -- >>> maybeHostAndPort "192.168.10.12:7272" -- Just ("192.168.10.12",Just "7272") maybeHostAndPort :: String -> Maybe (String, Maybe String)-maybeHostAndPort s = case hostAndPort s of-    (Right v) -> Just v-    (Left _) -> Nothing+maybeHostAndPort s = either (const Nothing) Just $ hostAndPort s   -- | Function will take default port and connection string@@ -206,4 +244,4 @@ defaultHostAndPort :: String                    -- ^ default Port number                    -> String                    -- ^ connection string                    -> Maybe (String, String)    -- ^ Maybe (Host, Port)-defaultHostAndPort p s = (\(h, mp) -> (h, fromMaybe p mp)) <$> maybeHostAndPort s+defaultHostAndPort p s = second (fromMaybe p) <$> maybeHostAndPort s
tests/Spec.hs view
@@ -1,9 +1,14 @@ module Main where+import Text.Printf import Test.Hspec import Network.HostAndPort-import Text.Printf  +isLeft :: Either a b -> Bool+isLeft (Left _) = True+isLeft (Right _) = False++ main :: IO () main = hspec spec @@ -90,6 +95,21 @@         it "testing invalid" $ do             defaultHostAndPort "60" "localhost:99999" `shouldBe` Nothing             defaultHostAndPort "60" "[bad]:25" `shouldBe` Nothing++    describe "detailedHostAndPort" $ do+        it "parsing hosts" $ do+            detailedHostAndPort "localhost" `shouldBe` Right (HostName "localhost", Nothing)+            detailedHostAndPort "some-domain.com" `shouldBe` Right (HostName "some-domain.com", Nothing)+            detailedHostAndPort "42.another-domain.com:3030" `shouldBe` Right (HostName "42.another-domain.com", Just "3030")++        it "parsing ipv6address" $ do+            detailedHostAndPort "[::1]:8080" `shouldBe` Right (IPv6Address "::1", Just "8080")+            detailedHostAndPort "[10::1:f]:8080" `shouldBe` Right (IPv6Address "10::1:f", Just "8080")+            detailedHostAndPort "[::1]:65536" `shouldSatisfy` isLeft++        it "parsing ipv4address" $ do+            detailedHostAndPort "127.0.0.1" `shouldBe` Right (IPv4Address "127.0.0.1", Nothing)+            detailedHostAndPort "127.0.0.1:6060" `shouldBe` Right (IPv4Address "127.0.0.1", Just "6060")   where     valid f s = it (printf "valid \"%s\"" s) (f s `shouldBe` True)     invalid f s = it (printf "invalid \"%s\"" s) (f s `shouldBe` False)