App-karr
view release on metacpan or search on metacpan
lib/App/karr/BoardStore.pm view on Meta::CPAN
=head1 NAME
App::karr::BoardStore - Ref-backed board storage for karr
=head1 VERSION
version 0.600
=head1 SYNOPSIS
my $store = App::karr::BoardStore->new( git => $git );
my $config = $store->load_config;
my $id = $store->allocate_next_id;
my @tasks = $store->load_tasks;
=head1 DESCRIPTION
L<App::karr::BoardStore> treats C<refs/karr/*> as the canonical board state.
It can merge sparse config overrides with code defaults, allocate numeric task
ids through a dedicated metadata ref, and materialize or serialize temporary
board views for command handlers that still work with files internally.
=head2 git
The L<App::karr::Git> instance this store reads and writes board refs
through. Required.
=head1 SEE ALSO
L<karr>, L<App::karr>, L<App::karr::Git>, L<App::karr::Task>,
L<App::karr::Config>
=head2 board_exists
True when this repository holds an initialized board, which means exactly one
thing: C<refs/karr/config> is there. It used to accept C<refs/karr/meta/next-id>
on its own as well, and that is how a stray C<karr create> in the wrong
directory produced a board that C<karr init> then refused to touch for good --
the half-board counted as existing, so the name, the statuses and the
F<.gitignore> entries could never be written (#62).
my $whole = $store->board_exists;
Callers state the refusal through L<App::karr::Role::BoardDiscovery/require_board>
rather than testing this themselves: a repository that fails this check may
still hold a half-board's tasks, and the two cases need different words (#133).
=head2 has_board_refs
True when anything at all lives under C<refs/karr/>, initialized board or not.
This is the question the commands that clean up or read raw refs
(C<backup>, C<destroy>, C<materialize>, C<repair>) actually have: refusing them
on a half-board would strand the refs a pre-fix karr already left behind, with
no way to remove them from inside karr.
my $anything_here = $store->has_board_refs;
=head2 load_config_overrides
Returns the board's raw config overrides -- whatever C<refs/karr/config>
currently holds, decoded but not merged with the code defaults. A board with
no config ref yet, or one whose ref does not decode to a mapping, answers
C<{}> rather than C<undef> or dying.
my $overrides = $store->load_config_overrides; # sparse, not effective
This is the input L</load_config> merges over
L<App::karr::Config/default_config>; see that method for the merged result,
and L</effective_config> for its cached form.
=head2 load_config
Reads L</load_config_overrides> and merges them over the code defaults via
L<App::karr::Config/effective_config>, returning a plain hash reference --
not a blessed L<App::karr::Config> object. Every call re-reads the config
ref; L</effective_config> is the cached wrapper most callers want instead.
my $ec = $store->load_config;
=head2 effective_config
The board's merged config, cached for the lifetime of this C<$store>
instance. The first call runs L</load_config>; every call after returns the
same hash reference until L</save_config> invalidates the cache. This is the
entry point almost every command and role uses --
C<< App::karr::Config->from_merged( $store->effective_config ) >> is the
standard way to get a queryable L<App::karr::Config> object for the current
board (see L<App::karr::Config/from_merged>).
Not to be confused with the class method
L<App::karr::Config/effective_config>, which does the actual default/override
merge and takes no board at all; this method is the per-store cache built on
top of it.
my $ec = $store->effective_config;
my $config = App::karr::Config->from_merged($ec);
=head2 all_status_names
Returns a list of all status names from the effective config.
my @statuses = $store->all_status_names;
=head2 status_requires_claim
Returns true if the given status requires a claim.
if ($store->status_requires_claim('in-progress')) {
# must use --claim to move here
}
=head2 is_terminal_status
Returns true if the status is terminal for this board -- its final configured
status, or C<archived>.
unless ($store->is_terminal_status($task->status)) {
# task is still active
}
=head2 foundation_enabled
( run in 1.233 second using v1.01-cache-2.11-cpan-364913b4093 )