NAME

    YAML::LoadBundle - Load a directory of YAML files as a bundle

VERSION

    version v0.4.3

SYNOPSIS

      use YAML::LoadBundle qw(:all);
    
      my $hash = load_yaml_bundle( "/path/to/yaml_bundle/dir/" );

DESCRIPTION

    Adds additional features to YAML::XS to allow splitting a YAML file
    into multiple files in a common directory. This helps with readability
    when the file is large.

    It also provides more advanced merging features than the standard YAML
    spec.

Export

    Nothing is exported by default, but all the functions listed below are
    available for export.

    All will be exported with :all.

Exported Functions

 Load

  load_yaml

      load_yaml($filename)
      load_yaml(\*FILEHANDLE)
      load_yaml($yaml_data)

    Parses a YAML file (or string) with extra error-checking.

    When passed a $filename, the %YAML_cache will cache a dclone'd copy of
    the result for later retrieval, unless the file has been modified since
    the last load. This can be prevented by passing anything else as a 2nd
    parameter, if you know that the file will never be reloaded.

    When passed a string, the %YAML_cache will cache a copy of the result,
    using the SHA1 digest of the string as the hash key. Strings are only
    cached in memory, not on disk.

    After loading the YAML into a Perl data structure, some postprocessing
    is done on specially-named keys in hash references. Each is merged into
    their containing hash reference, though at different times and with
    different strategies.

      * -import

      shallow merge (e.g. %x = (%y, %x))

      * -export

      shallow merge

      * -merge

      deep merge (see Hash::Merge::Simple)

      * -clone

      clones intermediate hash keys, see "Cloning intermediate hash keys"
      below.

      * -flatten

          some_key: { -flatten: [*SomeArrayRef, *SomeOtherArrayRef] }

      Instead of doing any kind of special hash merging, this special key
      takes an arrayref of arrayrefs, merges all their contents into one
      large arrayref, then replaces its entire surrounding hash with the
      arrayref.

      In other words, the example above would look like this in Perl:

          { some_key => [@$some_array_ref, @$some_other_array_ref] }

      * -flattenhash

          some_key: { -flattenhash: [*SomeHashRef, *SomeOtherHashRef] }

      Sometimes it is desirable to import more than one hash object, but
      cannot due to limitations of keynames like -import. If you really
      want this behavior, add this flag.

    import and export are backwards-compatibility synonyms for -import and
    -export.

    Like normal list assignment in Perl, the right-hand side takes
    precedence (pseudocode):

      %hash = deep_merge(%merge, shallow_merge(%import, %export, %hash));

    Instead of a hash reference, any of these keys may contain an array
    reference of hash references, in which case those hash references are
    merged using whatever strategy normally applies (e.g. deep merge for
    -merge).

   Cloning intermediate hash keys

    -clone provides a way to repeat intermediate nodes in hashes:

      apple:
        -clone:
           letters:
             letters: &letters
               - a
               - b
             d: e
             f: g
           numbers:
             numbers:
               - 1
               - 2
             quattro: 4
             cinco:   5
        golf: g
        hotel: h
    
      banana:
        -clone:
          letters:
             letters:  *letters
             h: i
             j: k

    This results a hash with "d" and "f" keys getting cloned inside another
    hash using keys "a" and "b" for each cloned copy; "quattro" and "cinco"
    are also cloned under keys "1" and "2", together with "g" and "h" which
    are just along for the ride.

    The same "a" and "b" keys get referenced, without duplication, and used
    for intermediate keys in a different part of the hash.

    So the resulting hash would be:

       'apple' => {
             'a' => {
                 'd' => 'e',
                 'f' => 'g',
              },
             'b' => {
                 'd' => 'e',
                 'f' => 'g',
              },
             '1' => {
                 'quattro' => '4',
                 'cinco' => '5',
             },
             '2' => {
                 'quattro' => '4',
                 'cinco' => '5',
             },
             'golf' => 'g',
             'hotel' => 'h',
        },
        'banana' => {
             'a' => {
                 'h' => 'i',
                 'j' => 'k',
             },
             'b' => {
                 'h' => 'i',
                 'j' => 'k',
             },
         },

    Formally:

    -clone itself must be a hash key, and contains a hash, the "clone"
    hash, with one or more keys. Each value of those keys is a subhash that
    must have a key with the same name as its parent key in the "clone"
    hash. This key's value must be a list, and the rest of the subhash gets
    cloned, one for each value in the list, and placed into the -clone
    hash, with each value in the list being its key.

    This provides the means to have a single specification of a list and
    then repeat it (via the usual YAML "&" and "*") references but insert
    them as intermediate hash keys.

  load_yaml_bundle

      load_yaml_bundle($path, \%options)

    Similar to "load_yaml", but loads YAML from a bundle of configuration
    files. This may be a single file, a directory containing configuration
    files, or a whole directory tree of configuration files.

    The given path names the base location for the bundle. This starts by
    loading a file with the given name followed by a configuration prefix
    (either .yml or .conf by default). It then checks to see if there is a
    directory with the same name as the path. It then repeats the loading
    process for all nested files and directories where the file and
    directory names become the keys into which the configuration is
    injected.

    For example, given a directory layout like this:

      conf/base.conf
      conf/base/common.conf
      conf/base/user.conf
      conf/base/user/accounts.conf

    A hash would be returned mapped something like this (pseudo-code):

        {
            common => load_yaml("conf/base/common.conf"),
            user   => {
                accounts => load_yaml("conf/base/user/accounts.conf"),
                %{ load_yaml("conf/base/user.conf") }
            },
            %{ load_yaml("conf/base.conf") }
        }

    However, the actual merge will be a deep merge.

    The usual semantics related to import, export, and merging apply to
    these files as they do in "load_yaml".

    Symlinks can be used to share the data between multiple keys. By
    default, symlinks will be followed, but will cause an error if any of
    them are outside the root path of the bundle. If a symlink is
    permitted, this will follow symlinks to files or directories as if they
    were the files or directories set locally, allowing the original key to
    be renamed in any way desired. It also means that symlinks to files
    must have a correct configuraiton file suffix.

    This will ignore any file starting with a period.

    There are some options to modify the default behaviors:

    follow_symlinks_when

      This may be set to any of the following strings:

      bundled

	This is the default. Symlinks are followed, but only within the
	root.

      never

	Do not follow symlinks.

      always

	Always follow symlinks. Use this with caution.

    follow_symlinks_fail

      This may be set to any of the following strings:

      error

	This is the default. When symlinks are found, but not followed,
	croak.

      warn

	When symlinks are found, but not followed, carp.

      ignore

	When symlinks are found, but not followed... take no action at all.

    conf_suffixes

      This routine only considers files that have the given suffxes. The
      default includes "conf" and "yml". The suffixes are given as an array
      reference of strings. (All directories will be followed, at least to
      the maximum depth.)

    max_depth

      This defaults to 20 which is probably more than enough and mostly
      intended to prevent some sort of insane failure. If a directory is
      found at one further than the maximum depth, a warning will be
      issued.

 Observe

  add_yaml_observer

        add_yaml_observer(sub {
            my $filename = shift;
            warn "Yaml file $filename was just loaded.";
        });

    Adds an observer sub that will be notified just prior to a yaml file
    being loaded. Note that each observer is called even if the yaml file
    is cached and does not need to be reloaded.

  _notify_yaml_observers

    Called internally to notify each waiting observer that a new yaml file
    is being loaded.

  remove_yaml_observer

        remove_yaml_observer($subref);

    Removes an observer sub that was previously added via
    add_yaml_observer.

 Cache

  $YAML::LoadBundle::CacheDir

    Set this to a path that already exists of where to cache loaded files.

        $YAML::LoadBundle::CacheDir
            = File::Spec->catdir( File::Spec->tmpdir, 'yaml-loadbundle' );

    Defaults to $ENV{YAML_LOADBUNDLE_CACHEDIR}.

    If false, caching is disabled.

AUTHOR

    Grant Street Group <developers@grantstreet.com>

COPYRIGHT AND LICENSE

    This software is Copyright (c) 2016 - 2021 by Grant Street Group.

    This is free software, licensed under:

      The Artistic License 2.0 (GPL Compatible)