More doc edits for bidir
Getty Ritter
8 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 | -} |