NAME
    Config::Ini::OnDrugs - Yet another INI reader/writer (round trip,
    includes, variables, nest)

VERSION
    version 0.08

SYNOPSIS
     # oo interface
     use Config::Ini::OnDrugs;
     my $ini = Config::Ini::OnDrugs->new(file => "file.ini");
     my $section = $ini->get_section("Section"); # a hashref of param=>values
     my $val = $ini->get_value("Section", "Parameter");

     # not yet implemented
     $ini->add_section("Section2"); # empty section
     $ini->add_section("Section3", {Param=>Value, ...}); # section with values
     $ini->delete_section("Section2");
     $ini->set_value("Section", "Param", "New Value");
     $ini->delete_value("Section", "Param");

     $ini->as_tree;

     # dump back as string
     $ini->as_string;

     # procedural interface, Config::IOD is a shorter alias
     use Config::IOD qw(
         ini_get
         ini_get_section
         ini get_value
         ini_add_section ini_delete_section
         ini_add_value ini_set_value ini_delete_value
         ini_comment_value ini_uncomment_value
         ini_comment_section ini_uncomment_section
     );
     my $ini = ini_get("file.ini");
     my $section = ini_get_section("file.ini", "Section");
     my $value = ini_get_value("file.ini", "Section", "Parameter");
     ini_add_value("file.ini", , "Section", "Parameter", "Value");
     ...

DESCRIPTION
    WARNING: THIS MODULE IS NOT FUNCTIONAL, PLEASE DO NOT USE IT. I AM STILL
    REVISING THE SPECIFICATION, IMPLEMENTATION IS STILL VERY
    MINIMAL/PARTIAL.

    This module provides INI reading/writing class/functions. There are
    several other INI modules on CPAN; this one focuses on round trip
    parsing, includes, variables. The goal is to provide a usable format for
    configuration files suitable for automation (programatic modification)
    as well as editing by humans.

  What is round trip parsing, and why it is useful?
    It means preserving everything in the file, including comments and
    formatting (indents, whitespaces). In other words, if you load the INI
    file and dump it again, the resulting dump will be identical to the
    original file. If you modify just one parameter, the rest will be
    identical to the original (including whitespaces).

    Being round trip safe is useful for humans, because some of the things
    that are useful to humans are in the comments and whitespaces, which are
    not significant to machines.

    Example:

     ; Important, only set between 2 and 40, otherwise it will explode!!!
     ; In fact, only set between 2 and 27.5, other values are bunk!!
     frob        =  2.3
     plunk       = 20.1
     thingamagic = 27.4

    is much more useful than:

     frob=2.3
     plunk=20.1
     thingamagic=2.5

    Most other formats do not provide round trip parser, e.g. JSON, YAML,
    Config::General (Apache-style), XML; they all lose comments. They are
    good for automation but not ideal for humans. (Note: JSON documentation
    mentions the phrase "round trip", but it uses the phrase to mean
    integrity of values, not preserving comments/whitespaces.)

