-- | The... also... the simplest module you'll ever see. It contains -- the 'Letter' type and a Parsec parser to parse one. We don't -- export its constructor because then you could do something dumb -- like stick a digit inside one. -- -- These are defined in RFC1035, Section 2.3.1, \"Preferred name -- syntax\" : -- -- ::= any one of the 52 alphabetic characters A through -- Z in upper case and a through z in lower case -- module Network.DNS.RBL.Domain.Letter ( Letter, letter ) where import Data.Char ( toLower ) import qualified Text.Parsec as Parsec ( letter ) import Text.Parsec.String ( Parser ) import Network.DNS.RBL.Pretty ( Pretty(..) ) -- | A wrapper around a letter character. -- -- ==== _Examples_ -- -- >>> Letter 'x' -- Letter 'x' -- newtype Letter = Letter Char deriving (Show) -- | Pretty-printing for letters that we've already parsed. Just -- shows/prints the letter character. -- -- ==== _Examples_ -- -- >>> let l = Letter 'x' -- >>> pretty_print l -- x -- instance Pretty Letter where pretty_show (Letter l) = [l] -- | Parse a single letter, but wrap it in our 'Letter' type. -- -- ==== _Examples_ -- -- >>> import Text.Parsec ( parseTest ) -- -- Letters are parsed correctly: -- -- >>> parseTest letter "x" -- Letter 'x' -- -- But digits are not: -- -- >>> parseTest letter "1" -- parse error at (line 1, column 1): -- unexpected "1" -- expecting letter -- letter :: Parser Letter letter = fmap Letter Parsec.letter -- | The derived instance of 'Eq' for letters is incorrect. All -- comparisons should be made case-insensitively. The following -- is an excerpt from RFC1035: -- -- 2.3.3. Character Case -- -- For all parts of the DNS that are part of the official -- protocol, all comparisons between character strings (e.g., -- labels, domain names, etc.) are done in a case-insensitive -- manner... -- -- Since each part of DNS name is composed of our custom types, it -- suffices to munge the equality for 'Letter'. RFC4343 -- clarifies the -- case-insensitivity rules, but the fact that we're treating DNS -- names as strings makes most of those problems go away (in -- exchange for new ones). -- -- ==== _Examples_ -- -- >>> let l1 = Letter 'x' -- >>> let l2 = Letter 'x' -- >>> let l3 = Letter 'X' -- >>> let l4 = Letter 'X' -- >>> l1 == l2 -- True -- >>> l1 == l3 -- True -- >>> l1 == l4 -- True -- >>> l3 == l4 -- True -- instance Eq Letter where (Letter l1) == (Letter l2) = (toLower l1) == (toLower l2)