More doc edits for bidir
Getty Ritter
7 years ago
568 | 568 | _2 = lens snd (\ b (a, _) -> (a, b)) |
569 | 569 | |
570 | 570 | |
571 | {- | $main | |
572 | This module is an alternate API used for parsing INI files. | |
573 | unlike the standard API, it is bidirectional: it can be also used | |
574 | to emit an INI, or even to produce an updated INI file with minimal | |
575 | modification to the textual file provided. | |
571 | ||
572 | {- $main This module is an alternate API used for parsing INI files. | |
573 | Unlike the standard API, it is bidirectional: the same declarative | |
574 | structure can be also used to emit an INI file, or even to produce an | |
575 | updated INI file with minimal modification to the textual file | |
576 | provided. | |
576 | 577 | |
577 | 578 | This module makes some extra assumptions about your configuration type |
578 | 579 | and the way you interact with it: in particular, it assumes that you |
579 | 580 | have lenses for all the fields you're parsing, and that you have some |
580 | 581 | kind of sensible default value of that configuration. Instead of |
581 | 582 | providing combinators which can extract and parse a field of an INI |
582 | file into a value, the bidirectional API has you declaratively | |
583 | associate lenses into your structure with descriptions of their | |
584 | corresponding fields in INI files. | |
583 | file into a value, the bidirectional API allows you to declaratively | |
584 | map lenses into your structure to descriptions of corresponding fields | |
585 | in INI files. | |
585 | 586 | |
586 | 587 | Consider the following example INI file: |
587 | 588 | |
593 | 594 | > user = terry |
594 | 595 | |
595 | 596 | We'd like to parse this INI file into a @Config@ type which we've |
596 |
defined like this, using |
|
597 | defined like this, using "lens" or a similar library to provide | |
598 | lenses: | |
597 | 599 | |
598 | 600 | > data Config = Config |
599 | 601 | > { _cfHost :: String |
603 | 605 | > |
604 | 606 | > ''makeLenses Config |
605 | 607 | |
606 | We define a basic specification of type @IniSpec Config ()@ by using | |
607 | the provided combinators to declare sections and then associate fields | |
608 | in those sections with lenses into our @Config@ structure. | |
608 | We can now define a basic specification of the type @IniSpec Config | |
609 | ()@ by using the provided operations to declare our top-level | |
610 | sections, and then within those sections associate fields with lenses | |
611 | into our @Config@ structure. | |
609 | 612 | |
610 | 613 | > configSpec :: IniSpec Config () |
611 | 614 | > configSpec = do |
621 | 624 | configuration. Each 'field' invocation must include the name of the |
622 | 625 | field and a representation of the type of that field: 'string', |
623 | 626 | 'number', and 'text' in the above snippet are all values of type |
624 | 'FieldValue', which bundles together a parser and serializer for a | |
625 | value. | |
627 | 'FieldValue', which bundle together a parser and serializer so that | |
628 | they can be used bidirectionally. | |
626 | 629 | |
627 | 630 | We can also provide extra metadata about a field, allowing it to be |
628 | 631 | skipped in parsing, or to provide an explicit default value, or to |
634 | 637 | > configSpec = do |
635 | 638 | > section "NETWORK" $ do |
636 | 639 | > cfHost .= field "host" string |
637 |
> & comment [" |
|
640 | > & comment ["The desired hostname (optional)"] | |
641 | > & skipIfMissing | |
638 | 642 | > cfPost .= field "port" number |
643 | > & comment ["The port number"] | |
639 | 644 | > & defaultValue 9999 |
640 | 645 | > section "LOCAL" $ do |
641 | 646 | > cfUser .=? field "user" text |
642 | 647 | |
643 | 648 | In order to parse an INI file, we need to provide a default value of |
644 | our underlying @config@ type on which we can perform our 'Lens'-based | |
645 | updates. | |
649 | our underlying @Config@ type on which we can perform our 'Lens'-based | |
650 | updates. Parsing will then walk the specification and update each | |
651 | field in the default value to the field provided in the INI file. We | |
652 | can also use a value of our @Config@ type and serialize it directly, | |
653 | which is useful for generating a default configuration: this will | |
654 | include the comments we've provided and (optionally) commented-out | |
655 | key-value pairs representing default values. Finally, we can /update/ | |
656 | a configuration file, reflecting changes to a value back to an | |
657 | existing INI file in a way that preserves incidental structure like | |
658 | spacing and comments. | |
659 | ||
646 | 660 | -} |