semver 0.1.2 → 0.2.0
raw patch · 3 files changed
+114/−57 lines, 3 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
- Data.SemVer: Delimiters :: !Char -> !Char -> !Char -> !Char -> !Char -> Delimiters
- Data.SemVer: INum :: !Int -> Identifier
- Data.SemVer: IText :: !Text -> Identifier
- Data.SemVer: Version :: !Int -> !Int -> !Int -> [Identifier] -> [Identifier] -> Version
- Data.SemVer: _delimIdent :: Delimiters -> !Char
- Data.SemVer: _delimMeta :: Delimiters -> !Char
- Data.SemVer: _delimMinor :: Delimiters -> !Char
- Data.SemVer: _delimPatch :: Delimiters -> !Char
- Data.SemVer: _delimRelease :: Delimiters -> !Char
- Data.SemVer: _versionMajor :: Version -> !Int
- Data.SemVer: _versionMeta :: Version -> [Identifier]
- Data.SemVer: _versionMinor :: Version -> !Int
- Data.SemVer: _versionPatch :: Version -> !Int
- Data.SemVer: _versionRelease :: Version -> [Identifier]
- Data.SemVer: defaultDelimiters :: Delimiters
- Data.SemVer: defaultVersion :: Version
- Data.SemVer: instance Constructor C1_0Delimiters
- Data.SemVer: instance Constructor C1_0Identifier
- Data.SemVer: instance Constructor C1_0Version
- Data.SemVer: instance Constructor C1_1Identifier
- Data.SemVer: instance Datatype D1Delimiters
- Data.SemVer: instance Datatype D1Identifier
- Data.SemVer: instance Datatype D1Version
- Data.SemVer: instance Generic Delimiters
- Data.SemVer: instance Generic Identifier
- Data.SemVer: instance Generic Version
- Data.SemVer: instance Read Delimiters
- Data.SemVer: instance Read Identifier
- Data.SemVer: instance Read Version
- Data.SemVer: instance Selector S1_0_0Delimiters
- Data.SemVer: instance Selector S1_0_0Version
- Data.SemVer: instance Selector S1_0_1Delimiters
- Data.SemVer: instance Selector S1_0_1Version
- Data.SemVer: instance Selector S1_0_2Delimiters
- Data.SemVer: instance Selector S1_0_2Version
- Data.SemVer: instance Selector S1_0_3Delimiters
- Data.SemVer: instance Selector S1_0_3Version
- Data.SemVer: instance Selector S1_0_4Delimiters
- Data.SemVer: instance Selector S1_0_4Version
- Data.SemVer: instance Typeable Delimiters
- Data.SemVer: instance Typeable Identifier
- Data.SemVer: instance Typeable Version
+ Data.SemVer: _Numeric :: Applicative f => (Int -> f Int) -> Identifier -> f Identifier
+ Data.SemVer: _Textual :: Applicative f => (Text -> f Text) -> Identifier -> f Identifier
+ Data.SemVer: delimiters :: Delimiters
+ Data.SemVer: initial :: Version
+ Data.SemVer: numeric :: Int -> Identifier
+ Data.SemVer: textual :: Text -> Maybe Identifier
+ Data.SemVer: version :: Int -> Int -> Int -> [Identifier] -> [Identifier] -> Version
Files
- semver.cabal +1/−1
- src/Data/SemVer.hs +112/−55
- test/Main.hs +1/−1
semver.cabal view
@@ -1,5 +1,5 @@ name: semver-version: 0.1.2+version: 0.2.0 synopsis: Representation, manipulation, and de/serialisation of Semantic Versions. homepage: https://github.com/brendanhay/semver license: OtherLicense
src/Data/SemVer.hs view
@@ -1,7 +1,5 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} -- Module : Data.SemVer -- Copyright : (c) 2014 Brendan Hay <brendan.g.hay@gmail.com>@@ -17,56 +15,62 @@ -- <http://semver.org>. -- -- A canonical 'Version' type and functions representing behaviour as outlined--- in the specification are defined alongside additional lenses,+-- in the specification are defined alongside additional lenses, traversals, -- common manipulations, and serialisation primitives. module Data.SemVer ( -- * Version- Identifier (..)- , Version (..)- , defaultVersion-+ Version+ -- ** Constructors+ , version+ , initial -- ** Lenses+ -- $lenses , versionMajor , versionMinor , versionPatch , versionRelease , versionMeta- -- ** Incrementing+ -- $incrementing , incrementMajor , incrementMinor , incrementPatch- -- ** Predicates , isDevelopment , isPublic- -- ** Encoding , toString , toText , toLazyText , toBuilder- -- ** Decoding , fromText , fromLazyText , parser - -- * Delimiters- , Delimiters (..)- , defaultDelimiters+ -- * Identifiers+ , Identifier+ -- ** Constructors+ , numeric+ , textual+ -- ** Prisms+ , _Numeric+ , _Textual + -- * Delimiters+ -- $delimiters+ , Delimiters+ -- ** Constructor+ , delimiters -- ** Lenses , delimMinor , delimPatch , delimRelease , delimMeta , delimIdent- -- ** Encoding , toDelimitedBuilder- -- ** Decoding , delimitedParser ) where@@ -85,8 +89,6 @@ import Data.Text.Lazy.Builder (Builder) import qualified Data.Text.Lazy.Builder as Build import qualified Data.Text.Lazy.Builder.Int as Build-import Data.Typeable (Typeable)-import GHC.Generics import Prelude hiding (takeWhile) -- | A type representing an individual identifier from the release@@ -95,11 +97,35 @@ -- * The 'Ord' instance implements precedence according to the semantic version -- specification, with numeric identifiers being of /lower/ precedence than -- textual identifiers, otherwise lexicographic ordering is used.+--+-- The functions 'numeric' and 'textual' can be used to construct an 'Identifier'. data Identifier = INum !Int | IText !Text- deriving (Eq, Read, Show, Generic, Typeable)+ deriving (Eq, Show) +-- | Safely construct a numeric identifier.+numeric :: Int -> Identifier+numeric = INum+{-# INLINE numeric #-}++-- | Construct an identifier from the given 'Text', returning 'Nothing' if+-- neither a numeric or valid textual input is supplied.+textual :: Text -> Maybe Identifier+textual = either (const Nothing) Just+ . parseOnly (identifierParser endOfInput <* endOfInput)+{-# INLINE textual #-}++_Numeric :: Applicative f => (Int -> f Int) -> Identifier -> f Identifier+_Numeric f (INum x) = INum <$> f x+_Numeric _ x = pure x+{-# INLINE _Numeric #-}++_Textual :: Applicative f => (Text -> f Text) -> Identifier -> f Identifier+_Textual f (IText x) = IText <$> f x+_Textual _ x = pure x+{-# INLINE _Textual #-}+ instance Ord Identifier where compare a b = case (a, b) of (INum x, INum y) -> x `compare` y@@ -111,31 +137,38 @@ rnf (INum n) = rnf n rnf (IText t) = rnf t --- | A type representing a successfully decoded or constructed semantic version.+-- | An opaque type representing a successfully decoded or constructed+-- semantic version. See the related functions and lenses for modification and+-- update. -- -- * The 'Eq' instance represents exhaustive equality with all -- components considered. -- -- * The 'Ord' instance implements the precedence rules from the semantic--- version specification with metadata ('_versionMeta') being ignored.+-- version specification with metadata being ignored. data Version = Version { _versionMajor :: !Int- -- ^ The major version component. , _versionMinor :: !Int- -- ^ The minor version component. , _versionPatch :: !Int- -- ^ The patch level component. , _versionRelease :: [Identifier]- -- ^ A (potentially empty) list of release identifiers. , _versionMeta :: [Identifier]- -- ^ A (potentially empty) list of metadata.- } deriving (Eq, Read, Show, Generic, Typeable)+ } deriving (Eq, Show) +-- | Smart constructor fully specifying all available version components.+version :: Int -- ^ Major version component.+ -> Int -- ^ Minor version component.+ -> Int -- ^ Patch version component.+ -> [Identifier] -- ^ Release identifiers.+ -> [Identifier] -- ^ Metadata identifiers.+ -> Version+version = Version+{-# INLINE version #-}+ -- | A default 'Version' which can be used to signify initial development. -- -- Note: Equivalent to @0.0.0@-defaultVersion :: Version-defaultVersion = Version 0 0 0 [] []+initial :: Version+initial = version 0 0 0 [] [] instance Ord Version where compare a b = on compare versions a b <> on compare _versionRelease a b@@ -154,18 +187,27 @@ `seq` rnf _versionRelease `seq` rnf _versionMeta +-- $lenses+--+-- Something about using lenses to construct versions and increments to update+-- the version components due to the modification of all version according to spec++-- | Lens for the major version component. versionMajor :: Functor f => (Int -> f Int) -> Version -> f Version versionMajor f x = (\y -> x { _versionMajor = y }) <$> f (_versionMajor x) {-# INLINE versionMajor #-} +-- | Lens for minor version component. versionMinor :: Functor f => (Int -> f Int) -> Version -> f Version versionMinor f x = (\y -> x { _versionMinor = y }) <$> f (_versionMinor x) {-# INLINE versionMinor #-} +-- | Lens for the patch version component. versionPatch :: Functor f => (Int -> f Int) -> Version -> f Version versionPatch f x = (\y -> x { _versionPatch = y }) <$> f (_versionPatch x) {-# INLINE versionPatch #-} +-- | Lens for the list of release identifiers. versionRelease :: Functor f => ([Identifier] -> f [Identifier]) -> Version@@ -173,6 +215,7 @@ versionRelease f x = (\y -> x { _versionRelease = y }) <$> f (_versionRelease x) {-# INLINE versionRelease #-} +-- | Lens for the list of metadata identifiers. versionMeta :: Functor f => ([Identifier] -> f [Identifier]) -> Version@@ -180,15 +223,18 @@ versionMeta f x = (\y -> x { _versionMeta = y }) <$> f (_versionMeta x) {-# INLINE versionMeta #-} --- | A set of delimiters used to encode/decode a 'Version' and specifyc+-- $delimiters+--+-- A set of delimiters is used to encode/decode a 'Version' and specify -- alternative serialisation strategies. ----- Example: using alpha characters to encode the version as a valid--- DNS CNAME, such as:+-- Lenses can be used to modify the default delimiter set, as in the following+-- example - using alpha characters to encode the version as a valid+-- DNS CNAME: -- -- @ -- let Right v = fromText "1.2.3+40"--- let alpha = Delimiters \'m\' \'p\' \'r\' \'d\' \'i\'+-- let alpha = delimiters & delimMajor .= \'m\' & delimPatch .= \'p\' & delimRelease .= \'r\' & delimMeta .= \'d\' & delimIdent .= \'i\' -- -- Data.Text.Lazy.Builder.toLazyText (\"app01-\" <> toDelimitedBuilder alpha v <> \".dmz.internal\") -- @@@ -201,13 +247,16 @@ -- -- Using the same 'Delimiters' set with 'delimitedParser' would ensure -- correct decoding behaviour.++-- | An opaque set representing the seperators used to delimit semantic+-- version components. data Delimiters = Delimiters { _delimMinor :: !Char , _delimPatch :: !Char , _delimRelease :: !Char , _delimMeta :: !Char , _delimIdent :: !Char- } deriving (Eq, Ord, Read, Show, Generic, Typeable)+ } deriving (Eq, Ord, Show) -- | The default set of delimiters used in the semantic version specification. --@@ -217,8 +266,8 @@ -- @ -- 1.2.3-alpha.1+sha.exp.12ab3d9 -- @-defaultDelimiters :: Delimiters-defaultDelimiters = Delimiters+delimiters :: Delimiters+delimiters = Delimiters { _delimMinor = '.' , _delimPatch = '.' , _delimRelease = '-'@@ -234,26 +283,36 @@ `seq` rnf _delimMeta `seq` rnf _delimIdent +-- | Lens for the minor version delimiter. Default: @.@ delimMinor :: Functor f => (Char -> f Char) -> Delimiters -> f Delimiters delimMinor f x = (\y -> x { _delimMinor = y }) <$> f (_delimMinor x) {-# INLINE delimMinor #-} +-- | Lens for the patch version delimiter. Default: @.@ delimPatch :: Functor f => (Char -> f Char) -> Delimiters -> f Delimiters delimPatch f x = (\y -> x { _delimPatch = y }) <$> f (_delimPatch x) {-# INLINE delimPatch #-} +-- | Lens for the release component delimiter. Default: @-@ delimRelease :: Functor f => (Char -> f Char) -> Delimiters -> f Delimiters delimRelease f x = (\y -> x { _delimRelease = y }) <$> f (_delimRelease x) {-# INLINE delimRelease #-} +-- | Lens for the metadata component delimiter. Default: @+@ delimMeta :: Functor f => (Char -> f Char) -> Delimiters -> f Delimiters delimMeta f x = (\y -> x { _delimMeta = y }) <$> f (_delimMeta x) {-# INLINE delimMeta #-} +-- | Lens for the individual identifier delimiter. Default: @.@ delimIdent :: Functor f => (Char -> f Char) -> Delimiters -> f Delimiters delimIdent f x = (\y -> x { _delimIdent = y }) <$> f (_delimIdent x) {-# INLINE delimIdent #-} +-- $increments+--+-- Mention the usage of increments to correctly adjust version components+-- according to spec.+ -- | Increment the major component of a 'Version' by 1, resetting the minor -- and patch components. --@@ -326,7 +385,7 @@ -- Note: This is optimised for cases where you wish to use a 'String' and -- as such is faster than the semantically equivalent @unpack . toLazyText@. toString :: Version -> String-toString = toMonoid (:[]) show Text.unpack defaultDelimiters+toString = toMonoid (:[]) show Text.unpack delimiters -- | Convert a 'Version' to a strict 'Text' representation. --@@ -345,7 +404,7 @@ -- | Convert a 'Version' to a 'Builder'. toBuilder :: Version -> Builder-toBuilder = toDelimitedBuilder defaultDelimiters+toBuilder = toDelimitedBuilder delimiters -- | Convert a 'Version' to a 'Builder' using the specified 'Delimiters' set. toDelimitedBuilder :: Delimiters -> Version -> Builder@@ -390,7 +449,7 @@ -- | A greedy attoparsec 'Parser' which requires the entire 'Text' input to match. parser :: Parser Version-parser = delimitedParser defaultDelimiters+parser = delimitedParser delimiters -- | A greedy attoparsec 'Parser' using the specified 'Delimiters' set -- which requires the entire 'Text' input to match.@@ -403,20 +462,18 @@ <*> option [] (try (char _delimMeta) *> identifiers) <* endOfInput where- nonNegative :: (Show a, Integral a) => Parser a- nonNegative = do- n <- decimal- when (n < 0) $- fail ("Numeric value must be non-negative: " ++ show n)- return n- identifiers :: Parser [Identifier]- identifiers = many (num <|> text)+ identifiers = many (identifierParser $ void (char _delimIdent)) - num = INum- <$> nonNegative- <* (void (char _delimIdent) <|> endOfInput)+identifierParser :: Parser () -> Parser Identifier+identifierParser end = num <|> text+ where+ num = INum <$> nonNegative <* (end <|> endOfInput)+ text = IText <$> takeWhile1 (inClass "0-9A-Za-z-") <* optional end - text = IText- <$> takeWhile1 (inClass "0-9A-Za-z-")- <* optional (char _delimIdent)+nonNegative :: (Show a, Integral a) => Parser a+nonNegative = do+ n <- decimal+ when (n < 0) $+ fail ("Numeric value must be non-negative: " ++ show n)+ return n
test/Main.hs view
@@ -59,7 +59,7 @@ sv000, sv100, sv100alpha, sv100alpha1, sv101 :: Version sv110, sv200, sv123sha2ac, sv123beta1shaexpdc2 :: Version-sv000 = defaultVersion+sv000 = initial sv100 = sv "1.0.0" sv100alpha = sv "1.0.0-alpha" sv100alpha1 = sv "1.0.0-alpha.1"