File Coverage

blib/lib/Web/Microformats2/Item.pm
Criterion Covered Total %
statement 57 59 96.6
branch 8 10 80.0
condition 6 9 66.6
subroutine 12 12 100.0
pod 4 7 57.1
total 87 97 89.6


line stmt bran cond sub pod time code
1             package Web::Microformats2::Item;
2 2     2   16 use Moo;
  2         5  
  2         20  
3 2     2   1756 use MooX::HandlesVia;
  2         10047  
  2         27  
4 2     2   243 use Types::Standard qw(HashRef ArrayRef Str Maybe InstanceOf);
  2         5  
  2         84  
5 2     2   2396 use Carp;
  2         5  
  2         2037  
6              
7             has 'properties' => (
8             is => 'ro',
9             isa => HashRef,
10             handles_via => 'Hash',
11             default => sub { {} },
12             handles => {
13             has_properties => 'count',
14             has_property => 'get',
15             },
16             );
17              
18             has 'p_properties' => (
19             is => 'ro',
20             isa => HashRef,
21             handles_via => 'Hash',
22             default => sub { {} },
23             handles => {
24             has_p_properties => 'count',
25             has_p_property => 'get',
26             },
27             );
28              
29             has 'u_properties' => (
30             is => 'ro',
31             isa => HashRef,
32             handles_via => 'Hash',
33             default => sub { {} },
34             handles => {
35             has_u_properties => 'count',
36             has_u_property => 'get',
37             },
38             );
39              
40             has 'e_properties' => (
41             is => 'ro',
42             isa => HashRef,
43             handles_via => 'Hash',
44             default => sub { {} },
45             handles => {
46             has_e_properties => 'count',
47             has_e_property => 'get',
48             },
49             );
50              
51             has 'dt_properties' => (
52             is => 'ro',
53             isa => HashRef,
54             handles_via => 'Hash',
55             default => sub { {} },
56             handles => {
57             has_dt_properties => 'count',
58             has_dt_property => 'get',
59             },
60             );
61             has 'parent' => (
62             is => 'ro',
63             isa => Maybe[InstanceOf['Web::Microformats2::Item']],
64             weak_ref => 1,
65             );
66              
67             has 'children' => (
68             is => 'ro',
69             isa => ArrayRef[InstanceOf['Web::Microformats2::Item']],
70             default => sub { [] },
71             handles_via => 'Array',
72             handles => {
73             add_child => 'push',
74             has_children => 'count',
75             },
76             );
77              
78             has 'types' => (
79             is => 'ro',
80             isa => ArrayRef[Str],
81             required => 1,
82             handles_via => 'Array',
83             handles => {
84             find_type => 'first',
85             },
86              
87             );
88              
89             has 'value' => (
90             is => 'rw',
91             isa => Maybe[Str],
92             );
93              
94             has 'last_seen_date' => (
95             is => 'rw',
96             isa => Maybe[InstanceOf['DateTime']],
97             );
98              
99             sub add_property {
100 418     418 0 724 my $self = shift;
101              
102 418         824 my ( $key, $value ) = @_;
103              
104 418         2317 my ( $prefix, $base ) = $key =~ /^(\w+)-(.*)$/;
105              
106 418 50 33     1731 unless ( $prefix && $base ) {
107 0         0 croak "You must call add_property with the full property name, "
108             . "including its prefix. (e.g. 'p-name', not 'name' )";
109             }
110              
111 418         787 my $base_method = "properties";
112 418         839 my $prefix_method = "${prefix}_properties";
113              
114 418         906 foreach ($base_method, $prefix_method ) {
115 836   100     4679 $self->$_->{$base} ||= [];
116 836         1176 push @{ $self->$_->{$base} }, $value;
  836         3829  
117             }
118             }
119              
120             # add_base_property: Like add_property, but don't look for or insist on
121             # prefixes. Good for inflating from JSON, which has no
122             # prefix information.
123             sub add_base_property {
124 8     8 0 19 my $self = shift;
125              
126 8         19 my ( $key, $value ) = @_;
127              
128 8   50     50 $self->properties->{$key} ||= [];
129 8         11 push @{ $self->properties->{$key} }, $value;
  8         32  
130             }
131              
132             sub get_properties {
133 40     40 1 86 my $self = shift;
134              
135 40         91 my ( $key ) = @_;
136              
137 40   100     201 return $self->{properties}->{$key} || [];
138             }
139              
140             sub get_property {
141 3     3 1 9 my $self = shift;
142              
143 3         9 my $properties_ref = $self->get_properties( @_ );
144              
145 3 50       10 if ( @$properties_ref > 1 ) {
146 0         0 carp "get_property called with multiple properties set\n";
147             }
148              
149 3         17 return $properties_ref->[0];
150              
151             }
152              
153             sub has_type {
154 4     4 1 12 my $self = shift;
155 4         10 my ( $type ) = @_;
156              
157 4         16 $type =~ s/^h-//;
158              
159 4     4   94 return $self->find_type( sub { $_ eq $type } );
  4         221  
160             }
161              
162             sub all_types {
163 2     2 1 1148 my $self = shift;
164 2         8 my ( %args ) = @_;
165              
166 2         5 my @types = @{ $self->types };
  2         10  
167              
168             # We add the 'h-' prefix to returned types unless told not to.
169 2 100       11 unless ( $args{ 'no_prefixes' } ) {
170 1         3 @types = map { "h-$_" } @types;
  1         29  
171             }
172              
173 2         10 return @types;
174             }
175              
176             sub TO_JSON {
177 143     143 0 300 my $self = shift;
178              
179             my $data = {
180             properties => $self->properties,
181 143         316 type => [ map { "h-$_" } @{ $self->types } ],
  145         634  
  143         339  
182             };
183 143 100       2531 if ( defined $self->value ) {
184 39         790 $data->{value} = $self->value;
185             }
186 143 100       950 if ( @{$self->children} ) {
  143         413  
187 9         23 $data->{children} = $self->children;
188             }
189 143         2218 return $data;
190             }
191              
192             1;
193              
194              
195             =pod
196              
197             =head1 NAME
198              
199             Web::Microformats2::Item - A parsed Microformats2 item
200              
201             =head1 DESCRIPTION
202              
203             An object of this class represents a Microformats2 item, contained
204             within a larger, parsed Microformats2 data structure. An item represents
205             a single semantically meaningful something-or-other: an article, a
206             person, a photograph, et cetera.
207              
208             The expected use-case is that you will never directly construct item
209             objects. Instead, your code will receive item objects by querying a
210             L<Web::Microformats2::Document> instance, itself created by running
211             Microformats2-laden HTML or JSON through a L<Web::Microformats2::Parser>
212             object.
213              
214             See L<Web::Microformats2> for further context and purpose.
215              
216             =head1 METHODS
217              
218             =head2 Object Methods
219              
220             =head3 get_properties
221              
222             $properties_ref = $item->get_properties( $property_key )
223              
224             # To get all "u-url" properties of this item:
225             $urls = $item->get_properties( 'url' );
226             # To get all "p-name" properties:
227             $names = $item->get_properties( 'name' );
228              
229             Returns a list reference of all property values identified by the given
230             key. Values can be strings, unblessed references, or more item objects.
231              
232             Note that Microformats2 stores its properties' keys without their
233             prefixes, so that's how you should query for them here. In order words,
234             pass in "name" or "url" as an argument, not "p-name" or "u-url".
235              
236             =head3 get_property
237              
238             $property_value = $item->get_property( $property_key );
239              
240             # To get the first (and maybe only?) "u-url" property of this item:
241             $url = $item->get_property( 'url' );
242             # To get its "p-name" property:
243             $name = $item->get_property( 'name' );
244              
245             Like L<"get_properties">, but returns only the first property value identified
246             by the given key.
247              
248             If this item contains more than one such value, this will also emit a warning.
249              
250             =head3 value
251              
252             $value = $item->value;
253              
254             Returns the special C<value> attribute, if this item has it defined.
255              
256             =head3 all_types
257              
258             my @types = $item->all_types;
259             # Returns e.g. ( 'h-org', 'h-card' )
260              
261             my @short_types = $item->all_types( no_prefixes => 1 );
262             # Returns e.g. ( 'org', 'card' )
263              
264             Returns a list of all the types that this item identifies as.
265             Guaranteed to contain at least one value.
266              
267             Takes an argument hash, which recognizes the following single key:
268              
269             =over
270              
271             =item no_prefixes
272              
273             If set to a true value, then this object will remove the prefixes from
274             the list of item types before returning it to you. Practically speaking,
275             this means that it will remove the leading C<h-> from every type.
276              
277             =back
278              
279             =head3 has_type
280              
281             $bool = $item->has_type( $type )
282              
283             Returns true if the item claims to be of the given type, false
284             otherwise. (The argument can include a prefix, so e.g. both "entry" and
285             "h-entry" return the same result here.)
286              
287             =head3 parent
288              
289             $parent = $item->parent;
290              
291             Returns this item's parent item, if set.
292              
293             =head3 children
294              
295             $children_ref = $item->children;
296              
297             Returns a list reference of child items.
298              
299             =head1 AUTHOR
300              
301             Jason McIntosh (jmac@jmac.org)
302              
303             =head1 COPYRIGHT AND LICENSE
304              
305             This software is Copyright (c) 2018 by Jason McIntosh.
306              
307             This is free software, licensed under:
308              
309             The MIT (X11) License