--- /dev/null
+package App::Commentry::Comment;
+
+use Moo;
+
+has title => (is => 'ro', required => 1);
+has body => (is => 'ro', required => 1);
+
+1;
--- /dev/null
+package App::Commentry::CommentSet;
+
+use aliased 'App::Commentry::Comment';
+use JSON;
+use Moo;
+
+has base_dir => (is => 'ro', required => 1);
+has path => (is => 'ro', required => 1);
+
+has _json => (is => 'lazy');
+
+sub _build__json { JSON->new->utf8->pretty }
+
+has _members => (is => 'lazy');
+
+sub _build__members {
+ my ($self) = @_;
+ my $file = join('/', $self->base_dir, $self->path).'.json';
+ return [] unless -e $file;
+ my $text = do {
+ open my $in, '<', $file
+ or die "Couldn't open ${file}: $!";
+ local $/; <$in>;
+ };
+ [ map Comment->new($_), @{$self->_json->decode($text)} ];
+}
+
+sub flatten {
+ my ($self) = @_;
+ @{$self->_members};
+}
+
+1;
--- /dev/null
+package App::Commentry::CommentStore;
+
+use aliased 'App::Commentry::CommentSet';
+use Moo;
+
+has base_dir => (is => 'ro', required => 1);
+
+has _cache => (is => 'ro', default => sub { {} });
+
+sub get {
+ my ($self, $proto) = @_;
+ my $path = $proto->{path} or die "->get requires a path key";
+ $self->_cache->{$path} ||= do {
+ CommentSet->new(base_dir => $self->base_dir, path => $path)
+ };
+}
+
+1;
--- /dev/null
+use strictures 1;
+use Test::More;
+use aliased 'App::Commentry::CommentStore';
+use aliased 'App::Commentry::Comment';
+
+my $store = CommentStore->new(base_dir => 't/var/exstore');
+
+is_deeply(
+ [ $store->get({ path => 'not/there' })->flatten ],
+ [], 'Nonexistent set is empty'
+);
+
+is_deeply(
+ [ $store->get({ path => 'one/two/three' })->flatten ],
+ [ map Comment->new({ title => "Title $_", body => "Body $_" }), 1, 2 ],
+ 'Existing set loads ok'
+);
+
+done_testing;