aboutsummaryrefslogtreecommitdiff
path: root/lib/Sietima/HeaderURI.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sietima/HeaderURI.pm')
-rw-r--r--lib/Sietima/HeaderURI.pm169
1 files changed, 148 insertions, 21 deletions
diff --git a/lib/Sietima/HeaderURI.pm b/lib/Sietima/HeaderURI.pm
index d9c1bb0..347ca77 100644
--- a/lib/Sietima/HeaderURI.pm
+++ b/lib/Sietima/HeaderURI.pm
@@ -2,11 +2,52 @@ package Sietima::HeaderURI;
use Moo;
use Sietima::Policy;
use Sietima::Types qw(Address AddressFromStr is_Address);
-use Types::Standard qw(Str ClassName HashRef Optional);
+use Types::Standard qw(Str is_Str ClassName HashRef Optional);
use Type::Params qw(compile);
use Types::URI qw(Uri is_Uri);
+use Email::Address;
use namespace::clean;
+# VERSION
+# ABSTRACT: annotated URI for list headers
+
+=head1 SYNOPSIS
+
+ around list_addresses => sub($orig,$self) {
+ return +{
+ $self->$orig->%*,
+ one => Sietima::HeaderURI->new({
+ uri => 'http://foo/',
+ comment => 'a thing',
+ }),
+ two => Sietima::HeaderURI->new_from_address(
+ $self->owner,
+ { subject => 'Hello' },
+ ),
+ three => Sietima::HeaderURI->new('http://some/url'),
+ four => Sietima::HeaderURI->new('(comment) address@example.com'),
+ };
+ }
+
+=head1 DESCRIPTION
+
+This class pairs a L<< C<URI> >> with a comment, and knows how to
+render itself as a string that can be used in a list management header
+(see L<< C<Sietima::Role::Headers> >>).
+
+=head1 ATTRIBUTES
+
+All attributes are read-only.
+
+=attr C<uri>
+
+Required L<< C<URI> >> object, coercible from a string or a hashref
+(see L<< C<Types::Uri> >> for the details). This is the URI that users
+should follow to perform the action implied by the list management
+header.
+
+=cut
+
has uri => (
is => 'ro',
isa => Uri,
@@ -14,49 +55,108 @@ has uri => (
coerce => 1,
);
+=attr C<comment>
+
+Optional string, will be added to the list management header as a
+comment (in parentheses).
+
+=cut
+
has comment => (
is => 'ro',
isa => Str,
);
-# if it's not an Email::Address obect, we'll just take it as a string:
-# it could be a non-mailto URI, see RFC 2369 "The Use of URLs as
-# Meta-Syntax for Core Mail List Commands and their Transport through
-# Message Header Fields"
+=method C<new>
+
+ Sietima::HeaderURI->new({
+ uri => 'http://foo/', comment => 'a thing',
+ });
+
+ Sietima::HeaderURI->new(
+ Email::Address->parse('(comment) address@example.com'),
+ );
+
+ Sietima::HeaderURI->new( '(comment) address@example.com' );
+
+ Sietima::HeaderURI->new(
+ URI->new('http://some/url'),
+ );
+
+ Sietima::HeaderURI->new( 'http://some/url' );
+
+Objects of this class can be constructed in several ways.
+
+You can pass a hashref with URI (or something that L<< C<Types::Uri>
+>> can coerce into a URI) and a comment string, as in the first
+example.
+
+Or you can pass a single value that can be (or can be coerced into)
+either a L<< C<Email::Address> >> or a L<< C<URI> >>.
+
+Email addresse became C<mailto:> URIs, and the optional comment is
+preserved.
+
+=for Pod::Coverage BUILDARGS
+
+=cut
+
+sub _args_from_address {
+ my ($address, $query) = @_;
+ $query ||= {};
+
+ my $uri = URI->new($address->address,'mailto');
+ $uri->query_form($query->%*);
+
+ my $comment = $address->comment;
+ # Email::Address::comment always returns a string in paretheses,
+ # but we don't want that, since we add them back in as_header_raw
+ $comment =~ s{\A\((.*)\)\z}{$1} if $comment;
+
+ return {
+ uri => $uri,
+ comment => $comment,
+ };
+}
around BUILDARGS => sub {
my ($orig, $class, @args) = @_;
- if (@args != 1 or ref($args[0]) eq 'HASH') {
+ if (@args != 1 or ref($args[0]) eq 'HASH' and $args[0]->{uri}) {
return $class->$orig(@args);
}
my $item = $args[0];
if (is_Address($item)) {
- return Sietima::HeaderURI->_args_from_address($item);
+ return _args_from_address($item);
}
elsif (is_Uri($item)) {
return { uri => $item };
}
- elsif (my $address = AddressFromStr->coerce($item)) {
- return Sietima::HeaderURI->_args_from_address($address);
+ elsif (is_Str($item) and my $address = AddressFromStr->coerce($item)) {
+ return _args_from_address($address);
}
else {
return { uri => $item };
};
};
-sub _args_from_address {
- my ($class, $address, $query) = @_;
- $query ||= {};
+=method C<new_from_address>
- my $uri = URI->new($address->address,'mailto');
- $uri->query_form($query->%*);
+ Sietima::HeaderURI->new_from_address(
+ $email_address,
+ \%query,
+ );
- return {
- uri => $uri,
- comment => $address->comment,
- };
-}
+This constructor builds a complex C<mailto:> URI with the query hash
+you provide. It's a shortcut for:
+
+ my $uri = URI->new("mailto:$email_address");
+ $uri->query_form(\%query);
+
+Common query keys are C<subject> and C<body>. See RFC 6068 ("The
+'mailto' URI Scheme") for details.
+
+=cut
sub new_from_address {
state $check = compile(
@@ -66,15 +166,42 @@ sub new_from_address {
);
my ($class, $address, $query) = $check->(@_);
- return $class->new($class->_args_from_address($address,$query));
+ return $class->new(_args_from_address($address,$query));
}
+=method C<as_header_raw>
+
+ $mail->header_raw_set('List-Thing' => $headeruri->as_header_raw);
+
+This method returns a string representation of the L</URI> and
+L</comment> in the format specified by RFC 2369 ("The Use of URLs as
+Meta-Syntax for Core Mail List Commands and their Transport through
+Message Header Fields").
+
+For example:
+
+ Sietima::HeaderURI->new({
+ uri => 'http://foo/', comment => 'a thing',
+ })->as_header_raw eq '<http://foo/> (a thing)';
+
+ Sietima::HeaderURI->new( '(comment) address@example.com' )
+ ->as_header_raw eq '<mailto:address@example.com> (comment)';
+
+ Sietima::HeaderURI->new( 'http://some/url' )
+ ->as_header_raw eq '<http://some/url>';
+
+Notice that, since the list management headers are I<structured>, they
+should always be set with L<<
+C<header_raw_set>|Email::Simple::Header/header_raw_set >>.
+
+=cut
+
sub as_header_raw {
my ($self) = @_;
my $str = sprintf '<%s>',$self->uri;
if (my $c = $self->comment) {
- $str .= ' '.$c;
+ $str .= sprintf ' (%s)',$c;
}
return $str;