line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# This file is part of Software-Copyright |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# This software is Copyright (c) 2022 by Dominique Dumont <dod@debian.org>. |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# This is free software, licensed under: |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# The GNU General Public License, Version 3, June 2007 |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
package Software::Copyright::Statement; |
11
|
|
|
|
|
|
|
$Software::Copyright::Statement::VERSION = '0.011'; |
12
|
3
|
|
|
3
|
|
1478
|
use 5.20.0; |
|
3
|
|
|
|
|
11
|
|
13
|
3
|
|
|
3
|
|
15
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
91
|
|
14
|
|
|
|
|
|
|
|
15
|
3
|
|
|
3
|
|
1013
|
use Mouse; |
|
3
|
|
|
|
|
60592
|
|
|
3
|
|
|
|
|
36
|
|
16
|
3
|
|
|
3
|
|
2942
|
use Array::IntSpan; |
|
3
|
|
|
|
|
9380
|
|
|
3
|
|
|
|
|
89
|
|
17
|
3
|
|
|
3
|
|
40
|
use Carp; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
200
|
|
18
|
3
|
|
|
3
|
|
1598
|
use Software::Copyright::Owner; |
|
3
|
|
|
|
|
10
|
|
|
3
|
|
|
|
|
92
|
|
19
|
3
|
|
|
3
|
|
1579
|
use Date::Parse; |
|
3
|
|
|
|
|
23337
|
|
|
3
|
|
|
|
|
402
|
|
20
|
3
|
|
|
3
|
|
1025
|
use Time::localtime; |
|
3
|
|
|
|
|
12260
|
|
|
3
|
|
|
|
|
202
|
|
21
|
|
|
|
|
|
|
|
22
|
3
|
|
|
3
|
|
29
|
use feature qw/postderef signatures/; |
|
3
|
|
|
|
|
14
|
|
|
3
|
|
|
|
|
259
|
|
23
|
3
|
|
|
3
|
|
17
|
no warnings qw/experimental::postderef experimental::signatures/; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
147
|
|
24
|
|
|
|
|
|
|
|
25
|
3
|
|
|
3
|
|
15
|
use overload '""' => \&stringify; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
19
|
|
26
|
3
|
|
|
3
|
|
217
|
use overload 'cmp' => \&compare; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
14
|
|
27
|
3
|
|
|
3
|
|
174
|
use overload '==' => \&_equal; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
11
|
|
28
|
3
|
|
|
3
|
|
171
|
use overload 'eq' => \&_equal; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
11
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
has span => ( |
31
|
|
|
|
|
|
|
is => 'ro', |
32
|
|
|
|
|
|
|
isa => 'Array::IntSpan', |
33
|
|
|
|
|
|
|
required => 1 , # may be an empty span |
34
|
|
|
|
|
|
|
); |
35
|
|
|
|
|
|
|
|
36
|
11
|
|
|
11
|
0
|
344
|
sub range ($self) { |
|
11
|
|
|
|
|
19
|
|
|
11
|
|
|
|
|
15
|
|
37
|
11
|
|
|
|
|
38
|
return scalar $self->span->get_range_list; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
has owner => ( |
41
|
|
|
|
|
|
|
is => 'rw', |
42
|
|
|
|
|
|
|
isa => 'Software::Copyright::Owner', |
43
|
|
|
|
|
|
|
required => 1, |
44
|
|
|
|
|
|
|
handles => { |
45
|
|
|
|
|
|
|
map { $_ => $_ } qw/name email record identifier/ |
46
|
|
|
|
|
|
|
}, |
47
|
|
|
|
|
|
|
); |
48
|
|
|
|
|
|
|
|
49
|
126
|
|
|
126
|
|
183
|
sub __clean_copyright ($c) { |
|
126
|
|
|
|
|
181
|
|
|
126
|
|
|
|
|
174
|
|
50
|
126
|
|
|
|
|
260
|
$c =~ s/^©\s*//g; |
51
|
1
|
|
|
1
|
|
9
|
$c =~ s/\(c\)\s*//gi; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
16
|
|
|
126
|
|
|
|
|
323
|
|
52
|
|
|
|
|
|
|
# remove space around dash between number (eg. 2003 - 2004 => 2003-2004) |
53
|
126
|
|
|
|
|
28165
|
$c =~ s/(\d+)\s*-\s*(?=\d+)/$1-/g; |
54
|
|
|
|
|
|
|
# extract year from YY-MM-DD:hh:mm:ss format |
55
|
126
|
|
|
|
|
303
|
$c =~ s/(\d{2,4}-\d\d-\d{2,4})[:\d]*/my @r = strptime($1); $r[5]+1900/gex; |
|
3
|
|
|
|
|
70
|
|
|
3
|
|
|
|
|
402
|
|
56
|
|
|
|
|
|
|
# remove extra years inside range, e,g 2003- 2004- 2008 -> 2003- 2008 |
57
|
126
|
|
|
|
|
301
|
$c =~ s/(?<=\b\d{4})\s*-\s*\d{4}(?=\s*-\s*(\d{4})\b)//g; |
58
|
|
|
|
|
|
|
# add space after a comma between years |
59
|
126
|
|
|
|
|
1043
|
$c =~ s/\b(\d{4}),?\s+([\S^\d])/$1, $2/g; |
60
|
126
|
|
|
|
|
318
|
$c =~ s/\s+by\s+//g; |
61
|
126
|
|
|
|
|
257
|
$c =~ s/(\\n)*all\s+rights?\s+reserved\.?(\\n)*\s*//gi; # yes there are literal \n |
62
|
126
|
100
|
|
|
|
371
|
$c = '' if $c =~ /^\*No copyright/i; |
63
|
126
|
|
|
|
|
211
|
$c =~ s/\(r\)//g; |
64
|
|
|
|
|
|
|
# remove spurious characters at beginning or end of string |
65
|
126
|
|
|
|
|
754
|
$c =~ s!^[\s,/*]+|[\s,#/*-]+$!!g; |
66
|
126
|
|
|
|
|
220
|
$c =~ s/--/-/g; |
67
|
126
|
|
|
|
|
192
|
$c =~ s!\s+\*/\s+! !; |
68
|
|
|
|
|
|
|
# remove copyright word surrounded by non alpha char (like "@copyright{}"); |
69
|
126
|
|
|
|
|
207
|
$c =~ s/\W+copyright\W+//; |
70
|
|
|
|
|
|
|
# libuv1 has copyright like "2000, -present" |
71
|
126
|
|
|
|
|
207
|
$c =~ s![,\s]*-present!'-'.(localtime->year() + 1900)!e; |
|
1
|
|
|
|
|
3
|
|
72
|
|
|
|
|
|
|
# cleanup markdown copyright |
73
|
126
|
|
|
|
|
332
|
$c =~ s/\[([\w\s]+)\]\(mailto:([\w@.+-]+)\)/$1 <$2>/; |
74
|
126
|
|
|
|
|
319
|
return $c; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
137
|
|
|
137
|
|
10370
|
sub __split_copyright ($c) { |
|
137
|
|
|
|
|
246
|
|
|
137
|
|
|
|
|
188
|
|
78
|
137
|
|
|
|
|
546
|
my ($years,$owner) = $c =~ /^(\d\d[\s,\d-]+)(.*)/; |
79
|
|
|
|
|
|
|
# say "undef year in $c" unless defined $years; |
80
|
137
|
100
|
|
|
|
355
|
if (not defined $years) { |
81
|
|
|
|
|
|
|
# try owner and years in reversed order (works also without year) |
82
|
24
|
|
|
|
|
181
|
($owner,$years) = $c =~ m/(.*?)(\d\d[\s,\d-]+)?$/; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
137
|
|
50
|
|
|
292
|
$owner //=''; |
86
|
|
|
|
|
|
|
|
87
|
137
|
100
|
|
|
|
572
|
my @data = defined $years ? split /(?<=\d)[,\s]+/, $years : (); |
88
|
137
|
|
|
|
|
679
|
$owner =~ s/^[\s.,-]+|[\s,*-]+$//g; |
89
|
137
|
|
|
|
|
493
|
return ($owner,@data); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
around BUILDARGS => sub ($orig, $class, @args) { |
93
|
|
|
|
|
|
|
my $c = __clean_copyright($args[0]); |
94
|
|
|
|
|
|
|
my ($owner_str, @data) = __split_copyright($c); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
my $span = Array::IntSpan->new(); |
97
|
|
|
|
|
|
|
my $owner = Software::Copyright::Owner->new($owner_str); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
foreach my $year (@data) { |
100
|
|
|
|
|
|
|
last if $year =~ /[^\d-]/; # bail-out |
101
|
|
|
|
|
|
|
# take care of ranges written like 2002-3 |
102
|
|
|
|
|
|
|
$year =~ s/^(\d\d\d)(\d)-(\d)$/$1$2-$1$3/; |
103
|
|
|
|
|
|
|
# take care of ranges written like 2014-15 |
104
|
|
|
|
|
|
|
$year =~ s/^(\d\d)(\d\d)-(\d\d)$/$1$2-$1$3/; |
105
|
|
|
|
|
|
|
eval { |
106
|
|
|
|
|
|
|
# the value stored in range is not used. |
107
|
|
|
|
|
|
|
$span->set_range_as_string($year, $owner->identifier // 'unknown'); |
108
|
|
|
|
|
|
|
}; |
109
|
|
|
|
|
|
|
if ($@) { |
110
|
|
|
|
|
|
|
warn "Invalid year span: '$year' found in statement '$c'\n"; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
$span->consolidate(); |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
return $class->$orig({ |
116
|
|
|
|
|
|
|
span => $span, |
117
|
|
|
|
|
|
|
owner => $owner, |
118
|
|
|
|
|
|
|
}) ; |
119
|
|
|
|
|
|
|
}; |
120
|
|
|
|
|
|
|
|
121
|
218
|
|
|
218
|
1
|
1030
|
sub stringify ($self,$=1,$=1) { |
|
218
|
|
|
|
|
321
|
|
|
218
|
|
|
|
|
317
|
|
|
218
|
|
|
|
|
287
|
|
|
218
|
|
|
|
|
307
|
|
122
|
218
|
|
|
|
|
585
|
my $range = $self->span->get_range_list; |
123
|
218
|
|
|
|
|
2759
|
return join (', ', grep { $_ } ($range, $self->owner)); |
|
436
|
|
|
|
|
2659
|
|
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
42
|
|
|
42
|
0
|
210
|
sub compare ($self, $other, $swap) { |
|
42
|
|
|
|
|
68
|
|
|
42
|
|
|
|
|
64
|
|
|
42
|
|
|
|
|
74
|
|
|
42
|
|
|
|
|
58
|
|
127
|
|
|
|
|
|
|
# we must force stringify before calling cmp |
128
|
42
|
|
|
|
|
82
|
return "$self" cmp "$other"; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
7
|
|
|
7
|
|
1746
|
sub _equal ($self, $other, $swap) { |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
13
|
|
|
7
|
|
|
|
|
17
|
|
132
|
|
|
|
|
|
|
# we must force stringify before calling eq |
133
|
7
|
|
|
|
|
16
|
return "$self" eq "$other"; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
22
|
|
|
22
|
1
|
35
|
sub merge ($self, $other) { |
|
22
|
|
|
|
|
32
|
|
|
22
|
|
|
|
|
28
|
|
|
22
|
|
|
|
|
31
|
|
137
|
22
|
50
|
|
|
|
48
|
if ($self->identifier eq $other->identifier ) { |
138
|
22
|
100
|
|
|
|
49
|
$self->email($other->email) if $other->email; |
139
|
22
|
|
|
|
|
395
|
$self->span->set_range_as_string(scalar $other->span->get_range_list, $other->identifier); |
140
|
22
|
|
|
|
|
1060
|
$self->span->consolidate(); |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
else { |
143
|
0
|
|
|
|
|
0
|
croak "Cannot merge statement with mismatching owners"; |
144
|
|
|
|
|
|
|
} |
145
|
22
|
|
|
|
|
452
|
return $self; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
5
|
|
|
5
|
1
|
19
|
sub add_years ($self, $range) { |
|
5
|
|
|
|
|
27
|
|
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
7
|
|
149
|
5
|
|
|
|
|
22
|
$self->span->set_range_as_string($range, $self->owner->identifier); |
150
|
5
|
|
|
|
|
437
|
$self->span->consolidate; |
151
|
5
|
|
|
|
|
153
|
return $self; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
15
|
|
|
15
|
1
|
36
|
sub contains($self, $other) { |
|
15
|
|
|
|
|
23
|
|
|
15
|
|
|
|
|
19
|
|
|
15
|
|
|
|
|
53
|
|
155
|
15
|
100
|
|
|
|
40
|
return 0 unless $self->identifier eq $other->identifier; |
156
|
|
|
|
|
|
|
|
157
|
14
|
|
|
|
|
36
|
my $span = Array::IntSpan->new; |
158
|
14
|
|
|
|
|
173
|
$span->set_range_as_string(scalar $self->span->get_range_list, $self->identifier); |
159
|
|
|
|
|
|
|
# now $span is a copy of $self->span. Merge $other-span. |
160
|
14
|
|
|
|
|
499
|
$span->set_range_as_string(scalar $other->span->get_range_list, $self->identifier); |
161
|
14
|
|
|
|
|
925
|
$span->consolidate; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# if other span is contained in self->span, the merged result is not changed. |
164
|
14
|
100
|
|
|
|
186
|
return scalar $span->get_range_list eq scalar $self->span->get_range_list ? 1 : 0; |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
1; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# ABSTRACT: a copyright statement for one owner |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
__END__ |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=pod |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=encoding UTF-8 |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head1 NAME |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Software::Copyright::Statement - a copyright statement for one owner |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head1 VERSION |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
version 0.011 |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head1 SYNOPSIS |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
use Software::Copyright::Statement; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
my $statement = Software::Copyright::Statement->new('2020,2021, Joe <joe@example.com>'); |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
$statement->name; # => is "Joe" |
192
|
|
|
|
|
|
|
$statement->email; # => is 'joe@example.com' |
193
|
|
|
|
|
|
|
$statement->range; # => is '2020, 2021' |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# merge records |
196
|
|
|
|
|
|
|
$statement->merge(Software::Copyright::Statement->new('2022, Joe <joe@example.com>')); |
197
|
|
|
|
|
|
|
$statement->range; # => is '2020-2022' |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# update the year range |
200
|
|
|
|
|
|
|
$statement->add_years('2015, 2016-2019')->stringify; # => is '2015-2022, Joe <joe@example.com>' |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# stringification |
203
|
|
|
|
|
|
|
my $string = "$statement"; # => is '2015-2022, Joe <joe@example.com>' |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# test if a statement "contains" another one |
206
|
|
|
|
|
|
|
my $st_2020 = Software::Copyright::Statement->new('2020, Joe <joe@example.com>'); |
207
|
|
|
|
|
|
|
$statement->contains($st_2020); # => is '1' |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head1 DESCRIPTION |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
This class holds one copyright statement, i.e. year range, name |
212
|
|
|
|
|
|
|
and email of one copyright contributor. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
On construction, a cleanup is done to make the statement more |
215
|
|
|
|
|
|
|
standard. Here are some cleanup example: |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
2002-6 Joe => 2002-2006, Joe |
218
|
|
|
|
|
|
|
2001,2002,2003,2004 Joe => 2001-2004, Joe |
219
|
|
|
|
|
|
|
# found in markdown documents |
220
|
|
|
|
|
|
|
2002 Joe mailto:joe@example.com => 2002, Joe <joe@example.com> |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
The constructor can be called without argument or with a string |
225
|
|
|
|
|
|
|
containing: |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=over |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=item * |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
a year range (optional) |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=item * |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
a name (mandatory) |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=item * |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
an email address (optional) |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=back |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
E.g: |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
my $st = Software::Copyright::Statement->new(); |
246
|
|
|
|
|
|
|
my $st = Software::Copyright::Statement->new('2002, Joe <joe@example.com>'); |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=head1 Methods |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=head2 name |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Set or get owner's name |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head2 email |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Set or get owner's name |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 owner |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Returns a L<Software::Copyright::Owner> object. This object can be |
261
|
|
|
|
|
|
|
used as a string. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 merge |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
Merge 2 statements. Note that the 2 statements must belong to the same |
266
|
|
|
|
|
|
|
owner (the name attributes must be identical). |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
See the Synopsis for an example. |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
This method returns C<$self> |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head2 add_years |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
Add a year range to the copyright owner. This method accepts year |
275
|
|
|
|
|
|
|
ranges like "2020", "2018, 2020", "2016-2020,2022". White spaces are |
276
|
|
|
|
|
|
|
ignored. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
This method returns C<$self> |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head2 stringify |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Returns a string containing a year range (if any), a name and email |
283
|
|
|
|
|
|
|
(if any) of the copyright owner. |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=head2 contains |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Return 1 if the other statement is contained in current statement, |
288
|
|
|
|
|
|
|
i.e. owner or record are identical and other year range is contained |
289
|
|
|
|
|
|
|
in current year range. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
For instance: |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=over |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=item * |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
C<2016, Joe> is contained in C<2014-2020, Joe> |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=item * |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
C<2010, Joe> is B<not> contained in C<2014-2020, Joe> |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=back |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head2 Operator overload |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Operator C<""> is overloaded to call C<stringify>. |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head1 AUTHOR |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Dominique Dumont |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
This software is Copyright (c) 2022 by Dominique Dumont <dod@debian.org>. |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
This is free software, licensed under: |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
The GNU General Public License, Version 3, June 2007 |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=cut |