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 16     16   4909 use strict;
  16         34  
  16         443  
4 16     16   75 use warnings FATAL => 'all';
  16         25  
  16         497  
5              
6 16     16   4732 use App::NDTools::INC;
  16         50  
  16         83  
7 16     16   5848 use App::NDTools::Slurp qw(s_dump s_load);
  16         39  
  16         964  
8 16     16   6958 use Encode::Locale;
  16         184093  
  16         719  
9 16     16   103 use Encode qw(decode);
  16         28  
  16         1080  
10 16     16   9875 use Getopt::Long qw(GetOptionsFromArray :config bundling noignore_case);
  16         142021  
  16         61  
11 16     16   3249 use Log::Log4Cli;
  16         53  
  16         1206  
12 16     16   6816 use Struct::Path 0.80 qw(path);
  16         29318  
  16         13407  
13              
14             our $VERSION = '0.34';
15              
16             sub arg_opts {
17 223     223 0 2306 my $self = shift;
18              
19             return (
20             'dump-opts' => \$self->{OPTS}->{'dump-opts'},
21             'help|h' => sub {
22 4     4   3330 $self->{OPTS}->{help} = 1;
23 4         17 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   5151 $self->{OPTS}->{version} = 1;
31 4         30 die "!FINISH";
32             },
33 223         5699 );
34             }
35              
36             sub check_args {
37 71     71 0 176 my $self = shift;
38              
39             die_fatal 'At least one argument expected', 1
40 71 100 100     199 unless (@_ or $self->{OPTS}->{'dump-opts'});
41              
42 70         177 return $self;
43             }
44              
45             sub configure {
46 130     130 0 183 my $self = shift;
47              
48 130         193 return $self->check_args(@{$self->{ARGV}});
  130         391  
49             }
50              
51             sub defaults {
52             return {
53 138     138 0 1794 'ofmt' => 'JSON',
54             'pretty' => 1,
55             'verbose' => $Log::Log4Cli::LEVEL,
56             };
57             }
58              
59             sub dump_opts {
60 1     1 0 1 my $self = shift;
61              
62 1         2 delete $self->{OPTS}->{'dump-opts'};
63 1         4 s_dump(\*STDOUT, undef, undef, $self->{OPTS});
64             }
65              
66             sub grep {
67 15     15 0 1722 my ($self, $spaths, @structs) = @_;
68 15         19 my @out;
69              
70 15         31 for my $struct (@structs) {
71 15         29 my (%map_idx, $path, $ref, $grepped);
72              
73 15         19 for (@{$spaths}) {
  15         28  
74 19         356 my @found = eval { path($struct, $_, deref => 1, paths => 1) };
  19         52  
75              
76 19         6419 while (($path, $ref) = splice @found, 0, 2) {
77             # remap array's indexes
78 34         2203 my $map_key = "";
79 34         47 my $map_path = [];
80              
81 34         41 for my $step (@{$path}) {
  34         54  
82 104 100       164 if (ref $step eq 'ARRAY') {
83 52         60 $map_key .= "[]";
84 52 100       119 unless (exists $map_idx{$map_key}->{$step->[0]}) {
85             $map_idx{$map_key}->{$step->[0]} =
86 37         41 keys %{$map_idx{$map_key}};
  37         90  
87             }
88              
89 52         57 push @{$map_path}, [$map_idx{$map_key}->{$step->[0]}];
  52         97  
90             } else { # HASH
91 52         73 $map_key .= "{$step->{K}->[0]}";
92 52         55 push @{$map_path}, $step;
  52         77  
93             }
94             }
95              
96 34         71 path($grepped, $map_path, assign => $ref, expand => 1);
97             }
98             }
99              
100 15 100       1316 push @out, $grepped if (defined $grepped);
101             }
102              
103 15         85 return @out;
104             }
105              
106             sub load_struct {
107 302     302 0 2605 my ($self, $uri, $fmt) = @_;
108              
109 302 0   0   1573 log_trace { ref $uri ? "Reading from STDIN" : "Loading '$uri'" };
  0         0  
110 302         1765 s_load($uri, $fmt);
111             }
112              
113             sub new {
114 222     222 0 15212 my $self = bless {}, shift;
115              
116 222         736 $self->{OPTS} = $self->defaults();
117             $self->{ARGV} =
118 222 100       768 [ map { decode(locale => "$_", Encode::FB_CROAK) } @_ ? @_ : @ARGV ];
  984         30219  
119              
120 222         8918 $self->{TTY} = -t STDOUT;
121              
122 222 100       1045 unless (GetOptionsFromArray ($self->{ARGV}, $self->arg_opts)) {
123 1         510 $self->usage;
124 1         3880 die_fatal "Unsupported opts used", 1;
125             }
126              
127 221 100       226630 if ($self->{OPTS}->{help}) {
128 4         37 $self->usage;
129 4         75895 die_info, 0;
130             }
131              
132 217 100       561 if ($self->{OPTS}->{version}) {
133 4         246 print $self->VERSION . "\n";
134 4         37 die_info, 0;
135             }
136              
137 213         840 $self->configure();
138              
139 207 100       531 if ($self->{OPTS}->{'dump-opts'}) {
140 1         3 $self->dump_opts();
141 1         5 die_info, 0;
142             }
143              
144 206         665 return $self;
145             }
146              
147             sub usage {
148 7     7 0 2658 require Pod::Usage;
149 7         158060 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