File Coverage

blib/lib/JSON/JQ.pm
Criterion Covered Total %
statement 63 68 92.6
branch 24 36 66.6
condition 3 6 50.0
subroutine 12 12 100.0
pod 2 2 100.0
total 104 124 83.8


line stmt bran cond sub pod time code
1             package JSON::JQ;
2 6     6   513395 use strict;
  6         50  
  6         135  
3 6     6   26 use warnings;
  6         10  
  6         105  
4 6     6   23 use Carp;
  6         8  
  6         379  
5            
6             our $VERSION = '0.09';
7             # internal flags
8             our $DEBUG = 0;
9             our $DUMP_DISASM = 0;
10            
11 6     6   1904 use FindBin ();
  6         4381  
  6         167  
12             FindBin::again();
13 6     6   30 use POSIX qw/isatty/;
  6         12  
  6         55  
14 6     6   12376 use Path::Tiny qw/path/;
  6         67761  
  6         300  
15 6     6   3286 use JSON qw/from_json/;
  6         49410  
  6         26  
16            
17             # jv_print_flags in jv.h
18 6     6   2810 use enum qw/BITMASK:JV_PRINT_ PRETTY ASCII COLOR SORTED INVALID REFCOUNT TAB ISATTY SPACE0 SPACE1 SPACE2/;
  6         4674  
  6         34  
19             # jq.h
20 6     6   4643 use enum qw/:JQ_DEBUG_=1 TRACE TRACE_DETAIL TRACE_ALL/;
  6         12  
  6         15  
21            
22 6     6   1213 use XSLoader;
  6         11  
  6         2496  
23             XSLoader::load('JSON::JQ', $VERSION);
24            
25             sub new {
26 51     51 1 2832 my ( $pkg, $param ) = @_;
27            
28 51 0 33     196 croak "script or script_file parameter required" unless exists $param->{script} or exists $param->{script_file};
29 51         84 my $self = {};
30             # script string or script file
31 51 50       180 $self->{script} = $param->{script} if exists $param->{script};
32 51 50       125 $self->{script_file} = $param->{script_file} if exists $param->{script_file};
33             # script initial arguments
34 51 100       134 $self->{variable} = exists $param->{variable} ? $param->{variable} : {};
35             # internal attributes
36 51 50       233 $self->{_attribute}->{JQ_ORIGIN} = path($FindBin::Bin)->realpath->stringify if $FindBin::Bin;
37             $self->{_attribute}->{JQ_LIBRARY_PATH} = exists $param->{library_paths} ? $param->{library_paths} :
38 51 100       10829 [ '~/.jq', '$ORIGIN/../lib/jq', '$ORIGIN/lib' ];
39 51 50       141 $self->{_attribute}->{PROGRAM_ORIGIN} = exists $param->{script_file} ? path($param->{script_file})->parent->stringify : '.';
40             # error callback will push error messages into this array
41 51         98 $self->{_errors} = [];
42             # debug callback print flags
43 51         154 my $dump_opts = JV_PRINT_INDENT_FLAGS(2);
44 51         88 $dump_opts |= JV_PRINT_SORTED;
45 51 50       1205 $dump_opts |= JV_PRINT_COLOR | JV_PRINT_ISATTY if isatty(*STDERR);
46 51         1771 $self->{_dumpopts} = $dump_opts;
47             # jq debug flags
48 51 50       133 $self->{jq_flags} = exists $param->{debug_flag} ? $param->{debug_flag} : 0;
49 51         87 bless $self, $pkg;
50 51 100       3423595 unless ($self->_init()) {
51 1         4 croak "jq_compile_args() failed with errors:\n ". join("\n ", @{ $self->{_errors} });
  1         229  
52             }
53 50         429 return $self;
54             }
55            
56             sub process {
57 60     60 1 2103 my ( $self, $param ) = @_;
58            
59 60         82 my $input;
60 60 100       183 if (exists $param->{data}) {
    50          
    0          
61 59         118 $input = $param->{data};
62             }
63             elsif (exists $param->{json}) {
64 1         7 $input = from_json($param->{json}, { utf8 => 1 });
65             }
66             elsif (exists $param->{json_file}) {
67 0         0 my $file = path($param->{json_file});
68 0         0 $input = from_json($file->slurp, { utf8 => 1 });
69             }
70             else {
71 0         0 croak "JSON::JQ::process(): required parameter not found, check method documentation";
72             }
73 60         146 my $output = [];
74 60         1363 my $rc = $self->_process($input, $output);
75             # treat it as option EXIT_STATUS is on
76 60 100       183 $rc -= 10 if $rc >= 10;
77 60 100 66     226 if ($rc == 1) {
    100          
    50          
78             # NOTE: treat this case as successful run
79 4         174 warn "JSON::JQ::process(): returned null/false (undef output), perhaps the input is undef.\n";
80             }
81 2         12 elsif ($rc == 4 and @{ $self->{_errors} } == 0) {
82             # treat it as succeeded
83 2         6 push @$output, undef;
84             }
85             elsif ($rc != 0) {
86 0         0 croak "JSON::JQ::process(): failed with return code = $rc and errors:\n ". join("\n ", @{ $self->{_errors} });
  0         0  
87             }
88 60 100       381 return wantarray ? @$output : $output;
89             }
90            
91             =head1 NAME
92            
93             JSON::JQ - jq (https://stedolan.github.io/jq/) library binding
94            
95             =head1 SYNOPSIS
96            
97             use JSON::JQ;
98             my $jq = JSON::JQ->new({ script => '.' });
99             # 1. process perl data
100             my $results = $jq->process({ data => { foo => 'bar' }});
101             # 2. process json string
102             my $results = $jq->process({ json => '{ "foo": "bar" }'});
103             # 3. process json file
104             my $results = $jq->process({ json_file => 'foo.json' });
105             # check items in @$results
106            
107            
108             =head1 DESCRIPTION
109            
110             This is a L library binding, making it possible to process
111             data using jq script/filter/module. Check the jq homepage for a detailed explanation and documentation.
112            
113            
114             =head1 METHODS
115            
116             =head2 new({ parameter => value, ... })
117            
118             Construct a jq engine instance and return it, jq script must be provided by either I