packages feed

css-selectors 0.3.0.0 → 0.4.0.0

raw patch · 6 files changed

+83/−25 lines, 6 filesdep +hashable

Dependencies added: hashable

Files

CHANGELOG.md view
@@ -2,6 +2,10 @@  For a full list of changes, see the history on [GitHub](https://github.com/hapytex/css-selectors). +## Version 0.4.0.0++All css items are now a member of the `Generic` and the `Hashable` typeclass.+ ## Version 0.3.0.0  The css items are now an instance of `Binary` and can be serialized and deserialized; and compressed. One
README.md view
@@ -129,17 +129,21 @@ is often useful, since javascript itself has no syntax for css selectors, and often strings are used to represent these. -## `Binary` instances--The css-elements are all a member of the `Binary` typeclass, that converts the-css selector to a compact binary format. This is *not* standard format. This is-more to write a css-selector to a binary format and back.- ## `Arbitrary` css selectors  One can generate arbitrary CSS selectors (and their subcomponents). It is however not advisable to use this for anything other than for validation purposes (like with `QuickCheck`).++## `Binary` and `Hashable` instances++The css-elements are all members of the `Binary` and `Hashable` typeclasses,+The `Binary` typeclass converts the css selector to a compact binary format.+This is *not* standard format. This is more to write a css-selector to a+binary format and back.++css-elements are an instance of `Hashable` as well, for example to use as+keys in a `HashMap`.  ## `css-selectors` is not *safe* Haskell 
css-selectors.cabal view
@@ -1,5 +1,5 @@ name:                css-selectors-version:             0.3.0.0+version:             0.4.0.0 synopsis:            Parsing, rendering and manipulating css selectors in Haskell. description:   A library for parsing, manipulating, and rendering css selectors (not css files,@@ -48,6 +48,7 @@     , bytestring >=0.9     , data-default >=0.7 && <0.8     , Decimal >=0.5.1 && <0.5.2+    , hashable >=1.2.7.0     , QuickCheck >=2.13 && <2.14     , shakespeare >=2.0 && <3.0     , template-haskell >=2.12.0 && <2.16.0@@ -66,6 +67,7 @@       base     , binary >=0.2 && <0.8.8.0     , css-selectors+    , hashable >=1.2.7.0     , text     , test-framework     , test-framework-quickcheck2
src/Css3/Selector/Core.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveDataTypeable, OverloadedStrings, PatternSynonyms, TemplateHaskellQuotes, TypeFamilies #-}+{-# LANGUAGE DeriveDataTypeable, DeriveGeneric, OverloadedStrings, PatternSynonyms, TemplateHaskellQuotes, TypeFamilies #-}  {-| Module      : Css3.Selector.Core@@ -52,6 +52,7 @@ import Data.Data(Data) import Data.Default(Default(def)) import Data.Function(on)+import Data.Hashable(Hashable) import Data.List(sort, unfoldr) import Data.List.NonEmpty(NonEmpty((:|))) import qualified Data.List.NonEmpty@@ -61,6 +62,7 @@ import Data.Text(Text, cons, inits, intercalate, pack, tails, unpack)  import GHC.Exts(IsList(Item, fromList, toList))+import GHC.Generics(Generic)  import Language.Haskell.TH.Lib(appE, conE) import Language.Haskell.TH.Syntax(Lift(lift), Exp(AppE, ConE, LitE), Lit(StringL), Name, Pat(ConP, ListP, ViewP), Q)@@ -77,10 +79,12 @@ -- -- The specificity is calculated with @100*a+10*b+c@ where @a@, @b@ and @c@ -- count certain elements of the css selector.-data SelectorSpecificity =-      SelectorSpecificity Int Int Int -- ^ Create a 'SelectorSpecificity' object with a given value for @a@, @b@, and @c@.-    deriving (Data, Show)+data SelectorSpecificity+    = SelectorSpecificity Int Int Int -- ^ Create a 'SelectorSpecificity' object with a given value for @a@, @b@, and @c@.+    deriving (Data, Generic, Show) +instance Hashable SelectorSpecificity+ -- | Calculate the specificity value of the 'SelectorSpecificity' specificityValue :: SelectorSpecificity -- ^ The 'SelectorSpecificity' to calculate the specificity value from.     -> Int  -- ^ The specificity level of the 'SelectorSpecificity'. If the value is higher, the rules in the css selector take precedence.@@ -152,24 +156,30 @@ -- selectors. newtype SelectorGroup = SelectorGroup {     unSelectorGroup :: NonEmpty Selector -- ^ Unwrap the given 'NonEmpty' list of 'Selector's from the 'SelectorGroup' object.-  } deriving (Data, Eq, Ord, Show)+  } deriving (Data, Eq, Generic, Ord, Show) +instance Hashable SelectorGroup+ -- | The type of a single selector. This is a sequence of 'SelectorSequence's that -- are combined with a 'SelectorCombinator'. data Selector =       Selector SelectorSequence -- ^ Convert a given 'SelectorSequence' to a 'Selector'.     | Combined SelectorSequence SelectorCombinator Selector -- ^ Create a combined selector where we have a 'SelectorSequence' that is combined with a given 'SelectorCombinator' to a 'Selector'.-    deriving (Data, Eq, Ord, Show)+    deriving (Data, Eq, Generic, Ord, Show) +instance Hashable Selector + -- | A type that contains the possible ways to combine 'SelectorSequence's. data SelectorCombinator =       Descendant -- ^ The second tag is a descendant of the first one, denoted in css with a space.     | Child -- ^ The second tag is the (direct) child of the first one, denoted with a @>@ in css.     | DirectlyPreceded -- ^ The second tag is directly preceded by the first one, denoted with a @+@ in css.     | Preceded -- ^ The second tag is preceded by the first one, denoted with a @~@ in css.-    deriving (Bounded, Data, Enum, Eq, Ord, Read, Show)+    deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show) +instance Hashable SelectorCombinator+ -- | Convert the 'SelectorCombinator' to the equivalent css selector text. A -- space for 'Descendant', a @>@ for 'Child', a @+@ for 'DirectlyPreceded', and -- a @~@ for 'Preceded'@@ -213,8 +223,10 @@ data SelectorSequence =       SimpleSelector TypeSelector -- ^ Convert a 'TypeSelector' into a 'SimpleSelector'.     | Filter SelectorSequence SelectorFilter -- ^ Apply an additional 'SelectorFilter' to the 'SelectorSequence'.-    deriving (Data, Eq, Ord, Show)+    deriving (Data, Eq, Generic, Ord, Show) +instance Hashable SelectorSequence+ -- | Add a given list of 'SelectorFilter's to the given 'SelectorSequence'. The -- filters are applied left-to-right. addFilters :: SelectorSequence -- ^ The 'SelectorSequence' to apply the filter on.@@ -248,16 +260,20 @@       SHash Hash -- ^ A 'Hash' object as filter.     | SClass Class -- ^ A 'Class' object as filter.     | SAttrib Attrib -- ^ An 'Attrib' object as filter.-    deriving (Data, Eq, Ord, Show)+    deriving (Data, Eq, Generic, Ord, Show) +instance Hashable SelectorFilter+ -- | A css attribute can come in two flavors: either a constraint that the -- attribute should exists, or a constraint that a certain attribute should have -- a certain value (prefix, suffix, etc.). data Attrib =       Exist AttributeName -- ^ A constraint that the given 'AttributeName' should exist.     | Attrib AttributeName AttributeCombinator AttributeValue -- ^ A constraint about the value associated with the given 'AttributeName'.-    deriving (Data, Eq, Ord, Show)+    deriving (Data, Eq, Generic, Ord, Show) +instance Hashable Attrib+ -- | A flipped version of the 'Attrib' data constructor, where one first -- specifies the conbinator, then the 'AttributeName' and finally the value. attrib :: AttributeCombinator -- ^ The 'AttributeCombinator' that specifies the required relation between the attribute and a value.@@ -334,8 +350,10 @@ data Namespace =       NAny -- ^ A typeselector part that specifies that we accept all namespaces, in css denoted with @*@.     | Namespace Text -- ^ A typselector part that specifies that we accept a certain namespace name.-    deriving (Data, Eq, Ord, Show)+    deriving (Data, Eq, Generic, Ord, Show) +instance Hashable Namespace+ -- | The empty namespace. This is /not/ the wildcard namespace (@*@). This is a -- bidirectional namespace and can thus be used in expressions as well. pattern NEmpty :: Namespace@@ -346,22 +364,28 @@ data ElementName =       EAny -- ^ A typeselector part that specifies that we accept all element names, in css denoted with @*@.     | ElementName Text -- ^ A typeselector part that specifies that we accept a certain element name.-    deriving (Data, Eq, Ord, Show)+    deriving (Data, Eq, Generic, Ord, Show) +instance Hashable ElementName+ -- | A typeselector is a combination of a selector for a namespace, and a -- selector for an element name. One, or both can be a wildcard. data TypeSelector = TypeSelector {     selectorNamespace :: Namespace, -- ^ The selector for the namespace.     elementName :: ElementName -- ^ The selector for the element name.-  } deriving (Data, Eq, Ord, Show)+  } deriving (Data, Eq, Generic, Ord, Show) +instance Hashable TypeSelector+ -- | An attribute name is a name that optionally has a namespace, and the name -- of the attribute. data AttributeName = AttributeName {     attributeNamespace :: Namespace, -- ^ The namespace to which the attribute name belongs. This can be 'NAny' as well.     attributeName :: Text  -- ^ The name of the attribute over which we make a claim.-  } deriving (Data, Eq, Ord, Show)+  } deriving (Data, Eq, Generic, Ord, Show) +instance Hashable AttributeName+ -- | We use 'Text' as the type to store an attribute value. type AttributeValue = Text @@ -374,19 +398,25 @@     | PrefixMatch -- ^ The value is a prefix of the value in the attribute, denoted with @^=@ in css.     | SuffixMatch -- ^ The value is a suffix of the value in the attribute, denoted with @$=@ in css.     | SubstringMatch -- ^The value is a substring of the value in the attribute, denoted with @*=@ in css.-    deriving (Bounded, Data, Enum, Eq, Ord, Read, Show)+    deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show) +instance Hashable AttributeCombinator+ -- | A css class, this is wrapped in a data type. The type only wraps the class -- name, not the dot prefix. newtype Class = Class {     unClass :: Text -- ^ Obtain the name from the class.-  } deriving (Data, Eq, Ord, Show)+  } deriving (Data, Eq, Generic, Ord, Show) +instance Hashable Class+ -- | A css hash (used to match an element with a given id). The type only wraps -- the hash name, not the hash (@#@) prefix. newtype Hash = Hash {     unHash :: Text -- ^ Obtain the name from the hash.-  } deriving (Data, Eq, Ord, Show)+  } deriving (Data, Eq, Generic, Ord, Show)++instance Hashable Hash  -- | Convert the given 'AttributeCombinator' to its css selector counterpart. attributeCombinatorText :: AttributeCombinator -- ^ The 'AttributeCombinator' for which we obtain the corresponding css selector text.
src/Css3/Selector/Utils.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ {-| Module      : Css3.Selector.Utils Description : A set of utility methods to encode and decode strings.
test/Spec.hs view
@@ -5,6 +5,7 @@  import Data.Binary(Binary, encode, decode) import Data.Function(on)+import Data.Hashable(Hashable(hashWithSalt)) import Data.Text(pack, unpack)  import Test.Framework (defaultMain, testGroup)@@ -70,8 +71,20 @@         testProperty "Binary uniqness: attribute name" (uniqnessEncoding @AttributeName),         testProperty "Binary uniqness: class" (uniqnessEncoding @Class),         testProperty "Binary uniqness: hash" (uniqnessEncoding @Hash)+    ],+    testGroup "Check hash constraint for the Hashable instances" [+        testProperty "Different hash implies different items: selector group" (hashingDifferent @SelectorGroup),+        testProperty "Different hash implies different items: selector" (hashingDifferent @Selector),+        testProperty "Different hash implies different items: selector sequence" (hashingDifferent @SelectorSequence),+        testProperty "Different hash implies different items: selector filter" (hashingDifferent @SelectorFilter),+        testProperty "Different hash implies different items: namespace" (hashingDifferent @Namespace),+        testProperty "Different hash implies different items: element name" (hashingDifferent @ElementName),+        testProperty "Different hash implies different items: type selector" (hashingDifferent @TypeSelector),+        testProperty "Different hash implies different items: attribute" (hashingDifferent @Attrib),+        testProperty "Different hash implies different items: attribute name" (hashingDifferent @AttributeName),+        testProperty "Different hash implies different items: class" (hashingDifferent @Class),+        testProperty "Different hash implies different items: hash" (hashingDifferent @Hash)     ]-   ]  encodeDecode :: Char -> String -> Bool@@ -85,6 +98,9 @@  binaryEquivalent :: (Binary a, Eq a, ToCssSelector a) => a -> Bool binaryEquivalent x = decode (encode x) == x++hashingDifferent :: (Hashable a, Eq a) => Int -> a -> a -> Bool+hashingDifferent slt xa xb = (hashWithSalt slt xa == hashWithSalt slt xb) || (xa /= xb)  uniqnessEncoding :: (Binary a, Eq a, ToCssSelector a) => a -> a -> Bool uniqnessEncoding ca cb = (encode ca == encode cb) == (ca == cb)