1Hash::Layout(3)       User Contributed Perl Documentation      Hash::Layout(3)
2
3
4

NAME

6       Hash::Layout - hashes with predefined levels, composite keys and
7       default values
8

SYNOPSIS

10        use Hash::Layout;
11
12        # Create new Hash::Layout object with 3 levels and unique delimiters:
13        my $HL = Hash::Layout->new({
14         levels => [
15           { delimiter => ':' },
16           { delimiter => '/' },
17           {}, # <-- last level never has a delimiter
18         ]
19        });
20
21        # load using actual hash structure:
22        $HL->load({
23          '*' => {
24            '*' => {
25              foo_rule => 'always deny',
26              blah     => 'thing'
27            },
28            NewYork => {
29              foo_rule => 'prompt'
30            }
31          }
32        });
33
34        # load using composite keys:
35        $HL->load({
36          'Office:NewYork/foo_rule' => 'allow',
37          'Store:*/foo_rule'        => 'other',
38          'Store:London/blah'       => 'purple'
39        });
40
41        # load composite keys w/o values (uses default_value):
42        $HL->load(qw/baz:bool_key flag01/);
43
44        # get a copy of the hash data:
45        my $hash = $HL->Data;
46
47        #  $hash now contains:
48        #
49        #    {
50        #      "*" => {
51        #        "*" => {
52        #          blah => "thing",
53        #          flag01 => 1,
54        #          foo_rule => "always deny"
55        #        },
56        #        NewYork => {
57        #          foo_rule => "prompt"
58        #        }
59        #      },
60        #      Office => {
61        #        NewYork => {
62        #          foo_rule => "allow"
63        #        }
64        #      },
65        #      Store => {
66        #        "*" => {
67        #          foo_rule => "other"
68        #        },
69        #        London => {
70        #          blah => "purple"
71        #        }
72        #      },
73        #      baz => {
74        #        "*" => {
75        #          bool_key => 1
76        #        }
77        #      }
78        #    }
79        #
80
81
82        # lookup values by composite keys:
83        $HL->lookup('*:*/foo_rule')              # 'always deny'
84        $HL->lookup('foo_rule')                  # 'always deny'
85        $HL->lookup('ABC:XYZ/foo_rule')          # 'always deny'  # (virtual/fallback)
86        $HL->lookup('Lima/foo_rule')             # 'always deny'  # (virtual/fallback)
87        $HL->lookup('NewYork/foo_rule')          # 'prompt'
88        $HL->lookup('Office:NewYork/foo_rule')   # 'allow'
89        $HL->lookup('Store:foo_rule')            # 'other'
90        $HL->lookup('baz:Anything/bool_key')     # 1              # (virtual/fallback)
91
92        # lookup values by full/absolute paths:
93        $HL->lookup_path(qw/ABC XYZ foo_rule/)   # 'always deny'  # (virtual/fallback)
94        $HL->lookup_path(qw/Store * foo_rule/)   # 'other'
95

DESCRIPTION

97       "Hash::Layout" provides deep hashes with a predefined number of levels
98       which you can access using special "composite keys". These are
99       essentially string paths that inflate into actual hash keys according
100       to the defined levels and delimiter mappings, which can be the same or
101       different for each level.  This is useful both for shorter keys as well
102       as merge/fallback to default values, such as when defining overlapping
103       configs ranging from broad to narrowing scope (see example in SYNOPIS
104       above).
105
106       This module is general-purpose, but was written specifically for the
107       flexible filter() feature of DBIx::Class::Schema::Diff, so refer to its
108       documentation as well for a real-world example application. There are
109       also lots of examples and use scenarios in the unit tests under "t/".
110

METHODS

