{-# LANGUAGE CPP #-} -------------------------------------------------- {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE DeriveFunctor , DeriveFoldable , DeriveTraversable , DeriveGeneric , DeriveAnyClass #-} -------------------------------------------------- -------------------------------------------------- {-| "Enrich" some standard functions. In particular: * wrap some over-broad types in @newtype@s; * perform additional validation. -} module Prelude.Spiros.Enriched where #include <sboo-base-feature-macros.h> -------------------------------------------------- -------------------------------------------------- import qualified "text" Data.Text as Strict import qualified "text" Data.Text.Lazy as Lazy -------------------------------------------------- -- import "base" _ -------------------------------------------------- import Prelude.Spiros.Reexports -------------------------------------------------- -------------------------------------------------- {-| Intended Specializations: * @'Replace' 'Strict.Text'@ * @'Replace' 'Lazy.Text'@ -} data Replace a = Replace { old :: !a , new :: !a } deriving ( Show,Read,Eq,Ord,Generic --TODO CPP for Generic #if HAS_EXTENSION_DeriveFunctor , Functor,Foldable,Traversable #endif #if HAS_EXTENSION_DeriveAnyClass , NFData, Hashable #endif #if HAS_EXTENSION_DerivingLift , Lift #endif ) -- deriving stock (Show,Read,Eq,Ord,Lift,Generic) -- deriving anyclass (NFData,Hashable) -------------------------------------------------- {-| Ensure that 'Replace.old' is nonempty. -} checkReplace :: (IsString t, Eq t) => Replace t -> Maybe (Replace t) checkReplace x@Replace{old} = if old == "" then Nothing else Just x -------------------------------------------------- -------------------------------------------------- {-| =(Original Documention...) /O(m+n)/ Replace every non-overlapping occurrence of @needle@ (a.k.a. @'Replace.old'@) in @haystack@ with @replacement@ (a.k.a. @'Replace.new'@). This function behaves as though it was defined as follows: @ replace_StrictText Replace{old,new} haystack = 'Strict.intercalate' new ('Strict.splitOn' needle haystack) @ As this suggests, each occurrence is replaced exactly once. So if @needle@ occurs in @replacement@, that occurrence will /not/ itself be replaced recursively: >>> replace_StrictText Replace{ old = "oo", new = "foo" } "oo" "foo" In cases where several instances of @needle@ overlap, only the first one will be replaced: >>> replace_StrictText Replace{ old = "ofo", new = "bar" } "ofofo" "barfo" =(Additional Documention...) this function has two differences from the function it wraps: * the "enriched" argument record 'Replace', done for clarity of argument order. * the behavior when @'Replace.new'@ (i.e. @needle@), is empty (i.e. @""@), which simply outputs the input unchanged, rather than erroring. i.e. >>> replace_StrictText Replace{ old = "", new = "anything" } "unchanged" "unchanged" You can use (the trivial) 'checkReplace'. -} replace_StrictText :: Replace Strict.Text -> Strict.Text -> Strict.Text replace_StrictText Replace{old = ""} t = t replace_StrictText Replace{old, new} t = Strict.replace old new t -------------------------------------------------- {-| Alias for 'replace_StrictText'. (See 'replace_StrictText' for documentation). -} replace :: Replace Strict.Text -> Strict.Text -> Strict.Text replace = replace_StrictText -------------------------------------------------- {-| Lazy analogue to 'replace_StrictText'. (See 'replace_StrictText' for documentation). -} replace_LazyText :: Replace Lazy.Text -> Lazy.Text -> Lazy.Text replace_LazyText Replace{old = ""} t = t replace_LazyText Replace{old, new} t = Lazy.replace old new t -------------------------------------------------- -------------------------------------------------- {-| -} -------------------------------------------------- --------------------------------------------------