File Coverage

blib/lib/App/NDTools/NDTool.pm
Criterion Covered Total %
statement 93 94 98.9
branch 18 20 90.0
condition 3 3 100.0
subroutine 20 21 95.2
pod 0 9 0.0
total 134 147 91.1


line stmt bran cond sub pod time code
1             package App::NDTools::NDTool;
2              
3 19     19   7050 use strict;
  19         42  
  19         670  
4 19     19   114 use warnings FATAL => 'all';
  19         51  
  19         673  
5              
6 19     19   6306 use App::NDTools::INC;
  19         63  
  19         111  
7 19     19   7832 use App::NDTools::Slurp qw(s_dump s_load);
  19         57  
  19         1363  
8 19     19   9658 use Encode::Locale;
  19         258410  
  19         1038  
9 19     19   143 use Encode qw(decode);
  19         43  
  19         1396  
10 19     19   13668 use Getopt::Long qw(GetOptionsFromArray :config bundling noignore_case);
  19         199709  
  19         95  
11 19     19   4600 use Log::Log4Cli;
  19         43  
  19         1673  
12 19     19   9142 use Struct::Path 0.80 qw(path);
  19         42517  
  19         19147  
13              
14             our $VERSION = '0.34';
15              
16             sub arg_opts {
17 254     254 0 2599 my $self = shift;
18              
19             return (
20             'dump-opts' => \$self->{OPTS}->{'dump-opts'},
21             'help|h' => sub {
22 4     4   3971 $self->{OPTS}->{help} = 1;
23 4         19 die "!FINISH";
24             },
25             'ifmt=s' => \$self->{OPTS}->{ifmt},
26             'ofmt=s' => \$self->{OPTS}->{ofmt},
27             'pretty!' => \$self->{OPTS}->{pretty},
28             'verbose|v:+' => \$Log::Log4Cli::LEVEL,
29             'version|V' => sub {
30 4     4   6392 $self->{OPTS}->{version} = 1;
31 4         37 die "!FINISH";
32             },
33 254         7587 );
34             }
35              
36             sub check_args {
37 98     98 0 229 my $self = shift;
38              
39             die_fatal 'At least one argument expected', 1
40 98 100 100     653 unless (@_ or $self->{OPTS}->{'dump-opts'});
41              
42 97         309 return $self;
43             }
44              
45             sub configure {
46 132     132 0 241 my $self = shift;
47              
48 132         214 return $self->check_args(@{$self->{ARGV}});
  132         462  
49             }
50              
51             sub defaults {
52             return {
53 140     140 0 1917 'ofmt' => 'JSON',
54             'pretty' => 1,
55             'verbose' => $Log::Log4Cli::LEVEL,
56             };
57             }
58              
59             sub dump_opts {
60 1     1 0 2 my $self = shift;
61              
62 1         2 delete $self->{OPTS}->{'dump-opts'};
63 1         5 s_dump(\*STDOUT, undef, undef, $self->{OPTS});
64             }
65              
66             sub grep {
67 15     15 0 2165 my ($self, $spaths, @structs) = @_;
68 15         26 my @out;
69              
70 15         40 for my $struct (@structs) {
71 15         28 my (%map_idx, $path, $ref, $grepped);
72              
73 15         23 for (@{$spaths}) {
  15         30  
74 19         435 my @found = eval { path($struct, $_, deref => 1, paths => 1) };
  19         61  
75              
76 19         8078 while (($path, $ref) = splice @found, 0, 2) {
77             # remap array's indexes
78 34         2831 my $map_key = "";
79 34         59 my $map_path = [];
80              
81 34         49 for my $step (@{$path}) {
  34         67  
82 104 100       190 if (ref $step eq 'ARRAY') {
83 52         89 $map_key .= "[]";
84 52 100       163 unless (exists $map_idx{$map_key}->{$step->[0]}) {
85             $map_idx{$map_key}->{$step->[0]} =
86 37         52 keys %{$map_idx{$map_key}};
  37         102  
87             }
88              
89 52         72 push @{$map_path}, [$map_idx{$map_key}->{$step->[0]}];
  52         133  
90             } else { # HASH
91 52         97 $map_key .= "{$step->{K}->[0]}";
92 52         65 push @{$map_path}, $step;
  52         96  
93             }
94             }
95              
96 34         86 path($grepped, $map_path, assign => $ref, expand => 1);
97             }
98             }
99              
100 15 100       1597 push @out, $grepped if (defined $grepped);
101             }
102              
103 15         92 return @out;
104             }
105              
106             sub load_struct {
107 353     353 0 3844 my ($self, $uri, $fmt) = @_;
108              
109 353 0   0   2200 log_trace { ref $uri ? "Reading from STDIN" : "Loading '$uri'" };
  0         0  
110 353         2436 s_load($uri, $fmt);
111             }
112              
113             sub new {
114 253     253 0 17062 my $self = bless {}, shift;
115              
116 253         961 $self->{OPTS} = $self->defaults();
117             $self->{ARGV} =
118 253 100       1051 [ map { decode(locale => "$_", Encode::FB_CROAK) } @_ ? @_ : @ARGV ];
  1187         44832  
119              
120 253         11962 $self->{TTY} = -t STDOUT;
121              
122 253 100       1409 unless (GetOptionsFromArray ($self->{ARGV}, $self->arg_opts)) {
123 1         588 $self->usage;
124 1         4726 die_fatal "Unsupported opts used", 1;
125             }
126              
127 252 100       317531 if ($self->{OPTS}->{help}) {
128 4         48 $self->usage;
129 4         98009 die_info, 0;
130             }
131              
132 248 100       783 if ($self->{OPTS}->{version}) {
133 4         234 print $self->VERSION . "\n";
134 4         43 die_info, 0;
135             }
136              
137 244         1125 $self->configure();
138              
139 238 100       711 if ($self->{OPTS}->{'dump-opts'}) {
140 1         3 $self->dump_opts();
141 1         7 die_info, 0;
142             }
143              
144 237         998 return $self;
145             }
146              
147             sub usage {
148 6     6 0 3264 require Pod::Usage;
149 6         192589 Pod::Usage::pod2usage(
150             -exitval => 'NOEXIT',
151             -output => \*STDERR,
152             -sections => 'SYNOPSIS|OPTIONS|EXAMPLES',
153             -verbose => 99
154             );
155             }
156              
157             1; # End of App::NDTools::NDTool