From: t0m Date: Tue, 3 Feb 2009 21:23:45 +0000 (+0000) Subject: Merge to trunk, add version note X-Git-Tag: 1.100~10 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=778b6a5a2193aa793dd1902e2b71423e0422bd3f;p=catagits%2FCatalyst-View-ContentNegotiation-XHTML.git Merge to trunk, add version note --- diff --git a/Changes b/Changes index b70205f..1ad28f9 100644 --- a/Changes +++ b/Changes @@ -1,16 +1,19 @@ +1.100 + - Refactor into a Moose Role for use with alternate views. (rafl) + - Additional documentation (t0m) 1.004 - Nick the OSX fragment out of the Catalyst::Runtime Makefile.PL to - beat my Mac into generating a correct dist. + beat my Mac into generating a correct dist. (t0m) 1.003 - Fixes an tests to be fully Internet Explorer compatible (David Dorward) - Change to MRO::Compat for perl 5.10 (t0m) 1.002 2008-12-13 - Add 'use Class::C3' so that the module works on the currently - released Catalyst version. + released Catalyst version. (t0m) 1.001 2008-12-12 - Add tests for other Accept header cases where the current code will get it wrong. (David Dorward) - Fix all of these tests. (t0m) 1.000 2008-12-12 - First working version of the module extracted from the quick hack - I have in every Catalyst application I've ever written. + I have in every Catalyst application I've ever written. (t0m) diff --git a/Makefile.PL b/Makefile.PL index 67af4d9..d6c1f7b 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,16 +1,16 @@ use inc::Module::Install; -name 'Catalyst-View-TT-XHTML'; -all_from 'lib/Catalyst/View/TT/XHTML.pm'; +name 'Catalyst-View-ContentNegotiation-XHTML'; +all_from 'lib/Catalyst/View/ContentNegotiation/XHTML.pm'; requires 'Catalyst::Runtime'; requires 'Catalyst::View::TT'; requires 'HTTP::Negotiate'; requires 'MRO::Compat'; -build_requires 'Catalyst::Action::RenderView'; -build_requires 'Test::WWW::Mechanize::Catalyst'; -build_requires 'Test::More'; +test_requires 'Catalyst::Action::RenderView'; +test_requires 'Test::WWW::Mechanize::Catalyst'; +test_requires 'Test::More'; resources repository => 'http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-View-TT-XHTML'; diff --git a/README b/README index 0bca51d..24ab739 100644 --- a/README +++ b/README @@ -1,49 +1,73 @@ NAME - Catalyst::View::TT::XHTML - A sub-class of the standard TT view which - serves application/xhtml+xml content if the browser accepts it. + Catalyst::View::ContentNegotiation::XHTML - A Moose Role to apply to + Catalyst views adjusts the response Content-Type header to + application/xhtml+xml content if the browser accepts it. SYNOPSIS - package MyApp::View::XHTML; - use strict; - use warnings; - use base qw/Catalyst::View::TT::XHTML MyApp::View::TT/; - + package Catalyst::View::TT; + + use Moose; + use namespace::clean -except => 'meta'; + + extends qw/Catalyst::View::TT/; + with qw/Catalyst::View::ContentNegotiation::XHTML/; + 1; - + DESCRIPTION - This is a very simple sub-class of Catalyst::View::TT, which sets the - response "Content-Type" to be "application/xhtml+xml" if the user's - browser sends an "Accept" header indicating that it is willing to - process that MIME type. + This is a very simple Role which uses a method modifier to run after the + "process" method, and sets the response "Content-Type" to be + "application/xhtml+xml" if the users browser sends an "Accept" header + indicating that it is willing to process that MIME type. Changing the "Content-Type" causes browsers to interpret the page as - strict XHTML, meaning that the markup must be well formed. + XML, meaning that the markup must be well formed. This is useful when you're developing your application, as you know that - all pages you view are rendered strictly, so any markup errors will show - up at once. + all pages you view are parsed as XML, so any errors caused by your + markup not being well-formed will show up at once. + +METHOD MODIFIERS + after process + Changes the response "Content-Type" if appropriate (from the requests + "Accept" header). METHODS - process - Overrides the standard process method, delegating to Catalyst::View::TT - to render the template, and then changing the response "Content-Type" if - appropriate (from the requests "Accept" header). + pragmatic_accept + Some browsers (such as Internet Explorer) have a nasty way of sending + Accept */* and this claiming to support XHTML just as well as HTML. + Saving to a file on disk or opening with another application does count + as accepting, but it really should have a lower q value then text/html. + This sub takes a pragmatic approach and corrects this mistake by + modifying the Accept header before passing it to content negotiation. -BUGS - There should be a more elegant way to inherit the config of your normal - TT view. +ATTRIBUTES + variants + Returns an array ref of 3 part arrays, comprising name, priority, output + mime-type, which is used for the content negotiation algorithm. + +PRIVATE METHODS + _build_variants + Returns the default variant attribute contents. - Configuration (as loaded by Catalyst::Plugin::ConfigLoader) for the TT - view is not used. +SEE ALSO + Catalyst::View::TT::XHTML - Trivial Catalyst TT view using this role. + - Content + negotiation RFC. + +BUGS + Will only work with Views which implement a process method. - No helper to generate the view file needed (just copy the code in the - SYNOPSIS). + Should be split into a base ContentNegotiation role which is consumed by + ContentNegotiation::XHTML. AUTHOR - Tomas Doran "" + Tomas Doran (t0m) "" CONTRIBUTORS - David Dorward - test patches + David Dorward - test patches and */* pragmatism. + Florian Ragwitz (rafl) "" - Conversion into a Moose + Role COPYRIGHT This module itself is copyright (c) 2008 Tomas Doran and is licensed diff --git a/lib/Catalyst/View/ContentNegotiation/XHTML.pm b/lib/Catalyst/View/ContentNegotiation/XHTML.pm new file mode 100644 index 0000000..f79c829 --- /dev/null +++ b/lib/Catalyst/View/ContentNegotiation/XHTML.pm @@ -0,0 +1,148 @@ +package Catalyst::View::ContentNegotiation::XHTML; + +use Moose::Role; +use MooseX::Types::Moose qw/Num Str ArrayRef/; +use MooseX::Types::Structured qw/Tuple/; +use HTTP::Negotiate qw/choose/; + +use namespace::clean -except => 'meta'; + +our $VERSION = '1.100'; + +has variants => ( + is => 'ro', + isa => ArrayRef[Tuple[Str, Num, Str]], + lazy => 1, + builder => '_build_variants', +); + +sub _build_variants { + return [ + [qw| xhtml 1.000 application/xhtml+xml |], + [qw| html 0.900 text/html |], + ]; +} + +after process => sub { + my ($self, $c) = @_; + if ($c->request->header('Accept') && $c->response->headers->{'content-type'} =~ m|text/html|) { + $self->pragmatic_accept($c); + my $var = choose($self->variants, $c->request->headers); + if ($var eq 'xhtml') { + $c->response->headers->{'content-type'} =~ s|text/html|application/xhtml+xml|; + } + } +}; + +sub pragmatic_accept { + my ($self, $c) = @_; + my $accept = $c->request->header('Accept'); + if ($accept =~ m|text/html|) { + $accept =~ s!\*/\*\s*([,]+|$)!*/*;q=0.5$1!; + } else { + $accept =~ s!\*/\*\s*([,]+|$)!text/html,*/*;q=0.5$1!; + } + $c->request->header('Accept' => $accept); +} + +1; + +__END__ + +=head1 NAME + +Catalyst::View::ContentNegotiation::XHTML - A Moose Role to apply to +Catalyst views adjusts the response Content-Type header to +application/xhtml+xml content if the browser accepts it. + +=head1 SYNOPSIS + + package Catalyst::View::TT; + + use Moose; + use namespace::clean -except => 'meta'; + + extends qw/Catalyst::View::TT/; + with qw/Catalyst::View::ContentNegotiation::XHTML/; + + 1; + +=head1 DESCRIPTION + +This is a very simple Role which uses a method modifier to run after the +C method, and sets the response C to be +C if the users browser sends an C header +indicating that it is willing to process that MIME type. + +Changing the C causes browsers to interpret the page as +XML, meaning that the markup must be well formed. + +This is useful when you're developing your application, as you know that +all pages you view are parsed as XML, so any errors caused by your markup +not being well-formed will show up at once. + +=head1 METHOD MODIFIERS + +=head2 after process + +Changes the response C if appropriate (from the requests C header). + +=head1 METHODS + +=head2 pragmatic_accept + +Some browsers (such as Internet Explorer) have a nasty way of sending +Accept */* and this claiming to support XHTML just as well as HTML. +Saving to a file on disk or opening with another application does +count as accepting, but it really should have a lower q value then +text/html. This sub takes a pragmatic approach and corrects this mistake +by modifying the Accept header before passing it to content negotiation. + +=head1 ATTRIBUTES + +=head2 variants + +Returns an array ref of 3 part arrays, comprising name, priority, output +mime-type, which is used for the content negotiation algorithm. + +=head1 PRIVATE METHODS + +=head2 _build_variants + +Returns the default variant attribute contents. + +=head1 SEE ALSO + +=over + +=item L - Trivial Catalyst TT view using this role. + +=item L - Content negotiation RFC. + +=back + +=head1 BUGS + +Will only work with Views which implement a process method. + +Should be split into a base ContentNegotiation role which is consumed by ContentNegotiation::XHTML. + +=head1 AUTHOR + +Tomas Doran (t0m) C<< >> + +=head1 CONTRIBUTORS + +=over + +=item David Dorward - test patches and */* pragmatism. + +=item Florian Ragwitz (rafl) C<< >> - Conversion into a Moose Role + +=back + +=head1 COPYRIGHT + +This module itself is copyright (c) 2008 Tomas Doran and is licensed under the same terms as Perl itself. + +=cut diff --git a/t/podspelling.t b/t/podspelling.t index e58e38b..f5fd76f 100644 --- a/t/podspelling.t +++ b/t/podspelling.t @@ -18,3 +18,6 @@ XHTML TT Doran Dorward +rafl +ContentNegotiation +Ragwitz