App-karr

 view release on metacpan or  search on metacpan

docs/superpowers/plans/2026-03-19-v0004-implementation.md  view on Meta::CPAN

is $read_back, $test_content, 'read_ref returns original content';

# Verify the ref points to a commit (not a blob)
my $obj_type = $git->_git_cmd('cat-file', '-t', 'refs/karr/test/data');
is $obj_type, 'commit', 'ref points to a commit object';

# Test read of nonexistent ref
my $missing = $git->read_ref('refs/karr/nonexistent');
is $missing, '', 'missing ref returns empty string';

# Test delete_ref
$git->delete_ref('refs/karr/test/data');
my $after_delete = $git->read_ref('refs/karr/test/data');
is $after_delete, '', 'deleted ref returns empty string';
```

- [ ] **Step 6: Run test to verify it passes**

Run: `prove -l t/13-git-refs.t`
Expected: PASS

- [ ] **Step 7: Run all existing tests to verify no regressions**

Run: `prove -l t/`
Expected: All pass (Git.pm interface is backward-compatible for existing callers)

- [ ] **Step 8: Commit**

```bash
git add lib/App/karr/Git.pm t/13-git-refs.t
git commit -m "feat: rewrite Git.pm with safe execution and commit-wrapped refs"
```

---

### Task 2: Refactor Task.pm parsing

**Files:**
- Modify: `lib/App/karr/Task.pm`
- Test: `t/14-task-parse.t`

- [ ] **Step 1: Write failing test for `from_string`**

```perl
# t/14-task-parse.t
use strict;
use warnings;
use Test::More;
use File::Temp qw( tempdir );
use Path::Tiny;
use App::karr::Task;

my $content = <<'MD';
---
id: 42
title: Test from_string
status: todo
priority: high
class: standard
created: 2026-03-19T10:00:00Z
updated: 2026-03-19T10:00:00Z
---

This is the body.
MD

# Test from_string
my $task = App::karr::Task->from_string($content);
is $task->id, 42, 'from_string: id';
is $task->title, 'Test from_string', 'from_string: title';
is $task->status, 'todo', 'from_string: status';
is $task->body, 'This is the body.', 'from_string: body';
ok !$task->has_file_path, 'from_string: no file_path';

# Test from_file gives same result
my $dir = tempdir( CLEANUP => 1 );
my $file = path($dir)->child('042-test-from-string.md');
$file->spew_utf8($content);

my $file_task = App::karr::Task->from_file($file);
is $file_task->id, $task->id, 'from_file matches from_string: id';
is $file_task->title, $task->title, 'from_file matches from_string: title';
is $file_task->body, $task->body, 'from_file matches from_string: body';
ok $file_task->has_file_path, 'from_file: has file_path';

done_testing;
```

- [ ] **Step 2: Run test to verify it fails**

Run: `prove -l t/14-task-parse.t`
Expected: FAIL (`from_string` method does not exist yet)

- [ ] **Step 3: Implement `_parse_content` and `from_string`, refactor `from_file`**

In `lib/App/karr/Task.pm`, replace the existing `from_file` with:

```perl
sub _parse_content {
    my ($class, $content) = @_;
    my ($yaml, $body) = $content =~ m{^---\n(.+?)---\n(.*)$}s
        or die "Invalid task format\n";
    $body //= '';
    $body =~ s/^\n//;
    $body =~ s/\n$//;
    return (Load($yaml), $body);
}

sub from_string {
    my ($class, $content) = @_;
    my ($fm, $body) = $class->_parse_content($content);
    return $class->new(%$fm, body => $body);
}

sub from_file {
    my ($class, $file) = @_;
    $file = path($file);
    my ($fm, $body) = $class->_parse_content($file->slurp_utf8);
    return $class->new(%$fm, body => $body, file_path => $file);
}
```



( run in 0.314 second using v1.01-cache-2.11-cpan-bbe5e583499 )