Catalyst-View-Email-0.36/000755 000765 000024 00000000000 12601303644 015263 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/Changes000644 000765 000024 00000010323 12601303523 016551 0ustar00garustaff000000 000000 Revision history for Perl extension Catalyst::View::Email. 0.34 2014-05-17 - switched from Class::MOP::load_class to Module::Runtime::require_module per cf. https://rt.cpan.org/Public/Bug/Display.html?id=91013 - canonical repo now on github as noted in Makefile.PL - typo fix per https://rt.cpan.org/Public/Bug/Display.html?id=87370 - packaged with /usr/bin/gnutar on OSX cf. https://rt.cpan.org/Public/Bug/Display.html?id=83970 0.33 2013-02-13 - applied patch to fix Moo->Moose inflation that Email::Sender does per https://rt.cpan.org/Ticket/Display.html?id=83241 - removed inc/ so running perl Makefile.PL would do so in author mode - removed META.yml, MANIFEST, and various other files that shouldn't be in git - updated Makefile.PL to use version_from "lib/Catalyst/View/Email.pm" per https://rt.cpan.org/Ticket/Display.html?id=83195&results=0eb39711cb23f5f318a3738cf7d089df 0.32 2013-01-15 - Removed Bcc references per https://rt.cpan.org/Public/Bug/Display.html?id=75775 - Fixed documentation bug, changed 'Host' to 'host' per https://rt.cpan.org/Ticket/Display.html?id=58748 - Added patch (with additional tests) to enable proper content_type setting for email templates per https://rt.cpan.org/Ticket/Display.html?id=66495&results=73b48805c7d356914e91ea95e31ddef6 - Removed unneccesary test - Added documentation for specifying envelope info per https://rt.cpan.org/Ticket/Display.html?id=64162 0.31 2011-01-17 - Added handling and test for encoding and quoting parts RT #56391 0.30 2010-05-22 - Added Test::Requires to 06config.t 0.29 2010-05-21 - Using Test::Requires for Mason and Template::Toolkit dependency check - Removed Template::Toolkit and Mason as prereqs 0.28 2010-05-14 - Added version numbers to Helpers 0.27 2010-03-23 - made ::View::TT and ::View::Mason hard deps - adjusted tests to reflect the aforementioned - patches welcome 0.25_02 2010-02-21 - cleaned up tests - made Test::More 0.88 a prereq 0.25_01 2010-02-21 - updated/corrected docs - added proper svn repo url 0.25 2010-02-01 - converted to Module::Install 0.23 2010-01-30 - removed Email::Send::Test from t/lib/* views 0.22 2010-01-28 - small fixes, version bumpage etc 0.21_01 2010-01-27 - dev release to test recent fixes 0.21 2010-01-27 - provided a sane MANIFEST.SKIP for dzil 0.20 2010-01-26 - fix transport instantiation thanks to Chris Nehren 0.19 2010-01-18 - fixed optional dependencies - added META stuff back in 0.18 2010-01-17 - Fixed version dependencies for failing regressions - added Email::Send::Test as a dependency 0.17 2010-01-14 - fixed MANIFEST 0.16 2010-01-12 - Fixed a Makefile.PL issue 0.15 2010-01-12 - Fixed teeny version issue with Email::Sender::Simple 0.14 2010-01-09 - Ported over to using Email::Sender::Simple, and Moose - Fixed Mason test so that it doesn't choke, as around 'process' seems to make it die. 0.13 2009-02-22 14:06:00 - bcc: POD corrections thanks to Lance Brown 0.12 2009-01-22 06:52:00 - Fixing tests for new versions of MIME::Creator - Better structure of the code so that ::Template can also handle plain text views - Added onto troubleshooting 0.11 2008-07-04 09:14:00 - Fixing a bug where content-type was ignored so multipart/alternative failed. RT #32215 0.10 2007-11-22 23:00:00 - Refactored by Alexander Hartmaier with api changes and POD improvements 0.06 - Fixing some slight issues with configuration not being handled appropriately (thanks dwc and mst) 0.05 - Better support for configuration - Adding Mason tests 0.04 - Fixing MANIFEST, distribution 0.03 - Improved handling of configuration, thanks to mst. 0.02 - Allow configuration from application or ConfigLoader - Minor POD updates 0.01 2007-06-03 - Initial release Catalyst-View-Email-0.36/inc/000755 000765 000024 00000000000 12601303643 016033 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/lib/000755 000765 000024 00000000000 12601303643 016030 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/Makefile.PL000644 000765 000024 00000002514 12601303523 017233 0ustar00garustaff000000 000000 use inc::Module::Install 0.91; test_requires 'Test::Requires'; name 'Catalyst-View-Email'; all_from 'lib/Catalyst/View/Email.pm'; author 'J. Shirley '; license 'perl'; version_from 'lib/Catalyst/View/Email.pm'; test_requires 'Test::More'; requires 'MIME::Base64' => '3.08'; requires 'Authen::SASL' => '2.13'; requires 'Catalyst' => '5.7'; requires 'Moose' => '0.93'; requires 'parent' => '0.223'; requires 'Email::Sender::Simple' => '0.100110'; requires 'Email::MIME' => '1.859'; requires 'Email::MIME::Creator' => '1.455'; requires 'Test::More' => '0.88'; requires 'Module::Runtime' => '0.014'; #requires 'Catalyst::View::TT' => '0.31'; #requires 'Catalyst::View::Mason' => '0.18'; # Rebuild README for maintainers if ($Module::Install::AUTHOR) { system("pod2text lib/Catalyst/View/Email.pm > README"); } realclean_files 'README'; resources 'IRC' => 'irc://irc.perl.org/#catalyst'; resources 'license' => 'http://dev.perl.org/licenses/'; resources 'repository' => 'http://github.com/dhoss/catalyst-view-email'; resources 'Mailing_list' => 'http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst'; resources 'bugtracker' => 'https://github.com/dhoss/catalyst-view-email/issues'; auto_provides; auto_install; WriteAll; Catalyst-View-Email-0.36/MANIFEST000644 000765 000024 00000001673 12601303641 016420 0ustar00garustaff000000 000000 Changes inc/Module/AutoInstall.pm inc/Module/Install.pm inc/Module/Install/AutoInstall.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/Catalyst/Helper/View/Email.pm lib/Catalyst/Helper/View/Email/Template.pm lib/Catalyst/View/Email.pm lib/Catalyst/View/Email/Template.pm Makefile.PL MANIFEST This list of files META.yml README README.md t/01use.t t/02pod.t t/04basic.t t/05template.t t/06config.t t/07mason.t t/lib/TestApp.pm t/lib/TestApp/Controller/Root.pm t/lib/TestApp/View/Email.pm t/lib/TestApp/View/Email/AppConfig.pm t/lib/TestApp/View/Email/Template.pm t/lib/TestApp/View/Email/Template/AppConfig.pm t/lib/TestApp/View/Mason.pm t/lib/TestApp/View/TT.pm t/root/text_html/test.m t/root/text_html/test.tt t/root/text_plain/test.m t/root/text_plain/test.tt Catalyst-View-Email-0.36/META.yml000644 000765 000024 00000002046 12601303626 016536 0ustar00garustaff000000 000000 --- abstract: 'Send Email from Catalyst' author: - 'J. Shirley ' - 'J. Shirley ' build_requires: ExtUtils::MakeMaker: 6.36 Test::More: 0 Test::Requires: 0 configure_requires: ExtUtils::MakeMaker: 6.36 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.14' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Catalyst-View-Email no_index: directory: - inc - t requires: Authen::SASL: '2.13' Catalyst: '5.7' Email::MIME: '1.859' Email::MIME::Creator: '1.455' Email::Sender::Simple: '0.100110' MIME::Base64: '3.08' Module::Runtime: '0.014' Moose: '0.93' Test::More: '0.88' parent: '0.223' resources: IRC: irc://irc.perl.org/#catalyst Mailing_list: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst bugtracker: https://github.com/dhoss/catalyst-view-email/issues license: http://dev.perl.org/licenses/ repository: http://github.com/dhoss/catalyst-view-email version: '0.36' Catalyst-View-Email-0.36/README000644 000765 000024 00000016746 12601303626 016161 0ustar00garustaff000000 000000 NAME Catalyst::View::Email - Send Email from Catalyst SYNOPSIS This module sends out emails from a stash key specified in the configuration settings. CONFIGURATION WARNING: since version 0.10 the configuration options slightly changed! Use the helper to create your View: $ script/myapp_create.pl view Email Email In your app configuration: __PACKAGE__->config( 'View::Email' => { # Where to look in the stash for the email information. # 'email' is the default, so you don't have to specify it. stash_key => 'email', # Define the defaults for the mail default => { # Defines the default content type (mime type). Mandatory content_type => 'text/plain', # Defines the default charset for every MIME part with the # content type text. # According to RFC2049 a MIME part without a charset should # be treated as US-ASCII by the mail client. # If the charset is not set it won't be set for all MIME parts # without an overridden one. # Default: none charset => 'utf-8' }, # Setup how to send the email # all those options are passed directly to Email::Sender::Simple sender => { # if mailer doesn't start with Email::Sender::Simple::Transport::, # then this is prepended. mailer => 'SMTP', # mailer_args is passed directly into Email::Sender::Simple mailer_args => { host => 'smtp.example.com', # defaults to localhost sasl_username => 'sasl_username', sasl_password => 'sasl_password', } } } ); NOTE ON SMTP If you use SMTP and don't specify host, it will default to localhost and attempt delivery. This often means an email will sit in a queue and not be delivered. SENDING EMAIL Sending email is just filling the stash and forwarding to the view: sub controller : Private { my ( $self, $c ) = @_; $c->stash->{email} = { to => 'jshirley@gmail.com', cc => 'abraxxa@cpan.org', from => 'no-reply@foobar.com', subject => 'I am a Catalyst generated email', body => 'Body Body Body', }; $c->forward( $c->view('Email') ); } Alternatively you can use a more raw interface and specify the headers as an array reference like it is passed to Email::MIME::Creator. Note that you may also mix both syntaxes if you like ours better but need to specify additional header attributes. The attributes are appended to the header array reference without overwriting contained ones. $c->stash->{email} = { header => [ To => 'jshirley@gmail.com', Cc => 'abraxxa@cpan.org', Bcc => join ',', qw/hidden@secret.com hidden2@foobar.com/, From => 'no-reply@foobar.com', Subject => 'Note the capitalization differences', ], body => qq{Ain't got no body, and nobody cares.}, # Or, send parts parts => [ Email::MIME->create( attributes => { content_type => 'text/plain', disposition => 'attachment', charset => 'US-ASCII', }, body => qq{Got a body, but didn't get ahead.}, ) ], }; You can set the envelope sender and recipient as well: $c->stash->{email} = { envelope_from => 'envelope-from@example.com', from => 'header-from@example.com', envelope_to => [ 'foo@example.com', 'bar@example.com' ], to => 'Undisclosed Recipients:;', ... }; HANDLING ERRORS If the email fails to send, the view will die (throw an exception). After your forward to the view, it is a good idea to check for errors: $c->forward( $c->view('Email') ); if ( scalar( @{ $c->error } ) ) { $c->error(0); # Reset the error condition if you need to $c->response->body('Oh noes!'); } else { $c->response->body('Email sent A-OK! (At least as far as we can tell)'); } USING TEMPLATES FOR EMAIL Now, it's no fun to just send out email using plain strings. Take a look at Catalyst::View::Email::Template to see how you can use your favourite template engine to render the mail body. METHODS new Validates the base config and creates the Email::Sender::Simple object for later use by process. process($c) The process method does the actual processing when the view is dispatched to. This method sets up the email parts and hands off to Email::Sender::Simple to handle the actual email delivery. setup_attributes($c, $attr) Merge attributes with the configured defaults. You can override this method to return a structure to pass into generate_message which subsequently passes the return value of this method to Email::MIME->create under the "attributes" key. generate_message($c, $attr) Generate a message part, which should be an Email::MIME object and return it. Takes the attributes, merges with the defaults as necessary and returns a message object. TROUBLESHOOTING As with most things computer related, things break. Email even more so. Typically any errors are going to come from using SMTP as your sending method, which means that if you are having trouble the first place to look is at Email::Sender::Transport::SMTP. This module is just a wrapper for Email::Sender::Simple, so if you get an error on sending, it is likely from there anyway. If you are using SMTP and have troubles sending, whether it is authentication or a very bland "Can't send" message, make sure that you have Net::SMTP and, if applicable, Net::SMTP::SSL installed. It is very simple to check that you can connect via Net::SMTP, and if you do have sending errors the first thing to do is to write a simple script that attempts to connect. If it works, it is probably something in your configuration so double check there. If it doesn't, well, keep modifying the script and/or your mail server configuration until it does! SEE ALSO Catalyst::View::Email::Template - Send fancy template emails with Cat Catalyst::Manual - The Catalyst Manual Catalyst::Manual::Cookbook - The Catalyst Cookbook AUTHORS J. Shirley Alexander Hartmaier CONTRIBUTORS (Thanks!) Matt S Trout Daniel Westermann-Clark Simon Elliott Roman Filippov Lance Brown Devin Austin Chris Nehren COPYRIGHT Copyright (c) 2007 - 2009 the Catalyst::View::Email "AUTHORS" and "CONTRIBUTORS" as listed above. LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. Catalyst-View-Email-0.36/README.md000644 000765 000024 00000016102 12601303523 016536 0ustar00garustaff000000 000000 Catalyst::View::Email - Send Email from Catalyst ------------------------------------------------ This module sends out emails from a stash key specified in the configuration settings. #### Configuration: **WARNING:** since version 0.10 the configuration options slightly changed! Use the helper to create your View: $ script/myapp_create.pl view Email Email In your app configuration: ```perl __PACKAGE__->config( 'View::Email' => { # Where to look in the stash for the email information. # 'email' is the default, so you don't have to specify it. stash_key => 'email', # Define the defaults for the mail default => { # Defines the default content type (mime type). Mandatory content_type => 'text/plain', # Defines the default charset for every MIME part with the # content type text. # According to RFC2049 a MIME part without a charset should # be treated as US-ASCII by the mail client. # If the charset is not set it won't be set for all MIME parts # without an overridden one. # Default: none charset => 'utf-8' }, # Setup how to send the email # all those options are passed directly to Email::Sender::Simple sender => { # if mailer doesn't start with Email::Sender::Simple::Transport::, # then this is prepended. mailer => 'SMTP', # mailer_args is passed directly into Email::Sender::Simple mailer_args => { host => 'smtp.example.com', # defaults to localhost sasl_username => 'sasl_username', sasl_password => 'sasl_password', } } } ); ``` **NOTE ON SMTP**: If you use SMTP and don't specify host, it will default to localhost and attempt delivery. This often means an email will sit in a queue and not be delivered. #### Sending Email Sending email is just filling the stash and forwarding to the view: ```perl sub controller : Private { my ( $self, $c ) = @_; $c->stash->{email} = { to => 'jshirley@gmail.com', cc => 'abraxxa@cpan.org', from => 'no-reply@foobar.com', subject => 'I am a Catalyst generated email', body => 'Body Body Body', }; $c->forward( $c->view('Email') ); } ``` Alternatively you can use a more raw interface and specify the headers as an array reference like it is passed to Email::MIME::Creator. Note that you may also mix both syntaxes if you like ours better but need to specify additional header attributes. The attributes are appended to the header array reference without overwriting contained ones. ```perl $c->stash->{email} = { header => [ To => 'jshirley@gmail.com', Cc => 'abraxxa@cpan.org', Bcc => join ',', qw/hidden@secret.com hidden2@foobar.com/, From => 'no-reply@foobar.com', Subject => 'Note the capitalization differences', ], body => qq{Ain't got no body, and nobody cares.}, # Or, send parts parts => [ Email::MIME->create( attributes => { content_type => 'text/plain', disposition => 'attachment', charset => 'US-ASCII', }, body => qq{Got a body, but didn't get ahead.}, ) ], }; ``` You can set the envelope sender and recipient as well: ```perl $c->stash->{email} = { envelope_from => 'envelope-from@example.com', from => 'header-from@example.com', envelope_to => [ 'foo@example.com', 'bar@example.com' ], to => 'Undisclosed Recipients:;', ... }; ``` #### Handling Errors If the email fails to send, the view will die (throw an exception). After your forward to the view, it is a good idea to check for errors: ```perl $c->forward( $c->view('Email') ); if ( scalar( @{ $c->error } ) ) { $c->error(0); # Reset the error condition if you need to $c->response->body('Oh noes!'); } else { $c->response->body('Email sent A-OK! (At least as far as we can tell)'); } ``` #### Using Templates for Email Now, it's no fun to just send out email using plain strings. Take a look at Catalyst::View::Email::Template to see how you can use your favourite template engine to render the mail body. #### Methods * **new** - Validates the base config and creates the Email::Sender::Simple object for later use by process. * **process($c)** - The process method does the actual processing when the view is dispatched to. This method sets up the email parts and hands off to Email::Sender::Simple to handle the actual email delivery. * **setup_attributes($c, $attr)** - Merge attributes with the configured defaults. You can override this method to return a structure to pass into generate_message which subsequently passes the return value of this method to Email::MIME->create under the "attributes" key. * **generate_message($c, $attr)** - Generate a message part, which should be an Email::MIME object and return it. Takes the attributes, merges with the defaults as necessary and returns a message object. #### Troubleshooting As with most things computer related, things break. Email even more so. Typically any errors are going to come from using SMTP as your sending method, which means that if you are having trouble the first place to look is at Email::Sender::Transport::SMTP. This module is just a wrapper for Email::Sender::Simple, so if you get an error on sending, it is likely from there anyway. If you are using SMTP and have troubles sending, whether it is authentication or a very bland "Can't send" message, make sure that you have Net::SMTP and, if applicable, Net::SMTP::SSL installed. It is very simple to check that you can connect via Net::SMTP, and if you do have sending errors the first thing to do is to write a simple script that attempts to connect. If it works, it is probably something in your configuration so double check there. If it doesn't, well, keep modifying the script and/or your mail server configuration until it does! #### See Also * Catalyst::View::Email::Template - Send fancy template emails with Cat * Catalyst::Manual - The Catalyst Manual * Catalyst::Manual::Cookbook - The Catalyst Cookbook #### Authors J. Shirley Alexander Hartmaier #### Contributors (Thanks!) Matt S Trout Daniel Westermann-Clark Simon Elliott Roman Filippov Lance Brown Devin Austin Chris Nehren #### COPYRIGHT Copyright (c) 2007 - 2015 the Catalyst::View::Email "AUTHORS" and "CONTRIBUTORS" as listed above. #### LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. Catalyst-View-Email-0.36/t/000755 000765 000024 00000000000 12601303644 015526 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/01use.t000644 000765 000024 00000000137 12601303523 016645 0ustar00garustaff000000 000000 use Test::More tests => 1; use_ok 'Catalyst::View::Email', 'Catalyst::View::Email::Template'; Catalyst-View-Email-0.36/t/02pod.t000644 000765 000024 00000000276 12601303523 016640 0ustar00garustaff000000 000000 use Test::More; eval "use Test::Pod 1.14"; plan skip_all => 'Test::Pod 1.14 required' if $@; plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD}; all_pod_files_ok(); Catalyst-View-Email-0.36/t/04basic.t000644 000765 000024 00000001063 12601303523 017134 0ustar00garustaff000000 000000 use strict; use warnings; BEGIN { $ENV{EMAIL_SENDER_TRANSPORT} = 'Test' } use Test::More; use Email::Sender::Simple; use FindBin; use lib "$FindBin::Bin/lib"; use_ok('Catalyst::Test', 'TestApp'); my $response; my $time = time; ok( ($response = request("/email?time=$time"))->is_success, 'request ok'); my @emails = Email::Sender::Simple->default_transport->deliveries; is( scalar @emails, 1, "got emails"); isa_ok( $emails[0]->{'email'}, 'Email::Abstract', 'email is ok' ); like($emails[0]->{'email'}->[0]->body, qr/$time/, 'Got our email'); done_testing(); Catalyst-View-Email-0.36/t/05template.t000644 000765 000024 00000003103 12601303523 017664 0ustar00garustaff000000 000000 use strict; use warnings; BEGIN { $ENV{EMAIL_SENDER_TRANSPORT} = 'Test' } use Test::More; use Test::Requires { 'Catalyst::View::TT' => '0.31', }; use Email::Sender::Simple; use FindBin; use lib "$FindBin::Bin/lib"; use Data::Dump qw(ddx); use_ok('Catalyst::Test', 'TestApp'); my $response; my $response2; my $time = time; ok( ( $response = request("/template_email?time=$time"))->is_success, 'request ok' ); my @emails = Email::Sender::Simple->default_transport->deliveries; like( $response->content, qr/Template Email Ok/, 'controller says ok' ); cmp_ok(@emails, '==', 1, 'got emails'); isa_ok( $emails[0]->{'email'}, 'Email::Abstract', 'email is ok' ); like($emails[0]->{'email'}[0]->header("Content-type"), qr#^multipart/alternative#, 'Multipart email'); my @parts = $emails[0]->{'email'}[0]->parts; cmp_ok(@parts, '==', 2, 'got parts'); is($parts[0]->content_type, 'text/plain', 'text/plain part ok'); like($parts[0]->body, qr/test-email\@example.com on $time/, 'got content back'); is($parts[1]->content_type, 'text/html', 'text/html ok'); like($parts[1]->body, qr{test-email\@example.com on $time}, 'got content back'); ok( ( $response2 = request("/template_email_single?time=$time"))->is_success, 'request ok' ); like( $response2->content, qr/Template Email Ok/, 'controller says ok' ); my @emails2 = Email::Sender::Simple->default_transport->deliveries; my @parts2 = $emails2[0]->{'email'}[0]->parts; is($parts2[1]->content_type, 'text/html', 'text/html ok'); like($parts2[1]->body, qr{test-email\@example.com on $time}, 'got content back'); done_testing(); Catalyst-View-Email-0.36/t/06config.t000644 000765 000024 00000002526 12601303523 017327 0ustar00garustaff000000 000000 use strict; use warnings; BEGIN { $ENV{EMAIL_SENDER_TRANSPORT} = 'Test' } use Test::Requires { 'Catalyst::View::TT' => '0.31', }; use Test::More; use Email::Sender::Simple; use FindBin; use lib "$FindBin::Bin/lib"; use_ok('Catalyst::Test', 'TestApp'); my $response; my $time; my @emails; $time = time; ok( ($response = request("/email_app_config?time=$time"))->is_success, 'request ok'); @emails = Email::Sender::Simple->default_transport->deliveries; is(scalar @emails, 1, "got emails"); isa_ok( $emails[0]->{'email'}, 'Email::Abstract', 'email is ok' ); like($emails[0]->{'email'}->[0]->body, qr/$time/, 'Got our email'); Email::Sender::Simple->default_transport->clear_deliveries; $time = time; ok( ($response = request("/template_email_app_config?time=$time"))->is_success, 'request ok'); @emails = Email::Sender::Simple->default_transport->deliveries; is(scalar @emails, 1, "got emails"); isa_ok( $emails[0]->{'email'}, 'Email::Abstract', 'email is ok' ); my @parts = $emails[0]->{'email'}[0]->parts; cmp_ok(@parts, '==', 2, 'got parts'); is($parts[0]->content_type, 'text/plain', 'text/plain ok'); like($parts[0]->body, qr/test-email\@example.com on $time/, 'got content back'); is($parts[1]->content_type, 'text/html', 'text/html ok'); like($parts[1]->body, qr{test-email\@example.com on $time}, 'got content back'); done_testing(); Catalyst-View-Email-0.36/t/07mason.t000644 000765 000024 00000002130 12601303523 017167 0ustar00garustaff000000 000000 use strict; use warnings; use Test::More; use Test::Requires { 'Catalyst::View::Mason' => '0.18', }; ## BEGIN { $ENV{EMAIL_SENDER_TRANSPORT} = 'Test' } use FindBin; use lib "$FindBin::Bin/lib"; use Email::Sender::Simple; use_ok('Catalyst::Test', 'TestApp'); TestApp->config->{default_view} = 'Mason'; my $response; my $time = time; ok( ( $response = request("/mason_email?time=$time"))->is_success, 'request ok' ); like( $response->content, qr/Mason Email Ok/, 'controller says ok' ); my @emails = Email::Sender::Simple->default_transport->deliveries; cmp_ok(@emails, '==', 1, 'got emails'); isa_ok( $emails[0]->{'email'}, 'Email::Abstract', 'email is ok' ); my @parts = $emails[0]->{'email'}[0]->parts; cmp_ok(@parts, '==', 2, 'got parts'); is($parts[0]->content_type, 'text/plain', 'text/plain ok'); like($parts[0]->body, qr/test-email\@example.com on $time/, 'got content back'); is($parts[1]->content_type, 'text/html', 'text/html ok'); like($parts[1]->body, qr{test-email\@example.com on $time}, 'got content back'); #like($emails[0]->body, qr/$time/, 'Got our email'); done_testing(); Catalyst-View-Email-0.36/t/lib/000755 000765 000024 00000000000 12601303644 016274 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/root/000755 000765 000024 00000000000 12601303643 016510 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/root/text_html/000755 000765 000024 00000000000 12601303643 020520 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/root/text_plain/000755 000765 000024 00000000000 12601303643 020657 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/root/text_plain/test.m000644 000765 000024 00000000163 12601303523 022011 0ustar00garustaff000000 000000 <%args> $time $email I am plain text. I have no style. I was sent to <% $email->{to} %> on <% $time %> Catalyst-View-Email-0.36/t/root/text_plain/test.tt000644 000765 000024 00000000124 12601303523 022201 0ustar00garustaff000000 000000 I am plain text. I have no style. I was sent to [% $stash_key.to %] on [% time %] Catalyst-View-Email-0.36/t/root/text_html/test.m000644 000765 000024 00000000235 12601303523 021652 0ustar00garustaff000000 000000 <%args> $time $email

