File Coverage

blib/lib/DateTime/Format/Builder.pm
Criterion Covered Total %
statement 110 113 97.3
branch 35 42 83.3
condition 11 18 61.1
subroutine 25 27 92.5
pod 10 14 71.4
total 191 214 89.2


line stmt bran cond sub pod time code
1             package DateTime::Format::Builder;
2             {
3             $DateTime::Format::Builder::VERSION = '0.81';
4             }
5              
6 23     23   546168 use strict;
  23         59  
  23         1286  
7 23     23   195 use warnings;
  23         48  
  23         642  
8              
9 23     23   626 use 5.005;
  23         74  
  23         1016  
10 23     23   194 use Carp;
  23         57  
  23         2535  
11 23     23   48284 use DateTime 1.00;
  23         5479611  
  23         1356  
12 23         2573 use Params::Validate 0.72 qw(
13             validate SCALAR ARRAYREF HASHREF SCALARREF CODEREF GLOB GLOBREF UNDEF
14 23     23   282 );
  23         552  
15 23     23   139 use vars qw( %dispatch_data );
  23         46  
  23         6423  
16              
17             my $parser = 'DateTime::Format::Builder::Parser';
18              
19             sub verbose {
20 0     0 0 0 warn "Use of verbose() deprecated for the interim.";
21 0         0 1;
22             }
23              
24             sub import {
25 36     36   17508 my $class = shift;
26 36 100       55072 $class->create_class( @_, class => (caller)[0] ) if @_;
27             }
28              
29             sub create_class {
30 21     21 1 3743 my $class = shift;
31 21         1264 my %args = validate(
32             @_,
33             {
34             class => { type => SCALAR, default => (caller)[0] },
35             version => { type => SCALAR, optional => 1 },
36             verbose => { type => SCALAR | GLOBREF | GLOB, optional => 1 },
37             parsers => { type => HASHREF },
38             groups => { type => HASHREF, optional => 1 },
39             constructor =>
40             { type => UNDEF | SCALAR | CODEREF, optional => 1 },
41             }
42             );
43              
44 21 50       349 verbose( $args{verbose} ) if exists $args{verbose};
45              
46 21         56 my $target = $args{class}; # where we're writing our methods and such.
47              
48             # Create own lovely new package
49             {
50 23     23   142 no strict 'refs';
  23         44  
  23         7852  
  21         39  
51              
52 21 100       77 ${"${target}::VERSION"} = $args{version} if exists $args{version};
  4         32  
53              
54 21         156 $class->create_constructor(
55             $target, exists $args{constructor},
56             $args{constructor}
57             );
58              
59             # Turn groups of parser specs in to groups of parsers
60             {
61 19         44 my $specs = $args{groups};
  19         43  
62 19         41 my %groups;
63              
64 19         76 for my $label ( keys %$specs ) {
65 3         5 my $parsers = $specs->{$label};
66 3         12 my $code = $class->create_parser($parsers);
67 3         13 $groups{$label} = $code;
68             }
69              
70 19         103 $dispatch_data{$target} = \%groups;
71             }
72              
73             # Write all our parser methods, creating parsers as we go.
74 19         44 while ( my ( $method, $parsers ) = each %{ $args{parsers} } ) {
  36         437  
75 19         82 my $globname = $target . "::$method";
76 19         673 croak "Will not override a preexisting method $method()"
77 19 100       37 if defined &{$globname};
78 17         87 *$globname = $class->create_end_parser($parsers);
79             }
80             }
81              
82             }
83              
84             sub create_constructor {
85 21     21 0 44 my $class = shift;
86 21         93 my ( $target, $intended, $value ) = @_;
87              
88 21         58 my $new = $target . "::new";
89 21 100       72 $value = 1 unless $intended;
90              
91 21 100       64 return unless $value;
92 18 100 100     165 return if not $intended and defined &$new;
93 16 100       759 croak "Will not override a preexisting constructor new()"
94             if defined &$new;
95              
96 23     23   126 no strict 'refs';
  23         39  
  23         24749  
97              
98 14 100       68 return *$new = $value if ref $value eq 'CODE';
99             return *$new = sub {
100 16     16   13071 my $class = shift;
101 16 100       277 croak "${class}->new takes no parameters." if @_;
102              
103 15   66     110 my $self = bless {}, ref($class) || $class;
104              
105             # If called on an object, clone, but we've nothing to
106             # clone
107              
108 15         49 $self;
109 12         137 };
110             }
111              
112             sub create_parser {
113 40     40 0 18334 my $class = shift;
114 40         115 my @common = ( maker => $class );
115 40 100       145 if ( @_ == 1 ) {
116 27         43 my $parsers = shift;
117 27 50       168 my @parsers = (
    100          
118             ( ref $parsers eq 'HASH' )
119             ? %$parsers
120             : ( ( ref $parsers eq 'ARRAY' ) ? @$parsers : $parsers )
121             );
122 27         234 $parser->create_parser( \@common, @parsers );
123             }
124             else {
125 13         82 $parser->create_parser( \@common, @_ );
126             }
127             }
128              
129              
130             sub create_end_parser {
131 23     23 0 50 my ( $class, $parsers ) = @_;
132 23         96 $class->create_method( $class->create_parser($parsers) );
133             }
134              
135             sub create_method {
136 23     23 1 47 my ( $class, $parser ) = @_;
137             return sub {
138 31     31   11223 my $self = shift;
139 31         162 $parser->parse( $self, @_ );
140             }
141 23         186 }
142              
143             sub on_fail {
144 3     3 1 8 my ( $class, $input ) = @_;
145              
146 3         10 my $pkg;
147 3         7 my $i = 0;
148 3         50 while ( ($pkg) = caller( $i++ ) ) {
149             last
150 15 100 66     226 if ( !UNIVERSAL::isa( $pkg, 'DateTime::Format::Builder' )
151             && !UNIVERSAL::isa( $pkg, 'DateTime::Format::Builder::Parser' ) );
152             }
153 3         129 local $Carp::CarpLevel = $i;
154 3         1170 croak "Invalid date format: $input";
155             }
156              
157             sub new {
158 11     11 1 902 my $class = shift;
159 11 100       217 croak "Constructor 'new' takes no parameters" if @_;
160             my $self = bless {
161 1     1   105 parser => sub { croak "No parser set." }
162             },
163 10   66     100 ref($class) || $class;
164 10 100       44 if ( ref $class ) {
165              
166             # If called on an object, clone
167 2         7 $self->set_parser( $class->get_parser );
168              
169             # and that's it. we don't store that much info per object
170             }
171 10         24 return $self;
172             }
173              
174             sub parser {
175 6     6 1 1787 my $class = shift;
176 6         33 my $parser = $class->create_end_parser( \@_ );
177              
178             # Do we need to instantiate a new object for return,
179             # or are we modifying an existing object?
180 6         18 my $self;
181 6 50       29 $self = ref $class ? $class : $class->new();
182              
183 6         23 $self->set_parser($parser);
184              
185 6         18 $self;
186             }
187              
188             sub clone {
189 1     1 1 404 my $self = shift;
190 1 50       6 croak "Calling object method as class method!" unless ref $self;
191 1         3 return $self->new();
192             }
193              
194             sub set_parser {
195 8     8 1 14 my ( $self, $parser ) = @_;
196 8 50 33     60 croak "set_parser given something other than a coderef"
197             unless $parser
198             and ref $parser eq 'CODE';
199 8         39 $self->{parser} = $parser;
200 8         27 $self;
201             }
202              
203             sub get_parser {
204 6     6 1 626 my ($self) = @_;
205 6         21 return $self->{parser};
206             }
207              
208             sub parse_datetime {
209 14     14 1 17612 my $self = shift;
210 14 50 33     122 croak "parse_datetime is an object method, not a class method."
211             unless ref $self and $self->isa(__PACKAGE__);
212 14 50       45 croak "No date specified." unless @_;
213 14         44 return $self->{parser}->( $self, @_ );
214             }
215              
216             sub format_datetime {
217 0     0 1   croak __PACKAGE__ . "::format_datetime not implemented.";
218             }
219              
220             require DateTime::Format::Builder::Parser;
221              
222             1;
223              
224             # ABSTRACT: Create DateTime parser classes and objects.
225              
226             __END__