| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
|
2
|
3
|
|
|
3
|
|
3490
|
use v5.26; |
|
|
3
|
|
|
|
|
9
|
|
|
3
|
3
|
|
|
3
|
|
1719
|
use utf8; |
|
|
3
|
|
|
|
|
32
|
|
|
|
3
|
|
|
|
|
18
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package App::url; |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '1.006'; |
|
8
|
|
|
|
|
|
|
|
|
9
|
3
|
|
|
3
|
|
188
|
use Carp qw(carp); |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
211
|
|
|
10
|
3
|
|
|
3
|
|
1040
|
use Mojo::Base -strict, -signatures; |
|
|
3
|
|
|
|
|
382724
|
|
|
|
3
|
|
|
|
|
33
|
|
|
11
|
3
|
|
|
3
|
|
10280
|
use Mojo::URL; |
|
|
3
|
|
|
|
|
23634
|
|
|
|
3
|
|
|
|
|
24
|
|
|
12
|
3
|
|
|
3
|
|
1652
|
use String::Sprintf; |
|
|
3
|
|
|
|
|
1566
|
|
|
|
3
|
|
|
|
|
154
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=encoding utf8 |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 NAME |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
App::url - format a URL according to a sprintf-like template |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
$ url '%h' http://www.example.com/a/b/c |
|
23
|
|
|
|
|
|
|
www.example.com |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
$ url '%H' http://www.example.com/a/b/c |
|
26
|
|
|
|
|
|
|
www |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
$ url '%P' http://www.example.com/a/b/c |
|
29
|
|
|
|
|
|
|
/a/b/c |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Decompose the URL and reformat it according to |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head2 The formats |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=over 4 |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=item * C<%a> - the path |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=item * C<%f> - the fragment |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=item * C<%h> - the hostname, with domain info |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=item * C<%H> - the hostname without domain info |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=item * C<%i> - the hostname in punycode |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=item * C<%I> - space-separated list of IP addresses for the host |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=item * C<%P> - the password of the userinfo portion |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item * C<%p> - the port |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=item * C<%q> - the query string |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=item * C<%s> - the scheme |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item * C<%S> - the public suffix |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=item * C<%u> - the complete URL |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=item * C<%U> - the username of the userinfo portion |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=back |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
There are also some bonus formats unrelated to the URL: |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=over 4 |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item * C<%n> - newline |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=item * C<%t> - tab |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item * C<%%> - literal percent |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=back |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 Methods |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=over 4 |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=item * run( TEMPLATE, ARRAY ) |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Format each URL in ARRAY according to TEMPLATE and return an array |
|
86
|
|
|
|
|
|
|
reference |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=back |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Copyright © 2020-2021, brian d foy, all rights reserved. |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=head1 LICENSE |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
You can use this code under the terms of the Artistic License 2. |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=cut |
|
99
|
|
|
|
|
|
|
|
|
100
|
3
|
|
|
3
|
|
24
|
no warnings 'uninitialized'; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
3609
|
|
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# $w - width of field |
|
103
|
|
|
|
|
|
|
# $v - value that corresponds to position in template |
|
104
|
|
|
|
|
|
|
# $V - list of all values |
|
105
|
|
|
|
|
|
|
# $l - letter |
|
106
|
|
|
|
|
|
|
my $formatter = String::Sprintf->formatter( |
|
107
|
|
|
|
|
|
|
a => sub ( $w, $v, $V, $l ) { $V->[0]->path }, |
|
108
|
|
|
|
|
|
|
f => sub ( $w, $v, $V, $l ) { $V->[0]->fragment }, |
|
109
|
|
|
|
|
|
|
h => sub ( $w, $v, $V, $l ) { $V->[0]->host }, |
|
110
|
|
|
|
|
|
|
H => sub ( $w, $v, $V, $l ) { ( split /\./, $V->[0]->host )[0] }, |
|
111
|
|
|
|
|
|
|
i => sub ( $w, $v, $V, $l ) { $V->[0]->ihost }, |
|
112
|
|
|
|
|
|
|
I => sub ( $w, $v, $V, $l ) { |
|
113
|
|
|
|
|
|
|
state $rc = require Socket; |
|
114
|
|
|
|
|
|
|
my @addresses = gethostbyname( $V->[0]->host ); |
|
115
|
|
|
|
|
|
|
@addresses = map { Socket::inet_ntoa($_) } @addresses[4..$#addresses]; |
|
116
|
|
|
|
|
|
|
"@addresses"; |
|
117
|
|
|
|
|
|
|
}, |
|
118
|
|
|
|
|
|
|
p => sub ( $w, $v, $V, $l ) { $V->[0]->port // do { |
|
119
|
|
|
|
|
|
|
if( $V->[0]->protocol eq 'http' ) { 80 } |
|
120
|
|
|
|
|
|
|
elsif( $V->[0]->protocol eq 'https' ) { 443 } |
|
121
|
|
|
|
|
|
|
}; |
|
122
|
|
|
|
|
|
|
}, |
|
123
|
|
|
|
|
|
|
P => sub ( $w, $v, $V, $l ) { $V->[0]->password }, |
|
124
|
|
|
|
|
|
|
'q' => sub ( $w, $v, $V, $l ) { $V->[0]->query }, |
|
125
|
|
|
|
|
|
|
's' => sub ( $w, $v, $V, $l ) { $V->[0]->protocol }, |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
S => sub ( $w, $v, $V, $l ) { |
|
128
|
|
|
|
|
|
|
state $rc = eval { require Net::PublicSuffixList }; |
|
129
|
|
|
|
|
|
|
unless( $rc ) { |
|
130
|
|
|
|
|
|
|
carp "%${l} requires Net::PublicSuffixList\n"; |
|
131
|
|
|
|
|
|
|
return; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
state $psl = Net::PublicSuffixList->new; |
|
134
|
|
|
|
|
|
|
my $hash = $psl->split_host( $V->[0]->host ); |
|
135
|
|
|
|
|
|
|
$hash->{suffix}; |
|
136
|
|
|
|
|
|
|
}, |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
U => sub ( $w, $v, $V, $l ) { $V->[0]->username }, |
|
139
|
|
|
|
|
|
|
u => sub ( $w, $v, $V, $l ) { $V->[0]->to_string }, |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
n => sub { "\n" }, |
|
142
|
|
|
|
|
|
|
t => sub { "\t" }, |
|
143
|
|
|
|
|
|
|
'%' => sub { '%' }, |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
'*' => sub ( $w, $v, $V, $l ) { warn "Invalid specifier <$l>\n" }, |
|
146
|
|
|
|
|
|
|
); |
|
147
|
|
|
|
|
|
|
|
|
148
|
0
|
|
|
0
|
1
|
|
sub run ( $class, $template, @urls ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
|
my @strings; |
|
150
|
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
|
foreach my $url ( @urls ) { |
|
152
|
0
|
|
|
|
|
|
push @strings, $formatter->sprintf( $template, Mojo::URL->new($url) ); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
|
|
|
|
|
return \@strings; |
|
156
|
|
|
|
|
|
|
} |