File Coverage

blib/lib/Text/Microformat/Element.pm
Criterion Covered Total %
statement 138 163 84.6
branch 40 54 74.0
condition 17 29 58.6
subroutine 25 29 86.2
pod 1 10 10.0
total 221 285 77.5


line stmt bran cond sub pod time code
1             package Text::Microformat::Element;
2 3     3   13 use warnings;
  3         7  
  3         74  
3 3     3   13 use strict;
  3         6  
  3         73  
4 3     3   15 use Carp;
  3         4  
  3         212  
5 3     3   2360 use UNIVERSAL::require;
  3         5016  
  3         33  
6              
7 3     3   91 use base qw/Class::Data::Inheritable Class::Accessor/;
  3         8  
  3         2674  
8             __PACKAGE__->mk_classdata('_params' => {}); # the params we were initialized with
9             __PACKAGE__->mk_classdata('_children' => []); # identifiers of the schema children
10             __PACKAGE__->mk_accessors(qw/_element/);
11              
12             sub _init {
13 531     531   932 my $class = shift;
14 531         600 my $params = shift;
15 531 50 33     2462 croak "params hashref is required" unless defined $params and ref $params eq 'HASH';
16 531         3203 $class->_params($params);
17 531         17524 my $criteria = $params->{criteria};
18 531 50       1113 if (defined $criteria) {
19 531 50       1138 croak "criteria: hashref expected" unless ref $criteria eq 'HASH';
20 531         1896 while (my($k,$v) = each %$criteria) {
21 531 100 66     4490 if ($k eq 'class' and defined $v and !ref $v) {
      100        
22 9         52 $criteria->{$k} = Text::Microformat->class_regex($v);
23             }
24             }
25             }
26 531         722 my $schema = $params->{schema};
27 531 100       1218 if (defined $schema) {
28 300         349 my @children;
29 300 100       817 if (ref $schema eq 'HASH') {
    100          
    50          
30 18         124 @children = keys %$schema;
31             }
32             elsif (ref $schema eq 'ARRAY') {
33 240         479 @children = @$schema;
34             }
35             elsif (!ref $schema) {
36 42         61 @children = ();
37             }
38             else {
39 0         0 croak "Bad schema $schema";
40             }
41 300         980 $class->_init_child_class($_) for @children;
42 300         1990 $class->mk_accessors(map _to_identifier($_), @children);
43             #print STDERR "_init $class: ", join(', ', @children), "\n";
44 300         29209 $class->_children(\@children);
45             }
46             }
47              
48             sub _to_identifier {
49 2402     2402   5201 (my $thing = shift) =~ s/\W+/_/g;
50 2402         2919 $thing =~ s/^_//;
51 2402         5758 return $thing;
52             }
53              
54             sub _default_child_class {
55 1101     1101   1167 my $class = shift;
56 1101         1212 my $child = shift;
57 1101         1569 my $child_class = _to_identifier($child);
58 1101         2946 return $class . '::' . $child_class;
59             }
60              
61             sub _init_child_class {
62 519     519   656 my $class = shift;
63 519         541 my $child = shift;
64 519         1434 $class->_get_child_class($child, 1);
65             }
66              
67             sub _to_criteria {
68 513     513   576 my $child = shift;
69 513         1506 return {class => Text::Microformat->class_regex($child)};
70             }
71              
72             sub _get_child_class {
73 1101     1101   1236 my $class = shift;
74 1101         1093 my $child = shift;
75 1101         1119 my $init = shift;
76 1101         2892 my $schema = $class->_params->{schema};
77 1101         7580 my $child_class = _default_child_class($class, $child);
78 1101         1348 my $base_class = 'Text::Microformat::Element';
79 1101         1130 my %opts;
80             # if a specific class is specified in the schema, use it
81 1101 100 66     7561 if (ref $schema eq 'HASH' and defined $schema->{$child} and !ref $schema->{$child} and length $schema->{$child}) {
      100        
      66        
82 124         308 my $spec_class = 'Text::Microformat::Element::' . _to_identifier($schema->{$child});
83 124         609 $spec_class->require;
84 124 100       3851 if ($spec_class->_params->{criteria}) {
85 18         156 $opts{isa_format}++;
86 18 100       70 if ($schema->{$child} =~ /^!/) {
87 8         18 $opts{use_child_criteria}++;
88             }
89             }
90 124         956 $base_class = $spec_class;
91             }
92 1101 100       2176 if ($init) {
93 3     3   3177 no strict 'refs';
  3         6  
  3         2885  
94 519         552 @{$child_class.'::ISA'} = $base_class;
  519         11838  
95             #print STDERR "$child_class ISA $base_class\n";
96 519 100       1339 if (ref $schema eq 'HASH') {
97 297 100       529 if ($opts{isa_format}) {
98 12 100       30 if ($opts{use_child_criteria}) {
99 6         22 $child_class->_init({criteria => $base_class->_params->{criteria}, schema => $base_class->_params->{schema}});
100             }
101             else {
102 6         22 $child_class->_init({criteria => _to_criteria($child), schema => $base_class->_params->{schema}});
103             }
104             }
105             else {
106 285         510 $child_class->_init({criteria => _to_criteria($child), schema => $schema->{$child}});
107             }
108             }
109             else {
110 222         393 $child_class->_init({criteria => _to_criteria($child)});
111             }
112             }
113             #print STDERR "_get_child_class($class, $child) = $child_class\n";
114 1101         12611 return $child_class;
115             }
116              
117             sub Find {
118 662     662 0 2683 my $class = shift;
119 662         839 my $element = shift;
120 662         783 my @found;
121 662         2805 my $criteria = $class->_params->{criteria};
122 662 50 33     7187 croak "missing criteria" unless defined $criteria and ref $criteria eq 'HASH';
123 662         1989 return map ($class->new($_), $element->look_down(
124 662         860 %{$class->_params->{criteria}},
125             Text::Microformat->element_filter($element),
126             ));
127             }
128              
129             sub new {
130 162     162 1 8624 my $proto = shift;
131 162   33     717 my $class = ref $proto || $proto;
132 162         578 my $self = bless {}, $class;
133 162         260 my $element = shift;
134 162 50 33     1089 croak 'element is required' unless $element and UNIVERSAL::isa($element, 'HTML::Element');
135            
136             # Mixin the local_name method
137 162 100       484 if (ref $element eq 'HTML::Element') {
    50          
138 137         406 $element = bless $element, 'Text::Microformat::HTML::Element';
139             }
140             elsif (ref $element eq 'XML::Element') {
141 0         0 $element = bless $element, 'Text::Microformat::XML::Element';
142             }
143            
144 162         818 $self->_element($element);
145 162         2711 foreach my $child (@{$class->_children}) {
  162         732  
146 582         43138 my $accessor = _to_identifier($child);
147 582         1736 my $child_class = $class->_get_child_class($child);
148 582         4192 $self->$accessor([$child_class->Find($element)]);
149             }
150 162         5556 return $self;
151             }
152              
153             sub HumanValue {
154 25     25 0 726 my $self = shift;
155 25         69 return $self->_element->as_trimmed_text;
156             }
157              
158             sub MachineValue {
159 81     81 0 676 my $self = shift;
160 81         208 return $self->_element->attr('title');
161             }
162              
163             sub Value {
164 61     61 0 143 my $self = shift;
165 61 100       189 return defined $self->MachineValue ? $self->MachineValue : $self->HumanValue;
166             }
167              
168             sub ToHash {
169 0     0 0 0 my $self = shift;
170            
171 0 0       0 if (@{$self->_children}) {
  0         0  
172 0         0 my %hash;
173 0         0 foreach my $child (@{$self->_children}) {
  0         0  
174 0         0 my $accessor = _to_identifier($child);
175 0 0       0 if (@{$self->$accessor}) {
  0         0  
176 0         0 $hash{$child} = [map $_->ToHash, @{$self->$accessor}];
  0         0  
177             }
178             }
179 0         0 return \%hash;
180             }
181             else {
182 0         0 return $self->Value;
183             }
184             }
185              
186             sub ToYAML {
187 0     0 0 0 eval {require YAML};
  0         0  
188 0 0       0 warn "YAML not found" if $@;
189 0         0 return YAML::Dump(shift->ToHash);
190             }
191              
192             sub GetM {
193 0     0 0 0 my $self = shift;
194 0         0 my $path = shift;
195 0         0 return $self->Get($path, 'MachineValue');
196             }
197              
198             sub GetH {
199 0     0 0 0 my $self = shift;
200 0         0 my $path = shift;
201 0         0 return $self->Get($path, 'HumanValue');
202             }
203              
204             sub Get {
205 67     67 0 1298 my $self = shift;
206 67         122 my $path = shift;
207 67   50     316 my $accessor = shift || 'Value';
208 67         93 my $v;
209 67         80 my $o = $self;
210 67         269 my @path = map _to_identifier($_), split(/\./, $path);
211 67         249 while (my $bit = shift @path) {
212 70 100       363 last unless UNIVERSAL::can($o, $bit);
213 64         248 $o = $o->$bit->[0];
214 64 100       899 last unless UNIVERSAL::can($o, $accessor);
215 63 100       266 $v = $o->$accessor if !@path;
216             }
217 67         2688 return $v
218             }
219              
220             package Text::Microformat::ML::Element;
221              
222 3     3   17 use strict;
  3         6  
  3         108  
