1 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
3 -- | The 'Weight' type, its instances, and a Parsec parser to parse
4 -- one off the end of a 'Site'.
6 -- This is a simple newtype wrapper around an 'Int', meant to be
7 -- used wherever a weight or an RBL score is intended (to prevent
8 -- integer mixups). For example, the RBLs are all weighted with
9 -- 'Weight's, and when a user supplied a \"badness\" threshold, it
10 -- will be as a 'Weight' as well. The two are then comparable but
11 -- not with other 'Int's.
13 module Network.DNS.RBL.Weight (
18 import System.Console.CmdArgs.Default ( Default(..) )
27 import Text.Parsec.String ( Parser )
28 import Text.Read ( readMaybe )
30 import Network.DNS.RBL.Pretty ( Pretty(..) )
33 -- | The 'Weight' wrapper around an 'Int. We use
34 -- GeneralizedNewtypeDeriving to derive num automatically (so that we
35 -- can sum these things).
39 -- >>> let w1 = Weight 1
42 -- >>> let w2 = Weight 1
45 -- >>> let w3 = Weight 2
48 -- >>> sum [w1, w2, w3]
51 newtype Weight = Weight Int deriving (Eq, Num, Ord, Show)
54 -- | Pretty-print a 'Weight'. This just shows/prints the underlying 'Int'.
58 -- >>> pretty_print $ Weight 17
61 instance Pretty Weight where
62 pretty_show (Weight w) = show w
65 -- | Set a default value for the weight. We use the 'Default' class
66 -- from the CmdArgs class so that 'Weight's can be easily parsed on
74 instance Default Weight where def = 1
77 -- | Parse the weight multiplier off the end of an input 'Site'. This
78 -- expects there to be a \"multiplier\" character (an asterisk)
79 -- before the integral weight.
83 -- >>> import Text.Parsec ( parseTest )
85 -- Negative, zero, and positive integers are all supported:
87 -- >>> parseTest weight "*-5"
90 -- >>> parseTest weight "*0"
93 -- >>> parseTest weight "*17"
96 -- If the weight is empty, it defaults to @1@:
98 -- >>> parseTest weight ""
101 -- The default is used whenever parsing fails:
103 -- >>> parseTest weight "*hello"
106 -- The 'Pretty' instance works as intended:
108 -- >>> import Text.Parsec ( parse )
109 -- >>> pretty_print $ parse weight "" "*3"
112 weight :: Parser Weight
113 weight = try parse_weight <|> return (Weight 1)
117 sign <- (char '-') <|> (option '+' (char '+'))
119 case ( readMaybe w :: Maybe Int ) of
120 -- If "many1 digit" gives us a list of digits, we should be able
121 -- to convert that to an Int! It will overflow rather than fail
122 -- if the input is too big/small, so it should really always
124 Nothing -> unexpected "weight: readMaybe failed on a sequence of digits!"
125 Just k -> return $ Weight (if sign == '-' then negate k else k)