File Coverage

blib/lib/MooX/JSON_LD.pm
Criterion Covered Total %
statement 55 55 100.0
branch 8 14 57.1
condition 7 10 70.0
subroutine 14 14 100.0
pod n/a
total 84 93 90.3


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             MooX::JSON_LD - Extend Moo to provide JSON-LD mark-up for your objects.
4              
5             =head1 SYNOPSIS
6              
7             # Your Moo (or Moose) Class
8             package My::Moo::Class;
9              
10             use Moo;
11              
12             use MooX::JSON_LD 'Person';
13              
14             has first_name => (
15             is => 'ro',
16             # various other properties...
17             json_ld => 1,
18             );
19              
20             has last_name => (
21             is => 'ro',
22             # various other properties...
23             json_ld => 1,
24             );
25              
26             has birth_date => (
27             is => 'ro',
28             # various other properties...
29             json_ld => 'birthDate',
30             json_ld_serializer => sub { shift->birth_date },
31             );
32              
33             # Then, in a program somewhere...
34             use My::Moo::Class;
35              
36             my $obj = My::Moo::Class->new({
37             first_name => 'David',
38             last_name => 'Bowie',
39             birth_date => '1947-01-08',
40             });
41              
42             # print a text representation of the JSON-LD
43             print $obj->json_ld;
44              
45             # print the raw data structure for the JSON-LD
46             use Data::Dumper;
47             print Dumper $obj->json_ld_data;
48              
49             =head1 DESCRIPTION
50              
51             This is a companion module for L<MooX::Role::JSON_LD>. It extends the
52             C<has> method to support options to add attributes to the
53             C<json_ld_fields> and create the C<json_ld_type> .
54              
55             To declare the type, add it as the option when importing the module,
56             e.g.
57              
58             use MooX::JSON_LD 'Thing';
59              
60             Moo attributes are extended with the following options:
61              
62             =over
63              
64             =item C<json_ld>
65              
66             has headline => (
67             is => 'ro',
68             json_ld => 1,
69             );
70              
71             This adds the "headline" attribute to the C<json_ld_fields>.
72              
73             has alt_headline => (
74             is => 'ro',
75             json_ld => 'alternateHeadline',
76             );
77              
78             This adds the "alt_headline" attribute to the C<json_ld_fields>, with
79             the label "alternateHeadline".
80              
81             =item C<json_ld_serializer>
82              
83             has birth_date => (
84             is => 'ro',
85             isa => InstanceOf['DateTime'],
86             json_ld => 'birthDate',
87             json_ld_serializer => sub { shift->birth_date->ymd },
88             );
89              
90             This allows you to specify a method for converting the data into an
91             object that L<JSON> can serialize.
92              
93             =back
94              
95             =head1 AUTHOR
96              
97             Robert Rothenberg <rrwo@cpan.org>
98              
99             =head1 SEE ALSO
100              
101             L<MooX::Role::JSON_LD>
102              
103             =head1 COPYRIGHT AND LICENSE
104              
105             Copyright (C) 2018, Robert Rothenberg. All Rights Reserved.
106              
107             This script is free software; you can redistribute it and/or modify it
108             under the same terms as Perl itself.
109              
110              
111             =cut
112              
113             package MooX::JSON_LD;
114              
115 5     5   536920 use strict;
  5         32  
  5         154  
116 5     5   26 use warnings;
  5         7  
  5         124  
117              
118 5     5   23 use Moo ();
  5         9  
  5         62  
119 5     5   2715 use Moo::Role ();
  5         44855  
  5         148  
120              
121 5     5   2693 use MRO::Compat;
  5         9322  
  5         185  
122 5     5   36 use List::Util qw/ all /;
  5         9  
  5         690  
123 5     5   2827 use Sub::Quote qw/ quote_sub /;
  5         25748  
  5         539  
124              
125             our $VERSION = '1.0.1';
126              
127             my %Attributes;
128              
129             sub import {
130 8     8   39473 my ( $class, $type ) = @_;
131              
132 8         23 my $target = caller;
133              
134 5     5   42 no strict 'refs';
  5         11  
  5         146  
135 5     5   27 no warnings 'redefine';
  5         10  
  5         1973  
136              
137 8 50       127 my $installer =
138             $target->isa("Moo::Object")
139             ? \&Moo::_install_tracked
140             : \&Moo::Role::_install_tracked;
141              
142 8 50       75 if ( my $has = $target->can('has') ) {
143             my $new_has = sub {
144 16     16   74964 $has->( _process_has(@_) );
145 8         42 };
146 8         37 $installer->( $target, "has", $new_has );
147             }
148              
149 8 50       329 if ( defined $type ) {
150 8         41 quote_sub "${target}::json_ld_type", "'${type}'";
151             }
152              
153 8         1099 my $name = "json_ld_fields";
154              
155             quote_sub "${target}::${name}", '$code->(@_)',
156             {
157             '$code' => \sub {
158 25     25   307 my ($self) = @_;
159 25   100     128 my $fields = $self->maybe::next::method || [];
160             return [
161 25         47 @{$fields},
162 25 50       350 @{$Attributes{$target} || []}
  25         135  
163             ];
164             },
165             }, {
166 8         109 no_defer => 1,
167             package => $target,
168             };
169              
170              
171 8 50   8   4361 unless ( all { $target->can($_) }
  8         87  
172             qw/ json_ld_encoder json_ld_data json_ld / )
173             {
174              
175 8         61 Moo::Role->apply_single_role_to_package( $target,
176             'MooX::Role::JSON_LD' );
177              
178             }
179              
180             }
181              
182             sub _process_has {
183 16     16   76 my ( $name, %opts ) = @_;
184              
185 16 50 33     66 if ( $opts{json_ld} || $opts{json_ld_serializer} ) {
186              
187 16         41 my $class = caller(1);
188 16   100     78 $Attributes{$class} ||= [];
189              
190 16         33 my $label = delete $opts{json_ld};
191 16         31 my $method = delete $opts{json_ld_serializer};
192              
193 16 100 66     28 push @{ $Attributes{$class} }, {
  16         117  
194             $label eq "1" ? $name : $label => $method || $name
195             };
196             }
197              
198 16         91 return ( $name, %opts );
199             }
200              
201             1;