Ivan Wills




    # The config files (all produce the same data structures)
    # JSON relaxed : data.dc.js
        # shell/perl style comments ok
        "PARENT": "other/path",
        "hash" : {
            "key" : "value", # allows trailing commas
            "action" : {
                "MODULE" : "My::Module",
                "METHOD" : "my_action",

    # JSON strict : data.dc.json
        "PARENT": "other/path",
        "hash" : {
            "key" : "value"
            "action" : {
                "MODULE" : "My::Module",
                "METHOD" : "my_action"

    # YAML : data.dc.yml
    PARENT: other/path
        key : value
            MODULE: My::Module
            METHOD: my_action

    # XML : data.dc.xml

    # in perl
    use Data::Context;
    my $dc = Data::Context->new(
        path => [qw{ /path/one /paht/two }],
        fallback => 1,
        actions  => {
            do_something => sub { ... },
    my $data = $dc->get('data', { some => 'vars' });


The power of Data::Context is it's simple handling of many configuration files. It supports configuration files in JSON format (strict & relaxed variants), YAML and XML (via XML::Simple). Basically the aim is to support any format that allows arbitrary depth data structures (eg not ini style files).


Each config file can specify a PARENT config file, the raw data of the parent file is merged (via Hash::Merge) into the current config's raw data. This is done recursively so the current config parent can itself inherit another file. No checking is done circular references.

Variable substitutions

Config files may contain markers for data to be substituted the specified position at run time.This consists of a dot separated list of hash keys or array indexes surrounded by hashes (#).

 eg #my.path.3.value.0#

This would be the equivalent to accessing the data as


Checking is done along the path to access the data correctly, if an element is a blessed object the path position will be attempted to be used as an accessor.

 eg if my is an object

If at any point in the expansion of the path no data is found undef is returned for that value.


Variable expansion is actually a special case of an action. An action (in the general form) is called by the config by specifying either METHOD and/or MODULE keys.

If only METHOD is specified the method is called against the action_class parameter of the Data::Context object which by default is Data::Context::Action. Any actions passed into the Data::Context object are made available this way.

If only MODULE is specified then the action_method (by default get_data) is used to call against MODULE.

If both MODULE and METHOD are specified then MODULE->METHID is used.

The contents of the hash containing MODULE and/or METHOD are passed to the method, along with the vars the request was called with, the dotted path thought the config and a reference to the Data::Context::Instance object. The return value of the call is used to replace the original hash value. That is unless the returned value is an AnyEvent::CondVar variable. If the result is a condvar then it will be recv()ed allowing for multiple longer running events to occur. The result of the recv() (ie what is passed to the ->send) is used to replace the original hash.


The default order that actions are called is the reverse of the order that they are encountered. This allows an action to include the output of another action. If this ordering is not what the application requires, the hash where the action is defined can specify ORDER to overwrite the default order. If ORDER is a positive integer (including 0) then the method will be called before other non ordered methods (but in increasing numerical order by ORDER). If the value is negative then it will be run after all non ordered actions (again negative ORDERs will be run in increasing numerical order ie most negative to lease negative).

    eg data.dc.yml
            METHOD: get_unordered_second
            METHOD: get_second
            ORDER: 1
            METHOD: get_first
            ORDER: 0
            METHOD: get_unordered_first
            METHOD: get_last
            ORDER: -1
            METHOD: get_last_but1
            ORDER: -2

    This will execute in order

How Actions are called


Still to be implemented. Currently all method calls are class calls but the NEW key will be used to specify creating an object.


There are no known bugs in this module.

Please report problems to Ivan Wills (ivan.wills@gmail.com).

Patches are welcome.


Ivan Wills - (ivan.wills@gmail.com)


Copyright (c) 2012 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077). All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.