1Hash::Layout(3) User Contributed Perl Documentation Hash::Layout(3)
2
3
4
6 Hash::Layout - hashes with predefined levels, composite keys and
7 default values
8
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
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
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 enable_globmatch
210 If true, key value lookup calls will automatically try to match
211 wildcard (text glob) expressions. Defaults to false (0).
212
213 clone
214 Returns a new/cloned "Hash::Layout" instance
215
216 coerce
217 Dynamic method coerces supplied value into a new "Hash::Layout"
218 instance with a new set of loaded data. See unit tests for more info.
219
220 coercer
221 CodeRef wrapper around coerce(), suitable for use in a Moo-compatible
222 attribute declaration
223
224 load
225 Loads new data into the hash.
226
227 Data can be supplied as hashrefs with normal/local keys or composite
228 keys, or both. Composite keys can also be supplied as sub-keys and are
229 resolved relative to the location in which they appear as one would
230 expect.
231
232 Composite keys can also be supplied as simple strings w/o corresponding
233 values in which case their value is set to whatever "default_value" is
234 set to (which defaults to 1).
235
236 See the unit tests for more details and lots of examples of using
237 load().
238
239 set
240 Simpler alternative to load(). Expects exactly two arguments as
241 standard key/values.
242
243 resolve_key_path
244 Converts a composite key string into its full path and returns it as a
245 list. Called internally wherever composite keys are resolved.
246
247 path_to_composite_key
248 Inverse of "resolve_key_path"; takes a path as a list and returns a
249 single composite key string (i.e. joins using the delimiters for each
250 level). Obviously, it only returns fully-qualified, non-ambiguous (not
251 partial) composite keys.
252
253 exists
254 Returns true if the supplied composite key exists and false if it
255 doesn't. Does not consider default/fallback key paths.
256
257 exists_path
258 Like exists(), but requires the key to be supplied as a
259 resolved/fully-qualified path as a list of arguments. Used internally
260 by exists().
261
262 get
263 Retrieves the real value of the supplied composite key, or undef if it
264 does not exist. Use exists() to distinguish undef values. Does not
265 consider default/fallback key paths (that is what lookup() is for).
266
267 get_path
268 Like get(), but requires the key to be supplied as a
269 resolved/fully-qualified path as a list of arguments. Used internally
270 by get().
271
272 lookup
273 Returns the value of the supplied composite key, falling back to
274 default key paths if it does not exist, depending on the value of
275 "lookup_mode".
276
277 If the lookup_mode is set to 'get', lookup() behaves exactly the same
278 as get().
279
280 If the lookup_mode is set to 'fallback' and the supplied key does not
281 exist, lookup() will search the hierarchy of matching default key
282 paths, returning the first value that exists.
283
284 If the lookup_mode is set to 'merge', lookup() behaves the same as it
285 does in 'fallback' mode for all non-hashref values. For hashref values,
286 the hierarchy of default key paths is searched and all matches (that
287 are themselves hashrefs), including the exact/lowest value itself, are
288 merged and returned.
289
290 lookup_path
291 Like lookup(), but requires the key to be supplied as a
292 resolved/fully-qualified path as a list of arguments. Used internally
293 by lookup().
294
295 lookup_leaf_path
296 Like lookup_path(), but only returns the value if it is a "leaf" (i.e.
297 not a hashref with deeper sub-values). Empty hashrefs ("{}") are also
298 considered leaf values.
299
300 lookup_path_globmatch
301 Like lookup_path(), but matches/returns by comparing a full composite
302 key string with wildcard (text glob) expressions.
303
304 delete
305 Deletes the supplied composite key and returns the deleted value, or
306 undef if it does not exist. Does not consider default/fallback key
307 paths, or delete multiple items at once (e.g. like the Linux "rm"
308 command does with shell globs).
309
310 delete_path
311 Like delete(), but requires the key to be supplied as a
312 resolved/fully-qualified path as a list of arguments. Used internally
313 by delete().
314
315 Data
316 Returns a read-only (i.e. cloned) copy of the full loaded hash
317 structure.
318
319 num_levels
320 Returns the number of levels defined for this "Hash::Layout" instance.
321
322 level_keys
323 Returns a hashref of all the keys that have been loaded/exist for the
324 supplied level index (the first level is at index 0).
325
326 def_key_bitmask_strings
327 Debug method. Returns a list of all the default key paths as a list of
328 bitmasks (in binary/string form). Any key path which has at least one
329 default key at any level is considered a default path and is indexed as
330 a bitmask, with '1' values representing the default key position(s).
331 For instance, the key path "{*}{*}{foo_rule}" from the 3-level example
332 from the SYNOPSIS is indexed as the bitmask 110 (6 in decimal).
333
334 These bitmasks are used internally to efficiently search for and
335 properly order default key values for quick fallback/merge lookups,
336 even when there are a very large number of levels (and thus very, VERY
337 large number of possible default paths). That is why they are tracked
338 and indexed ahead of time.
339
340 This is a debug method which should not be needed to be used for any
341 production code. I decided to leave it in just to help document some of
342 the internal workings of this module.
343
344 reset
345 Clears and removes all loaded data and resets internal key indexes and
346 counters.
347
349 For more examples, see the following:
350
351 • The SYNOPSIS
352
353 • The unit tests in "t/"
354
355 • DBIx::Class::Schema::Diff#filter
356
358 Henry Van Styn <vanstyn@cpan.org>
359
361 This software is copyright (c) 2014 by IntelliTree Solutions llc.
362
363 This is free software; you can redistribute it and/or modify it under
364 the same terms as the Perl 5 programming language system itself.
365
366
367
368perl v5.36.0 2023-01-20 Hash::Layout(3)