Look at my style

I was sent to <% $email->{to} %> on <% $time %>

Catalyst-View-Email-0.36/t/root/text_html/test.tt000644 000765 000024 00000000177 12601303523 022052 0ustar00garustaff000000 000000

Look at my style

I was sent to [% $stash_key.to %] on [% time %]

Catalyst-View-Email-0.36/t/lib/TestApp/000755 000765 000024 00000000000 12601303644 017654 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/lib/TestApp.pm000644 000765 000024 00000001015 12601303523 020203 0ustar00garustaff000000 000000 package # Hide from PAUSE TestApp; use Catalyst; use FindBin; TestApp->config( root => "$FindBin::Bin/root", default_view => 'TT', 'View::Email::AppConfig' => { sender => { mailer => 'Test', }, }, 'View::Email::Template::AppConfig' => { stash_key => 'template_email', sender => { mailer => 'Test', }, content_type => 'text/html', default => { view => 'TT', }, }, ); TestApp->setup; 1; Catalyst-View-Email-0.36/t/lib/TestApp/Controller/000755 000765 000024 00000000000 12601303644 021777 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/lib/TestApp/View/000755 000765 000024 00000000000 12601303643 020565 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/lib/TestApp/View/Email/000755 000765 000024 00000000000 12601303643 021614 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/lib/TestApp/View/Email.pm000644 000765 000024 00000000245 12601303523 022150 0ustar00garustaff000000 000000 package # Hide from PAUSE TestApp::View::Email; use base 'Catalyst::View::Email'; __PACKAGE__->config( sender => { mailer => 'Test' }, ); 1; Catalyst-View-Email-0.36/t/lib/TestApp/View/Mason.pm000644 000765 000024 00000000272 12601303523 022176 0ustar00garustaff000000 000000 package # Hide me. TestApp::View::Mason; use strict; eval "use base 'Catalyst::View::Mason';"; eval "__PACKAGE__->config( data_dir => TestApp->path_to('cache')->stringify );"; 1; Catalyst-View-Email-0.36/t/lib/TestApp/View/TT.pm000644 000765 000024 00000000142 12601303523 021444 0ustar00garustaff000000 000000 package # Hide me. TestApp::View::TT; use strict; eval "use base 'Catalyst::View::TT';"; 1; Catalyst-View-Email-0.36/t/lib/TestApp/View/Email/AppConfig.pm000644 000765 000024 00000000202 12601303523 024007 0ustar00garustaff000000 000000 package # Hide from PAUSE TestApp::View::Email::AppConfig; use Email::Sender::Simple; use base 'Catalyst::View::Email'; 1; Catalyst-View-Email-0.36/t/lib/TestApp/View/Email/Template/000755 000765 000024 00000000000 12601303643 023367 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/t/lib/TestApp/View/Email/Template.pm000644 000765 000024 00000000367 12601303523 023730 0ustar00garustaff000000 000000 package # Hide me TestApp::View::Email::Template; use strict; use base 'Catalyst::View::Email::Template'; __PACKAGE__->config( sender => { mailer => 'Test' }, stash_key => 'email', template_prefix => '', ); 1; Catalyst-View-Email-0.36/t/lib/TestApp/View/Email/Template/AppConfig.pm000644 000765 000024 00000000226 12601303523 025570 0ustar00garustaff000000 000000 package # Hide from PAUSE TestApp::View::Email::Template::AppConfig; use Email::Sender::Simple; use base 'Catalyst::View::Email::Template'; 1; Catalyst-View-Email-0.36/t/lib/TestApp/Controller/Root.pm000644 000765 000024 00000013620 12601303523 023256 0ustar00garustaff000000 000000 package # Hide from PAUSE TestApp::Controller::Root; use base qw(Catalyst::Controller); use Encode; sub default : Private { my ( $self, $c ) = @_; $c->res->body(qq{Nothing Here}); } sub email : Global('email') { my ($self, $c, @args) = @_; my $time = $c->req->params->{time} || time; $c->stash->{email} = { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Email Test', body => "Email Sent at: $time" }; $c->forward('TestApp::View::Email'); if ( scalar( @{ $c->error } ) ) { $c->res->status(500); $c->res->body('Email Failed'); } else { $c->res->body('Plain Email Ok'); } } sub email_app_config : Global('email_app_config') { my ($self, $c, @args) = @_; my $time = $c->req->params->{time} || time; $c->stash->{email} = { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Email Test', body => "Email Sent at: $time" }; $c->forward('TestApp::View::Email::AppConfig'); if ( scalar( @{ $c->error } ) ) { $c->res->status(500); $c->res->body('Email Failed'); } else { $c->res->body('Plain Email Ok'); } } sub template_email : Global('template_email') { my ($self, $c, @args) = @_; $c->stash->{time} = $c->req->params->{time} || time; $c->stash->{email} = { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Just a test', content_type => 'multipart/alternative', templates => [ { template => 'text_plain/test.tt', content_type => 'text/plain', }, { view => 'TT', template => 'text_html/test.tt', content_type => 'text/html', }, ], }; $c->forward('TestApp::View::Email::Template'); if ( scalar( @{ $c->error } ) ) { $c->res->status(500); $c->res->body('Template Email Failed'); } else { $c->res->body('Template Email Ok'); } } sub template_email_single : Global('template_email_single') { my ($self, $c, @args) = @_; $c->stash->{time} = $c->req->params->{time} || time; $c->stash->{email} = { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Just a test', content_type => 'multipart/alternative', templates => { view => 'TT', template => 'text_html/test.tt', content_type => 'text/html', }, }; $c->forward('TestApp::View::Email::Template'); if ( scalar( @{ $c->error } ) ) { $c->res->status(500); $c->res->body('Template Email Failed'); } else { $c->res->body('Template Email Ok'); } } sub template_email_utf8 : Global('template_email_utf8') { my ($self, $c, @args) = @_; $c->stash->{time} = $c->req->params->{time} || time; $c->stash->{chars} = decode('utf-8', "✔ ✈ ✉"); $c->stash->{email} = { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Just a test', content_type => 'multipart/alternative', templates => [ { template => 'text_plain/test.tt', content_type => 'text/plain', charset => 'utf-8', encoding => 'quoted-printable', }, { view => 'TT', template => 'text_html/test_utf8.tt', content_type => 'text/html', charset => 'utf-8', encoding => 'quoted-printable', }, ], }; $c->forward('TestApp::View::Email::Template'); if ( scalar( @{ $c->error } ) ) { $c->res->status(500); $c->res->body('Template Email Failed'); } else { $c->res->body('Template Email Ok'); } } sub template_email_app_config : Global('template_email_app_config') { my ($self, $c, @args) = @_; $c->stash->{time} = $c->req->params->{time} || time; $c->stash->{template_email} = { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Just a test', templates => [ { template => 'text_plain/test.tt', content_type => 'text/plain', }, { view => 'TT', template => 'text_html/test.tt', content_type => 'text/html', }, ], }; $c->forward('TestApp::View::Email::Template::AppConfig'); if ( scalar( @{ $c->error } ) ) { $c->res->status(500); $c->res->body('Template Email Failed'); } else { $c->res->body('Template Email Ok'); } } sub mason_email : Global('mason_email') { my ($self, $c, @args) = @_; $c->stash->{time} = $c->req->params->{time} || time; $c->stash->{email} = { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Just a test', templates => [ { view => 'Mason', template => 'text_plain/test.m', content_type => 'text/plain', }, { view => 'Mason', template => 'text_html/test.m', content_type => 'text/html', }, ], }; $c->forward('TestApp::View::Email::Template'); if ( scalar( @{ $c->error } ) ) { $c->res->status(500); $c->res->body('Mason Email Failed'); } else { $c->res->body('Mason Email Ok'); } } 1; Catalyst-View-Email-0.36/lib/Catalyst/000755 000765 000024 00000000000 12601303643 017614 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/lib/Catalyst/Helper/000755 000765 000024 00000000000 12601303643 021033 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/lib/Catalyst/View/000755 000765 000024 00000000000 12601303643 020526 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/lib/Catalyst/View/Email/000755 000765 000024 00000000000 12601303643 021555 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/lib/Catalyst/View/Email.pm000644 000765 000024 00000031573 12601303523 022121 0ustar00garustaff000000 000000 package Catalyst::View::Email; use Moose; use Carp; use Encode qw(encode decode); use Email::Sender::Simple qw/ sendmail /; use Email::MIME::Creator; use Module::Runtime; extends 'Catalyst::View'; our $VERSION = '0.36'; $VERSION = eval $VERSION; has 'mailer' => ( is => 'rw', isa => 'Str', lazy => 1, default => sub { "sendmail" } ); has '_mailer_obj' => ( is => 'rw', does => 'Email::Sender::Transport', lazy => 1, builder => '_build_mailer_obj', ); has 'stash_key' => ( is => 'rw', isa => 'Str', lazy => 1, default => sub { "email" } ); has 'default' => ( is => 'rw', isa => 'HashRef', default => sub { { content_type => 'text/plain' } }, lazy => 1, ); has 'sender' => ( is => 'rw', isa => 'HashRef', lazy => 1, default => sub { { mailer => shift->mailer } } ); has 'content_type' => ( is => 'rw', isa => 'Str', default => sub { shift->default->{content_type} }, lazy => 1, ); =head1 NAME Catalyst::View::Email - Send Email from Catalyst =head1 SYNOPSIS This module sends out emails from a stash key specified in the configuration settings. =head1 CONFIGURATION WARNING: since version 0.10 the configuration options slightly changed! Use the helper to create your View: $ script/myapp_create.pl view Email Email In your app configuration: __PACKAGE__->config( 'View::Email' => { # Where to look in the stash for the email information. # 'email' is the default, so you don't have to specify it. stash_key => 'email', # Define the defaults for the mail default => { # Defines the default content type (mime type). Mandatory content_type => 'text/plain', # Defines the default charset for every MIME part with the # content type text. # According to RFC2049 a MIME part without a charset should # be treated as US-ASCII by the mail client. # If the charset is not set it won't be set for all MIME parts # without an overridden one. # Default: none charset => 'utf-8' }, # Setup how to send the email # all those options are passed directly to Email::Sender::Simple sender => { # if mailer doesn't start with Email::Sender::Simple::Transport::, # then this is prepended. mailer => 'SMTP', # mailer_args is passed directly into Email::Sender::Simple mailer_args => { host => 'smtp.example.com', # defaults to localhost sasl_username => 'sasl_username', sasl_password => 'sasl_password', } } } ); =head1 NOTE ON SMTP If you use SMTP and don't specify host, it will default to localhost and attempt delivery. This often means an email will sit in a queue and not be delivered. =cut =head1 SENDING EMAIL Sending email is just filling the stash and forwarding to the view: sub controller : Private { my ( $self, $c ) = @_; $c->stash->{email} = { to => 'jshirley@gmail.com', cc => 'abraxxa@cpan.org', from => 'no-reply@foobar.com', subject => 'I am a Catalyst generated email', body => 'Body Body Body', }; $c->forward( $c->view('Email') ); } Alternatively you can use a more raw interface and specify the headers as an array reference like it is passed to L. Note that you may also mix both syntaxes if you like ours better but need to specify additional header attributes. The attributes are appended to the header array reference without overwriting contained ones. $c->stash->{email} = { header => [ To => 'jshirley@gmail.com', Cc => 'abraxxa@cpan.org', Bcc => join ',', qw/hidden@secret.com hidden2@foobar.com/, From => 'no-reply@foobar.com', Subject => 'Note the capitalization differences', ], body => qq{Ain't got no body, and nobody cares.}, # Or, send parts parts => [ Email::MIME->create( attributes => { content_type => 'text/plain', disposition => 'attachment', charset => 'US-ASCII', }, body => qq{Got a body, but didn't get ahead.}, ) ], }; You can set the envelope sender and recipient as well: $c->stash->{email} = { envelope_from => 'envelope-from@example.com', from => 'header-from@example.com', envelope_to => [ 'foo@example.com', 'bar@example.com' ], to => 'Undisclosed Recipients:;', ... }; =head1 HANDLING ERRORS If the email fails to send, the view will die (throw an exception). After your forward to the view, it is a good idea to check for errors: $c->forward( $c->view('Email') ); if ( scalar( @{ $c->error } ) ) { $c->error(0); # Reset the error condition if you need to $c->response->body('Oh noes!'); } else { $c->response->body('Email sent A-OK! (At least as far as we can tell)'); } =head1 USING TEMPLATES FOR EMAIL Now, it's no fun to just send out email using plain strings. Take a look at L to see how you can use your favourite template engine to render the mail body. =head1 METHODS =over 4 =item new Validates the base config and creates the L object for later use by process. =cut sub BUILD { my $self = shift; my $stash_key = $self->stash_key; croak "$self stash_key isn't defined!" if ( $stash_key eq '' ); } sub _build_mailer_obj { my ($self) = @_; my $transport_class = ucfirst $self->sender->{mailer}; # borrowed from Email::Sender::Simple -- apeiron, 2010-01-26 if ( $transport_class !~ /^Email::Sender::Transport::/ ) { $transport_class = "Email::Sender::Transport::$transport_class"; } Module::Runtime::require_module($transport_class); return $transport_class->new( $self->sender->{mailer_args} || {} ); } =item process($c) The process method does the actual processing when the view is dispatched to. This method sets up the email parts and hands off to L to handle the actual email delivery. =cut sub process { my ( $self, $c ) = @_; croak "Unable to send mail, bad mail configuration" unless $self->sender->{mailer}; my $email = $c->stash->{ $self->stash_key }; croak "Can't send email without a valid email structure" unless $email; # Default content type if ( $self->content_type and not $email->{content_type} ) { $email->{content_type} = $self->content_type; } my $header = $email->{header} || []; push @$header, ( 'To' => delete $email->{to} ) if $email->{to}; push @$header, ( 'Cc' => delete $email->{cc} ) if $email->{cc}; push @$header, ( 'From' => delete $email->{from} ) if $email->{from}; push @$header, ( 'Subject' => Encode::encode( 'MIME-Header', delete $email->{subject} ) ) if $email->{subject}; push @$header, ( 'Content-type' => $email->{content_type} ) if $email->{content_type}; my $parts = $email->{parts}; my $body = $email->{body}; unless ( $parts or $body ) { croak "Can't send email without parts or body, check stash"; } my %mime = ( header => $header, attributes => {} ); if ( $parts and ref $parts eq 'ARRAY' ) { $mime{parts} = $parts; } else { $mime{body} = $body; } $mime{attributes}->{content_type} = $email->{content_type} if $email->{content_type}; if ( $mime{attributes} and not $mime{attributes}->{charset} and $self->{default}->{charset} ) { $mime{attributes}->{charset} = $self->{default}->{charset}; } $mime{attributes}->{encoding} = $email->{encoding} if $email->{encoding}; my $message = $self->generate_message( $c, \%mime ); if ($message) { my $return = sendmail( $message, { exists $email->{envelope_from} ? ( from => $email->{envelope_from} ) : (), exists $email->{envelope_to} ? ( to => $email->{envelope_to} ) : (), transport => $self->_mailer_obj, } ); # return is a Return::Value object, so this will stringify as the error # in the case of a failure. croak "$return" if !$return; } else { croak "Unable to create message"; } } =item setup_attributes($c, $attr) Merge attributes with the configured defaults. You can override this method to return a structure to pass into L which subsequently passes the return value of this method to Email::MIME->create under the C key. =cut sub setup_attributes { my ( $self, $c, $attrs ) = @_; my $default_content_type = $self->default->{content_type}; my $default_charset = $self->default->{charset}; my $default_encoding = $self->default->{encoding}; my $e_m_attrs = {}; if ( exists $attrs->{content_type} && defined $attrs->{content_type} && $attrs->{content_type} ne '' ) { $c->log->debug( 'C::V::Email uses specified content_type ' . $attrs->{content_type} . '.' ) if $c->debug; $e_m_attrs->{content_type} = $attrs->{content_type}; } elsif ( defined $default_content_type && $default_content_type ne '' ) { $c->log->debug( "C::V::Email uses default content_type $default_content_type.") if $c->debug; $e_m_attrs->{content_type} = $default_content_type; } if ( exists $attrs->{charset} && defined $attrs->{charset} && $attrs->{charset} ne '' ) { $e_m_attrs->{charset} = $attrs->{charset}; } elsif ( defined $default_charset && $default_charset ne '' ) { $e_m_attrs->{charset} = $default_charset; } if ( exists $attrs->{encoding} && defined $attrs->{encoding} && $attrs->{encoding} ne '' ) { $c->log->debug( 'C::V::Email uses specified encoding ' . $attrs->{encoding} . '.' ) if $c->debug; $e_m_attrs->{encoding} = $attrs->{encoding}; } elsif ( defined $default_encoding && $default_encoding ne '' ) { $c->log->debug( "C::V::Email uses default encoding $default_encoding.") if $c->debug; $e_m_attrs->{encoding} = $default_encoding; } return $e_m_attrs; } =item generate_message($c, $attr) Generate a message part, which should be an L object and return it. Takes the attributes, merges with the defaults as necessary and returns a message object. =cut sub generate_message { my ( $self, $c, $attr ) = @_; # setup the attributes (merge with defaults) $attr->{attributes} = $self->setup_attributes( $c, $attr->{attributes} ); Email::MIME->create( %$attr ); } =back =head1 TROUBLESHOOTING As with most things computer related, things break. Email even more so. Typically any errors are going to come from using SMTP as your sending method, which means that if you are having trouble the first place to look is at L. This module is just a wrapper for L, so if you get an error on sending, it is likely from there anyway. If you are using SMTP and have troubles sending, whether it is authentication or a very bland "Can't send" message, make sure that you have L and, if applicable, L installed. It is very simple to check that you can connect via L, and if you do have sending errors the first thing to do is to write a simple script that attempts to connect. If it works, it is probably something in your configuration so double check there. If it doesn't, well, keep modifying the script and/or your mail server configuration until it does! =head1 SEE ALSO =head2 L - Send fancy template emails with Cat =head2 L - The Catalyst Manual =head2 L - The Catalyst Cookbook =head1 AUTHORS J. Shirley Alexander Hartmaier =head1 CONTRIBUTORS (Thanks!) Matt S Trout Daniel Westermann-Clark Simon Elliott Roman Filippov Lance Brown Devin Austin Chris Nehren =head1 COPYRIGHT Copyright (c) 2007 - 2009 the Catalyst::View::Email L and L as listed above. =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-View-Email-0.36/lib/Catalyst/View/Email/Template.pm000644 000765 000024 00000023735 12601303523 023675 0ustar00garustaff000000 000000 package Catalyst::View::Email::Template; use Moose; use Carp; use Scalar::Util qw/ blessed /; extends 'Catalyst::View::Email'; our $VERSION = '0.36'; $VERSION = eval $VERSION; =head1 NAME Catalyst::View::Email::Template - Send Templated Email from Catalyst =head1 SYNOPSIS Sends templated mail, based upon your default view. It captures the output of the rendering path, slurps in based on mime-types and assembles a multi-part email using L and sends it out. =head1 CONFIGURATION WARNING: since version 0.10 the configuration options slightly changed! Use the helper to create your view: $ script/myapp_create.pl view Email::Template Email::Template For basic configuration look at L. In your app configuration (example in L): View::Email::Template: # Optional prefix to look somewhere under the existing configured # template paths. # Default: none template_prefix: email # Define the defaults for the mail default: # Defines the default view used to render the templates. # If none is specified neither here nor in the stash # Catalysts default view is used. # Warning: if you don't tell Catalyst explicit which of your views should # be its default one, C::V::Email::Template may choose the wrong one! view: TT =head1 SENDING EMAIL Sending email works just like for L but by specifying the template instead of the body and forwarding to your Email::Template view: sub controller : Private { my ( $self, $c ) = @_; $c->stash->{email} = { to => 'jshirley@gmail.com', cc => 'abraxxa@cpan.org', from => 'no-reply@foobar.com', subject => 'I am a Catalyst generated email', template => 'test.tt', content_type => 'multipart/alternative' }; $c->forward( $c->view('Email::Template') ); } Alternatively if you want more control over your templates you can use the following idiom to override the defaults. If charset and encoding given, the body become properly encoded. templates => [ { template => 'email/test.html.tt', content_type => 'text/html', charset => 'utf-8', encoding => 'quoted-printable', view => 'TT', }, { template => 'email/test.plain.mason', content_type => 'text/plain', charset => 'utf-8', encoding => 'quoted-printable', view => 'Mason', } ] =head1 HANDLING ERRORS See L. =cut # here the defaults of Catalyst::View::Email are extended by the additional # ones Template.pm needs. has 'stash_key' => ( is => 'rw', isa => 'Str', default => sub { "email" }, lazy => 1, ); has 'template_prefix' => ( is => 'rw', isa => 'Str', default => sub { '' }, lazy => 1, ); has 'default' => ( is => 'rw', isa => 'HashRef', default => sub { { view => 'TT', content_type => 'text/html', }; }, lazy => 1, ); # This view hitches into your default view and will call the render function # on the templates provided. This means that you have a layer of abstraction # and you aren't required to modify your templates based on your desired engine # (Template Toolkit or Mason, for example). As long as the view adequately # supports ->render, all things are good. Mason, and others, are not good. # # The path here is to check configuration for the template root, and then # proceed to call render on the subsequent templates and stuff each one # into an Email::MIME container. The mime-type will be stupidly guessed with # the subdir on the template. # # Set it up so if you have multiple parts, they're alternatives. # This is on the top-level message, not the individual parts. #multipart/alternative sub _validate_view { my ( $self, $view ) = @_; croak "C::V::Email::Template's configured view '$view' isn't an object!" unless ( blessed($view) ); croak "C::V::Email::Template's configured view '$view' isn't an Catalyst::View!" unless ( $view->isa('Catalyst::View') ); croak "C::V::Email::Template's configured view '$view' doesn't have a render method!" unless ( $view->can('render') ); } =head1 METHODS =over 4 =item generate_part Generates a MIME part to include in the email. Since the email is template based every template piece is a separate part that is included in the email. =cut sub generate_part { my ( $self, $c, $attrs ) = @_; my $template_prefix = $self->template_prefix; my $default_view = $self->default->{view}; my $default_content_type = $self->default->{content_type}; my $default_charset = $self->default->{charset}; my $view; # use the view specified for the email part if ( exists $attrs->{view} && defined $attrs->{view} && $attrs->{view} ne '' ) { $view = $c->view( $attrs->{view} ); $c->log->debug( "C::V::Email::Template uses specified view $view for rendering.") if $c->debug; } # if none specified use the configured default view elsif ($default_view) { $view = $c->view($default_view); $c->log->debug( "C::V::Email::Template uses default view $view for rendering.") if $c->debug; } # else fallback to Catalysts default view else { $view = $c->view; $c->log->debug( "C::V::Email::Template uses Catalysts default view $view for rendering." ) if $c->debug; } # validate the per template view $self->_validate_view($view); # prefix with template_prefix if configured my $template = $template_prefix ne '' ? join( '/', $template_prefix, $attrs->{template} ) : $attrs->{template}; # setup the attributes (merge with defaults) my $e_m_attrs = $self->SUPER::setup_attributes( $c, $attrs ); # render the email part my $output = $view->render( $c, $template, { content_type => $e_m_attrs->{content_type}, stash_key => $self->stash_key, %{$c->stash}, } ); if ( ref $output ) { croak $output->can('as_string') ? $output->as_string : $output; } if ( exists $e_m_attrs->{encoding} && defined $e_m_attrs->{encoding} && exists $e_m_attrs->{charset} && defined $e_m_attrs->{charset} ) { return Email::MIME->create( attributes => $e_m_attrs, body_str => $output, ); } else { return Email::MIME->create( attributes => $e_m_attrs, body => $output, ); } } =item process The process method is called when the view is dispatched to. This creates the multipart message and then sends the message contents off to L for processing, which in turn hands off to L. =cut around 'process' => sub { my ( $orig, $self, $c, @args ) = @_; my $stash_key = $self->stash_key; return $self->$orig( $c, @args ) unless $c->stash->{$stash_key}->{template} or $c->stash->{$stash_key}->{templates}; # in case of the simple api only one my @parts = (); # now find out if the single or multipart api was used # prefer the multipart one # multipart api if ( $c->stash->{$stash_key}->{templates} && ref $c->stash->{$stash_key}->{templates} eq 'ARRAY' && ref $c->stash->{$stash_key}->{templates}[0] eq 'HASH' ) { # loop through all parts of the mail foreach my $part ( @{ $c->stash->{$stash_key}->{templates} } ) { push @parts, $self->generate_part( $c, { view => $part->{view}, template => $part->{template}, content_type => $part->{content_type}, charset => $part->{charset}, encoding => $part->{encoding}, } ); } } # single part api elsif ( $c->stash->{$stash_key}->{template} ) { my $part_args = { template => $c->stash->{$stash_key}->{template} }; if (my $ctype = $c->stash->{$stash_key}->{content_type}) { $part_args->{content_type} = $ctype; } push @parts, $self->generate_part( $c, $part_args ); } delete $c->stash->{$stash_key}->{body}; $c->stash->{$stash_key}->{parts} ||= []; push @{ $c->stash->{$stash_key}->{parts} }, @parts; return $self->$orig($c); }; =back =head1 TODO =head2 ATTACHMENTS There needs to be a method to support attachments. What I am thinking is something along these lines: attachments => [ # Set the body to a file handle object, specify content_type and # the file name. (name is what it is sent at, not the file) { body => $fh, name => "foo.pdf", content_type => "application/pdf" }, # Or, specify a filename that is added, and hey, encoding! { filename => "foo.gif", name => "foo.gif", content_type => "application/pdf", encoding => "quoted-printable" }, # Or, just a path to a file, and do some guesswork for the content type "/path/to/somefile.pdf", ] =head1 SEE ALSO =head2 L - Send plain boring emails with Catalyst =head2 L - The Catalyst Manual =head2 L - The Catalyst Cookbook =head1 AUTHORS J. Shirley Simon Elliott Alexander Hartmaier =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-View-Email-0.36/lib/Catalyst/Helper/View/000755 000765 000024 00000000000 12601303643 021745 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/lib/Catalyst/Helper/View/Email/000755 000765 000024 00000000000 12601303643 022774 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/lib/Catalyst/Helper/View/Email.pm000644 000765 000024 00000002335 12601303523 023332 0ustar00garustaff000000 000000 package Catalyst::Helper::View::Email; our $VERSION = '0.36'; $VERSION = eval $VERSION; use strict; =head1 NAME Catalyst::Helper::View::Email - Helper for Email Views =head1 SYNOPSIS $ script/myapp_create.pl view Email Email =head1 DESCRIPTION Helper for Email Views. =head2 METHODS =head3 mk_compclass =cut sub mk_compclass { my ( $self, $helper ) = @_; my $file = $helper->{file}; $helper->render_file( 'compclass', $file ); } =head1 SEE ALSO L L, L, L, L, L =head1 AUTHOR J. Shirley C =head1 LICENSE This library is free software . You can redistribute it and/or modify it under the same terms as perl itself. =cut 1; __DATA__ __compclass__ package [% class %]; use strict; use base 'Catalyst::View::Email'; __PACKAGE__->config( stash_key => 'email' ); =head1 NAME [% class %] - Email View for [% app %] =head1 DESCRIPTION View for sending email from [% app %]. =head1 AUTHOR [% author %] =head1 SEE ALSO L<[% app %]> =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-View-Email-0.36/lib/Catalyst/Helper/View/Email/Template.pm000644 000765 000024 00000002545 12601303523 025110 0ustar00garustaff000000 000000 package Catalyst::Helper::View::Email::Template; use strict; our $VERSION = '0.36'; $VERSION = eval $VERSION; =head1 NAME Catalyst::Helper::View::Email::Template - Helper for Templated Email Views =head1 SYNOPSIS $ script/myapp_create.pl view Email::Template Email::Template =head1 DESCRIPTION Helper for Template-based Email Views. =head2 METHODS =head3 mk_compclass =cut sub mk_compclass { my ( $self, $helper ) = @_; my $file = $helper->{file}; $helper->render_file( 'compclass', $file ); } =head1 SEE ALSO L L, L, L, L, L =head1 AUTHOR J. Shirley C =head1 LICENSE This library is free software . You can redistribute it and/or modify it under the same terms as perl itself. =cut 1; __DATA__ __compclass__ package [% class %]; use strict; use base 'Catalyst::View::Email::Template'; __PACKAGE__->config( stash_key => 'email', template_prefix => '' ); =head1 NAME [% class %] - Templated Email View for [% app %] =head1 DESCRIPTION View for sending template-generated email from [% app %]. =head1 AUTHOR [% author %] =head1 SEE ALSO L<[% app %]> =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-View-Email-0.36/inc/Module/000755 000765 000024 00000000000 12601303643 017260 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/inc/Module/AutoInstall.pm000644 000765 000024 00000062254 12601303626 022067 0ustar00garustaff000000 000000 #line 1 package Module::AutoInstall; use strict; use Cwd (); use File::Spec (); use ExtUtils::MakeMaker (); use vars qw{$VERSION}; BEGIN { $VERSION = '1.14'; } # special map on pre-defined feature sets my %FeatureMap = ( '' => 'Core Features', # XXX: deprecated '-core' => 'Core Features', ); # various lexical flags my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $InstallDepsTarget, $HasCPANPLUS ); my ( $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly, $AllDeps, $UpgradeDeps ); my ( $PostambleActions, $PostambleActionsNoTest, $PostambleActionsUpgradeDeps, $PostambleActionsUpgradeDepsNoTest, $PostambleActionsListDeps, $PostambleActionsListAllDeps, $PostambleUsed, $NoTest); # See if it's a testing or non-interactive session _accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); _init(); sub _accept_default { $AcceptDefault = shift; } sub _installdeps_target { $InstallDepsTarget = shift; } sub missing_modules { return @Missing; } sub do_install { __PACKAGE__->install( [ $Config ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) : () ], @Missing, ); } # initialize various flags, and/or perform install sub _init { foreach my $arg ( @ARGV, split( /[\s\t]+/, $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' ) ) { if ( $arg =~ /^--config=(.*)$/ ) { $Config = [ split( ',', $1 ) ]; } elsif ( $arg =~ /^--installdeps=(.*)$/ ) { __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--upgradedeps=(.*)$/ ) { $UpgradeDeps = 1; __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--default(?:deps)?$/ ) { $AcceptDefault = 1; } elsif ( $arg =~ /^--check(?:deps)?$/ ) { $CheckOnly = 1; } elsif ( $arg =~ /^--skip(?:deps)?$/ ) { $SkipInstall = 1; } elsif ( $arg =~ /^--test(?:only)?$/ ) { $TestOnly = 1; } elsif ( $arg =~ /^--all(?:deps)?$/ ) { $AllDeps = 1; } } } # overrides MakeMaker's prompt() to automatically accept the default choice sub _prompt { goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; my ( $prompt, $default ) = @_; my $y = ( $default =~ /^[Yy]/ ); print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; print "$default\n"; return $default; } # the workhorse sub import { my $class = shift; my @args = @_ or return; my $core_all; print "*** $class version " . $class->VERSION . "\n"; print "*** Checking for Perl dependencies...\n"; my $cwd = Cwd::getcwd(); $Config = []; my $maxlen = length( ( sort { length($b) <=> length($a) } grep { /^[^\-]/ } map { ref($_) ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) : '' } map { +{@args}->{$_} } grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } )[0] ); # We want to know if we're under CPAN early to avoid prompting, but # if we aren't going to try and install anything anyway then skip the # check entirely since we don't want to have to load (and configure) # an old CPAN just for a cosmetic message $UnderCPAN = _check_lock(1) unless $SkipInstall || $InstallDepsTarget; while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { my ( @required, @tests, @skiptests ); my $default = 1; my $conflict = 0; if ( $feature =~ m/^-(\w+)$/ ) { my $option = lc($1); # check for a newer version of myself _update_to( $modules, @_ ) and return if $option eq 'version'; # sets CPAN configuration options $Config = $modules if $option eq 'config'; # promote every features to core status $core_all = ( $modules =~ /^all$/i ) and next if $option eq 'core'; next unless $option eq 'core'; } print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); unshift @$modules, -default => &{ shift(@$modules) } if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward compatibility while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { if ( $mod =~ m/^-(\w+)$/ ) { my $option = lc($1); $default = $arg if ( $option eq 'default' ); $conflict = $arg if ( $option eq 'conflict' ); @tests = @{$arg} if ( $option eq 'tests' ); @skiptests = @{$arg} if ( $option eq 'skiptests' ); next; } printf( "- %-${maxlen}s ...", $mod ); if ( $arg and $arg =~ /^\D/ ) { unshift @$modules, $arg; $arg = 0; } # XXX: check for conflicts and uninstalls(!) them. my $cur = _version_of($mod); if (_version_cmp ($cur, $arg) >= 0) { print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; push @Existing, $mod => $arg; $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { if (not defined $cur) # indeed missing { print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; } else { # no need to check $arg as _version_cmp ($cur, undef) would satisfy >= above print "too old. ($cur < $arg)\n"; } push @required, $mod => $arg; } } next unless @required; my $mandatory = ( $feature eq '-core' or $core_all ); if ( !$SkipInstall and ( $CheckOnly or ($mandatory and $UnderCPAN) or $AllDeps or $InstallDepsTarget or _prompt( qq{==> Auto-install the } . ( @required / 2 ) . ( $mandatory ? ' mandatory' : ' optional' ) . qq{ module(s) from CPAN?}, $default ? 'y' : 'n', ) =~ /^[Yy]/ ) ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } elsif ( !$SkipInstall and $default and $mandatory and _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) =~ /^[Nn]/ ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { $DisabledTests{$_} = 1 for map { glob($_) } @tests; } } if ( @Missing and not( $CheckOnly or $UnderCPAN) ) { require Config; my $make = $Config::Config{make}; if ($InstallDepsTarget) { print "*** To install dependencies type '$make installdeps' or '$make installdeps_notest'.\n"; } else { print "*** Dependencies will be installed the next time you type '$make'.\n"; } # make an educated guess of whether we'll need root permission. print " (You may need to do that as the 'root' user.)\n" if eval '$>'; } print "*** $class configuration finished.\n"; chdir $cwd; # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; return (@Existing, @Missing); } sub _running_under { my $thing = shift; print <<"END_MESSAGE"; *** Since we're running under ${thing}, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } # Check to see if we are currently running under CPAN.pm and/or CPANPLUS; # if we are, then we simply let it taking care of our dependencies sub _check_lock { return unless @Missing or @_; if ($ENV{PERL5_CPANM_IS_RUNNING}) { return _running_under('cpanminus'); } my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING}; if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { return _running_under($cpan_env ? 'CPAN' : 'CPANPLUS'); } require CPAN; if ($CPAN::VERSION > '1.89') { if ($cpan_env) { return _running_under('CPAN'); } return; # CPAN.pm new enough, don't need to check further } # last ditch attempt, this -will- configure CPAN, very sorry _load_cpan(1); # force initialize even though it's already loaded # Find the CPAN lock-file my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); return unless -f $lock; # Check the lock local *LOCK; return unless open(LOCK, $lock); if ( ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' ) { print <<'END_MESSAGE'; *** Since we're running under CPAN, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } close LOCK; return; } sub install { my $class = shift; my $i; # used below to strip leading '-' from config keys my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); my ( @modules, @installed, @modules_to_upgrade ); while (my ($pkg, $ver) = splice(@_, 0, 2)) { # grep out those already installed if (_version_cmp(_version_of($pkg), $ver) >= 0) { push @installed, $pkg; if ($UpgradeDeps) { push @modules_to_upgrade, $pkg, $ver; } } else { push @modules, $pkg, $ver; } } if ($UpgradeDeps) { push @modules, @modules_to_upgrade; @installed = (); @modules_to_upgrade = (); } return @installed unless @modules; # nothing to do return @installed if _check_lock(); # defer to the CPAN shell print "*** Installing dependencies...\n"; return unless _connected_to('cpan.org'); my %args = @config; my %failed; local *FAILED; if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { while () { chomp; $failed{$_}++ } close FAILED; my @newmod; while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { push @newmod, ( $k => $v ) unless $failed{$k}; } @modules = @newmod; } if ( _has_cpanplus() and not $ENV{PERL_AUTOINSTALL_PREFER_CPAN} ) { _install_cpanplus( \@modules, \@config ); } else { _install_cpan( \@modules, \@config ); } print "*** $class installation finished.\n"; # see if we have successfully installed them while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { print FAILED "$pkg\n"; } } close FAILED if $args{do_once}; return @installed; } sub _install_cpanplus { my @modules = @{ +shift }; my @config = _cpanplus_config( @{ +shift } ); my $installed = 0; require CPANPLUS::Backend; my $cp = CPANPLUS::Backend->new; my $conf = $cp->configure_object; return unless $conf->can('conf') # 0.05x+ with "sudo" support or _can_write($conf->_get_build('base')); # 0.04x # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $conf->get_conf('makeflags') || ''; if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { # 0.03+ uses a hashref here $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; } else { # 0.02 and below uses a scalar $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); } $conf->set_conf( makeflags => $makeflags ); $conf->set_conf( prereqs => 1 ); while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { $conf->set_conf( $key, $val ); } my $modtree = $cp->module_tree; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { print "*** Installing $pkg...\n"; MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; my $success; my $obj = $modtree->{$pkg}; if ( $obj and _version_cmp( $obj->{version}, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $cp->install( modules => [ $obj->{module} ] ); if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation cancelled.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _cpanplus_config { my @config = (); while ( @_ ) { my ($key, $value) = (shift(), shift()); if ( $key eq 'prerequisites_policy' ) { if ( $value eq 'follow' ) { $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); } elsif ( $value eq 'ask' ) { $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); } elsif ( $value eq 'ignore' ) { $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); } else { die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; } push @config, 'prereqs', $value; } elsif ( $key eq 'force' ) { push @config, $key, $value; } elsif ( $key eq 'notest' ) { push @config, 'skiptest', $value; } else { die "*** Cannot convert option $key to CPANPLUS version.\n"; } } return @config; } sub _install_cpan { my @modules = @{ +shift }; my @config = @{ +shift }; my $installed = 0; my %args; _load_cpan(); require Config; if (CPAN->VERSION < 1.80) { # no "sudo" support, probe for writableness return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) and _can_write( $Config::Config{sitelib} ); } # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $CPAN::Config->{make_install_arg} || ''; $CPAN::Config->{make_install_arg} = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); # don't show start-up info $CPAN::Config->{inhibit_startup_message} = 1; # set additional options while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { ( $args{$opt} = $arg, next ) if $opt =~ /^(?:force|notest)$/; # pseudo-option $CPAN::Config->{$opt} = $arg; } if ($args{notest} && (not CPAN::Shell->can('notest'))) { die "Your version of CPAN is too old to support the 'notest' pragma"; } local $CPAN::Config->{prerequisites_policy} = 'follow'; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; print "*** Installing $pkg...\n"; my $obj = CPAN::Shell->expand( Module => $pkg ); my $success = 0; if ( $obj and _version_cmp( $obj->cpan_version, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = do { if ($args{force}) { CPAN::Shell->force( install => $pkg ) } elsif ($args{notest}) { CPAN::Shell->notest( install => $pkg ) } else { CPAN::Shell->install($pkg) } }; $rv ||= eval { $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) ->{install} if $CPAN::META; }; if ( $rv eq 'YES' ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation failed.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _has_cpanplus { return ( $HasCPANPLUS = ( $INC{'CPANPLUS/Config.pm'} or _load('CPANPLUS::Shell::Default') ) ); } # make guesses on whether we're under the CPAN installation directory sub _under_cpan { require Cwd; require File::Spec; my $cwd = File::Spec->canonpath( Cwd::getcwd() ); my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); return ( index( $cwd, $cpan ) > -1 ); } sub _update_to { my $class = __PACKAGE__; my $ver = shift; return if _version_cmp( _version_of($class), $ver ) >= 0; # no need to upgrade if ( _prompt( "==> A newer version of $class ($ver) is required. Install?", 'y' ) =~ /^[Nn]/ ) { die "*** Please install $class $ver manually.\n"; } print << "."; *** Trying to fetch it from CPAN... . # install ourselves _load($class) and return $class->import(@_) if $class->install( [], $class, $ver ); print << '.'; exit 1; *** Cannot bootstrap myself. :-( Installation terminated. . } # check if we're connected to some host, using inet_aton sub _connected_to { my $site = shift; return ( ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( qq( *** Your host cannot resolve the domain name '$site', which probably means the Internet connections are unavailable. ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/ ); } # check if a directory is writable; may create it on demand sub _can_write { my $path = shift; mkdir( $path, 0755 ) unless -e $path; return 1 if -w $path; print << "."; *** You are not allowed to write to the directory '$path'; the installation may fail due to insufficient permissions. . if ( eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( qq( ==> Should we try to re-execute the autoinstall process with 'sudo'?), ((-t STDIN) ? 'y' : 'n') ) =~ /^[Yy]/ ) { # try to bootstrap ourselves from sudo print << "."; *** Trying to re-execute the autoinstall process with 'sudo'... . my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; return unless system( 'sudo', $^X, $0, "--config=$config", "--installdeps=$missing" ); print << "."; *** The 'sudo' command exited with error! Resuming... . } return _prompt( qq( ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/; } # load a module and return the version it reports sub _load { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; local $@; return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); } # report version without loading a module sub _version_of { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; foreach my $dir ( @INC ) { next if ref $dir; my $path = File::Spec->catfile($dir, $file); next unless -e $path; require ExtUtils::MM_Unix; return ExtUtils::MM_Unix->parse_version($path); } return undef; } # Load CPAN.pm and it's configuration sub _load_cpan { return if $CPAN::VERSION and $CPAN::Config and not @_; require CPAN; # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to # CPAN::HandleConfig->load. CPAN reports that the redirection # is deprecated in a warning printed at the user. # CPAN-1.81 expects CPAN::HandleConfig->load, does not have # $CPAN::HandleConfig::VERSION but cannot handle # CPAN::Config->load # Which "versions expect CPAN::Config->load? if ( $CPAN::HandleConfig::VERSION || CPAN::HandleConfig->can('load') ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { # Older versions had the load method in Config directly CPAN::Config->load; } } # compare two versions, either use Sort::Versions or plain comparison # return values same as <=> sub _version_cmp { my ( $cur, $min ) = @_; return -1 unless defined $cur; # if 0 keep comparing return 1 unless $min; $cur =~ s/\s+$//; # check for version numbers that are not in decimal format if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { if ( ( $version::VERSION or defined( _load('version') )) and version->can('new') ) { # use version.pm if it is installed. return version->new($cur) <=> version->new($min); } elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) { # use Sort::Versions as the sorting algorithm for a.b.c versions return Sort::Versions::versioncmp( $cur, $min ); } warn "Cannot reliably compare non-decimal formatted versions.\n" . "Please install version.pm or Sort::Versions.\n"; } # plain comparison local $^W = 0; # shuts off 'not numeric' bugs return $cur <=> $min; } # nothing; this usage is deprecated. sub main::PREREQ_PM { return {}; } sub _make_args { my %args = @_; $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } if $UnderCPAN or $TestOnly; if ( $args{EXE_FILES} and -e 'MANIFEST' ) { require ExtUtils::Manifest; my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); $args{EXE_FILES} = [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; } $args{test}{TESTS} ||= 't/*.t'; $args{test}{TESTS} = join( ' ', grep { !exists( $DisabledTests{$_} ) } map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; $PostambleActions = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); my $deps_list = join( ',', @Missing, @Existing ); $PostambleActionsUpgradeDeps = "\$(PERL) $0 --config=$config --upgradedeps=$deps_list"; my $config_notest = join( ',', (UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config}), 'notest', 1 ) if $Config; $PostambleActionsNoTest = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config_notest --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); $PostambleActionsUpgradeDepsNoTest = "\$(PERL) $0 --config=$config_notest --upgradedeps=$deps_list"; $PostambleActionsListDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $Missing[$_], grep $_ % 2 == 0, 0..$#Missing); my @all = (@Missing, @Existing); $PostambleActionsListAllDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $all[$_], grep $_ % 2 == 0, 0..$#all); return %args; } # a wrapper to ExtUtils::MakeMaker::WriteMakefile sub Write { require Carp; Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; if ($CheckOnly) { print << "."; *** Makefile not written in check-only mode. . return; } my %args = _make_args(@_); no strict 'refs'; $PostambleUsed = 0; local *MY::postamble = \&postamble unless defined &MY::postamble; ExtUtils::MakeMaker::WriteMakefile(%args); print << "." unless $PostambleUsed; *** WARNING: Makefile written with customized MY::postamble() without including contents from Module::AutoInstall::postamble() -- auto installation features disabled. Please contact the author. . return 1; } sub postamble { $PostambleUsed = 1; my $fragment; $fragment .= <<"AUTO_INSTALL" if !$InstallDepsTarget; config :: installdeps \t\$(NOECHO) \$(NOOP) AUTO_INSTALL $fragment .= <<"END_MAKE"; checkdeps :: \t\$(PERL) $0 --checkdeps installdeps :: \t$PostambleActions installdeps_notest :: \t$PostambleActionsNoTest upgradedeps :: \t$PostambleActionsUpgradeDeps upgradedeps_notest :: \t$PostambleActionsUpgradeDepsNoTest listdeps :: \t$PostambleActionsListDeps listalldeps :: \t$PostambleActionsListAllDeps END_MAKE return $fragment; } 1; __END__ #line 1197 Catalyst-View-Email-0.36/inc/Module/Install/000755 000765 000024 00000000000 12601303643 020666 5ustar00garustaff000000 000000 Catalyst-View-Email-0.36/inc/Module/Install.pm000644 000765 000024 00000030217 12601303626 021230 0ustar00garustaff000000 000000 #line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.006; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.14'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::getcwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::getcwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($subpath . '.pm'); my $in_pod = 0; foreach ( split /\n/, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_NEW sub _read { local *FH; open( FH, "< $_[0]" ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_OLD sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_NEW sub _write { local *FH; open( FH, "> $_[0]" ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_OLD # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. Catalyst-View-Email-0.36/inc/Module/Install/AutoInstall.pm000644 000765 000024 00000004162 12601303626 023467 0ustar00garustaff000000 000000 #line 1 package Module::Install::AutoInstall; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub AutoInstall { $_[0] } sub run { my $self = shift; $self->auto_install_now(@_); } sub write { my $self = shift; $self->auto_install(@_); } sub auto_install { my $self = shift; return if $self->{done}++; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->build_requires, $self->requires; my @config = @_; # We'll need Module::AutoInstall $self->include('Module::AutoInstall'); require Module::AutoInstall; my @features_require = Module::AutoInstall->import( (@config ? (-config => \@config) : ()), (@core ? (-core => \@core) : ()), $self->features, ); my %seen; my @requires = map @$_, map @$_, grep ref, $self->requires; while (my ($mod, $ver) = splice(@requires, 0, 2)) { $seen{$mod}{$ver}++; } my @build_requires = map @$_, map @$_, grep ref, $self->build_requires; while (my ($mod, $ver) = splice(@build_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires; while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @deduped; while (my ($mod, $ver) = splice(@features_require, 0, 2)) { push @deduped, $mod => $ver unless $seen{$mod}{$ver}++; } $self->requires(@deduped); $self->makemaker_args( Module::AutoInstall::_make_args() ); my $class = ref($self); $self->postamble( "# --- $class section:\n" . Module::AutoInstall::postamble() ); } sub installdeps_target { my ($self, @args) = @_; $self->include('Module::AutoInstall'); require Module::AutoInstall; Module::AutoInstall::_installdeps_target(1); $self->auto_install(@args); } sub auto_install_now { my $self = shift; $self->auto_install(@_); Module::AutoInstall::do_install(); } 1; Catalyst-View-Email-0.36/inc/Module/Install/Base.pm000644 000765 000024 00000002147 12601303626 022103 0ustar00garustaff000000 000000 #line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.14'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 Catalyst-View-Email-0.36/inc/Module/Install/Can.pm000644 000765 000024 00000006157 12601303626 021737 0ustar00garustaff000000 000000 #line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 236 Catalyst-View-Email-0.36/inc/Module/Install/Fetch.pm000644 000765 000024 00000004627 12601303626 022267 0ustar00garustaff000000 000000 #line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Catalyst-View-Email-0.36/inc/Module/Install/Include.pm000644 000765 000024 00000001015 12601303626 022605 0ustar00garustaff000000 000000 #line 1 package Module::Install::Include; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub include { shift()->admin->include(@_); } sub include_deps { shift()->admin->include_deps(@_); } sub auto_include { shift()->admin->auto_include(@_); } sub auto_include_deps { shift()->admin->auto_include_deps(@_); } sub auto_include_dependent_dists { shift()->admin->auto_include_dependent_dists(@_); } 1; Catalyst-View-Email-0.36/inc/Module/Install/Makefile.pm000644 000765 000024 00000027437 12601303626 022757 0ustar00garustaff000000 000000 #line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-separated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 Catalyst-View-Email-0.36/inc/Module/Install/Metadata.pm000644 000765 000024 00000043302 12601303626 022747 0ustar00garustaff000000 000000 #line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) [\s|;]* /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashes delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; Catalyst-View-Email-0.36/inc/Module/Install/Win32.pm000644 000765 000024 00000003403 12601303626 022127 0ustar00garustaff000000 000000 #line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Catalyst-View-Email-0.36/inc/Module/Install/WriteAll.pm000644 000765 000024 00000002376 12601303626 022760 0ustar00garustaff000000 000000 #line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1;