NAME
    Config::Structured - provides generalized and structured configuration
    value access

SYNOPSIS
    Basic usage:

      use Config::Structured;

      my $conf = Config::Structured->new(
        structure => { 
          db => {
            host     => {
              isa         => 'Str',
              default     => 'localhost',
              description => 'the database server hostname',
            },
            username => {
              isa         => 'Str',
              default     => 'dbuser',
              description => 'the database user's username',
            },
            password => {
              isa         => 'Str',
              description => 'the database user's password',
            },
          }
        },
        config => { 
          db => {
            username => 'appuser',
            host     => {
              source   => 'env',
              ref      => 'DB_HOSTNAME',
            },
            password => {
              source => 'file',
              ref    => '/run/secrets/db_password',
            },
          }
        }
      );

      say $conf->db->username(); # appuser
      # assuming that the hostname value has been set in the DB_HOSTNAME env var
      say $conf->db->host; # prod_db_1.mydomain.com
      # assuming that the password value has been stored in /run/secrets/db_password
      say $conf->db->password(); # *mD9ua&ZSVzEeWkm93bmQzG

    Hooks example showing how to ensure config directories exist prior to
    first use:

      my $conf = Config::Structured->new(
        ...
        hooks => {
          '/paths/*' => {
            on_load => sub($node,$value) {
              Mojo::File->new($value)->make_path
            }
          }
        }
      )

DESCRIPTION
    Config::Structured provides a structured method of accessing
    configuration values

    This is predicated on the use of a configuration "structure" (required),
    This structure provides a hierarchical structure of configuration
    branches and leaves. Each branch becomes a Config::Structured method
    which returns a new Config::Structured instance rooted at that node,
    while each leaf becomes a method which returns the configuration value.

    The configuration value is normally provided in the "config" hash.
    However, a "config" node for a non-Hash value can be a hash containing
    the "source" and "ref" keys. This permits sourcing the config value from
    a file (when source="file") whose filesystem location is given in the
    "ref" value, or an environment variable (when source="env") whose name
    is given in the "ref" value.

    *Structure Leaf Nodes* are required to include an "isa" key, whose value
    is a type (see Moose::Util::TypeConstraints). If typechecking is not
    required, use isa => 'Any'. There are a few other keys that
    Config::Structured respects in a leaf node:

    "default"
        This key's value is the default configuration value if a data source
        or value is not provided by the configuation.

    "description"
    "notes"
        A human-readable description and implementation notes, respectively,
        of the configuration node. Config::Structured does not do anything
        with these values at present, but they provides inline documentation
        of configuration directivess within the structure (particularly
        useful in the common case where the structure is read from a file)

    Besides "structure" and "config", Config::Structured also accepts a
    "hooks" argument at initialization time. This argument must be a HashRef
    whose keys are patterns matching config node paths, and whose values are
    HashRefs containing "on_load" and/or "on_access" keys. These in turn
    point to CodeRefs which are run when the config value is initially
    loaded, or every time it is accessed, respectively.

CONSTRUCTORS
  Config::Structured->new( config => {...}, structure => {...} )
    Returns a new "Config::Structured" instance. "config" and "structure"
    are required parameters and must either be HashRefs or strings
    containing a data structure in "JSON", "YAML", or "perl" (i.e.,
    Data::Dumper) formats. The format of the structure will be autodetected.
    The content of these data structures is detailed above in the
    "DESCRIPTION" section.

METHODS
  get( [$name] )
    Class method.

    Returns a registered Config::Structured instance. If $name is not
    provided, returns the default instance. Instances can be registered with
    "__register_default" or "__register_as". This mechanism is used to
    provide global access to a configuration, even from code contexts that
    otherwise cannot share data.

  __register_default()
    Call on a Config::Structured instance to set the instance as the
    default.

  __register_as( $name )
    Call on a Config::Structured instance to register the instance as the
    provided name.

  __get_child_node_names()
    Returns a list of names (strings) of all immediate child nodes of the
    current config node

AUTHOR
    Mark Tyrrell "<mark@tyrrminal.dev>"

LICENSE
    Copyright (c) 2024 Mark Tyrrell

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the
    "Software"), to deal in the Software without restriction, including
    without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to
    permit persons to whom the Software is furnished to do so, subject to
    the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.