File Coverage

blib/lib/Text/Tags/Parser.pm
Criterion Covered Total %
statement 51 51 100.0
branch 21 22 95.4
condition 20 27 74.0
subroutine 7 7 100.0
pod 4 4 100.0
total 103 111 92.7


line stmt bran cond sub pod time code
1             package Text::Tags::Parser;
2              
3 4     4   82512 use warnings;
  4         9  
  4         126  
4 4     4   21 use strict;
  4         7  
  4         3792  
5              
6             sub new {
7 3     3 1 37 my $class = shift;
8 3         12 bless {}, $class;
9             }
10              
11             sub parse_tags {
12 55     55 1 32919 my $self = shift;
13 55         64 my $string = shift;
14              
15 55 100       125 return unless defined $string;
16              
17 54         54 my @tags;
18             my %seen;
19              
20             # In this regexp, the actual content of the tag is in the last
21             # paren-group which matches in each alternative.
22             # Thus it can be accessed as $+
23 54         242 while (
24             $string =~ /\G [\s,]* (?:
25             (") ([^"]*) (?: " | $) | # double-quoted string
26             (') ([^']*) (?: ' | $) | # single-quoted string
27             ([^\s,]+) # other
28             )/gx
29             )
30             {
31 106         194 my $tag = $+;
32 106   66     306 my $is_quoted = $1 || $3;
33              
34             # shed explictly quoted empty strings
35 106 100       233 next unless length $tag;
36              
37 94         179 $tag =~ s/^\s+//;
38 94         167 $tag =~ s/\s+$//;
39 94         147 $tag =~ s/\s+/ /g;
40              
41             # Tags should be unique, but in the right order
42 94 100       615 push @tags, $tag unless $seen{$tag}++;
43             }
44              
45 54         363 return @tags;
46             }
47              
48             sub join_tags {
49 12     12 1 6388 my $self = shift;
50 12         30 my @tags = @_;
51 12         35 return $self->_join_tags(undef, @tags);
52             }
53              
54             sub join_quoted_tags {
55 12     12 1 590 my $self = shift;
56 12         32 my @tags = @_;
57 12         27 return $self->_join_tags(1, @tags);
58             }
59              
60             sub _join_tags {
61 24     24   30 my $self = shift;
62 24         26 my $always_quote = shift;
63 24         37 my @tags = @_;
64              
65 24         27 my %seen;
66             my @quoted_tags;
67              
68 24         42 for my $tag (@tags) {
69 48         226 $tag =~ s/^\s+//;
70 48         83 $tag =~ s/\s+$//;
71 48         81 $tag =~ s/\s+/ /g;
72              
73 48 50       255 next unless length $tag;
74              
75 48         43 my $quote;
76              
77 48 100 100     355 if ( $tag =~ /"/ and $tag =~ /'/ ) {
    100 100        
    100          
    100          
78              
79             # This is an illegal tag. Normalize to just single-quotes.
80             # Quote it too, though technically the new form might not need it.
81 6         16 $tag =~ tr/"/'/;
82 6         7 $quote = q{"};
83             } elsif ( $tag =~ /"/ ) {
84              
85             # It contains a ", so either it needs to be unquoted or
86             # single-quoted
87 6 100 66     182 if ( $tag =~ / / or $tag =~ /,/ or $tag =~ /^"/ or $always_quote) {
      66        
      66        
88 5         8 $quote = q{'};
89             } else {
90 1         3 $quote = q{};
91             }
92             } elsif ( $tag =~ /'/ ) {
93              
94             # It contains a ', so either it needs to be unquoted or
95             # double-quoted
96 4 100 66     45 if ( $tag =~ / / or $tag =~ /,/ or $tag =~ /^'/ or $always_quote) {
      66        
      66        
97 3         8 $quote = q{"};
98             } else {
99 1         3 $quote = q{};
100             }
101             } elsif ( $tag =~ /[ ,]/ or $always_quote) {
102              
103             # By this point we know that it contains no quotes.
104             # But it needs to be quoted.
105 17         36 $quote = q{"};
106             } else {
107              
108             # No special characters at all!
109 15         23 $quote = q{};
110             }
111              
112             # $tag is now fully normalized (both by whitespace and by
113             # anti-illegalization). Have we seen it?
114              
115 48 100       152 next if $seen{$tag}++;
116              
117 46         133 push @quoted_tags, "$quote$tag$quote";
118             }
119              
120 24         185 return join ' ', @quoted_tags;
121             }
122              
123             1; # Magic true value required at end of module
124             __END__