NAME

Data::Hopen::Scope - a nested key-value store.

SYNOPSIS

A Scope represents a set of data available to operations. It is a key-value store that falls back to an outer Scope if a requested key isn't found.

This class is the abstract base of Scopes. See Data::Hopen::Scope::Hash for an example of a concrete implementation using a hash under the hood. Different subclasses use different representations. See "FUNCTIONS TO BE OVERRIDDEN IN SUBCLASSES" for more on that topic.

STATIC EXPORTS

FIRST_ONLY

A flag used as a "$set" (q.v.).

ATTRIBUTES

outer

The fallback Scope for looking up names not found in this Scope. If non is provided, it is undef, and no fallback will happen.

local

(Default falsy.) If truthy, do not go past this scope when doing local lookups (see "$levels" below).

name

Not used, but provided so you can use "hnew" in Data::Hopen to make Scopes.

merge_strategy

How the inputs of "merge" will be treated. Case-insensitive. Note that changes after the first time you call "merge" will be ignored! (TODO change this - just need a custom setter)

Values are:

undef or 'combine' (default)

"Retainment Precedence" in Hash::Merge. Same-name keys are merged, so no data is lost.

'keep'

"Left Precedence" in Hash::Merge. Existing data will not be replaced by new data.

'replace'

"Right Precedence" in Hash::Merge. New data will replace existing data. under a particular key will win.

PARAMETERS

The methods generally receive the same parameters. They are as follows.

$name

The name of an item to be looked up. Names must be truthy. That means, among other things, that '0' is not a valid name.

$set

A Scope can have multiple sets of data. $set specifies which one to look in.

  • If specified as a number or a name, look only in that set.

  • If '*', look in every available set at this level, and return a hashref of { set_name => value }. Note that this is not recursive --- it won't collect all instances of the given name from all sets in all the levels. (TODO? change this?)

  • If "FIRST_ONLY", look in only the first set (usually named 0).

  • If unspecified or undefined, look in every available set at this level, and return the first one found, regardless of which set it comes from.

$levels

How many levels up ("outer") to go when performing an operation. Note: chains more than POSIX::INT_MAX ("LIMITS" in POSIX) Scopes long may fail in unexpected ways, depending on your platform! For 32- or 64-bit platforms, that number is at least 2,000,000,000, so you're probably OK :) .

  • If numeric and non-negative, go up that many more levels (i.e., $levels==0 means only return this scope's local names).

  • If 'local', go up until reaching a scope with "local" set. If the current scope has "local" set, don't go up at all.

  • If not provided or not defined, go all the way to the outermost Scope.

METHODS

See also "put", below, which is part of the public API.

find

Find a named data item in the scope and return it. Looks up the scope chain to the outermost scope if necessary. Returns undef on failure. Usage:

$scope->find($name[, $set[, $levels]]);
$scope->find($name[, -set => $set][, -levels => $levels]);
    # Alternative using named arguments

Dies if given a falsy name, notably, '0'.

names

Returns a Set::Scalar of the names of the items available through this Scope, optionally including all its parent Scopes (if any). Usage and example:

my $set = $scope->names([$levels]);
say "Name $_ is available" foreach @$set;   # Set::Scalar supports @$set

If no names are available in the given $levels, returns an empty Set::Scalar.

TODO support a $set parameter

as_hashref

Returns a hash of the items available through this Scope, optionally including all its parent Scopes (if any). Usage:

my $hashref = $scope->as_hashref([-levels => $levels][, -deep => $deep])

If $levels is provided and nonzero, go up that many more levels (i.e., $levels==0 means only return this scope's local names). If $levels is not provided, go all the way to the outermost Scope.

If $deep is provided and truthy, make a deep copy of each value (using "clone" in Data::Hopen. Otherwise, just copy.

TODO support a $set parameter

outerize

Set "outer", and return a scalar that will restore "outer" when it goes out of scope. Usage:

my $saver = $scope->outerize($new_outer);

$new_outer may be undef or a valid Scope.

_merger (internal)

Creates a Hash::Merge instance based on "merge_strategy", if one doesn't exist. Returns the instance.

Provided for the convenience of subclasses; not actually used by any concrete functions in this package.

FUNCTIONS TO BE OVERRIDDEN IN SUBCLASSES

To implement a Scope with a different data-storage model than the hash this class uses, subclass Scope and override these functions. Of these, only "put" and "merge" are part of the public API.

put

Add key-value pairs to this scope. Returns the scope so you can chain. Example usage:

my $scope = Data::Hopen::Scope->new()->put(foo => 1);

put overwrites data in case of any conflicts. See "merge" if you want more control.

put may be called with no parameters, in which case it is a no-op. This is so you can say $s->put(%foo) without first having to check whether %foo is nonempty.

TODO add $set option. TODO? add -deep option?

merge

Merges key-value pairs into this scope. Returns the scope so you can chain. Example usage:

my $scope = Data::Hopen::Scope->new()->merge(foo => 1);

See "merge_strategy" for options controlling the behaviour of merge().

_names_here

Populates a Set::Scalar with the names of the items stored in this Scope, but not any outer Scope. Called as:

$scope->_names_here($retval[, $set])

$retval is the Set::Scalar instance. $set is as defined above.

No return value.

_find_here

Looks for a given item in this scope, but not any outer scope. Called as:

$scope->_find_here($name[, $set])

Returns the value, or undef if not found.

HELPER FUNCTIONS

is_first_only

Test whether the given scalar is "FIRST_ONLY". Usage: is_first_only($x).

_set0

For use only by subclasses.

Don't support -set, but permit -set=>0 and -set=>FIRST_ONLY for the sake of code calling through the Scope interface. Call as set0($set)>. Returns truthy if OK, falsy if not. May modify its argument. Better a readily-obvious crash than a subtle bug!