IOD FORMAT SPECIFICATION
    Since the INI format does not have any formal specification, here is the
    specification for INI as used by this module (from here on: IOD). IOD is
    an extended INI format. If you don't use any extended features, your IOD
    file is a plain INI file.

    A configuration text file containing a sequence of lines, each line is
    either a blank line, a comment line, a directive line, a section line,
    or a parameter line. Parsing is done line-by-line and in one pass.

  Blank line
    A blank line is a line containing zero or more whitespaces only. It is
    ignored.

  Comment line
    A comment line begins with ; or # as it's first nonblank character (note
    that some INI parsers do not allow indented comment). The use of ; is
    preferred over #, as some INI parsers (like one in PHP 5.3+) do not
    recognize or warn comments using #.

  Directive line
    A directive line is a special comment line, starting with an exclamation
    mark ("!") followed by a directive name and zero or more arguments. An
    invalid directive will be ignored and assumed to be a normal command
    (with warnings).

     ;!directivename arg ...

    Directives influence parsing and turn on/off features.

    Below is the list of known directives:

   !include <PATH>
    Include another file, as if the content of the included file is the next
    lines in the current file. If PATH is not absolute, it is assumed to be
    relative to the current file (or included file). A circular include will
    cause the parser to die with an error. Example:

    File dir1/a.ini: [sectionA] [sub1] a=1 ;!include ../dir2/b.ini

    File dir2/b.ini:

        b=2
     ;dedent

    File dir2/b2.ini: c := 2+1

    File dir2/b3.ini: c=4 [sectionB] c=1

    Will parsed, will result in this configuration:

     {
         sectionA => {
             sub1 => {
                 a => 1,
                 b => 2,
                 c => [3, 4],
             },
         },
         sectionB => {
             c => 1,
         },
     }

   !defaults <SECTION> <SECTION2> ...
    Specify that from now on, when encountering a new section, fill it with
    values from SECTION (and then SECTION2, and so on) unless the values are
    already specified.

    Example:

     [sect1]
     a=1
     b=2

     ;!defaults sect1

     [sect2]
     a=10

     [sect3]
     c=1

     [sect4]
     a=0
     b:=undef

    Will result in:

     {sect1 => {a=>1, b=>2},
      sect2 => {a=>10, b=>2},
      sect3 => {a=>1, b=>2, c=>1},
      sect4 => {a=>0, b=>undef},

    Another, more meaty example:

     [-defaults]
     quota=1000
     ftp=1
     shell=1
     mysql=0

     ;!defaults -defaults

     ; double quota for this user
     [user1]
     quota=2000

     ; disable ftp for this user
     [user2]
     ftp=0

     ; all admin users have unlimited quota
     [-admins]
     quota=-1

     ;!defaults -admins

     [admin1]

     ; this admin cannot use shell
     [admin2]
     shell=0

     ;no more defaults
     ;!defaults

    Defaults to the same section is ignored.

   !merge
    Mode-merging using Data::ModeMerge. Details to be specified later.

  Section line
    A section line introduces a section:

     [Section Name]
     ["quoted [] section name"]
     []
     [""]

    Comment is allowed at the end. To write a section name with problematic
    characters (like "\n", "\0", "]", etc.), use quotes.

    To specify nested section, you indent the subsection line relative to
    section line (minimum is 1 whitespace):

     [Outer]
       [Inner]
         [Further Inner]
           [a]
           val=1
           [b]
     [c]
     val=2

    will result in:

     {Outer => {
         Inner => {
             "Further Inner" => {
                 a => {
                     val => 1,
                 },
                 b => {
                 },
             },
         },
      c => {
          val => 1,
      },
     },

    Use of tab character is discouraged, but if exists as indentation it
    will be counted as 1 whitespace. Parameter line needs to be indented at
    least as its section:

     [Section]
       [Subsection]
       a=1
         b=2
       c=3
     d=4
      e=5

    In the above example, a, b, and c belong to Subsection will d and e
    belong to Section.

    Non-contiguous sections are allowed, they will be assumed to be set/add
    parameters, e.g.:

     [sect1]
     a=1

     [sect2]
     a=1

     [sect1]
     a=2
     b=3

    will result in "sect1" containing "a" as [1, 2] and "b" as 3. However,
    note:

     [sect1]
     a=1

     ;!defaults sect1
     [sect2]
     d=4

     [sect1]
     b=2

     [sect3]
     c=3

    "sect2" will contain {a=>1, d=>4} since at the point of parsing "sect2",
    "sect1" only contains {a=>1}. However, "sect3" will contain {a=>1, b=>2,
    c=>3} since at the point of parsing "sect3", "sect1" already becomes
    {a=>1, b=>2}.

  Parameter line
    Parameter lines specify name value pairs:

     Parameter name = value
       Parameter2=value ; this is not a comment and part of value

    Parameter name and value can be quoted:

     "Contains\nnewline" = "\0"

    Whitespace before parameter name is allowed and can be used to
    enter/leave subsection (see "Subsection line"). Whitespaces between the
    "=" character are allowed and ignored. Trailing whitespace is allowed
    and ignored for quoted values but significant for unquoted values.

     a=1<space>
     b="2"<space>

    In the above example, value of "a" is "1" followed by a space, while
    value of "b" is just "2".

    Note that some INI parsers forbid some/all of these whitespaces.

    Instead of "=" you can use ":=" to specify expression instead of literal
    value. Expression is parsed by Language::Expr. Using expression, you can
    specify a null (undefined) value:

     param1 := undef

    or alternative of writing arrays. Instead of:

     param=foo
     param=bar

    you can write:

     param := ["foo", "bar"]

    Using expression you can also specify an array with a single value (not
    possible using "=").

     param:=["foo"]

    You can also specify an empty array using expression:

     param:=[]

    To escape ":" as part of parameter name, use quoting:

     "param:"="literal, not expression"

    Normally a parameter line should occur below section line, so that
    parameter belongs to the section. But a parameter line is also allowed
    before section line, in which it will belong to section called "DEFAULT"
    (configurable via the parser's default_section attribute).

  Quoting
    Quoting is done with the double-quote (") character. Known escapes are
    \', \", \\, \r (linefeed), \f (formfeed), \$ (literal $), \n (newline),
    \t (tab), \b (backspace), \a (bell), \0, octal form ("\0377"), hex form
    ("\xff") and wide-hex form (\x{263a}).

    Quoting is allowed for section name in section line and for parameter
    name and value in parameter line.

  Includes
    You can include another file using the !include directive:

     ;!include "/My Home/foo.ini"

    See the documentation of the !include directive for more details.

  Variables and calculations
    You can use variables and calculations using the expressions.

     ; param is 1+2+$a, literal
     param=1+2+$a

     ; param is 5
     a=3
     b=4
     param := ($a**2 + $b**2) ** 0.5

     ; to refer to sections
     [Section1]
     lang="Perl"

     [Section2]
     param:="I love " + $CONFIG['Section1']['lang']

    Note: since parsing is done in 1-pass, make sure that you define a
    parameter first before using it in expressions.

  Specifying defaults
    To avoid repetition, you can specify defaults in a section and then use
    the values in that section for others. See documentation on the
    !defaults directive for more details.

  Merging between sections
    To be specified later.

  Summary of extended features
    Below is a summary of extended features provided by IOD over "standard"
    INI format:

    *   Round-trip parsing

    *   Quoting

    *   Indented section line, comments after section line

    *   Indented comment line

    *   Whitespaces before parameter name, between =, after parameter value

        Some INI parsers do not allow whitespaces at all.

    *   # as comment character

        Some strict INI parsers only recognize ";" as the comment starter.
        If in doubt, always use ";".

    *   Directives (e.g. include, defaults, merging)

        Other INI parsers will see directive line as regular comment line.

    *   Expressions

        Other INI parsers will see:

         param:=value

        as { "param:" => "value" }.

  Unsupported features
    Some INI implementation support other features, and listed below are
    those unsupported by IOD, usually because the features are not popular:

    *   Line continuation for multiline value

         param=line 1 \
         line 2\
         line 3

        Supported by Config::IniFiles. In IOD, use quoting:

         param="line 1 \nline 2\nline 3"

    *   Heredoc syntax for array

         param=<<EOT
         value1
         value2
         EOT

        Supported by Config::IniFiles. In IOD, use multiple assignment or
        expression:

         param=value1
         param=value2

        or:

         param:=["value1", "value2"]

METHODS
FUNCTIONS
    None are exported by default, but they are exportable.

FAQ
  Why use INI format for configuration files?
    It is popular and familiar to many users. The format is simple to
    understand (this cannot be said of other formats like YAML). The
    simplicity of INI format also makes it easier to write round trip parser
    for.

  Why use Config::Ini::OnDrugs (the IOD format) over standard INI files?
    IOD supports several useful (to me, at least) extended features over
    "standard" INI files, see "Summary of extended features".

  Downsides of Config::Ini::OnDrugs (IOD format)?
    *   Currently only has Perl parser

        INI parsers exist everywhere though, so some of the time you can
        fallback to INI.

    *   You need to learn another minilanguage for expressions

        It's very similar to Perl though. See Language::Expr.

    *   Expression parser is still slowish

        I plan to fix this in the future (e.g. by switching parser to
        Marpa).

  Why the name? Were you on drugs?
    Sorry, no.

SEE ALSO
    Other INI modules: Config::IniFiles, Config::INI, Config::INIPlus, etc.

    Other alternative formats: YAML, JSON, Config::General, XML, etc.

    The original blog post/discussion which leads to this module:
    http://blogs.perl.org/users/steven_haryanto/2011/09/yaml-vs-ini-again-an
    d-the-plan-for-yet-another-ini-module.html

    This module uses Log::Any logging framework.

    This module's functions has Sub::Spec specs.

AUTHOR
    Steven Haryanto <stevenharyanto@gmail.com>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2011 by Steven Haryanto.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

POD ERRORS
    Hey! The above document had some coding errors, which are explained
    below:

    Around line 911:
        You forgot a '=back' before '=head2'