112   new
113       Create a new Hash::Layout instance. The following build options are
114       supported:
115
116       levels
117           Required. ArrayRef of level config definitions, or a numeric number
118           of levels for default level configs. Each level can define its own
119           "delimiter" (except the last level) and list of "registered_keys",
120           both of which are optional and determine how ambiguous/partial
121           composite keys are resolved.
122
123           Level-specific delimiters provide a mechanism to supply partial
124           paths in composite keys but resolve to a specific level. The
125           word/string to the left of a delimiter character that is specific
126           to a given level is resolved as the key of that level, however, the
127           correct path order is required (keys are only tokenized in order
128           from left to right).
129
130           Specific strings can also be declared to belong to a particular
131           level with "registered_keys". This also only effects how ambiguity
132           is resolved with partial composite keys. See also the "no_fill" and
133           "no_pad" options.
134
135           See the unit tests for examples of exactly how this works.
136
137           Internally, the level configs are coerced into Hash::Layout::Level
138           objects.
139
140           For Hash::Layouts that don't need/want level-specific delimiters,
141           or level-specific registered_keys, a simple integer value can be
142           supplied instead for default level configs all using "/" as the
143           delimiter.
144
145           So, this:
146
147            my $HL = Hash::Layout->new({ levels => 5 });
148
149           Is equivalent to:
150
151            $HL = Hash::Layout->new({
152             levels => [
153               { delimiter => '/' }
154               { delimiter => '/' }
155               { delimiter => '/' }
156               { delimiter => '/' }
157               {} #<-- last level never has a delimiter
158             ]
159            });
160
161           "levels" is the only required parameter.
162
163       default_value
164           Value to assign keys when supplied to "load()" as simple strings
165           instead of key/value pairs.  Defaults to the standard bool/true
166           value of 1.
167
168       default_key
169           Value to use for the key for levels which are not specified, as
170           well as the key to use for default/fallback when looking up non-
171           existant keys (see also "lookup_mode"). Defaults to a single
172           asterisk "(*)".
173
174       no_fill
175           If true, partial composite keys are not expanded with the
176           default_key (in the middle) to fill to the last level.  Defaults to
177           0.
178
179       no_pad
180           If true, partial composite keys are not expanded with the
181           default_key (at the front or middle) to fill to the last level.
182           "no_pad" implies "no_fill". Again, see the tests for a more
183           complete explanation. Defaults to 0.
184
185       allow_deep_values
186           If true, values at the bottom level are allowed to be hashes, too,
187           for the purposes of addressing the deeper paths using composite
188           keys (see "deep_delimiter" below). Defaults to 1.
189
190       deep_delimiter
191           When "allow_deep_values" is enabled, the deep_delimiter character
192           is used to resolve composite key mappings into the deep hash values
193           (i.e. beyond the predefined levels). Must be different from the
194           delimiter used by any of the levels. Defaults to a single dot
195           "(.)".
196
197           For example:
198
199             $HL->lookup('something/foo.deeper.hash.path')
200
201       lookup_mode
202           One of either "get", "fallback" or "merge". In "fallback" mode,
203           when a non-existent composite key is looked up, the value of the
204           first closest found key path using default keys is returned instead
205           of "undef" as is the case with "get" mode. "merge" mode is like
206           "fallback" mode, except hashref values are merged with matching
207           default key paths which are also hashrefs. Defaults to "merge".
208
209   clone
210       Returns a new/cloned "Hash::Layout" instance
211
212   coerce
213       Dynamic method coerces supplied value into a new "Hash::Layout"
214       instance with a new set of loaded data.  See unit tests for more info.
215
216   coercer
217       CodeRef wrapper around "coerce()", suitable for use in a Moo-compatible
218       attribute declaration
219
220   load
221       Loads new data into the hash.
222
223       Data can be supplied as hashrefs with normal/local keys or composite
224       keys, or both. Composite keys can also be supplied as sub-keys and are
225       resolved relative to the location in which they appear as one would
226       expect.
227
228       Composite keys can also be supplied as simple strings w/o corresponding
229       values in which case their value is set to whatever "default_value" is
230       set to (which defaults to 1).
231
232       See the unit tests for more details and lots of examples of using
233       "load()".
234
235   set
236       Simpler alternative to "load()". Expects exactly two arguments as
237       standard key/values.
238
239   resolve_key_path
240       Converts a composite key string into its full path and returns it as a
241       list. Called internally wherever composite keys are resolved.
242
243   path_to_composite_key
244       Inverse of "resolve_key_path"; takes a path as a list and returns a
245       single composite key string (i.e. joins using the delimiters for each
246       level). Obviously, it only returns fully-qualified, non-ambiguous (not
247       partial) composite keys.
248
249   exists
250       Returns true if the supplied composite key exists and false if it
251       doesn't. Does not consider default/fallback key paths.
252
253   exists_path
254       Like "exists()", but requires the key to be supplied as a
255       resolved/fully-qualified path as a list of arguments.  Used internally
256       by "exists()".
257
258   get
259       Retrieves the real value of the supplied composite key, or undef if it
260       does not exist. Use "exists()" to distinguish undef values. Does not
261       consider default/fallback key paths (that is what "lookup()" is for).
262
263   get_path
264       Like "get()", but requires the key to be supplied as a
265       resolved/fully-qualified path as a list of arguments.  Used internally
266       by "get()".
267
268   lookup
269       Returns the value of the supplied composite key, falling back to
270       default key paths if it does not exist, depending on the value of
271       "lookup_mode".
272
273       If the lookup_mode is set to 'get', lookup() behaves exactly the same
274       as get().
275
276       If the lookup_mode is set to 'fallback' and the supplied key does not
277       exist, lookup() will search the hierarchy of matching default key
278       paths, returning the first value that exists.
279
280       If the lookup_mode is set to 'merge', lookup() behaves the same as it
281       does in 'fallback' mode for all non-hashref values. For hashref values,
282       the hierarchy of default key paths is searched and all matches (that
283       are themselves hashrefs), including the exact/lowest value itself, are
284       merged and returned.
285
286   lookup_path
287       Like "lookup()", but requires the key to be supplied as a
288       resolved/fully-qualified path as a list of arguments.  Used internally
289       by "lookup()".
290
291   lookup_leaf_path
292       Like "lookup_path()", but only returns the value if it is a "leaf"
293       (i.e. not a hashref with deeper sub-values).  Empty hashrefs ("{}") are
294       also considered leaf values.
295
296   delete
297       Deletes the supplied composite key and returns the deleted value, or
298       undef if it does not exist.  Does not consider default/fallback key
299       paths, or delete multiple items at once (e.g. like the Linux "rm"
300       command does with shell globs).
301
302   delete_path
303       Like "delete()", but requires the key to be supplied as a
304       resolved/fully-qualified path as a list of arguments.  Used internally
305       by "delete()".
306
307   Data
308       Returns a read-only (i.e. cloned) copy of the full loaded hash
309       structure.
310
311   num_levels
312       Returns the number of levels defined for this "Hash::Layout" instance.
313
314   level_keys
315       Returns a hashref of all the keys that have been loaded/exist for the
316       supplied level index (the first level is at index 0).
317
318   def_key_bitmask_strings
319       Debug method. Returns a list of all the default key paths as a list of
320       bitmasks (in binary/string form).  Any key path which has at least one
321       default key at any level is considered a default path and is indexed as
322       a bitmask, with '1' values representing the default key position(s).
323       For instance, the key path "{*}{*}{foo_rule}" from the 3-level example
324       from the SYNOPSIS is indexed as the bitmask 110 (6 in decimal).
325
326       These bitmasks are used internally to efficiently search for and
327       properly order default key values for quick fallback/merge lookups,
328       even when there are a very large number of levels (and thus very, VERY
329       large number of possible default paths). That is why they are tracked
330       and indexed ahead of time.
331
332       This is a debug method which should not be needed to be used for any
333       production code. I decided to leave it in just to help document some of
334       the internal workings of this module.
335
336   reset
337       Clears and removes all loaded data and resets internal key indexes and
338       counters.
339

EXAMPLES

341       For more examples, see the following:
342
343       ·   The SYNOPSIS
344
345       ·   The unit tests in "t/"
346
347       ·   DBIx::Class::Schema::Diff#filter
348

AUTHOR

350       Henry Van Styn <vanstyn@cpan.org>
351
353       This software is copyright (c) 2014 by IntelliTree Solutions llc.
354
355       This is free software; you can redistribute it and/or modify it under
356       the same terms as the Perl 5 programming language system itself.
357
358
359
360perl v5.32.0                      2020-07-28                   Hash::Layout(3)
Impressum