gdritter repos config-ini / b87e718
Removed defaultValue and sectionOpt in favor of simpler optional handling Getty Ritter 6 years ago
2 changed file(s) with 22 addition(s) and 36 deletion(s). Collapse all Expand all
3636 confPort .= field "port" number
3737 & comment [ "the port in question" ]
3838 confUseEncryption .= flag "encryption"
39 & defaultValue True
39 & skipIfMissing
4040 & comment [ "whether to use encryption (defaults to true)" ]
4141 confHostname .= field "hostname" text
42 & defaultValue "localhost"
42 & skipIfMissing
4343 & comment [ "hostname to connect to (optional)" ]
4444 confConfigFile .=? field "config file" text
4545 & placeholderValue "<file path>"
2424 -- * Section-Level Parsing
2525 -- $sections
2626 , section
27 , sectionOpt
2827 -- * Field-Level Parsing
2928 -- $fields
3029 , FieldDescription
3332 , field
3433 , flag
3534 , comment
36 , defaultValue
3735 , placeholderValue
3836 , skipIfMissing
3937 -- * FieldValues
139137 section :: Text -> SectionSpec s () -> IniSpec s ()
140138 section name (SectionSpec mote) = IniSpec $ do
141139 let fields = runBidirM mote
142 modify (Seq.|> Section name fields False)
143
144 -- | Define the specification of an optional top-level INI section. If
145 -- this section does not appear in a parsed INI file, then it will be
146 -- skipped.
147 sectionOpt :: Text -> SectionSpec s () -> IniSpec s ()
148 sectionOpt name (SectionSpec mote) = IniSpec $ do
149 let fields = runBidirM mote
150 modify (Seq.|> Section name fields True)
140 modify (Seq.|> Section name fields (allOptional fields))
141
142 allOptional :: (Seq (Field s)) -> Bool
143 allOptional = all isOptional
144 where isOptional (Field _ fd) = fdSkipIfMissing fd
145 isOptional (FieldMb _ fd) = fdSkipIfMissing fd
151146
152147 data Section s = Section Text (Seq (Field s)) Bool
153148
173168 data FieldDescription t = FieldDescription
174169 { fdName :: Text
175170 , fdValue :: FieldValue t
176 , fdDefault :: Maybe t
177171 , fdComment :: Seq Text
178172 , fdDummy :: Maybe Text
179173 , fdSkipIfMissing :: Bool
210204 -}
211205 comment :: [Text] -> FieldDescription t -> FieldDescription t
212206 comment cmt fd = fd { fdComment = Seq.fromList cmt }
213
214 {- |
215 Choose a default value to be used in case of a missing value. This will
216 only be used in the case of non-optional fields.
217 -}
218 defaultValue :: t -> FieldDescription t -> FieldDescription t
219 defaultValue def fd = fd { fdDefault = Just def }
220207
221208 -- | Choose a placeholder value to be displayed for optional fields.
222209 -- This is used when serializing an optional Ini field: the
254241 field name value = FieldDescription
255242 { fdName = name
256243 , fdValue = value
257 , fdDefault = Nothing
258244 , fdComment = Seq.empty
259245 , fdDummy = Nothing
260246 , fdSkipIfMissing = False
392378 runFields (set l value s) (Seq.viewl fs) sect
393379 | fdSkipIfMissing descr =
394380 runFields s (Seq.viewl fs) sect
395 | Just def <- fdDefault descr =
396 runFields (set l def s) (Seq.viewl fs) sect
397381 | otherwise = Left ("Unable to find field " ++ show (fdName descr))
398382 runFields s (FieldMb l descr Seq.:< fs) sect
399383 | Just v <- lkp (fdName descr) (isVals sect) = do
435419 mkIniValue (fvEmit (fdValue descr) (get l s)) descr False
436420 toVal (FieldMb l descr) =
437421 case get l s of
438 Nothing
439 | Just d <- fdDefault descr ->
440 mkIniValue (fvEmit (fdValue descr) d) descr True
441 | otherwise ->
442 mkIniValue "" descr True
422 Nothing ->
423 mkIniValue "" descr True
443424 Just v ->
444425 mkIniValue (fvEmit (fdValue descr) v) descr True
445426
511492 -> Seq (Section s)
512493 -> UpdatePolicy
513494 -> Either String (Seq (Text, IniSection))
514 updateIniSections s sections fields pol =
515 F.for sections $ \ (name, sec) -> do
495 updateIniSections s sections fields pol = do
496 existingSections <- F.for sections $ \ (name, sec) -> do
516497 let err = (Left ("Unexpected top-level section: " ++ show name))
517498 Section _ spec _ <- maybe err Right
518499 (F.find (\ (Section n _ _) -> T.toLower n == name) fields)
519500 newVals <- updateIniSection s (isVals sec) spec pol
520501 return (name, sec { isVals = newVals })
502 let existingSectionNames = fmap fst existingSections
503 newSections <- F.for fields $
504 \ (Section nm spec isOpt) ->
505 if nm `elem` existingSectionNames
506 then return mempty
507 else return mempty
508 return (existingSections <> F.asum newSections)
521509
522510 updateIniSection :: s -> Seq (Text, IniValue) -> Seq (Field s)
523511 -> UpdatePolicy -> Either String (Seq (Text, IniValue))
580568 -- were left out, but if we have any non-optional fields left
581569 -- over, then we definitely need to include them.
582570 go EmptyL fs = return (finish (Seq.viewl fs))
583 finish (f@(Field l descr) :< fs)
584 | or [ updateAddOptionalFields pol
585 , fdDefault descr /= Just (get l s)
586 ]
571 finish (f@(Field l _) :< fs)
572 | updateAddOptionalFields pol
587573 , Just val <- mkValue (fieldName f) f '=' =
588574 (fieldName f, val) <| finish (Seq.viewl fs)
589575 | otherwise = finish (Seq.viewl fs)
590576 finish (f@(FieldMb _ descr) :< fs)
591 | not (fdSkipIfMissing descr) && fdDefault descr == Nothing
577 | not (fdSkipIfMissing descr)
592578 , Just val <- mkValue (fieldName f) f '=' =
593579 (fieldName f, val) <| finish (Seq.viewl fs)
594580 | updateAddOptionalFields pol