Created
September 27, 2008 22:41
-
-
Save beppu/13381 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package CouchWiki; | |
use strict; | |
use warnings; | |
use base 'Squatting'; | |
use Coro::AnyEvent; | |
our %CONFIG = ( | |
db => 'couchwiki' | |
); | |
#_____________________________________________________________________________ | |
package CouchWiki::Models; | |
use strict; | |
use warnings; | |
use AnyEvent::CouchDB; | |
use Text::Textile; | |
use Clone 'clone'; | |
# $db = db | |
our $DB; | |
our $DESIGN_PAGES = { | |
_id => "_design/pages", | |
language => "javascript", | |
views => { | |
recent => { | |
map => "function(doc) { if (doc.type == 'Page') emit(doc.created_date, doc); }", | |
}, | |
}, | |
}; | |
sub db { | |
$DB || do { | |
$DB = couchdb($CouchWiki::CONFIG{db}); | |
eval { $DB->info->recv; }; | |
if ($@) { | |
$DB->create->recv; | |
$DB->save_doc($DESIGN_PAGES)->recv; | |
} | |
$DB; | |
}; | |
} | |
# timestamp - I had no idea this would be 60x faster than: DateTime->now.""; | |
sub timestamp { | |
my ($sec,$min,$hour,$mday,$mon,$year) = gmtime; | |
sprintf( | |
'%d-%02d-%02dT%02d:%02d:%02d', | |
$year+1900,$mon+1,$mday, | |
$hour,$min,$sec | |
); | |
} | |
# $doc = page('WikiPageTitle'); | |
# $doc = page('WikiPageTitle' => 'new text for page'); | |
our $PAGE = { type => 'Page', raw => 'Edit me.', html => '<div>Edit me.</div>' }; | |
our $TEXTILE = Text::Textile->new(disable_html => 1); | |
sub page { | |
my ($title, $text) = @_; | |
my $db = db; | |
my $doc; | |
eval { $doc = $db->open_doc($title)->recv; }; | |
if (!$doc) { | |
$doc = clone($PAGE); | |
$doc->{_id} = $title; | |
} | |
if ($text) { | |
$doc->{raw} = $text; | |
$doc->{html} = $TEXTILE->process($text); | |
$doc->{created_date} = timestamp; | |
$db->save_doc($doc)->recv; | |
} | |
return $doc; | |
} | |
# $pages = recent_changes(); | |
sub recent_changes { | |
my $db = db; | |
my $results = $db->view('pages/recent', { descending => "true" })->recv; | |
my @pages = map { $_->{value} } @{$results->{rows}}; | |
return \@pages; | |
} | |
#_____________________________________________________________________________ | |
package CouchWiki::Controllers; | |
use strict; | |
use warnings; | |
use Squatting ':controllers'; | |
use AnyEvent::CouchDB; | |
*page = \&CouchWiki::Models::page; | |
*recent_changes = \&CouchWiki::Models::recent_changes; | |
our @C = ( | |
C( | |
Page => [ '/', '/(\w+)', '/(\w+).(edit)' ], | |
get => sub { | |
my ($self, $title, $edit) = @_; | |
$title ||= 'Home'; | |
$self->v->{page} = page($title); | |
$self->v->{title} = $title; | |
if ($edit) { | |
$self->render('edit'); | |
} else { | |
$self->render('page'); | |
} | |
}, | |
post => sub { | |
my ($self, $title) = @_; | |
page($title => $self->input->{text}); | |
$self->redirect( R('Page', $title) ); | |
} | |
), | |
C( | |
RecentChanges => [ '/@recent_changes' ], | |
get => sub { | |
my ($self) = @_; | |
$self->v->{title} = "Recent Changes"; | |
$self->v->{pages} = recent_changes(); | |
$self->v->{no_edit} = 1; | |
$self->render('recent_changes'); | |
} | |
), | |
); | |
#_____________________________________________________________________________ | |
package CouchWiki::Views; | |
use strict; | |
use warnings; | |
use Squatting ':views'; | |
use HTML::AsSubs; | |
sub span { HTML::AsSubs::_elem('span', @_) } | |
sub thead { HTML::AsSubs::_elem('thead', @_) } | |
sub tbody { HTML::AsSubs::_elem('tbody', @_) } | |
sub x { map { HTML::Element->new('~literal', text => $_) } @_ } | |
our @V = ( | |
V('html', | |
layout => sub { | |
my ($self, $v, $content) = @_; | |
html( | |
head( | |
title($v->{title}) | |
), | |
body( | |
div({ id => 'couchwiki' }, | |
x($self->_menu($v)), | |
x($content), | |
) | |
), | |
)->as_HTML; | |
}, | |
_menu => sub { | |
my ($self, $v) = @_; | |
div( | |
a({ href => R('RecentChanges') }, 'Recent Changes'), | |
span(' | '), | |
a({ href => R('Page', 'Home') }, 'Home'), | |
do { | |
unless ($v->{no_edit}) { | |
( | |
span(' | '), | |
a({ href => R('Page', $v->{title}, 'edit') }, 'Edit This Page'), | |
); | |
} else { | |
() | |
} | |
}, | |
)->as_HTML; | |
}, | |
page => sub { | |
my ($self, $v) = @_; | |
div( | |
div(x($v->{page}->{html})) | |
)->as_HTML; | |
}, | |
edit => sub { | |
my ($self, $v) = @_; | |
div( | |
form( | |
{ | |
method => 'post', | |
action => R('Page', $v->{page}->{_id}), | |
}, | |
textarea( | |
{ | |
name => 'text', | |
cols => '80', | |
rows => '24', | |
}, | |
$v->{page}->{raw} | |
), | |
div(input({ type => 'submit' })), | |
), | |
)->as_HTML; | |
}, | |
recent_changes => sub { | |
my ($self, $v) = @_; | |
div( | |
ul( | |
map { | |
li( | |
a({ href => R('Page', $_->{_id}) }, $_->{_id}) | |
) | |
} @{$v->{pages}} | |
) | |
)->as_HTML; | |
}, | |
) | |
); | |
1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment