File Coverage

blib/lib/UR/Object/View/Default/Json.pm
Criterion Covered Total %
statement 57 66 86.3
branch 17 26 65.3
condition 2 3 66.6
subroutine 8 8 100.0
pod n/a
total 84 103 81.5


line stmt bran cond sub pod time code
1             package UR::Object::View::Default::Json;
2              
3 1     1   57 use strict;
  1         2  
  1         29  
4 1     1   4 use warnings;
  1         1  
  1         57  
5             require UR;
6             our $VERSION = "0.46"; # UR $VERSION;
7              
8 1     1   4 use JSON;
  1         2  
  1         8  
9              
10             class UR::Object::View::Default::Json {
11             is => 'UR::Object::View::Default::Text',
12             has_constant => [
13             toolkit => { value => 'json' },
14             ],
15             has_optional => [
16             encode_options => { is => 'ARRAY', default_value => ['ascii', 'pretty', 'allow_nonref', 'canonical'], doc => 'Options to enable on the JSON object; see the documentation for the JSON Perl module' },
17             ],
18             };
19              
20             my $json;
21             sub _json {
22 14     14   15 my ($self) = @_;
23 14 100       46 return $json if defined $json;
24              
25 1         12 $json = JSON->new;
26 1         2 foreach my $opt ( @{ $self->encode_options } ) {
  1         4  
27 4         4 eval { $json = $json->$opt; };
  4         16  
28 4 50       7 if ($@) {
29 0         0 Carp::croak("Can't initialize JSON object for encoding. Calling method $opt from encode_options died: $@");
30             }
31 4 50       9 if (!$json) {
32 0         0 Carp::croak("Can't initialize JSON object for encoding. Calling method $opt from encode_options returned false");
33             }
34             }
35 1         3 return $json;
36             }
37              
38             sub _generate_content {
39 14     14   10 my $self = shift;
40 14         42 return $self->_json->encode($self->_jsobj);
41             }
42              
43             sub _jsobj {
44 23     23   21 my $self = shift;
45              
46 23         41 my $subject = $self->subject();
47 23 50       42 return '' unless $subject;
48              
49 23         28 my %jsobj = ();
50              
51 23         50 for my $aspect ($self->aspects) {
52 41         90 my $val = $self->_generate_content_for_aspect($aspect);
53 41 50       127 $jsobj{$aspect->name} = $val if defined $val;
54             }
55              
56 23         199 return \%jsobj;
57             }
58              
59             sub _generate_content_for_aspect {
60 41     41   41 my $self = shift;
61 41         33 my $aspect = shift;
62              
63 41         80 my $subject = $self->subject;
64 41         89 my $aspect_name = $aspect->name;
65              
66 41         357 my $aspect_meta = $self->subject_class_name->__meta__->property($aspect_name);
67             #warn $aspect_name if ref($subject) =~ /Set/;
68              
69 41         41 my @value;
70 41         43 eval {
71 41         127 @value = $subject->$aspect_name;
72             };
73 41 50       76 if ($@) {
74 0         0 warn $@;
75 0         0 return;
76             }
77              
78             # Always look for a delegate view.
79             # This means we replace the value(s) with their
80             # subordinate widget content.
81 41 100       84 unless ($aspect->delegate_view) {
82 10         29 $aspect->generate_delegate_view;
83             }
84              
85 41         53 my $ref = [];
86              
87 41 50       75 if (my $delegate_view = $aspect->delegate_view) {
88 41         53 foreach my $value ( @value ) {
89 43 100       86 if (Scalar::Util::blessed($value)) {
90 9         23 $delegate_view->subject($value);
91             } else {
92 34         77 $delegate_view->subject_id($value);
93             }
94 43         107 $delegate_view->_update_view_from_subject();
95              
96 43 100       103 if ($delegate_view->can('_jsobj')) {
97 9         52 push @$ref, $delegate_view->_jsobj;
98             } else {
99 34         2033 my $delegate_text = $delegate_view->content();
100 34         73 push @$ref, $delegate_text;
101             }
102             }
103             }
104             else {
105 0         0 for my $value (@value) {
106 0 0       0 if (ref($value)) {
107 0         0 push @$ref, 'ref'; #TODO(ec) make this render references
108             } else {
109 0         0 push @$ref, $value;
110             }
111             }
112             }
113              
114 41 100 66     130 if ($aspect_meta && $aspect_meta->is_many) {
115 2         7 return $ref;
116             } else {
117 39         87 return shift @$ref;
118             }
119             }
120              
121             # Do not return any aspects by default if we're embedded in another view
122             # The creator of the view will have to specify them manually
123             sub _resolve_default_aspects {
124 2     2   3 my $self = shift;
125 2 50       14 unless ($self->parent_view) {
126 0         0 return $self->SUPER::_resolve_default_aspects;
127             }
128 2         7 return ('id');
129             }
130              
131             1;