regex-do 2.6.1 → 2.6.2
raw patch · 13 files changed
+176/−46 lines, 13 filesdep +mtl
Dependencies added: mtl
Files
- changelog.md +5/−0
- regex-do.cabal +4/−2
- src/Text/Regex/Do/Format.hs +17/−1
- src/Text/Regex/Do/Pcre/Ascii/Match.hs +22/−16
- src/Text/Regex/Do/Pcre/Ascii/MatchHint.hs +14/−11
- src/Text/Regex/Do/Pcre/Ascii/Replace.hs +2/−0
- src/Text/Regex/Do/Pcre/Utf8/Match.hs +18/−8
- src/Text/Regex/Do/Pcre/Utf8/MatchHint.hs +1/−5
- src/Text/Regex/Do/Pcre/Utf8/Replace.hs +2/−0
- src/Text/Regex/Do/Type/Regex.hs +61/−0
- test/Main.hs +2/−1
- test/TestRegex/TestMakeRegexM.hs +25/−0
- test/TestRegex/TestPcre.hs +3/−2
changelog.md view
@@ -1,3 +1,8 @@+##### 2.6.2+ compatible with 2.6.1+ + add makeRegexM, makeRegexOptM, RegexResult to catch regex construction errors+ ##### 2.6.1 compatible with 2.6
regex-do.cabal view
@@ -1,5 +1,5 @@ name: regex-do-version: 2.6.1+version: 2.6.2 synopsis: PCRE wrapper description: format, search, replace (String | ByteString) with PCRE regex. Utf8-safe author: Imants Cekusins@@ -40,7 +40,6 @@ other-modules: Text.Regex.Do.Result- ghc-options: -fwarn-unused-imports build-depends: base <= 5.0,@@ -48,6 +47,7 @@ regex-pcre, stringsearch, bytestring,+ mtl, array, text @@ -92,6 +92,7 @@ TestRegex.TestTrim TestRegex.TestReplaceOpen TestRegex.TestReplaceUtf+ TestRegex.TestMakeRegexM build-depends: base <= 5.0, hspec,@@ -99,6 +100,7 @@ regex-base, regex-pcre, stringsearch,+ mtl, bytestring, array, text,
src/Text/Regex/Do/Format.hs view
@@ -1,3 +1,17 @@+{- | ==== placeholder syntax:++ * index based++ { Int }++ * key based++ { 'String' | 'ByteString' | 'Text' }++ other placeholders may be implemented with++ "Text.Regex.Do.Pcre.Ascii.Replace" or "Text.Regex.Do.Pcre.Utf8.Replace" -}+ module Text.Regex.Do.Format (Format(..), ReplaceOne(..),@@ -20,7 +34,9 @@ * 'Text' -} class Format a arg where- format::a -> arg -> a+ format::a -- ^ text to format e.g. "today is {0}"+ -> arg -- ^ replacement: [a] or [(a,a)]+ -> a -- ^ formatted text instance ReplaceOne Int a =>
src/Text/Regex/Do/Pcre/Ascii/Match.hs view
@@ -19,31 +19,37 @@ import Text.Regex.Do.Type.MatchHint +{- | short version of 'match': arg without newtypes++ is borrowed from "Text.Regex.PCRE.Wrap" -}+(=~)::Match a b out =>+ a -- ^ pattern+ -> b -- ^ body+ -> out+(=~) p0 b0 = match (Pattern p0) (Body b0)+++ {- | * a: 'String', 'ByteString', 'Regex' * b: 'String', 'ByteString'- * out: ['String'], [['String']], ['ByteString'], [['ByteString']], 'Bool', ['PosLen'], [['PosLen']]+ * out: - 'match' covers all result types+ * ['String'], [['String']]+ * ['ByteString'], [['ByteString']]+ * 'Bool'+ * ['PosLen'], [['PosLen']] - compiler looks up the appropriate function depending on the result type - '=~' is borrowed from "Text.Regex.PCRE.Wrap",- is a short version of 'match'- precompiled Regex may be used as pattern too. see "Text.Regex.Do.Pcre.Utf8.Match" - See also "Text.Regex.Do.Pcre.Ascii.MatchHint" -}+ See also "Text.Regex.Do.Pcre.Ascii.MatchHint" + to catch regex construction __errors__, precompile 'Regex' with 'makeRegexM' or 'makeRegexOptM' -}+ class Match a b out where match::Pattern a -> Body b -> out --- | synonym for 'match'. arg without newtypes-(=~)::Match a b out =>- a -- ^ pattern- -> b -- ^ body- -> out-(=~) p0 b0 = match (Pattern p0) (Body b0) -- | match once@@ -56,16 +62,16 @@ match p0 (Body b0) = R.matchTest (makeRegex p0) b0 {- ^ test - >>> "в" =~ "тихо в лесу"::Bool+ >>> "chilly" =~ "it's chilly inside, chilly outside"::Bool True -} -- | match all instance Rx_ a b => Match a b [[b]] where match p0 = F.all (makeRegex' p0)-{- ^ >>> "well" =~ "all is well that ends well"::[[ByteString]]+{- ^ >>> "chilly" =~ "it's chilly inside, chilly outside"::[[ByteString]] - \[["well"\],\["well"\]] -}+ \[["chilly"\],\["chilly"\]] -} -- | match once instance Rx_ a b => Match a b [PosLen] where
src/Text/Regex/Do/Pcre/Ascii/MatchHint.hs view
@@ -3,15 +3,24 @@ this module is similar to "Text.Regex.Do.Pcre.Ascii.Match". The differences are: - "Text.Regex.Do.Pcre.Ascii.Match" is more flexible:+ * "Text.Regex.Do.Pcre.Ascii.Match" is more flexible:+ accepts 'Pattern' Regex,+ accepts 'Pattern' and 'Body' of different types - "Text.Regex.Do.Pcre.Ascii.Match" needs to infer result type+ * "Text.Regex.Do.Pcre.Ascii.Match" needs to infer result type - in this module the result type is determined by the hint- -}+ this module: + * 'Pattern' and 'Body' are of the same type++ * 'Hint' and inferrable 'Pattern' or 'Body' type determine the instance++ the result type is determined by the hint++ * handy when working with 'OverloadedStrings', in other cases when compiler needs a hint -}+ module Text.Regex.Do.Pcre.Ascii.MatchHint where import Text.Regex.Do.Type.Do hiding (Once,All)@@ -23,13 +32,7 @@ {- | * hint: 'Once', 'All', 'Test', 'PosLen'', 'PosLen_' * a: 'String', 'ByteString'-- picks 'M.Match' instance where 'Pattern' and 'Body' are of the same type-- 'Hint' and inferrable 'Pattern' or 'Body' type determine the instance-- handy when working with 'OverloadedStrings', in other cases when compiler needs a hint -}-+-} class (Hint hint, M.Match a a (F hint a)) =>
src/Text/Regex/Do/Pcre/Ascii/Replace.hs view
@@ -25,6 +25,8 @@ * ('All' | 'Once' (a)) * ('All' | 'Once' ('Pattern' a)) + to catch regex construction __errors__, precompile 'Regex' with 'makeRegexM' or 'makeRegexOptM'+ * repl: b: 'String' | 'ByteString' * ('Replacement' b)
src/Text/Regex/Do/Pcre/Utf8/Match.hs view
@@ -24,20 +24,30 @@ import Data.ByteString -{- | * enc: 'Utf8_'- * a: 'String', 'ByteString', 'Regex'- * b: 'String', 'ByteString'- * out: ['String'], [['String']], ['ByteString'], [['ByteString']], 'Bool', ['PosLen'], [['PosLen']]- -}-class Match enc a b out where- match::Pattern (enc a) -> Body (enc b) -> out- -- | synonym for 'match'. arg without newtypes (=~)::Match Utf8_ a b out => a -- ^ pattern -> b -- ^ body -> out (=~) p0 b0 = match (Pattern $ Utf8_ p0) (Body $ Utf8_ b0)++++{- | * enc: 'Utf8_'+ * a: 'String', 'ByteString', 'Regex'++ to catch regex construction __errors__, precompile 'Regex' with 'makeRegexM' or 'makeRegexOptM'++ * b: 'String', 'ByteString'+ * out:++ * ['String'], [['String']]+ * ['ByteString'], [['ByteString']]+ * 'Bool'+ * ['PosLen'], [['PosLen']] -}++class Match enc a b out where+ match::Pattern (enc a) -> Body (enc b) -> out {- | match once
src/Text/Regex/Do/Pcre/Utf8/MatchHint.hs view
@@ -15,12 +15,8 @@ {- | * hint: 'Once', 'All', 'Test', 'PosLen'', 'PosLen_' * a: 'String', 'ByteString' * enc: 'Utf8_'-- picks 'M.Match' instance where 'Pattern' and 'Body' are of the same type-- 'Hint' and inferrable 'Pattern' or 'Body' type determine the instance+-} - handy when working with 'OverloadedStrings', in other cases when compiler needs a hint -} class (Hint hint, M.Match enc a a (F hint a)) => MatchHint hint enc a where type F hint a
src/Text/Regex/Do/Pcre/Utf8/Replace.hs view
@@ -20,6 +20,8 @@ {- | see "Text.Regex.Do.Pcre.Ascii.Replace" for implemented types + to catch regex construction __errors__, precompile 'Regex' with 'makeRegexM' or 'makeRegexOptM'+ in full typed instance every b is wrapped in 'Utf8_' newtype 'GroupReplacer' is implemented only for 'ByteString' -}
src/Text/Regex/Do/Type/Regex.hs view
@@ -2,6 +2,7 @@ (Regex(..), makeRegex', makeRegexOpt',+ RegexResult(..), Rx_, Opt_, Ro_) where import qualified Text.Regex.Base.RegexLike as R@@ -13,9 +14,34 @@ class Regex a where makeRegex::Pattern a -> R.Regex+ makeRegexM::Monad m => Pattern a -> m R.Regex makeRegexOpt::Pattern a -> [Comp] -> [Exec] -> R.Regex+ makeRegexOptM::Monad m => Pattern a -> [Comp] -> [Exec] -> m R.Regex +{- ^ monadic + * 'makeRegexM'+ * 'makeRegexOptM'++ let catch regex construction errors++ for 'm' to catch errors, implement 'fail' in 'm'++ default 'm' implementation: 'RegexResult'++ ==== makeRegexM test case:++ >>> it "RegexResult test case" $ do+ rx1 `shouldNotSatisfy` isok1+ rx2 `shouldSatisfy` isok1+ where rx1 = T.makeRegexM $ Pattern "[["::RegexResult R.Regex+ rx2 = T.makeRegexM $ Pattern "."::RegexResult R.Regex+ isok1 (RegexResult (Left e1)) = traceShow e1 False+ isok1 _ = True++ >>> instance Show (RegexResult R.Regex) where+ show _ = "bon" -}+ makeRegex'::Regex a => Pattern a -> Pattern R.Regex makeRegex' = Pattern . makeRegex @@ -26,22 +52,30 @@ instance Regex a => Regex (Utf8_ a) where makeRegex p0 = makeRegexOpt (Pattern val <*> p0) [Utf8] []+ makeRegexM p0 = makeRegexOptM (Pattern val <*> p0) [Utf8] [] makeRegexOpt p0 c0 e0 = makeRegexOpt (Pattern val <*> p0) (Utf8:c0) e0+ makeRegexOptM p0 c0 e0 = makeRegexOptM (Pattern val <*> p0) (Utf8:c0) e0 instance Regex ByteString where makeRegex (Pattern p0) = R.makeRegex p0+ makeRegexM (Pattern p0) = R.makeRegexM p0 makeRegexOpt = makeRegexOpts+ makeRegexOptM = makeRegexOptsM instance Regex String where makeRegex (Pattern p0) = R.makeRegex p0+ makeRegexM (Pattern p0) = R.makeRegexM p0 makeRegexOpt = makeRegexOpts+ makeRegexOptM = makeRegexOptsM instance Regex R.Regex where makeRegex (Pattern p0) = p0+ makeRegexM (Pattern p0) = pure p0 makeRegexOpt (Pattern p0) _ _ = p0+ makeRegexOptM (Pattern p0) _ _ = pure p0 -- | tweak Regex with options@@ -55,6 +89,33 @@ rx1 = R.makeRegexOpts c1 e1 pat0 +makeRegexOptsM::(Monad m, Opt_ a) =>+ Pattern a ->+ [Comp] -> [Exec] ->+ m R.Regex+makeRegexOptsM (Pattern pat0) comp0 exec0 = rx1+ where c1 = comp comp0+ e1 = exec exec0+ rx1 = R.makeRegexOptsM c1 e1 pat0+++ type Rx_ a b = (Regex a, R.Extract b, R.RegexLike R.Regex b) type Opt_ a = R.RegexMaker R.Regex R.CompOption R.ExecOption a type Ro_ rx = (Regex rx, Opt_ rx)+++{- | catches regex construction __errors__ -}+newtype RegexResult a = RegexResult (Either [String] a) deriving (Functor)++instance Applicative RegexResult where+ pure = RegexResult . Right+ (<*>) (RegexResult (Left e1)) (RegexResult (Left e2)) = RegexResult $ Left $ e1 ++ e2+ (<*>) (RegexResult (Right fn0)) (RegexResult (Left e1)) = RegexResult $ Left e1+ (<*>) (RegexResult (Left e1)) (RegexResult (Right r1)) = RegexResult $ Left e1+ (<*>) (RegexResult (Right fn0)) (RegexResult (Right a0)) = pure $ fn0 a0++instance Monad RegexResult where+ (>>=) (RegexResult (Left e1)) fn0 = RegexResult $ Left e1+ (>>=) (RegexResult (Right a0)) fn0 = fn0 a0+ fail s0 = RegexResult $ Left [s0]
test/Main.hs view
@@ -7,7 +7,7 @@ import qualified TestRegex.TestReplaceOpen as O import qualified TestRegex.TestSplit as S import qualified TestRegex.TestTrim as T-+import qualified TestRegex.TestMakeRegexM as E main::IO() main = do@@ -18,3 +18,4 @@ O.main R.main U.main+ E.main
+ test/TestRegex/TestMakeRegexM.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE NoOverloadedStrings #-}+module TestRegex.TestMakeRegexM where++import Test.Hspec+import Text.Regex.Do.Type.Reexport as R+import Text.Regex.Do.Type.Regex as T+import Text.Regex.Do.Type.Do as T+import Debug.Trace+++main::IO()+main = hspec $ do+ describe "TestRegex.TestMakeRegexM" $ do+ it "RegexResult test case" $ do+ rx1 `shouldNotSatisfy` isok1+ rx2 `shouldSatisfy` isok1+ where rx1 = T.makeRegexM $ Pattern "[["::RegexResult R.Regex+ rx2 = T.makeRegexM $ Pattern "."::RegexResult R.Regex++ isok1 (RegexResult (Left e1)) = traceShow e1 False+ isok1 _ = True+++instance Show (RegexResult R.Regex) where+ show _ = "rx"
test/TestRegex/TestPcre.hs view
@@ -23,10 +23,11 @@ it " cd " $ S.match (PosLen' $ Pattern ("^cd"::String)) (Body "abcde") `shouldBe` [] it " ab " $ S.match (Test $ Pattern ("^ab"::String)) (Body "abc") `shouldBe` True it "doc 1" $ Test ("в"::ByteString) S.=~ "тихо в лесу" `shouldBe` True- it "doc 1" $ Test (toByteString "в") Su.=~ toByteString "тихо в лесу" `shouldBe` True+ it "doc 1.2" $ Test ("chilly"::ByteString) S.=~ "it's chilly inside, chilly outside" `shouldBe` True+ it "doc 1.3" $ Test (toByteString "в") Su.=~ toByteString "тихо в лесу" `shouldBe` True it "doc 2" $ S.Once ("^all"::String) S.=~ "all the time" `shouldBe` ["all"] it "doc 3" $ S.Once ("^all"::ByteString) S.=~ "all the time" `shouldBe` ["all"]- it "doc 4" $ S.All ("well"::ByteString) S.=~ "all is well that ends well" `shouldBe` ([["well"],["well"]])+ it "doc 4" $ S.All ("chilly"::ByteString) S.=~ "it's chilly inside, chilly outside" `shouldBe` ([["chilly"],["chilly"]]) it "doc 5" $ PosLen' ("и"::String) S.=~ "бывает и хуже" `shouldBe` [(13,2)] it "doc 6" $ PosLen' ("à"::String) S.=~ "tourner à gauche" `shouldBe` [(8,2)] it "doc 7" $ do