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   528408 use strict;
  6         56  
  6         165  
3 6     6   32 use warnings;
  6         13  
  6         117  
4 6     6   25 use Carp;
  6         10  
  6         396  
5            
6             our $VERSION = '0.08';
7             # internal flags
8             our $DEBUG = 0;
9             our $DUMP_DISASM = 0;
10            
11 6     6   2037 use FindBin ();
  6         4959  
  6         169  
12             FindBin::again();
13 6     6   35 use POSIX qw/isatty/;
  6         12  
  6         74  
14 6     6   13123 use Path::Tiny qw/path/;
  6         71237  
  6         332  
15 6     6   3468 use JSON qw/from_json/;
  6         51779  
  6         27  
16            
17             # jv_print_flags in jv.h
18 6     6   3002 use enum qw/BITMASK:JV_PRINT_ PRETTY ASCII COLOR SORTED INVALID REFCOUNT TAB ISATTY SPACE0 SPACE1 SPACE2/;
  6         4937  
  6         33  
19             # jq.h
20 6     6   4651 use enum qw/:JQ_DEBUG_=1 TRACE TRACE_DETAIL TRACE_ALL/;
  6         12  
  6         17  
21            
22 6     6   1225 use XSLoader;
  6         9  
  6         2540  
23             XSLoader::load('JSON::JQ', $VERSION);
24            
25             sub new {
26 51     51 1 2864 my ( $pkg, $param ) = @_;
27            
28 51 0 33     207 croak "script or script_file parameter required" unless exists $param->{script} or exists $param->{script_file};
29 51         76 my $self = {};
30             # script string or script file
31 51 50       185 $self->{script} = $param->{script} if exists $param->{script};
32 51 50       121 $self->{script_file} = $param->{script_file} if exists $param->{script_file};
33             # script initial arguments
34 51 100       131 $self->{variable} = exists $param->{variable} ? $param->{variable} : {};
35             # internal attributes
36 51 50       225 $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       11044 [ '~/.jq', '$ORIGIN/../lib/jq', '$ORIGIN/lib' ];
39 51 50       150 $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         91 $self->{_errors} = [];
42             # debug callback print flags
43 51         144 my $dump_opts = JV_PRINT_INDENT_FLAGS(2);
44 51         90 $dump_opts |= JV_PRINT_SORTED;
45 51 50       1090 $dump_opts |= JV_PRINT_COLOR | JV_PRINT_ISATTY if isatty(*STDERR);
46 51         1855 $self->{_dumpopts} = $dump_opts;
47             # jq debug flags
48 51 50       148 $self->{jq_flags} = exists $param->{debug_flag} ? $param->{debug_flag} : 0;
49 51         91 bless $self, $pkg;
50 51 100       3427507 unless ($self->_init()) {
51 1         5 croak "jq_compile_args() failed with errors:\n ". join("\n ", @{ $self->{_errors} });
  1         261  
52             }
53 50         464 return $self;
54             }
55            
56             sub process {
57 60     60 1 2162 my ( $self, $param ) = @_;
58            
59 60         86 my $input;
60 60 100       166 if (exists $param->{data}) {
    50          
    0          
61 59         105 $input = $param->{data};
62             }
63             elsif (exists $param->{json}) {
64 1         8 $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         178 my $output = [];
74 60         1355 my $rc = $self->_process($input, $output);
75             # treat it as option EXIT_STATUS is on
76 60 100       174 $rc -= 10 if $rc >= 10;
77 60 100 66     232 if ($rc == 1) {
    100          
    50          
78             # NOTE: treat this case as successful run
79 4         249 warn "JSON::JQ::process(): returned null/false (undef output), perhaps the input is undef.\n";
80             }
81 2         13 elsif ($rc == 4 and @{ $self->{_errors} } == 0) {
82             # treat it as succeeded
83 2         4 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       435 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