1DateTime::Format::BuildUesre:r:TCuotnotrriiablu(t3e)d PeDralteDToicmuem:e:nFtoartmiaotn::Builder::Tutorial(3)
2
3
4

NAME

6       DateTime::Format::Builder::Tutorial - Quick class on using Builder
7

VERSION

9       version 0.82
10

CREATING A CLASS

12       As most people who are writing modules know, you start a package with a
13       package declaration and some indication of module version:
14
15           package DateTime::Format::ICal;
16           our $VERSION = '0.04';
17
18       After that, you call Builder with some options. There are only a few
19       (detailed later). Right now, we're only interested in parsers.
20
21           use DateTime::Format::Builder
22           (
23               parsers => {
24               ...
25               }
26           );
27
28       The parsers option takes a reference to a hash of method names and
29       specifications:
30
31               parsers => {
32                   parse_datetime => ... ,
33                   parse_datetime_with_timezone => ... ,
34                   ...
35               }
36
37       Builder will create methods in your class, each method being a parser
38       that follows the given specifications. It is strongly recommended that
39       one method is called parse_datetime, be it a Builder created method or
40       one of your own.
41
42       In addition to creating any of the parser methods it also creates a
43       "new()" method that can instantiate (or clone) objects of this class.
44       This behaviour can be modified with the constructor option, but we
45       don't need to know that yet.
46
47       Each value corresponding to a method name in the parsers list is either
48       a single specification, or a list of specifications. We'll start with
49       the simple case.
50
51               parse_briefdate => {
52                   params => [ qw( year month day ) ],
53                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)$/,
54               },
55
56       This will result in a method named parse_briefdate which will take
57       strings in the form 20040716 and return DateTime objects representing
58       that date. A user of the class might write:
59
60           use DateTime::Format::ICal;
61           my $date = "19790716";
62           my $dt = DateTime::Format::ICal->parse_briefdate( $date );
63           print "My birth month is ", $dt->month_name, "\n";
64
65       The "regex" is applied to the input string, and if it matches, then $1,
66       $2, ... are mapped to the params given and handed to "DateTime->new()".
67       Essentially:
68
69           my $rv = DateTime->new( year => $1, month => $2, day => $3 );
70
71       There are more complicated things one can do within a single
72       specification, but we'll cover those later.
73
74       Often, you'll want a method to be able to take one string, and run it
75       against multiple parser specifications. It would be very irritating if
76       the user had to work out what format the datetime string was in and
77       then which method was most appropriate.
78
79       So, Builder lets you specify multiple specifications:
80
81           parse_datetime => [
82               {
83                   params => [ qw( year month day hour minute second ) ],
84                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)$/,
85               },
86               {
87                   params => [ qw( year month day hour minute ) ],
88                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)$/,
89               },
90               {
91                   params => [ qw( year month day hour ) ],
92                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)$/,
93               },
94               {
95                   params => [ qw( year month day ) ],
96                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)$/,
97               },
98           ],
99
100       It's an arrayref of specifications. A parser will be created that will
101       try each of these specifications sequentially, in the order you
102       specified.
103
104       There's a flaw with this though. In this example, we're building a
105       parser for ICal datetimes. One can place a timezone id at the start of
106       an ICal datetime. You might extract such an id with the following code:
107
108           if ( $date =~ s/^TZID=([^:]+):// )
109           {
110               $time_zone = $1;
111           }
112           # Z at end means UTC
113           elsif ( $date =~ s/Z$// )
114           {
115               $time_zone = 'UTC';
116           }
117           else
118           {
119               $time_zone = 'floating';
120           }
121
122       $date would end up without the id, and $time_zone would contain
123       something appropriate to give to DateTime's set_time_zone method, or
124       time_zone argument.
125
126       But how to get this scrap of code into your parser? You might be
127       tempted to call the parser something else and build a small wrapper.
128       There's no need though because an option is provided for preprocessing
129       dates:
130
131           parse_datetime => [
132               [ preprocess => \&_parse_tz ], # Only changed line!
133               {
134                   params => [ qw( year month day hour minute second ) ],
135                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)$/,
136               },
137               {
138                   params => [ qw( year month day hour minute ) ],
139                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)$/,
140               },
141               {
142                   params => [ qw( year month day hour ) ],
143                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)$/,
144               },
145               {
146                   params => [ qw( year month day ) ],
147                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)$/,
148               },
149           ],
150
151       It will necessitate _parse_tz to be written, and that routine looks
152       like this:
153
154           sub _parse_tz
155           {
156               my %args = @_;
157               my ($date, $p) = @args{qw( input parsed )};
158               if ( $date =~ s/^TZID=([^:]+):// )
159               {
160                   $p->{time_zone} = $1;
161               }
162               # Z at end means UTC
163               elsif ( $date =~ s/Z$// )
164               {
165                   $p->{time_zone} = 'UTC';
166               }
167               else
168               {
169                   $p->{time_zone} = 'floating';
170               }
171               return $date;
172           }
173
174       On input it is given a hash containing two items: the input date and a
175       hashref that will be used in the parsing. The return value from the
176       routine is what the parser specifications will run against, and
177       anything in the parsed hash ($p in the example) will be put in the call
178       to "DateTime->new(...)".
179
180       So, we now have a happily working ICal parser. It parses the assorted
181       formats, and can also handle timezones. Is there anything else it needs
182       to do? No. But we can make it work more efficiently.
183
184       At present, the specifications are tested sequentially.  However, each
185       one applies to strings of particular lengths.  Thus we could be
186       efficient and have the parser only test the given strings against a
187       parser that handles that string length. Again, Builder makes it easy:
188
189           parse_datetime => [
190               [ preprocess => \&_parse_tz ],
191               {
192                   length => 15, # We handle strings of exactly 15 chars
193                   params => [ qw( year month day hour minute second ) ],
194                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)$/,
195               },
196               {
197                   length => 13, # exactly 13 chars...
198                   params => [ qw( year month day hour minute ) ],
199                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)$/,
200               },
201               {
202                   length => 11, # 11..
203                   params => [ qw( year month day hour ) ],
204                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)$/,
205               },
206               {
207                   length => 8, # yes.
208                   params => [ qw( year month day ) ],
209                   regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)$/,
210               },
211               ],
212
213       Now the created parser will create a parser that only runs
214       specifications against appropriate strings.
215
216       So our complete code looks like:
217
218           package DateTime::Format::ICal;
219           use strict;
220           our $VERSION = '0.04';
221
222           use DateTime::Format::Builder
223           (
224               parsers => {
225                   parse_datetime => [
226                   [ preprocess => \&_parse_tz ],
227                   {
228                       length => 15,
229                       params => [ qw( year month day hour minute second ) ],
230                       regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)$/,
231                   },
232                   {
233                       length => 13,
234                       params => [ qw( year month day hour minute ) ],
235                       regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)$/,
236                   },
237                   {
238                       length => 11,
239                       params => [ qw( year month day hour ) ],
240                       regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)$/,
241                   },
242                   {
243                       length => 8,
244                       params => [ qw( year month day ) ],
245                       regex  => qr/^(\d\d\d\d)(\d\d)(\d\d)$/,
246                   },
247                   ],
248               },
249           );
250
251           sub _parse_tz
252           {
253               my %args = @_;
254               my ($date, $p) = @args{qw( input parsed )};
255               if ( $date =~ s/^TZID=([^:]+):// )
256               {
257                   $p->{time_zone} = $1;
258               }
259               # Z at end means UTC
260               elsif ( $date =~ s/Z$// )
261               {
262                   $p->{time_zone} = 'UTC';
263               }
264               else
265               {
266                   $p->{time_zone} = 'floating';
267               }
268               return $date;
269           }
270
271           1;
272
273       And that's an ICal parser. The actual DateTime::Format::ICal module
274       also includes formatting methods and parsing for durations, but Builder
275       doesn't support those yet. A drop in replacement (at the time of
276       writing the replacement) can be found in the examples directory of the
277       Builder distribution, along with similar variants of other common
278       modules.
279
281       Copyright (C) Iain Truskett, 2003. All rights reserved.
282
283       You can redistribute this document and/or modify it under the same
284       terms as Perl itself.
285
286       The full text of the licenses can be found in the Artistic and COPYING
287       files included with this document.
288

SEE ALSO

290       "datetime@perl.org" mailing list.
291
292       http://datetime.perl.org/
293
294       perl, DateTime, DateTime::Format::Builder
295

SUPPORT

297       Any errors you see in this document, please log them with CPAN RT
298       system via the web or email:
299
300           http://perl.dellah.org/rt/dtbuilder
301           bug-datetime-format-builder@rt.cpan.org
302
303       This makes it much easier for me to track things and thus means your
304       problem is less likely to be neglected.
305
306       Bugs may be submitted at
307       <http://rt.cpan.org/Public/Dist/Display.html?Name=DateTime-Format-Builder>
308       or via email to bug-datetime-format-builder@rt.cpan.org <mailto:bug-
309       datetime-format-builder@rt.cpan.org>.
310
311       I am also usually active on IRC as 'autarch' on "irc://irc.perl.org".
312

SOURCE

314       The source code repository for DateTime-Format-Builder can be found at
315       <https://github.com/houseabsolute/DateTime-Format-Builder>.
316

AUTHORS

318       ·   Dave Rolsky <autarch@urth.org>
319
320       ·   Iain Truskett
321
323       This software is Copyright (c) 2019 by Dave Rolsky.
324
325       This is free software, licensed under:
326
327         The Artistic License 2.0 (GPL Compatible)
328
329       The full text of the license can be found in the LICENSE file included
330       with this distribution.
331
332
333
334perl v5.30.0                      2019-07D-a2t6eTime::Format::Builder::Tutorial(3)
Impressum