In a typical Unix program, there are three levels of configuration: system-wide config file (/etc/myapp.conf), per-user config file (~/.myapprc), and command-line options. It's convenient programatically to load each of those in a hash and then merge (e.g. using Data::Merger or Hash::Merge) system-wide hash with the per-user hash, and then merge again the result with the command-line hash to get the a single hash as the final configuration. Your program can from there on deal with this just one hash instead of three.
In a typical merging process between two hashes (left-side and right-side), when there is a conflicting key, then the right-side key will override the left-side. This is usually the desired behaviour in our said program as the system-wide config is there to provide defaults, and the per-user config (and the command-line arguments) allow a user to override those defaults.
But suppose that the user wants to unset a certain configuration setting that is defined by the system-wide config? She can't do that unless she edits the system-wide config (in which she might need admin rights), or the program allows the user to disregard the system-wide config. The latter is usually what's implemented by many Unix programs, e.g. the
-noconfig
command-line option in mplayer
. But this has two drawbacks:- a slightly added complexity in the program. The program needs to provide a special, extra comand-line option.
- the user loses all the default settings in the system-wide config. What she needed in the first place was to just unset a single setting (a single key-value pair of the hash).
Here's where Data::PrefixMerge comes in. It provides a so-called DELETE mode.
prefix_merge({foo=>1, bar=>2}, {"!foo"=>undef, bar=>3, baz=>1});
will result ini:
{bar=>3, baz=>1}
The
!
prefix tells Data::ModeMerge to do a DELETE mode merging. So the final result will lack the foo
key.On the other hand, what if the system admin wants to protect a certain configuration setting from being overriden by the user or the command-line? This is useful in a hosting or other retrictive environment where we want to limit users' freedom to some degree. This is possible via the KEEP mode (prefix
^
):prefix_merge({"^bar"=>2, "^baz"=>1}, {bar=>3, "!baz"=>0, quux=>7});
will result in:
{bar=>2, baz=>1, quux=>7}
effectively protecting
bar
and baz
from being overriden/deleted/etc.Aside from the two mentioned modes, there are also a few others available by default: ADD (prefix
+
), CONCAT (prefix .
), SUBTRACT (prefix -
), as well as the plain ol' NORMAL/override (optional prefix *
).You can add other modes by writing a mode handler module. (planned in upcoming Data::ModeMerge release)
You can change the default prefixes for each mode if you want. You can disable each mode individually. (planned in upcoming Data::ModeMerge release)
You can default to always using a certain mode, like the NORMAL mode, and ignore all the prefixes, in which case Data::ModeMerge will behave like most other merge modules.
You can change default mode, prefixes, disabling/enabling mode, etc on a per-hash basis using the so-called options key.