223 3     3   13 use warnings;
  3         5  
  3         552  
224              
225             our @ISA = qw/HTML::Element/;
226              
227             sub local_name {
228 32     32   316 my $self = shift;
229 32         98 my $tag = $self->tag;
230 32 50       244 return $tag unless defined $tag;
231 32         45 $tag =~ s/^[\w][\w\.-]*://;
232 32         129 return $tag;
233             }
234              
235             package Text::Microformat::HTML::Element;
236              
237 3     3   14 use strict;
  3         6  
  3         90  
238 3     3   14 use warnings;
  3         5  
  3         180  
239              
240             our @ISA = qw/HTML::Element Text::Microformat::ML::Element/;
241              
242             package Text::Microformat::XML::Element;
243              
244 3     3   21 use strict;
  3         8  
  3         83  
245 3     3   14 use warnings;
  3         6  
  3         197  
246              
247             our @ISA = qw/XML::Element Text::Microformat::ML::Element/;
248              
249             =head1 NAME
250              
251             Text::Microformat::Element - a Microformat element
252              
253             =head1 SEE ALSO
254              
255             L, L
256              
257             =head1 AUTHOR
258              
259             Keith Grennan, C<< >>
260              
261             =head1 BUGS
262              
263             Log bugs and feature requests here: L
264              
265             =head1 SUPPORT
266              
267             Project homepage: L
268              
269             =head1 COPYRIGHT & LICENSE
270              
271             Copyright 2007 Keith Grennan, all rights reserved.
272              
273             This program is free software; you can redistribute it and/or modify it
274             under the same terms as Perl itself.
275              
276             =cut
277              
278             1;