Skip to content
Browse files

add the rest of the model

  • Loading branch information...
1 parent b192cc2 commit ead538c611860a3531859fc46384188d6695abbd @jrockway committed
View
2 lib/Ai/Article.pm
@@ -1,6 +1,6 @@
use MooseX::Declare;
-role Ai::Article with KiokuDB::Role::ID::Content {
+role Ai::Article with (KiokuDB::Role::ID::Content, Ai::Role::WithDependencies) {
use Digest::SHA1 qw(sha1_hex);
has [qw/title content/] => (
View
3 lib/Ai/Article/Simple.pm
@@ -2,7 +2,8 @@ use MooseX::Declare;
class Ai::Article::Simple
with Ai::Article
+ with Ai::Role::WithDependencies::Set
with Ai::Article::Versioned
with Ai::Article::Markdown {
-
+
}
View
4 lib/Ai/Dependency.pm
@@ -0,0 +1,4 @@
+use MooseX::Declare;
+
+# | Represents something that another resource depends on
+role Ai::Dependency {}
View
14 lib/Ai/Dependency/File.pm
@@ -0,0 +1,14 @@
+use MooseX::Declare;
+
+# | Represents a dependency on a file on the filesystem at
+# blog-creation time
+role Ai::Dependency::File with Ai::Dependency {
+ use MooseX::FileAttributes;
+
+ has_file 'path' => (
+ required => 1,
+ must_exist => 1,
+ );
+}
+
+1;
View
19 lib/Ai/Dependency/Image.pm
@@ -0,0 +1,19 @@
+use MooseX::Declare;
+
+# | An image
+role Ai::Dependency::Image {
+ has 'name' => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ has 'alt_text' => (
+ is => 'ro',
+ isa => 'Str',
+ predicate => 'has_alt_text',
+ );
+
+ requires 'image_format';
+ requires 'image_data';
+}
View
16 lib/Ai/Dependency/Image/File.pm
@@ -0,0 +1,16 @@
+use MooseX::Declare;
+
+# | An image that exists on disk
+class Ai::Dependency::Image::File with (Ai::Dependency::Image, Ai::Dependency::File) {
+
+ method image_format {
+ my $bn = $self->path->basename;
+ my (@parts) = split /[.]/, $bn;
+ return $parts[-1] || confess 'unknown format';
+ }
+
+ method image_data {
+ return $self->path->slurp;
+ }
+
+}
View
9 lib/Ai/Link.pm
@@ -0,0 +1,9 @@
+use MooseX::Declare;
+
+role Ai::Link with Ai::Dependency {
+ requires 'type';
+ requires 'namespace';
+ requires 'name';
+}
+
+1;
View
19 lib/Ai/Link/Resolved.pm
@@ -0,0 +1,19 @@
+use MooseX::Declare;
+
+class Ai::Link::Resolved with Ai::Link {
+ use Ai::Types qw(Dependency);
+
+ has [qw/type name namespace/] => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ has 'target' => (
+ is => 'ro',
+ isa => Dependency,
+ required => 1,
+ );
+}
+
+1;
View
9 lib/Ai/Link/Unresolved.pm
@@ -0,0 +1,9 @@
+use MooseX::Declare;
+
+class Ai::Link::Unresolved with Ai::Link {
+ has [qw/type name namespace/] => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+}
View
7 lib/Ai/Mapper.pm
@@ -0,0 +1,7 @@
+use MooseX::Declare;
+
+# | Map pages / dependencies to a URL
+role Ai::Mapper {
+ requires 'url_for';
+ requires 'storage_for';
+}
View
12 lib/Ai/Mapper/Blog.pm
@@ -0,0 +1,12 @@
+use MooseX::Declare;
+
+class Ai::Mapper::Blog with Ai::Role::WithSite {
+ use MooseX::MultiMethods;
+ use Ai::Types qw(Page Link);
+ use URI;
+
+ method url_for(Page $page){
+ return URI->new('urn:page:index.html')
+ if $page->isa('Ai::Page::Index');
+ }
+}
View
8 lib/Ai/Page.pm
@@ -0,0 +1,8 @@
+use MooseX::Declare;
+
+role Ai::Page with (Ai::Dependency, Ai::Role::WithDependencies) {
+ requires 'name';
+ requires 'content'; # hashref of filename -> data mapping
+}
+
+1;
View
20 lib/Ai/Page/Article.pm
@@ -0,0 +1,20 @@
+use MooseX::Declare;
+
+role Ai::Page::Article with Ai::Page {
+ use Ai::Types qw(Article);
+ has 'article' => (
+ is => 'ro',
+ isa => Article,
+ required => 1,
+ );
+
+ method name {
+ return $self->article->title;
+ }
+
+ around list_dependencies {
+ return $self->$orig, $self->article->list_dependencies;
+ }
+}
+
+1;
View
5 lib/Ai/Page/Blog.pm
@@ -0,0 +1,5 @@
+use MooseX::Declare;
+
+role Ai::Page::Blog with Ai::Page::WithSite {}
+
+1;
View
10 lib/Ai/Page/Blog/Article.pm
@@ -0,0 +1,10 @@
+use MooseX::Declare;
+
+class Ai::Page::Blog::Article with (Ai::Page::Blog, Ai::Page::Article) {
+ method content {
+ return {
+ html => 'brought to you by "'. $self->site->title. '": '.
+ $self->article->content_as_html,
+ };
+ }
+}
View
15 lib/Ai/Page/Blog/Index.pm
@@ -0,0 +1,15 @@
+use MooseX::Declare;
+
+class Ai::Page::Blog::Index with (Ai::Page::Blog, Ai::Page::Index) {
+ method name {
+ 'Index';
+ }
+
+ method content {
+ return {
+ html =>
+ 'index for "'. $self->site->title. '": '. join '',
+ map { $_->name } $self->site->pages->members,
+ }
+ }
+}
View
5 lib/Ai/Page/Index.pm
@@ -0,0 +1,5 @@
+use MooseX::Declare;
+
+role Ai::Page::Index with Ai::Page {}
+
+1;
View
9 lib/Ai/Page/WithSite.pm
@@ -0,0 +1,9 @@
+use MooseX::Declare;
+
+role Ai::Page::WithSite with (Ai::Role::WithSite, Ai::Role::WithDependencies::Set, Ai::Page) {
+ around list_dependencies {
+ return $self->site->list_dependencies, $self->$orig;
+ }
+}
+
+1;
View
7 lib/Ai/Role/WithDependencies.pm
@@ -0,0 +1,7 @@
+use MooseX::Declare;
+
+role Ai::Role::WithDependencies {
+ requires 'list_dependencies';
+}
+
+1;
View
23 lib/Ai/Role/WithDependencies/Set.pm
@@ -0,0 +1,23 @@
+use MooseX::Declare;
+
+role Ai::Role::WithDependencies::Set with Ai::Role::WithDependencies {
+ use Ai::Types qw(Set Dependency);
+ use KiokuDB::Util qw(set);
+
+ has 'dependencies' => (
+ is => 'ro',
+ isa => Set,
+ coerce => 1,
+ default => sub { set() },
+ );
+
+ method list_dependencies {
+ return $self->dependencies->members;
+ }
+
+ method add_dependency( Dependency $dep ) {
+ $self->dependencies->insert($dep);
+ }
+}
+
+1;
View
11 lib/Ai/Role/WithSite.pm
@@ -0,0 +1,11 @@
+use MooseX::Declare;
+
+role Ai::Role::WithSite {
+ use Ai::Types qw(Site);
+
+ has 'site' => (
+ is => 'ro',
+ isa => Site,
+ required => 1,
+ );
+}
View
9 lib/Ai/Site.pm
@@ -0,0 +1,9 @@
+use MooseX::Declare;
+
+role Ai::Site {
+ requires 'add_page';
+ requires 'list_pages';
+ requires 'url_mapper';
+}
+
+1;
View
35 lib/Ai/Site/Blog.pm
@@ -0,0 +1,35 @@
+use MooseX::Declare;
+
+class Ai::Site::Blog with (Ai::Site::Simple, Ai::Site::WithIndex) {
+ use Ai::Types qw(Article);
+ use Ai::Page::Blog::Article;
+ use Ai::Page::Blog::Index;
+
+ has 'title' => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ method _build_index_page {
+ Ai::Page::Blog::Index->new(
+ site => $self,
+ );
+ }
+
+ method _build_url_mapper {
+ Ai::Mapper::Blog->new(
+ site => $self,
+ );
+ }
+
+ method add_article(Article $article){
+ my $page = Ai::Page::Blog::Article->new(
+ site => $self,
+ article => $article,
+ );
+
+ $self->add_page($page);
+ return $page;
+ }
+}
View
39 lib/Ai/Site/Simple.pm
@@ -0,0 +1,39 @@
+use MooseX::Declare;
+
+role Ai::Site::Simple with (Ai::Site, Ai::Role::WithDependencies::Set) {
+ use Ai::Types qw(Set Page);
+ use KiokuDB::Util qw(set);
+
+ has 'pages' => (
+ is => 'ro',
+ isa => Set,
+ default => sub { set() },
+ coerce => 1,
+ handles => {
+ add_page => 'insert',
+ list_pages => 'members',
+ },
+ );
+
+ has 'url_mapper' => (
+ reader => '_moose_roles_suck',
+ is => 'ro',
+ lazy_build => 1,
+ );
+
+ method url_mapper { $self->_moose_roles_suck }
+
+ requires '_build_url_mapper';
+
+ method list_pages {
+ return $self->index_page, $self->pages->members;
+ }
+
+ method add_page(Page $page) {
+ $self->pages->insert($page);
+ }
+
+}
+
+1;
+
View
24 lib/Ai/Site/WithIndex.pm
@@ -0,0 +1,24 @@
+use MooseX::Declare;
+
+role Ai::Site::WithIndex {
+ use Ai::Types qw(IndexPage);
+
+ with 'Ai::Site';
+
+ has 'index_page' => (
+ is => 'ro',
+ isa => IndexPage,
+ lazy_build => 1,
+ );
+
+ requires '_build_index_page';
+
+ around list_pages {
+ return $self->index_page, $self->$orig;
+ }
+
+ before add_page($page){
+ confess 'cannot add an index page'
+ if $page->does('Ai::Page::Index');
+ }
+}
View
37 lib/Ai/Types.pm
@@ -2,21 +2,44 @@ package Ai::Types;
use strict;
use warnings;
-use KiokuDB::Set;
-use MooseX::Types -declare => [qw/Site Article Search Page Link Set PathPart/];
-use MooseX::Types::Moose qw(Str);
+use KiokuDB::Util qw(set);
+use MooseX::Types::Moose qw(ArrayRef);
+
+use MooseX::Types -declare => [qw{
+ Site
+ Article
+ Page
+ Dependency
+ Link
+
+ Set
+
+ Model
+
+ IndexPage
+
+ WithDependencies
+}];
role_type Site, { role => 'Ai::Site' };
role_type Article, { role => 'Ai::Article' };
-role_type Search, { role => 'Ai::Search' };
+
role_type Page, { role => 'Ai::Page' };
+role_type IndexPage, { role => 'Ai::Page::Index' };
+
+role_type Dependency, { role => 'Ai::Dependency' };
role_type Link, { role => 'Ai::Link' };
role_type Set, { role => 'KiokuDB::Set' };
+coerce Set, from ArrayRef, via {
+ my $array = shift;
+ my $set = set();
+ $set->insert($_) for @$array;
+ return $set;
+};
+class_type Model, { class => 'Ai::Model' };
-subtype PathPart, as Str,
- where { !m{/} },
- message { 'PathPart must not contain a /' };
+role_type WithDependencies, { role => 'Ai::Role::WithDependencies' };
1;
View
61 t/small-blog.t
@@ -0,0 +1,61 @@
+use strict;
+use warnings;
+use Test::More;
+
+use Ai::Site::Blog;
+use Ai::Article::Simple;
+
+use MooseX::Declare;
+
+class Image with (Ai::Dependency::Image) {
+ has 'image' => ( is => 'ro', required => 1);
+ method image_data { $self->image };
+ method image_format { 'txt' }
+}
+
+class Template with (Ai::Dependency) {
+ has 'name' => ( is => 'ro' );
+}
+
+my $blog = Ai::Site::Blog->new(
+ title => 'I CAN HAZ LOLCATS',
+ dependencies => [
+ Image->new(
+ name => 'cats.jpg',
+ image => '<picture of cats>',
+ ),
+ ],
+);
+
+my $article = Ai::Article::Simple->new(
+ title => 'OH HAI, HERE IS A KITTEH',
+ revision_date => DateTime->now,
+ dependencies => [
+ Image->new(
+ name => 'nibbler.jpg',
+ image => '<picture of nibbler the cat>',
+ alt_text => 'Nibbler the cat!',
+ ),
+ ],
+ content => 'Here is a picture of a cat: '.
+ '![Nibbler the cat](nibbler.jpg)',
+);
+
+$blog->add_article($article);
+
+my @pages = $blog->list_pages;
+ok @pages == 2, 'got 2 pages';
+
+my ($ip, $ap) = @pages;
+
+$ap->add_dependency(
+ Template->new( name => 'foo.tt' ),
+);
+
+ok $ip->does('Ai::Page::Index'), 'got an index page';
+ok $ap->does('Ai::Page'), 'got an article page';
+
+is_deeply [ sort map { $_->name } $ap->list_dependencies ],
+ [sort qw/foo.tt nibbler.jpg cats.jpg/], 'got dependencies for article page';
+
+done_testing;

0 comments on commit ead538c

Please sign in to comment.
Something went wrong with that request. Please try again.