File Coverage

blib/lib/JSON/WithComments.pm
Criterion Covered Total %
statement 34 44 77.2
branch 3 10 30.0
condition 2 5 40.0
subroutine 10 10 100.0
pod 0 3 0.0
total 49 72 68.0


line stmt bran cond sub pod time code
1             ###############################################################################
2             #
3             # This file copyright © 2017 by Randy J. Ray, all rights reserved
4             #
5             # See "LICENSE AND COPYRIGHT" in the POD for terms.
6             #
7             ###############################################################################
8             #
9             # Description: Simple support for comments in JSON content.
10             #
11             # Functions: import
12             # comment_style
13             # get_comment_style
14             # decode
15             #
16             # Libraries: JSON
17             #
18             # Global Consts: %PATTERNS
19             #
20             # Environment: None
21             #
22             ###############################################################################
23              
24             package JSON::WithComments;
25              
26 1     1   42953 use 5.008;
  1         4  
27 1     1   5 use strict;
  1         2  
  1         20  
28 1     1   4 use warnings;
  1         2  
  1         24  
29 1     1   4 use base qw(JSON);
  1         1  
  1         470  
30              
31 1     1   7923 use Carp ();
  1         1  
  1         343  
32              
33             our $VERSION = '0.002'; # VERSION
34              
35             # These regular expressions are adapted from Regexp::Common::comment.
36              
37             # The length of the regexp for JS multi-line comments triggers this:
38             ## no critic(RegularExpressions::RequireExtendedFormatting)
39             my $JS_SINGLE = qr{(?://)(?:[^\n]*)};
40             my $JS_MULTI = qr{(?:\/[*])(?:(?:[^*]+|[*](?!\/))*)(?:[*]\/)};
41             my $PERL = qr{(?:#)(?:[^\n]*)};
42             my %PATTERNS = (
43             perl => qr{(?
44             javascript => qr{(?
45             );
46              
47             # This is the comment-style that will be used if/when an object has not
48             # specified a style. It can be changed in import() with -default_comment_style.
49             # This is also the style that will be used by decode_json.
50             my $default_comment_style = 'javascript';
51              
52             # This table is used in lieu of per-object hashkeys, as the object is not a
53             # hashref when the JSON::XS backend is in use.
54             my %comment_style;
55              
56             sub import {
57 1     1   7 my ($class, @imports) = @_;
58              
59 1         2 my ($index, $style);
60 1         3 for my $idx (0 .. $#imports) {
61 0 0       0 if ($imports[$idx] eq '-default_comment_style') {
62 0         0 $index = $idx;
63 0         0 $style = $imports[$idx + 1];
64 0         0 last;
65             }
66             }
67 1 50       4 if (defined $index) {
68 0   0     0 $style ||= '(undef)';
69 0 0       0 if (! $PATTERNS{$style}) {
70 0         0 Carp::croak "Unknown comment style '$style' given as default";
71             }
72 0         0 $default_comment_style = $style;
73 0         0 splice @imports, $index, 2;
74             }
75              
76 1         12 return $class->SUPER::import(@imports);
77             }
78              
79             sub comment_style {
80 1     1 0 240 my ($self, $value) = @_;
81              
82 1 50       4 if (defined $value) {
83 1 50       5 if (! $PATTERNS{$value}) {
84 0         0 Carp::croak "Unknown comment_style ($value)";
85             }
86 1         4 $comment_style{"$self"} = $value;
87             }
88              
89 1         2 return $self;
90             }
91              
92             sub get_comment_style {
93 4     4 0 1027 my $self = shift;
94              
95 4   66     25 return $comment_style{"$self"} || $default_comment_style;
96             }
97              
98             sub decode {
99 2     2 0 6 my ($self, $text) = @_;
100              
101 2         3 my $comment_re = $PATTERNS{$self->get_comment_style};
102             # The JSON module reports errors using the character-offset within the
103             # string as a whole. So rather than deleting comments, replace them with a
104             # string of spaces of the same length. This should mean that any reported
105             # character offsets in the JSON data will still be correct.
106 2         20 $text =~ s/$comment_re/q{ } x length($1)/ge;
  9         44  
107              
108 2         28 return $self->SUPER::decode($text);
109             }
110              
111             sub DESTROY {
112 1     1   238 my $self = shift;
113              
114 1         3 delete $comment_style{"$self"};
115              
116 1         34 return;
117             }
118              
119             1;
120              
121             __END__