File Coverage

blib/lib/Test/ModuleVersion.pm
Criterion Covered Total %
statement 289 1441 20.0
branch 31 920 3.3
condition 11 425 2.5
subroutine 76 232 32.7
pod 2 3 66.6
total 409 3021 13.5


line stmt bran cond sub pod time code
1 1     1   28822 use 5.008007;
  1         4  
  1         87  
2             package Test::ModuleVersion;
3             our $VERSION = '0.17';
4              
5             package
6             Test::ModuleVersion::Object::Simple;
7              
8             our $VERSION = '3.0626';
9              
10 1     1   6 use strict;
  1         3  
  1         31  
11 1     1   5 use warnings;
  1         7  
  1         43  
12 1     1   6 no warnings 'redefine';
  1         2  
  1         39  
13              
14 1     1   5 use Carp ();
  1         2  
  1         73  
15              
16             sub import {
17 1     1   10 my ($class, @methods) = @_;
18            
19             # Caller
20 1         3 my $caller = caller;
21            
22             # Base
23 1 50 50     10 if ((my $flag = $methods[0] || '') eq '-base') {
24              
25             # Can haz?
26 1     1   5 no strict 'refs';
  1         2  
  1         30  
27 1     1   4 no warnings 'redefine';
  1         2  
  1         319  
28 0     0   0 *{"${caller}::has"} = sub { attr($caller, @_) };
  0         0  
  0         0  
29            
30             # Inheritance
31 0 0       0 if (my $module = $methods[1]) {
32 0         0 $module =~ s/::|'/\//g;
33 0 0       0 require "$module.pm" unless $module->can('new');
34 0         0 push @{"${caller}::ISA"}, $module;
  0         0  
35             }
36             else {
37 0         0 push @{"${caller}::ISA"}, $class;
  0         0  
38             }
39              
40             # strict!
41 0         0 strict->import;
42 0         0 warnings->import;
43              
44             # Modern!
45 0 0       0 feature->import(':5.10') if $] >= 5.010;
46             }
47             # Method export
48             else {
49            
50             # Exports
51 1         2 my %exports = map { $_ => 1 } qw/new attr class_attr dual_attr/;
  4         9  
52            
53             # Export methods
54 1         1955 foreach my $method (@methods) {
55            
56             # Can be Exported?
57 0 0       0 Carp::croak("Cannot export '$method'.")
58             unless $exports{$method};
59            
60             # Export
61 1     1   6 no strict 'refs';
  1         2  
  1         567  
62 0         0 *{"${caller}::$method"} = \&{"$method"};
  0         0  
  0         0  
63             }
64             }
65             }
66              
67             sub new {
68 2     2   1178 my $class = shift;
69 2 0 33     23 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  0 50       0  
70             }
71              
72             sub attr {
73 10     10   20 my ($self, @args) = @_;
74            
75 10   33     33 my $class = ref $self || $self;
76            
77             # Fix argument
78 10 100       22 unshift @args, (shift @args, undef) if @args % 2;
79            
80 10         47 for (my $i = 0; $i < @args; $i += 2) {
81            
82             # Attribute name
83 10         12 my $attrs = $args[$i];
84 10 50       25 $attrs = [$attrs] unless ref $attrs eq 'ARRAY';
85            
86             # Default
87 10         17 my $default = $args[$i + 1];
88            
89 10         16 foreach my $attr (@$attrs) {
90              
91 10 50 66     35 Carp::croak("Default value of attr must be string or number " .
92             "or code reference (${class}::$attr)")
93             unless !ref $default || ref $default eq 'CODE';
94              
95             # Code
96 10         9 my $code;
97 10 100 100     40 if (defined $default && ref $default) {
    100 66        
98              
99              
100              
101             $code = sub {
102 23 100   23   92 if(@_ == 1) {
103 20 100       73 return $_[0]->{$attr} = $default->($_[0]) unless exists $_[0]->{$attr};
104 15         71 return $_[0]->{$attr};
105             }
106 3         14 $_[0]->{$attr} = $_[1];
107 3         5 $_[0];
108             }
109              
110 7         22 }
111             elsif (defined $default && ! ref $default) {
112              
113              
114              
115             $code = sub {
116 4 50   4   15 if(@_ == 1) {
117 4 100       18 return $_[0]->{$attr} = $default unless exists $_[0]->{$attr};
118 2         8 return $_[0]->{$attr};
119             }
120 0         0 $_[0]->{$attr} = $_[1];
121 0         0 $_[0];
122             }
123              
124              
125              
126 2         6 }
127             else {
128              
129              
130              
131             $code = sub {
132 0 0   0   0 return $_[0]->{$attr} if @_ == 1;
133 0         0 $_[0]->{$attr} = $_[1];
134 0         0 $_[0];
135             }
136              
137              
138              
139 1         4 }
140            
141 1     1   6 no strict 'refs';
  1         2  
  1         88  
142 10         10 *{"${class}::$attr"} = $code;
  10         83  
143             }
144             }
145             }
146              
147             package
148             Test::ModuleVersion::HTTP::Tiny;
149 1     1   6 use strict;
  1         1  
  1         32  
150 1     1   6 use warnings;
  1         2  
  1         79  
151             # ABSTRACT: A small, simple, correct HTTP/1.1 client
152             our $VERSION = '0.016'; # VERSION
153              
154 1     1   22 use Carp ();
  1         1  
  1         42  
155              
156              
157             my @attributes;
158             BEGIN {
159 1     1   15 @attributes = qw(agent default_headers max_redirect max_size proxy timeout);
160 1     1   5 no strict 'refs';
  1         1  
  1         78  
161 1         4 for my $accessor ( @attributes ) {
162 6         283 *{$accessor} = sub {
163 0 0   0   0 @_ > 1 ? $_[0]->{$accessor} = $_[1] : $_[0]->{$accessor};
164 6         16 };
165             }
166             }
167              
168             sub new {
169 0     0   0 my($class, %args) = @_;
170 0         0 (my $agent = $class) =~ s{::}{-}g;
171 0   0     0 my $self = {
172             agent => $agent . "/" . ($class->VERSION || 0),
173             max_redirect => 5,
174             timeout => 60,
175             };
176 0         0 for my $key ( @attributes ) {
177 0 0       0 $self->{$key} = $args{$key} if exists $args{$key}
178             }
179              
180             # Never override proxy argument as this breaks backwards compat.
181 0 0 0     0 if (!exists $self->{proxy} && (my $http_proxy = $ENV{http_proxy})) {
182 0 0       0 if ($http_proxy =~ m{\Ahttp://[^/?#:@]+:\d+/?\z}) {
183 0         0 $self->{proxy} = $http_proxy;
184             }
185             else {
186 0         0 Carp::croak(qq{Environment 'http_proxy' must be in format http://:/\n});
187             }
188             }
189              
190 0         0 return bless $self, $class;
191             }
192              
193              
194             for my $sub_name ( qw/get head put post delete/ ) {
195             my $req_method = uc $sub_name;
196 1     1   5 no strict 'refs';
  1         2  
  1         2875  
197 0 0 0 0   0 eval <<"HERE";
  0 0 0 0   0  
  0 0 0 0   0  
  0 0 0 0   0  
  0 0 0 0   0  
  0   0     0  
  0   0     0  
  0   0     0  
  0   0     0  
  0   0     0  
  0   0     0  
  0   0     0  
  0   0     0  
  0   0     0  
  0   0     0  
198             sub $sub_name {
199             my (\$self, \$url, \$args) = \@_;
200             \@_ == 2 || (\@_ == 3 && ref \$args eq 'HASH')
201             or Carp::croak(q/Usage: \$http->$sub_name(URL, [HASHREF])/ . "\n");
202             return \$self->request('$req_method', \$url, \$args || {});
203             }
204             HERE
205             }
206              
207              
208             sub post_form {
209 0     0   0 my ($self, $url, $data, $args) = @_;
210 0 0 0     0 (@_ == 3 || @_ == 4 && ref $args eq 'HASH')
      0        
211             or Carp::croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n");
212              
213 0         0 my $headers = {};
214 0 0       0 while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
  0         0  
215 0         0 $headers->{lc $key} = $value;
216             }
217 0         0 delete $args->{headers};
218              
219 0         0 return $self->request('POST', $url, {
220             %$args,
221             content => $self->www_form_urlencode($data),
222             headers => {
223             %$headers,
224             'content-type' => 'application/x-www-form-urlencoded'
225             },
226             }
227             );
228             }
229              
230              
231             sub mirror {
232 0     0   0 my ($self, $url, $file, $args) = @_;
233 0 0 0     0 @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
      0        
234             or Carp::croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");
235 0 0 0     0 if ( -e $file and my $mtime = (stat($file))[9] ) {
236 0   0     0 $args->{headers}{'if-modified-since'} ||= $self->_http_date($mtime);
237             }
238 0         0 my $tempfile = $file . int(rand(2**31));
239 0 0       0 open my $fh, ">", $tempfile
240             or Carp::croak(qq/Error: Could not open temporary file $tempfile for downloading: $!\n/);
241 0         0 binmode $fh;
242 0     0   0 $args->{data_callback} = sub { print {$fh} $_[0] };
  0         0  
  0         0  
243 0         0 my $response = $self->request('GET', $url, $args);
244 0 0       0 close $fh
245             or Carp::croak(qq/Error: Could not close temporary file $tempfile: $!\n/);
246 0 0       0 if ( $response->{success} ) {
247 0 0       0 rename $tempfile, $file
248             or Carp::croak(qq/Error replacing $file with $tempfile: $!\n/);
249 0         0 my $lm = $response->{headers}{'last-modified'};
250 0 0 0     0 if ( $lm and my $mtime = $self->_parse_http_date($lm) ) {
251 0         0 utime $mtime, $mtime, $file;
252             }
253             }
254 0   0     0 $response->{success} ||= $response->{status} eq '304';
255 0         0 unlink $tempfile;
256 0         0 return $response;
257             }
258              
259              
260             my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/;
261              
262             sub request {
263 0     0   0 my ($self, $method, $url, $args) = @_;
264 0 0 0     0 @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
      0        
265             or Carp::croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/ . "\n");
266 0   0     0 $args ||= {}; # we keep some state in this during _request
267              
268             # RFC 2616 Section 8.1.4 mandates a single retry on broken socket
269 0         0 my $response;
270 0         0 for ( 0 .. 1 ) {
271 0         0 $response = eval { $self->_request($method, $url, $args) };
  0         0  
272 0 0 0     0 last unless $@ && $idempotent{$method}
      0        
273             && $@ =~ m{^(?:Socket closed|Unexpected end)};
274             }
275              
276 0 0       0 if (my $e = "$@") {
277 0         0 $response = {
278             success => q{},
279             status => 599,
280             reason => 'Internal Exception',
281             content => $e,
282             headers => {
283             'content-type' => 'text/plain',
284             'content-length' => length $e,
285             }
286             };
287             }
288 0         0 return $response;
289             }
290              
291              
292             sub www_form_urlencode {
293 0     0   0 my ($self, $data) = @_;
294 0 0 0     0 (@_ == 2 && ref $data)
295             or Carp::croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n");
296 0 0 0     0 (ref $data eq 'HASH' || ref $data eq 'ARRAY')
297             or Carp::croak("form data must be a hash or array reference");
298              
299 0 0       0 my @params = ref $data eq 'HASH' ? %$data : @$data;
300 0 0       0 @params % 2 == 0
301             or Carp::croak("form data reference must have an even number of terms\n");
302              
303 0         0 my @terms;
304 0         0 while( @params ) {
305 0         0 my ($key, $value) = splice(@params, 0, 2);
306 0 0       0 if ( ref $value eq 'ARRAY' ) {
307 0         0 unshift @params, map { $key => $_ } @$value;
  0         0  
308             }
309             else {
310 0         0 push @terms, join("=", map { $self->_uri_escape($_) } $key, $value);
  0         0  
311             }
312             }
313              
314 0         0 return join("&", sort @terms);
315             }
316              
317             #--------------------------------------------------------------------------#
318             # private methods
319             #--------------------------------------------------------------------------#
320              
321             my %DefaultPort = (
322             http => 80,
323             https => 443,
324             );
325              
326             sub _request {
327 0     0   0 my ($self, $method, $url, $args) = @_;
328              
329 0         0 my ($scheme, $host, $port, $path_query) = $self->_split_url($url);
330              
331 0 0       0 my $request = {
332             method => $method,
333             scheme => $scheme,
334             host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
335             uri => $path_query,
336             headers => {},
337             };
338              
339 0         0 my $handle = Test::ModuleVersion::HTTP::Tiny::Handle->new(timeout => $self->{timeout});
340              
341 0 0       0 if ($self->{proxy}) {
342 0         0 $request->{uri} = "$scheme://$request->{host_port}$path_query";
343 0 0       0 die(qq/HTTPS via proxy is not supported\n/)
344             if $request->{scheme} eq 'https';
345 0         0 $handle->connect(($self->_split_url($self->{proxy}))[0..2]);
346             }
347             else {
348 0         0 $handle->connect($scheme, $host, $port);
349             }
350              
351 0         0 $self->_prepare_headers_and_cb($request, $args);
352 0         0 $handle->write_request($request);
353              
354 0         0 my $response;
355 0         0 do { $response = $handle->read_response_header }
  0         0  
356             until (substr($response->{status},0,1) ne '1');
357              
358 0 0       0 if ( my @redir_args = $self->_maybe_redirect($request, $response, $args) ) {
359 0         0 $handle->close;
360 0         0 return $self->_request(@redir_args, $args);
361             }
362              
363 0 0 0     0 if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
364             # response has no message body
365             }
366             else {
367 0         0 my $data_cb = $self->_prepare_data_cb($response, $args);
368 0         0 $handle->read_body($data_cb, $response);
369             }
370              
371 0         0 $handle->close;
372 0         0 $response->{success} = substr($response->{status},0,1) eq '2';
373 0         0 return $response;
374             }
375              
376             sub _prepare_headers_and_cb {
377 0     0   0 my ($self, $request, $args) = @_;
378              
379 0         0 for ($self->{default_headers}, $args->{headers}) {
380 0 0       0 next unless defined;
381 0         0 while (my ($k, $v) = each %$_) {
382 0         0 $request->{headers}{lc $k} = $v;
383             }
384             }
385 0         0 $request->{headers}{'host'} = $request->{host_port};
386 0         0 $request->{headers}{'connection'} = "close";
387 0   0     0 $request->{headers}{'user-agent'} ||= $self->{agent};
388              
389 0 0       0 if (defined $args->{content}) {
390 0   0     0 $request->{headers}{'content-type'} ||= "application/octet-stream";
391 0 0       0 if (ref $args->{content} eq 'CODE') {
392 0 0 0     0 $request->{headers}{'transfer-encoding'} = 'chunked'
393             unless $request->{headers}{'content-length'}
394             || $request->{headers}{'transfer-encoding'};
395 0         0 $request->{cb} = $args->{content};
396             }
397             else {
398 0         0 my $content = $args->{content};
399 0 0       0 if ( $] ge '5.008' ) {
400 0 0       0 utf8::downgrade($content, 1)
401             or die(qq/Wide character in request message body\n/);
402             }
403 0 0 0     0 $request->{headers}{'content-length'} = length $content
404             unless $request->{headers}{'content-length'}
405             || $request->{headers}{'transfer-encoding'};
406 0     0   0 $request->{cb} = sub { substr $content, 0, length $content, '' };
  0         0  
407             }
408 0 0       0 $request->{trailer_cb} = $args->{trailer_callback}
409             if ref $args->{trailer_callback} eq 'CODE';
410             }
411 0         0 return;
412             }
413              
414             sub _prepare_data_cb {
415 0     0   0 my ($self, $response, $args) = @_;
416 0         0 my $data_cb = $args->{data_callback};
417 0         0 $response->{content} = '';
418              
419 0 0 0     0 if (!$data_cb || $response->{status} !~ /^2/) {
420 0 0       0 if (defined $self->{max_size}) {
421             $data_cb = sub {
422 0     0   0 $_[1]->{content} .= $_[0];
423 0 0       0 die(qq/Size of response body exceeds the maximum allowed of $self->{max_size}\n/)
424             if length $_[1]->{content} > $self->{max_size};
425 0         0 };
426             }
427             else {
428 0     0   0 $data_cb = sub { $_[1]->{content} .= $_[0] };
  0         0  
429             }
430             }
431 0         0 return $data_cb;
432             }
433              
434             sub _maybe_redirect {
435 0     0   0 my ($self, $request, $response, $args) = @_;
436 0         0 my $headers = $response->{headers};
437 0         0 my ($status, $method) = ($response->{status}, $request->{method});
438 0 0 0     0 if (($status eq '303' or ($status =~ /^30[127]/ && $method =~ /^GET|HEAD$/))
      0        
      0        
439             and $headers->{location}
440             and ++$args->{redirects} <= $self->{max_redirect}
441             ) {
442 0 0       0 my $location = ($headers->{location} =~ /^\//)
443             ? "$request->{scheme}://$request->{host_port}$headers->{location}"
444             : $headers->{location} ;
445 0 0       0 return (($status eq '303' ? 'GET' : $method), $location);
446             }
447 0         0 return;
448             }
449              
450             sub _split_url {
451 0     0   0 my $url = pop;
452              
453             # URI regex adapted from the URI module
454 0 0       0 my ($scheme, $authority, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)>
455             or die(qq/Cannot parse URL: '$url'\n/);
456              
457 0         0 $scheme = lc $scheme;
458 0 0       0 $path_query = "/$path_query" unless $path_query =~ m<\A/>;
459              
460 0 0       0 my $host = (length($authority)) ? lc $authority : 'localhost';
461 0         0 $host =~ s/\A[^@]*@//; # userinfo
462 0         0 my $port = do {
463 0 0 0     0 $host =~ s/:([0-9]*)\z// && length $1
    0          
    0          
464             ? $1
465             : ($scheme eq 'http' ? 80 : $scheme eq 'https' ? 443 : undef);
466             };
467              
468 0         0 return ($scheme, $host, $port, $path_query);
469             }
470              
471             # Date conversions adapted from HTTP::Date
472             my $DoW = "Sun|Mon|Tue|Wed|Thu|Fri|Sat";
473             my $MoY = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
474             sub _http_date {
475 0     0   0 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($_[1]);
476 0         0 return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
477             substr($DoW,$wday*4,3),
478             $mday, substr($MoY,$mon*4,3), $year+1900,
479             $hour, $min, $sec
480             );
481             }
482              
483             sub _parse_http_date {
484 0     0   0 my ($self, $str) = @_;
485 0         0 require Time::Local;
486 0         0 my @tl_parts;
487 0 0       0 if ($str =~ /^[SMTWF][a-z]+, +(\d{1,2}) ($MoY) +(\d\d\d\d) +(\d\d):(\d\d):(\d\d) +GMT$/) {
    0          
    0          
488 0         0 @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
489             }
490             elsif ($str =~ /^[SMTWF][a-z]+, +(\d\d)-($MoY)-(\d{2,4}) +(\d\d):(\d\d):(\d\d) +GMT$/ ) {
491 0         0 @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
492             }
493             elsif ($str =~ /^[SMTWF][a-z]+ +($MoY) +(\d{1,2}) +(\d\d):(\d\d):(\d\d) +(?:[^0-9]+ +)?(\d\d\d\d)$/ ) {
494 0         0 @tl_parts = ($5, $4, $3, $2, (index($MoY,$1)/4), $6);
495             }
496 0         0 return eval {
497 0 0       0 my $t = @tl_parts ? Time::Local::timegm(@tl_parts) : -1;
498 0 0       0 $t < 0 ? undef : $t;
499             };
500             }
501              
502             # URI escaping adapted from URI::Escape
503             # c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
504             # perl 5.6 ready UTF-8 encoding adapted from Test::ModuleVersion::JSON::PP
505             my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
506             $escapes{' '}="+";
507             my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;
508              
509             sub _uri_escape {
510 0     0   0 my ($self, $str) = @_;
511 0 0       0 if ( $] ge '5.008' ) {
512 0         0 utf8::encode($str);
513             }
514             else {
515             $str = pack("U*", unpack("C*", $str)) # UTF-8 encode a byte string
516 1 0   1   1316 if ( length $str == do { use bytes; length $str } );
  1         13  
  1         5  
  0         0  
  0         0  
517 0         0 $str = pack("C*", unpack("C*", $str)); # clear UTF-8 flag
518             }
519 0         0 $str =~ s/($unsafe_char)/$escapes{$1}/ge;
  0         0  
520 0         0 return $str;
521             }
522              
523             package
524             Test::ModuleVersion::HTTP::Tiny::Handle; # hide from PAUSE/indexers
525 1     1   113 use strict;
  1         3  
  1         35  
526 1     1   5 use warnings;
  1         2  
  1         40  
527              
528 1     1   947 use Errno qw[EINTR EPIPE];
  1         1451  
  1         139  
529 1     1   1380 use IO::Socket qw[SOCK_STREAM];
  1         27595  
  1         5  
530              
531             sub BUFSIZE () { 32768 }
532              
533             my $Printable = sub {
534             local $_ = shift;
535             s/\r/\\r/g;
536             s/\n/\\n/g;
537             s/\t/\\t/g;
538             s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge;
539             $_;
540             };
541              
542             my $Token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
543              
544             sub new {
545 0     0   0 my ($class, %args) = @_;
546 0         0 return bless {
547             rbuf => '',
548             timeout => 60,
549             max_line_size => 16384,
550             max_header_lines => 64,
551             %args
552             }, $class;
553             }
554              
555             my $ssl_verify_args = {
556             check_cn => "when_only",
557             wildcards_in_alt => "anywhere",
558             wildcards_in_cn => "anywhere"
559             };
560              
561             sub connect {
562 0 0   0   0 @_ == 4 || die(q/Usage: $handle->connect(scheme, host, port)/ . "\n");
563 0         0 my ($self, $scheme, $host, $port) = @_;
564              
565 0 0       0 if ( $scheme eq 'https' ) {
    0          
566 0 0       0 eval "require IO::Socket::SSL"
567             unless exists $INC{'IO/Socket/SSL.pm'};
568 0 0       0 die(qq/IO::Socket::SSL must be installed for https support\n/)
569             unless $INC{'IO/Socket/SSL.pm'};
570             }
571             elsif ( $scheme ne 'http' ) {
572 0         0 die(qq/Unsupported URL scheme '$scheme'\n/);
573             }
574              
575 0 0       0 $self->{fh} = 'IO::Socket::INET'->new(
576             PeerHost => $host,
577             PeerPort => $port,
578             Proto => 'tcp',
579             Type => SOCK_STREAM,
580             Timeout => $self->{timeout}
581             ) or die(qq/Could not connect to '$host:$port': $@\n/);
582              
583 0 0       0 binmode($self->{fh})
584             or die(qq/Could not binmode() socket: '$!'\n/);
585              
586 0 0       0 if ( $scheme eq 'https') {
587 0         0 IO::Socket::SSL->start_SSL($self->{fh});
588 0 0       0 ref($self->{fh}) eq 'IO::Socket::SSL'
589             or die(qq/SSL connection failed for $host\n/);
590 0 0       0 $self->{fh}->verify_hostname( $host, $ssl_verify_args )
591             or die(qq/SSL certificate not valid for $host\n/);
592             }
593              
594 0         0 $self->{host} = $host;
595 0         0 $self->{port} = $port;
596              
597 0         0 return $self;
598             }
599              
600             sub close {
601 0 0   0   0 @_ == 1 || die(q/Usage: $handle->close()/ . "\n");
602 0         0 my ($self) = @_;
603 0 0       0 CORE::close($self->{fh})
604             or die(qq/Could not close socket: '$!'\n/);
605             }
606              
607             sub write {
608 0 0   0   0 @_ == 2 || die(q/Usage: $handle->write(buf)/ . "\n");
609 0         0 my ($self, $buf) = @_;
610              
611 0 0       0 if ( $] ge '5.008' ) {
612 0 0       0 utf8::downgrade($buf, 1)
613             or die(qq/Wide character in write()\n/);
614             }
615              
616 0         0 my $len = length $buf;
617 0         0 my $off = 0;
618              
619 0         0 local $SIG{PIPE} = 'IGNORE';
620              
621 0         0 while () {
622 0 0       0 $self->can_write
623             or die(qq/Timed out while waiting for socket to become ready for writing\n/);
624 0         0 my $r = syswrite($self->{fh}, $buf, $len, $off);
625 0 0       0 if (defined $r) {
    0          
    0          
626 0         0 $len -= $r;
627 0         0 $off += $r;
628 0 0       0 last unless $len > 0;
629             }
630             elsif ($! == EPIPE) {
631 0         0 die(qq/Socket closed by remote server: $!\n/);
632             }
633             elsif ($! != EINTR) {
634 0         0 die(qq/Could not write to socket: '$!'\n/);
635             }
636             }
637 0         0 return $off;
638             }
639              
640             sub read {
641 0 0 0 0   0 @_ == 2 || @_ == 3 || die(q/Usage: $handle->read(len [, allow_partial])/ . "\n");
642 0         0 my ($self, $len, $allow_partial) = @_;
643              
644 0         0 my $buf = '';
645 0         0 my $got = length $self->{rbuf};
646              
647 0 0       0 if ($got) {
648 0 0       0 my $take = ($got < $len) ? $got : $len;
649 0         0 $buf = substr($self->{rbuf}, 0, $take, '');
650 0         0 $len -= $take;
651             }
652              
653 0         0 while ($len > 0) {
654 0 0       0 $self->can_read
655             or die(q/Timed out while waiting for socket to become ready for reading/ . "\n");
656 0         0 my $r = sysread($self->{fh}, $buf, $len, length $buf);
657 0 0       0 if (defined $r) {
    0          
658 0 0       0 last unless $r;
659 0         0 $len -= $r;
660             }
661             elsif ($! != EINTR) {
662 0         0 die(qq/Could not read from socket: '$!'\n/);
663             }
664             }
665 0 0 0     0 if ($len && !$allow_partial) {
666 0         0 die(qq/Unexpected end of stream\n/);
667             }
668 0         0 return $buf;
669             }
670              
671             sub readline {
672 0 0   0   0 @_ == 1 || die(q/Usage: $handle->readline()/ . "\n");
673 0         0 my ($self) = @_;
674              
675 0         0 while () {
676 0 0       0 if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) {
677 0         0 return $1;
678             }
679 0 0       0 if (length $self->{rbuf} >= $self->{max_line_size}) {
680 0         0 die(qq/Line size exceeds the maximum allowed size of $self->{max_line_size}\n/);
681             }
682             $self->can_read
683 0 0       0 or die(qq/Timed out while waiting for socket to become ready for reading\n/);
684 0         0 my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf});
685 0 0       0 if (defined $r) {
    0          
686 0 0       0 last unless $r;
687             }
688             elsif ($! != EINTR) {
689 0         0 die(qq/Could not read from socket: '$!'\n/);
690             }
691             }
692 0         0 die(qq/Unexpected end of stream while looking for line\n/);
693             }
694              
695             sub read_header_lines {
696 0 0 0 0   0 @_ == 1 || @_ == 2 || die(q/Usage: $handle->read_header_lines([headers])/ . "\n");
697 0         0 my ($self, $headers) = @_;
698 0   0     0 $headers ||= {};
699 0         0 my $lines = 0;
700 0         0 my $val;
701              
702 0         0 while () {
703 0         0 my $line = $self->readline;
704              
705 0 0       0 if (++$lines >= $self->{max_header_lines}) {
    0          
    0          
    0          
706 0         0 die(qq/Header lines exceeds maximum number allowed of $self->{max_header_lines}\n/);
707             }
708             elsif ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) {
709 0         0 my ($field_name) = lc $1;
710 0 0       0 if (exists $headers->{$field_name}) {
711 0         0 for ($headers->{$field_name}) {
712 0 0       0 $_ = [$_] unless ref $_ eq "ARRAY";
713 0         0 push @$_, $2;
714 0         0 $val = \$_->[-1];
715             }
716             }
717             else {
718 0         0 $val = \($headers->{$field_name} = $2);
719             }
720             }
721             elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) {
722 0 0       0 $val
723             or die(qq/Unexpected header continuation line\n/);
724 0 0       0 next unless length $1;
725 0 0       0 $$val .= ' ' if length $$val;
726 0         0 $$val .= $1;
727             }
728             elsif ($line =~ /\A \x0D?\x0A \z/x) {
729 0         0 last;
730             }
731             else {
732 0         0 die(q/Malformed header line: / . $Printable->($line) . "\n");
733             }
734             }
735 0         0 return $headers;
736             }
737              
738             sub write_request {
739 0 0   0   0 @_ == 2 || die(q/Usage: $handle->write_request(request)/ . "\n");
740 0         0 my($self, $request) = @_;
741 0         0 $self->write_request_header(@{$request}{qw/method uri headers/});
  0         0  
742 0 0       0 $self->write_body($request) if $request->{cb};
743 0         0 return;
744             }
745              
746             my %HeaderCase = (
747             'content-md5' => 'Content-MD5',
748             'etag' => 'ETag',
749             'te' => 'TE',
750             'www-authenticate' => 'WWW-Authenticate',
751             'x-xss-protection' => 'X-XSS-Protection',
752             );
753              
754             sub write_header_lines {
755 0 0 0 0   0 (@_ == 2 && ref $_[1] eq 'HASH') || die(q/Usage: $handle->write_header_lines(headers)/ . "\n");
756 0         0 my($self, $headers) = @_;
757              
758 0         0 my $buf = '';
759 0         0 while (my ($k, $v) = each %$headers) {
760 0         0 my $field_name = lc $k;
761 0 0       0 if (exists $HeaderCase{$field_name}) {
762 0         0 $field_name = $HeaderCase{$field_name};
763             }
764             else {
765 0 0       0 $field_name =~ /\A $Token+ \z/xo
766             or die(q/Invalid HTTP header field name: / . $Printable->($field_name) . "\n");
767 0         0 $field_name =~ s/\b(\w)/\u$1/g;
768 0         0 $HeaderCase{lc $field_name} = $field_name;
769             }
770 0 0       0 for (ref $v eq 'ARRAY' ? @$v : $v) {
771 0 0       0 /[^\x0D\x0A]/
772             or die(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_). "\n");
773 0         0 $buf .= "$field_name: $_\x0D\x0A";
774             }
775             }
776 0         0 $buf .= "\x0D\x0A";
777 0         0 return $self->write($buf);
778             }
779              
780             sub read_body {
781 0 0   0   0 @_ == 3 || die(q/Usage: $handle->read_body(callback, response)/ . "\n");
782 0         0 my ($self, $cb, $response) = @_;
783 0   0     0 my $te = $response->{headers}{'transfer-encoding'} || '';
784 0 0       0 if ( grep { /chunked/i } ( ref $te eq 'ARRAY' ? @$te : $te ) ) {
  0 0       0  
785 0         0 $self->read_chunked_body($cb, $response);
786             }
787             else {
788 0         0 $self->read_content_body($cb, $response);
789             }
790 0         0 return;
791             }
792              
793             sub write_body {
794 0 0   0   0 @_ == 2 || die(q/Usage: $handle->write_body(request)/ . "\n");
795 0         0 my ($self, $request) = @_;
796 0 0       0 if ($request->{headers}{'content-length'}) {
797 0         0 return $self->write_content_body($request);
798             }
799             else {
800 0         0 return $self->write_chunked_body($request);
801             }
802             }
803              
804             sub read_content_body {
805 0 0 0 0   0 @_ == 3 || @_ == 4 || die(q/Usage: $handle->read_content_body(callback, response, [read_length])/ . "\n");
806 0         0 my ($self, $cb, $response, $content_length) = @_;
807 0   0     0 $content_length ||= $response->{headers}{'content-length'};
808              
809 0 0       0 if ( $content_length ) {
810 0         0 my $len = $content_length;
811 0         0 while ($len > 0) {
812 0 0       0 my $read = ($len > BUFSIZE) ? BUFSIZE : $len;
813 0         0 $cb->($self->read($read, 0), $response);
814 0         0 $len -= $read;
815             }
816             }
817             else {
818 0         0 my $chunk;
819 0         0 $cb->($chunk, $response) while length( $chunk = $self->read(BUFSIZE, 1) );
820             }
821              
822 0         0 return;
823             }
824              
825             sub write_content_body {
826 0 0   0   0 @_ == 2 || die(q/Usage: $handle->write_content_body(request)/ . "\n");
827 0         0 my ($self, $request) = @_;
828              
829 0         0 my ($len, $content_length) = (0, $request->{headers}{'content-length'});
830 0         0 while () {
831 0         0 my $data = $request->{cb}->();
832              
833 0 0 0     0 defined $data && length $data
834             or last;
835              
836 0 0       0 if ( $] ge '5.008' ) {
837 0 0       0 utf8::downgrade($data, 1)
838             or die(qq/Wide character in write_content()\n/);
839             }
840              
841 0         0 $len += $self->write($data);
842             }
843              
844 0 0       0 $len == $content_length
845             or die(qq/Content-Length missmatch (got: $len expected: $content_length)\n/);
846              
847 0         0 return $len;
848             }
849              
850             sub read_chunked_body {
851 0 0   0   0 @_ == 3 || die(q/Usage: $handle->read_chunked_body(callback, $response)/ . "\n");
852 0         0 my ($self, $cb, $response) = @_;
853              
854 0         0 while () {
855 0         0 my $head = $self->readline;
856              
857 0 0       0 $head =~ /\A ([A-Fa-f0-9]+)/x
858             or die(q/Malformed chunk head: / . $Printable->($head) . "\n");
859              
860 0 0       0 my $len = hex($1)
861             or last;
862              
863 0         0 $self->read_content_body($cb, $response, $len);
864              
865 0 0       0 $self->read(2) eq "\x0D\x0A"
866             or die(qq/Malformed chunk: missing CRLF after chunk data\n/);
867             }
868 0         0 $self->read_header_lines($response->{headers});
869 0         0 return;
870             }
871              
872             sub write_chunked_body {
873 0 0   0   0 @_ == 2 || die(q/Usage: $handle->write_chunked_body(request)/ . "\n");
874 0         0 my ($self, $request) = @_;
875              
876 0         0 my $len = 0;
877 0         0 while () {
878 0         0 my $data = $request->{cb}->();
879              
880 0 0 0     0 defined $data && length $data
881             or last;
882              
883 0 0       0 if ( $] ge '5.008' ) {
884 0 0       0 utf8::downgrade($data, 1)
885             or die(qq/Wide character in write_chunked_body()\n/);
886             }
887              
888 0         0 $len += length $data;
889              
890 0         0 my $chunk = sprintf '%X', length $data;
891 0         0 $chunk .= "\x0D\x0A";
892 0         0 $chunk .= $data;
893 0         0 $chunk .= "\x0D\x0A";
894              
895 0         0 $self->write($chunk);
896             }
897 0         0 $self->write("0\x0D\x0A");
898 0 0       0 $self->write_header_lines($request->{trailer_cb}->())
899             if ref $request->{trailer_cb} eq 'CODE';
900 0         0 return $len;
901             }
902              
903             sub read_response_header {
904 0 0   0   0 @_ == 1 || die(q/Usage: $handle->read_response_header()/ . "\n");
905 0         0 my ($self) = @_;
906              
907 0         0 my $line = $self->readline;
908              
909 0 0       0 $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x
910             or die(q/Malformed Status-Line: / . $Printable->($line). "\n");
911              
912 0         0 my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
913              
914 0 0       0 die (qq/Unsupported HTTP protocol: $protocol\n/)
915             unless $version =~ /0*1\.0*[01]/;
916              
917             return {
918 0         0 status => $status,
919             reason => $reason,
920             headers => $self->read_header_lines,
921             protocol => $protocol,
922             };
923             }
924              
925             sub write_request_header {
926 0 0   0   0 @_ == 4 || die(q/Usage: $handle->write_request_header(method, request_uri, headers)/ . "\n");
927 0         0 my ($self, $method, $request_uri, $headers) = @_;
928              
929 0         0 return $self->write("$method $request_uri HTTP/1.1\x0D\x0A")
930             + $self->write_header_lines($headers);
931             }
932              
933             sub _do_timeout {
934 0     0   0 my ($self, $type, $timeout) = @_;
935 0 0 0     0 $timeout = $self->{timeout}
936             unless defined $timeout && $timeout >= 0;
937              
938 0         0 my $fd = fileno $self->{fh};
939 0 0 0     0 defined $fd && $fd >= 0
940             or die(qq/select(2): 'Bad file descriptor'\n/);
941              
942 0         0 my $initial = time;
943 0         0 my $pending = $timeout;
944 0         0 my $nfound;
945              
946 0         0 vec(my $fdset = '', $fd, 1) = 1;
947              
948 0         0 while () {
949 0 0       0 $nfound = ($type eq 'read')
950             ? select($fdset, undef, undef, $pending)
951             : select(undef, $fdset, undef, $pending) ;
952 0 0       0 if ($nfound == -1) {
953 0 0       0 $! == EINTR
954             or die(qq/select(2): '$!'\n/);
955 0 0 0     0 redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0;
956 0         0 $nfound = 0;
957             }
958 0         0 last;
959             }
960 0         0 $! = 0;
961 0         0 return $nfound;
962             }
963              
964             sub can_read {
965 0 0 0 0   0 @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_read([timeout])/ . "\n");
966 0         0 my $self = shift;
967 0         0 return $self->_do_timeout('read', @_)
968             }
969              
970             sub can_write {
971 0 0 0 0   0 @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_write([timeout])/ . "\n");
972 0         0 my $self = shift;
973 0         0 return $self->_do_timeout('write', @_)
974             }
975              
976 1     1   4553 no warnings 'once';
  1         4  
  1         65  
977             package Test::ModuleVersion::JSON::PP;
978             # JSON-2.0
979              
980 1     1   35 use 5.005;
  1         3  
  1         43  
981 1     1   6 use strict;
  1         2  
  1         39  
982 1     1   5 use base qw(Exporter);
  1         2  
  1         138  
983 1     1   1767 use overload ();
  1         1270  
  1         25  
984              
985 1     1   8 use Carp ();
  1         2  
  1         17  
986 1     1   6 use B ();
  1         2  
  1         50  
987             #use Devel::Peek;
988              
989             $Test::ModuleVersion::JSON::PP::VERSION = '2.27200';
990              
991             @Test::ModuleVersion::JSON::PP::EXPORT = qw(encode_json decode_json from_json to_json);
992              
993             # instead of hash-access, i tried index-access for speed.
994             # but this method is not faster than what i expected. so it will be changed.
995              
996 1     1   5 use constant P_ASCII => 0;
  1         3  
  1         84  
997 1     1   6 use constant P_LATIN1 => 1;
  1         2  
  1         57  
998 1     1   6 use constant P_UTF8 => 2;
  1         3  
  1         47  
999 1     1   17 use constant P_INDENT => 3;
  1         2  
  1         59  
1000 1     1   7 use constant P_CANONICAL => 4;
  1         2  
  1         45  
1001 1     1   5 use constant P_SPACE_BEFORE => 5;
  1         3  
  1         53  
1002 1     1   5 use constant P_SPACE_AFTER => 6;
  1         2  
  1         54  
1003 1     1   27 use constant P_ALLOW_NONREF => 7;
  1         2  
  1         44  
1004 1     1   6 use constant P_SHRINK => 8;
  1         1  
  1         45  
1005 1     1   5 use constant P_ALLOW_BLESSED => 9;
  1         1  
  1         1519  
1006 1     1   6 use constant P_CONVERT_BLESSED => 10;
  1         1  
  1         44  
1007 1     1   4 use constant P_RELAXED => 11;
  1         2  
  1         40  
1008              
1009 1     1   5 use constant P_LOOSE => 12;
  1         2  
  1         39  
1010 1     1   5 use constant P_ALLOW_BIGNUM => 13;
  1         1  
  1         39  
1011 1     1   4 use constant P_ALLOW_BAREKEY => 14;
  1         2  
  1         44  
1012 1     1   5 use constant P_ALLOW_SINGLEQUOTE => 15;
  1         1  
  1         45  
1013 1     1   5 use constant P_ESCAPE_SLASH => 16;
  1         2  
  1         38  
1014 1     1   18 use constant P_AS_NONBLESSED => 17;
  1         1  
  1         46  
1015              
1016 1     1   5 use constant P_ALLOW_UNKNOWN => 18;
  1         1  
  1         52  
1017              
1018 1 50   1   5 use constant OLD_PERL => $] < 5.008 ? 1 : 0;
  1         1  
  1         206  
1019              
1020             BEGIN {
1021 1     1   4 my @xs_compati_bit_properties = qw(
1022             latin1 ascii utf8 indent canonical space_before space_after allow_nonref shrink
1023             allow_blessed convert_blessed relaxed allow_unknown
1024             );
1025 1         3 my @pp_bit_properties = qw(
1026             allow_singlequote allow_bignum loose
1027             allow_barekey escape_slash as_nonblessed
1028             );
1029              
1030             # Perl version check, Unicode handling is enable?
1031             # Helper module sets @Test::ModuleVersion::JSON::PP::_properties.
1032 1 50       5 if ($] < 5.008 ) {
1033 0 0       0 my $helper = $] >= 5.006 ? 'Test::ModuleVersion::JSON::PP::Compat5006' : 'Test::ModuleVersion::JSON::PP::Compat5005';
1034 0         0 eval qq| require $helper |;
1035 0 0       0 if ($@) { Carp::croak $@; }
  0         0  
1036             }
1037              
1038 1         2 for my $name (@xs_compati_bit_properties, @pp_bit_properties) {
1039 19         40 my $flag_name = 'P_' . uc($name);
1040              
1041 19 0   0   6882 eval qq/
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0   0   0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1042             sub $name {
1043             my \$enable = defined \$_[1] ? \$_[1] : 1;
1044              
1045             if (\$enable) {
1046             \$_[0]->{PROPS}->[$flag_name] = 1;
1047             }
1048             else {
1049             \$_[0]->{PROPS}->[$flag_name] = 0;
1050             }
1051              
1052             \$_[0];
1053             }
1054              
1055             sub get_$name {
1056             \$_[0]->{PROPS}->[$flag_name] ? 1 : '';
1057             }
1058             /;
1059             }
1060              
1061             }
1062              
1063              
1064              
1065             # Functions
1066              
1067             my %encode_allow_method
1068             = map {($_ => 1)} qw/utf8 pretty allow_nonref latin1 self_encode escape_slash
1069             allow_blessed convert_blessed indent indent_length allow_bignum
1070             as_nonblessed
1071             /;
1072             my %decode_allow_method
1073             = map {($_ => 1)} qw/utf8 allow_nonref loose allow_singlequote allow_bignum
1074             allow_barekey max_size relaxed/;
1075              
1076              
1077             my $JSON; # cache
1078              
1079             sub encode_json ($) { # encode
1080 0   0 0   0 ($JSON ||= __PACKAGE__->new->utf8)->encode(@_);
1081             }
1082              
1083              
1084             sub decode_json { # decode
1085 0   0 0   0 ($JSON ||= __PACKAGE__->new->utf8)->decode(@_);
1086             }
1087              
1088             # Obsoleted
1089              
1090             sub to_json($) {
1091 0     0   0 Carp::croak ("Test::ModuleVersion::JSON::PP::to_json has been renamed to encode_json.");
1092             }
1093              
1094              
1095             sub from_json($) {
1096 0     0   0 Carp::croak ("Test::ModuleVersion::JSON::PP::from_json has been renamed to decode_json.");
1097             }
1098              
1099              
1100             # Methods
1101              
1102             sub new {
1103 0     0   0 my $class = shift;
1104             my $self = {
1105             max_depth => 512,
1106             max_size => 0,
1107             indent => 0,
1108             FLAGS => 0,
1109 0     0   0 fallback => sub { encode_error('Invalid value. JSON can only reference.') },
1110 0         0 indent_length => 3,
1111             };
1112              
1113 0         0 bless $self, $class;
1114             }
1115              
1116              
1117             sub encode {
1118 0     0   0 return $_[0]->PP_encode_json($_[1]);
1119             }
1120              
1121              
1122             sub decode {
1123 0     0   0 return $_[0]->PP_decode_json($_[1], 0x00000000);
1124             }
1125              
1126              
1127             sub decode_prefix {
1128 0     0   0 return $_[0]->PP_decode_json($_[1], 0x00000001);
1129             }
1130              
1131              
1132             # accessor
1133              
1134              
1135             # pretty printing
1136              
1137             sub pretty {
1138 0     0   0 my ($self, $v) = @_;
1139 0 0       0 my $enable = defined $v ? $v : 1;
1140              
1141 0 0       0 if ($enable) { # indent_length(3) for JSON::XS compatibility
1142 0         0 $self->indent(1)->indent_length(3)->space_before(1)->space_after(1);
1143             }
1144             else {
1145 0         0 $self->indent(0)->space_before(0)->space_after(0);
1146             }
1147              
1148 0         0 $self;
1149             }
1150              
1151             # etc
1152              
1153             sub max_depth {
1154 0 0   0   0 my $max = defined $_[1] ? $_[1] : 0x80000000;
1155 0         0 $_[0]->{max_depth} = $max;
1156 0         0 $_[0];
1157             }
1158              
1159              
1160 0     0   0 sub get_max_depth { $_[0]->{max_depth}; }
1161              
1162              
1163             sub max_size {
1164 0 0   0   0 my $max = defined $_[1] ? $_[1] : 0;
1165 0         0 $_[0]->{max_size} = $max;
1166 0         0 $_[0];
1167             }
1168              
1169              
1170 0     0   0 sub get_max_size { $_[0]->{max_size}; }
1171              
1172              
1173             sub filter_json_object {
1174 0 0   0   0 $_[0]->{cb_object} = defined $_[1] ? $_[1] : 0;
1175 0 0 0     0 $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
1176 0         0 $_[0];
1177             }
1178              
1179             sub filter_json_single_key_object {
1180 0 0   0   0 if (@_ > 1) {
1181 0         0 $_[0]->{cb_sk_object}->{$_[1]} = $_[2];
1182             }
1183 0 0 0     0 $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
1184 0         0 $_[0];
1185             }
1186              
1187             sub indent_length {
1188 0 0 0 0   0 if (!defined $_[1] or $_[1] > 15 or $_[1] < 0) {
      0        
1189 0         0 Carp::carp "The acceptable range of indent_length() is 0 to 15.";
1190             }
1191             else {
1192 0         0 $_[0]->{indent_length} = $_[1];
1193             }
1194 0         0 $_[0];
1195             }
1196              
1197             sub get_indent_length {
1198 0     0   0 $_[0]->{indent_length};
1199             }
1200              
1201             sub sort_by {
1202 0 0   0   0 $_[0]->{sort_by} = defined $_[1] ? $_[1] : 1;
1203 0         0 $_[0];
1204             }
1205              
1206             sub allow_bigint {
1207 0     0   0 Carp::carp("allow_bigint() is obsoleted. use allow_bignum() insted.");
1208             }
1209              
1210             ###############################
1211              
1212             ###
1213             ### Perl => JSON
1214             ###
1215              
1216              
1217             { # Convert
1218              
1219             my $max_depth;
1220             my $indent;
1221             my $ascii;
1222             my $latin1;
1223             my $utf8;
1224             my $space_before;
1225             my $space_after;
1226             my $canonical;
1227             my $allow_blessed;
1228             my $convert_blessed;
1229              
1230             my $indent_length;
1231             my $escape_slash;
1232             my $bignum;
1233             my $as_nonblessed;
1234              
1235             my $depth;
1236             my $indent_count;
1237             my $keysort;
1238              
1239              
1240             sub PP_encode_json {
1241 0     0   0 my $self = shift;
1242 0         0 my $obj = shift;
1243              
1244 0         0 $indent_count = 0;
1245 0         0 $depth = 0;
1246              
1247 0         0 my $idx = $self->{PROPS};
1248              
1249 0         0 ($ascii, $latin1, $utf8, $indent, $canonical, $space_before, $space_after, $allow_blessed,
1250             $convert_blessed, $escape_slash, $bignum, $as_nonblessed)
1251 0         0 = @{$idx}[P_ASCII .. P_SPACE_AFTER, P_ALLOW_BLESSED, P_CONVERT_BLESSED,
1252             P_ESCAPE_SLASH, P_ALLOW_BIGNUM, P_AS_NONBLESSED];
1253              
1254 0         0 ($max_depth, $indent_length) = @{$self}{qw/max_depth indent_length/};
  0         0  
1255              
1256 0 0   0   0 $keysort = $canonical ? sub { $a cmp $b } : undef;
  0         0  
1257              
1258 0 0       0 if ($self->{sort_by}) {
1259             $keysort = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by}
1260             : $self->{sort_by} =~ /\D+/ ? $self->{sort_by}
1261 0 0   0   0 : sub { $a cmp $b };
  0 0       0  
1262             }
1263              
1264 0 0 0     0 encode_error("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)")
1265             if(!ref $obj and !$idx->[ P_ALLOW_NONREF ]);
1266              
1267 0         0 my $str = $self->object_to_json($obj);
1268              
1269 0 0       0 $str .= "\n" if ( $indent ); # JSON::XS 2.26 compatible
1270              
1271 0 0 0     0 unless ($ascii or $latin1 or $utf8) {
      0        
1272 0         0 utf8::upgrade($str);
1273             }
1274              
1275 0 0       0 if ($idx->[ P_SHRINK ]) {
1276 0         0 utf8::downgrade($str, 1);
1277             }
1278              
1279 0         0 return $str;
1280             }
1281              
1282              
1283             sub object_to_json {
1284 0     0   0 my ($self, $obj) = @_;
1285 0         0 my $type = ref($obj);
1286              
1287 0 0       0 if($type eq 'HASH'){
    0          
    0          
1288 0         0 return $self->hash_to_json($obj);
1289             }
1290             elsif($type eq 'ARRAY'){
1291 0         0 return $self->array_to_json($obj);
1292             }
1293             elsif ($type) { # blessed object?
1294 0 0       0 if (blessed($obj)) {
1295              
1296 0 0       0 return $self->value_to_json($obj) if ( $obj->isa('Test::ModuleVersion::JSON::PP::Boolean') );
1297              
1298 0 0 0     0 if ( $convert_blessed and $obj->can('TO_JSON') ) {
1299 0         0 my $result = $obj->TO_JSON();
1300 0 0 0     0 if ( defined $result and ref( $result ) ) {
1301 0 0       0 if ( refaddr( $obj ) eq refaddr( $result ) ) {
1302 0         0 encode_error( sprintf(
1303             "%s::TO_JSON method returned same object as was passed instead of a new one",
1304             ref $obj
1305             ) );
1306             }
1307             }
1308              
1309 0         0 return $self->object_to_json( $result );
1310             }
1311              
1312 0 0 0     0 return "$obj" if ( $bignum and _is_bignum($obj) );
1313 0 0 0     0 return $self->blessed_to_json($obj) if ($allow_blessed and $as_nonblessed); # will be removed.
1314              
1315 0 0       0 encode_error( sprintf("encountered object '%s', but neither allow_blessed "
1316             . "nor convert_blessed settings are enabled", $obj)
1317             ) unless ($allow_blessed);
1318              
1319 0         0 return 'null';
1320             }
1321             else {
1322 0         0 return $self->value_to_json($obj);
1323             }
1324             }
1325             else{
1326 0         0 return $self->value_to_json($obj);
1327             }
1328             }
1329              
1330              
1331             sub hash_to_json {
1332 0     0   0 my ($self, $obj) = @_;
1333 0         0 my @res;
1334              
1335 0 0       0 encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
1336             if (++$depth > $max_depth);
1337              
1338 0 0       0 my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
1339 0 0       0 my $del = ($space_before ? ' ' : '') . ':' . ($space_after ? ' ' : '');
    0          
1340              
1341 0         0 for my $k ( _sort( $obj ) ) {
1342 0         0 if ( OLD_PERL ) { utf8::decode($k) } # key for Perl 5.6 / be optimized
1343 0   0     0 push @res, string_to_json( $self, $k )
1344             . $del
1345             . ( $self->object_to_json( $obj->{$k} ) || $self->value_to_json( $obj->{$k} ) );
1346             }
1347              
1348 0         0 --$depth;
1349 0 0       0 $self->_down_indent() if ($indent);
1350              
1351 0 0       0 return '{' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' ) . '}';
    0          
1352             }
1353              
1354              
1355             sub array_to_json {
1356 0     0   0 my ($self, $obj) = @_;
1357 0         0 my @res;
1358              
1359 0 0       0 encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
1360             if (++$depth > $max_depth);
1361              
1362 0 0       0 my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
1363              
1364 0         0 for my $v (@$obj){
1365 0   0     0 push @res, $self->object_to_json($v) || $self->value_to_json($v);
1366             }
1367              
1368 0         0 --$depth;
1369 0 0       0 $self->_down_indent() if ($indent);
1370              
1371 0 0       0 return '[' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' ) . ']';
    0          
1372             }
1373              
1374              
1375             sub value_to_json {
1376 0     0   0 my ($self, $value) = @_;
1377              
1378 0 0       0 return 'null' if(!defined $value);
1379              
1380 0         0 my $b_obj = B::svref_2object(\$value); # for round trip problem
1381 0         0 my $flags = $b_obj->FLAGS;
1382              
1383 0 0 0     0 return $value # as is
1384             if $flags & ( B::SVp_IOK | B::SVp_NOK ) and !( $flags & B::SVp_POK ); # SvTYPE is IV or NV?
1385              
1386 0         0 my $type = ref($value);
1387              
1388 0 0 0     0 if(!$type){
    0          
    0          
1389 0         0 return string_to_json($self, $value);
1390             }
1391             elsif( blessed($value) and $value->isa('Test::ModuleVersion::JSON::PP::Boolean') ){
1392 0 0       0 return $$value == 1 ? 'true' : 'false';
1393             }
1394             elsif ($type) {
1395 0 0       0 if ((overload::StrVal($value) =~ /=(\w+)/)[0]) {
1396 0         0 return $self->value_to_json("$value");
1397             }
1398              
1399 0 0 0     0 if ($type eq 'SCALAR' and defined $$value) {
1400 0 0       0 return $$value eq '1' ? 'true'
    0          
    0          
1401             : $$value eq '0' ? 'false'
1402             : $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ? 'null'
1403             : encode_error("cannot encode reference to scalar");
1404             }
1405              
1406 0 0       0 if ( $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ) {
1407 0         0 return 'null';
1408             }
1409             else {
1410 0 0 0     0 if ( $type eq 'SCALAR' or $type eq 'REF' ) {
1411 0         0 encode_error("cannot encode reference to scalar");
1412             }
1413             else {
1414 0         0 encode_error("encountered $value, but JSON can only represent references to arrays or hashes");
1415             }
1416             }
1417              
1418             }
1419             else {
1420 0 0 0     0 return $self->{fallback}->($value)
1421             if ($self->{fallback} and ref($self->{fallback}) eq 'CODE');
1422 0         0 return 'null';
1423             }
1424              
1425             }
1426              
1427              
1428             my %esc = (
1429             "\n" => '\n',
1430             "\r" => '\r',
1431             "\t" => '\t',
1432             "\f" => '\f',
1433             "\b" => '\b',
1434             "\"" => '\"',
1435             "\\" => '\\\\',
1436             "\'" => '\\\'',
1437             );
1438              
1439              
1440             sub string_to_json {
1441 0     0   0 my ($self, $arg) = @_;
1442              
1443 0         0 $arg =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/g;
1444 0 0       0 $arg =~ s/\//\\\//g if ($escape_slash);
1445 0         0 $arg =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg;
  0         0  
1446              
1447 0 0       0 if ($ascii) {
1448 0         0 $arg = JSON_PP_encode_ascii($arg);
1449             }
1450              
1451 0 0       0 if ($latin1) {
1452 0         0 $arg = JSON_PP_encode_latin1($arg);
1453             }
1454              
1455 0 0       0 if ($utf8) {
1456 0         0 utf8::encode($arg);
1457             }
1458              
1459 0         0 return '"' . $arg . '"';
1460             }
1461              
1462              
1463             sub blessed_to_json {
1464 0   0 0   0 my $reftype = reftype($_[1]) || '';
1465 0 0       0 if ($reftype eq 'HASH') {
    0          
1466 0         0 return $_[0]->hash_to_json($_[1]);
1467             }
1468             elsif ($reftype eq 'ARRAY') {
1469 0         0 return $_[0]->array_to_json($_[1]);
1470             }
1471             else {
1472 0         0 return 'null';
1473             }
1474             }
1475              
1476              
1477             sub encode_error {
1478 0     0   0 my $error = shift;
1479 0         0 Carp::croak "$error";
1480             }
1481              
1482              
1483             sub _sort {
1484 0 0   0   0 defined $keysort ? (sort $keysort (keys %{$_[0]})) : keys %{$_[0]};
  0         0  
  0         0  
1485             }
1486              
1487              
1488             sub _up_indent {
1489 0     0   0 my $self = shift;
1490 0         0 my $space = ' ' x $indent_length;
1491              
1492 0         0 my ($pre,$post) = ('','');
1493              
1494 0         0 $post = "\n" . $space x $indent_count;
1495              
1496 0         0 $indent_count++;
1497              
1498 0         0 $pre = "\n" . $space x $indent_count;
1499              
1500 0         0 return ($pre,$post);
1501             }
1502              
1503              
1504 0     0   0 sub _down_indent { $indent_count--; }
1505              
1506              
1507             sub PP_encode_box {
1508             {
1509 0     0   0 depth => $depth,
1510             indent_count => $indent_count,
1511             };
1512             }
1513              
1514             } # Convert
1515              
1516              
1517             sub _encode_ascii {
1518 0 0       0 join('',
    0          
1519             map {
1520 0     0   0 $_ <= 127 ?
1521             chr($_) :
1522             $_ <= 65535 ?
1523             sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
1524             } unpack('U*', $_[0])
1525             );
1526             }
1527              
1528              
1529             sub _encode_latin1 {
1530 0 0       0 join('',
    0          
1531             map {
1532 0     0   0 $_ <= 255 ?
1533             chr($_) :
1534             $_ <= 65535 ?
1535             sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
1536             } unpack('U*', $_[0])
1537             );
1538             }
1539              
1540              
1541             sub _encode_surrogates { # from perlunicode
1542 0     0   0 my $uni = $_[0] - 0x10000;
1543 0         0 return ($uni / 0x400 + 0xD800, $uni % 0x400 + 0xDC00);
1544             }
1545              
1546              
1547             sub _is_bignum {
1548 0 0   0   0 $_[0]->isa('Math::BigInt') or $_[0]->isa('Math::BigFloat');
1549             }
1550              
1551              
1552              
1553             #
1554             # JSON => Perl
1555             #
1556              
1557             my $max_intsize;
1558              
1559             BEGIN {
1560 1     1   3 my $checkint = 1111;
1561 1         3 for my $d (5..64) {
1562 17         23 $checkint .= 1;
1563 17         691 my $int = eval qq| $checkint |;
1564 17 100       81 if ($int =~ /[eE]/) {
1565 1         3 $max_intsize = $d - 1;
1566 1         489 last;
1567             }
1568             }
1569             }
1570              
1571             { # PARSE
1572              
1573             my %escapes = ( # by Jeremy Muhlich
1574             b => "\x8",
1575             t => "\x9",
1576             n => "\xA",
1577             f => "\xC",
1578             r => "\xD",
1579             '\\' => '\\',
1580             '"' => '"',
1581             '/' => '/',
1582             );
1583              
1584             my $text; # json data
1585             my $at; # offset
1586             my $ch; # 1chracter
1587             my $len; # text length (changed according to UTF8 or NON UTF8)
1588             # INTERNAL
1589             my $depth; # nest counter
1590             my $encoding; # json text encoding
1591             my $is_valid_utf8; # temp variable
1592             my $utf8_len; # utf8 byte length
1593             # FLAGS
1594             my $utf8; # must be utf8
1595             my $max_depth; # max nest nubmer of objects and arrays
1596             my $max_size;
1597             my $relaxed;
1598             my $cb_object;
1599             my $cb_sk_object;
1600              
1601             my $F_HOOK;
1602              
1603             my $allow_bigint; # using Math::BigInt
1604             my $singlequote; # loosely quoting
1605             my $loose; #
1606             my $allow_barekey; # bareKey
1607              
1608             # $opt flag
1609             # 0x00000001 .... decode_prefix
1610             # 0x10000000 .... incr_parse
1611              
1612             sub PP_decode_json {
1613 0     0   0 my ($self, $opt); # $opt is an effective flag during this decode_json.
1614              
1615 0         0 ($self, $text, $opt) = @_;
1616              
1617 0         0 ($at, $ch, $depth) = (0, '', 0);
1618              
1619 0 0 0     0 if ( !defined $text or ref $text ) {
1620 0         0 decode_error("malformed JSON string, neither array, object, number, string or atom");
1621             }
1622              
1623 0         0 my $idx = $self->{PROPS};
1624              
1625 0         0 ($utf8, $relaxed, $loose, $allow_bigint, $allow_barekey, $singlequote)
1626 0         0 = @{$idx}[P_UTF8, P_RELAXED, P_LOOSE .. P_ALLOW_SINGLEQUOTE];
1627              
1628 0 0       0 if ( $utf8 ) {
1629 0 0       0 utf8::downgrade( $text, 1 ) or Carp::croak("Wide character in subroutine entry");
1630             }
1631             else {
1632 0         0 utf8::upgrade( $text );
1633             }
1634              
1635 0         0 $len = length $text;
1636              
1637 0         0 ($max_depth, $max_size, $cb_object, $cb_sk_object, $F_HOOK)
1638 0         0 = @{$self}{qw/max_depth max_size cb_object cb_sk_object F_HOOK/};
1639              
1640 0 0       0 if ($max_size > 1) {
1641 1     1   10 use bytes;
  1         2  
  1         9  
1642 0         0 my $bytes = length $text;
1643 0 0       0 decode_error(
1644             sprintf("attempted decode of JSON text of %s bytes size, but max_size is set to %s"
1645             , $bytes, $max_size), 1
1646             ) if ($bytes > $max_size);
1647             }
1648              
1649             # Currently no effect
1650             # should use regexp
1651 0         0 my @octets = unpack('C4', $text);
1652 0 0 0     0 $encoding = ( $octets[0] and $octets[1]) ? 'UTF-8'
    0 0        
    0 0        
    0          
    0          
1653             : (!$octets[0] and $octets[1]) ? 'UTF-16BE'
1654             : (!$octets[0] and !$octets[1]) ? 'UTF-32BE'
1655             : ( $octets[2] ) ? 'UTF-16LE'
1656             : (!$octets[2] ) ? 'UTF-32LE'
1657             : 'unknown';
1658              
1659 0         0 white(); # remove head white space
1660              
1661 0         0 my $valid_start = defined $ch; # Is there a first character for JSON structure?
1662              
1663 0         0 my $result = value();
1664              
1665 0 0 0     0 return undef if ( !$result && ( $opt & 0x10000000 ) ); # for incr_parse
1666              
1667 0 0       0 decode_error("malformed JSON string, neither array, object, number, string or atom") unless $valid_start;
1668              
1669 0 0 0     0 if ( !$idx->[ P_ALLOW_NONREF ] and !ref $result ) {
1670 0         0 decode_error(
1671             'JSON text must be an object or array (but found number, string, true, false or null,'
1672             . ' use allow_nonref to allow this)', 1);
1673             }
1674              
1675 0 0       0 Carp::croak('something wrong.') if $len < $at; # we won't arrive here.
1676              
1677 0 0       0 my $consumed = defined $ch ? $at - 1 : $at; # consumed JSON text length
1678              
1679 0         0 white(); # remove tail white space
1680              
1681 0 0       0 if ( $ch ) {
1682 0 0       0 return ( $result, $consumed ) if ($opt & 0x00000001); # all right if decode_prefix
1683 0         0 decode_error("garbage after JSON object");
1684             }
1685              
1686 0 0       0 ( $opt & 0x00000001 ) ? ( $result, $consumed ) : $result;
1687             }
1688              
1689              
1690             sub next_chr {
1691 0 0   0   0 return $ch = undef if($at >= $len);
1692 0         0 $ch = substr($text, $at++, 1);
1693             }
1694              
1695              
1696             sub value {
1697 0     0   0 white();
1698 0 0       0 return if(!defined $ch);
1699 0 0       0 return object() if($ch eq '{');
1700 0 0       0 return array() if($ch eq '[');
1701 0 0 0     0 return string() if($ch eq '"' or ($singlequote and $ch eq "'"));
      0        
1702 0 0 0     0 return number() if($ch =~ /[0-9]/ or $ch eq '-');
1703 0         0 return word();
1704             }
1705              
1706             sub string {
1707 0     0   0 my ($i, $s, $t, $u);
1708 0         0 my $utf16;
1709 0         0 my $is_utf8;
1710              
1711 0         0 ($is_valid_utf8, $utf8_len) = ('', 0);
1712              
1713 0         0 $s = ''; # basically UTF8 flag on
1714              
1715 0 0 0     0 if($ch eq '"' or ($singlequote and $ch eq "'")){
      0        
1716 0         0 my $boundChar = $ch;
1717              
1718 0         0 OUTER: while( defined(next_chr()) ){
1719              
1720 0 0       0 if($ch eq $boundChar){
    0          
1721 0         0 next_chr();
1722              
1723 0 0       0 if ($utf16) {
1724 0         0 decode_error("missing low surrogate character in surrogate pair");
1725             }
1726              
1727 0 0       0 utf8::decode($s) if($is_utf8);
1728              
1729 0         0 return $s;
1730             }
1731             elsif($ch eq '\\'){
1732 0         0 next_chr();
1733 0 0       0 if(exists $escapes{$ch}){
    0          
1734 0         0 $s .= $escapes{$ch};
1735             }
1736             elsif($ch eq 'u'){ # UNICODE handling
1737 0         0 my $u = '';
1738              
1739 0         0 for(1..4){
1740 0         0 $ch = next_chr();
1741 0 0       0 last OUTER if($ch !~ /[0-9a-fA-F]/);
1742 0         0 $u .= $ch;
1743             }
1744              
1745             # U+D800 - U+DBFF
1746 0 0       0 if ($u =~ /^[dD][89abAB][0-9a-fA-F]{2}/) { # UTF-16 high surrogate?
    0          
1747 0         0 $utf16 = $u;
1748             }
1749             # U+DC00 - U+DFFF
1750             elsif ($u =~ /^[dD][c-fC-F][0-9a-fA-F]{2}/) { # UTF-16 low surrogate?
1751 0 0       0 unless (defined $utf16) {
1752 0         0 decode_error("missing high surrogate character in surrogate pair");
1753             }
1754 0         0 $is_utf8 = 1;
1755 0   0     0 $s .= JSON_PP_decode_surrogates($utf16, $u) || next;
1756 0         0 $utf16 = undef;
1757             }
1758             else {
1759 0 0       0 if (defined $utf16) {
1760 0         0 decode_error("surrogate pair expected");
1761             }
1762              
1763 0 0       0 if ( ( my $hex = hex( $u ) ) > 127 ) {
1764 0         0 $is_utf8 = 1;
1765 0   0     0 $s .= JSON_PP_decode_unicode($u) || next;
1766             }
1767             else {
1768 0         0 $s .= chr $hex;
1769             }
1770             }
1771              
1772             }
1773             else{
1774 0 0       0 unless ($loose) {
1775 0         0 $at -= 2;
1776 0         0 decode_error('illegal backslash escape sequence in string');
1777             }
1778 0         0 $s .= $ch;
1779             }
1780             }
1781             else{
1782              
1783 0 0       0 if ( ord $ch > 127 ) {
1784 0 0       0 if ( $utf8 ) {
1785 0 0       0 unless( $ch = is_valid_utf8($ch) ) {
1786 0         0 $at -= 1;
1787 0         0 decode_error("malformed UTF-8 character in JSON string");
1788             }
1789             else {
1790 0         0 $at += $utf8_len - 1;
1791             }
1792             }
1793             else {
1794 0         0 utf8::encode( $ch );
1795             }
1796              
1797 0         0 $is_utf8 = 1;
1798             }
1799              
1800 0 0       0 if (!$loose) {
1801 0 0       0 if ($ch =~ /[\x00-\x1f\x22\x5c]/) { # '/' ok
1802 0         0 $at--;
1803 0         0 decode_error('invalid character encountered while parsing JSON string');
1804             }
1805             }
1806              
1807 0         0 $s .= $ch;
1808             }
1809             }
1810             }
1811              
1812 0         0 decode_error("unexpected end of string while parsing JSON string");
1813             }
1814              
1815              
1816             sub white {
1817 0     0   0 while( defined $ch ){
1818 0 0       0 if($ch le ' '){
    0          
1819 0         0 next_chr();
1820             }
1821             elsif($ch eq '/'){
1822 0         0 next_chr();
1823 0 0 0     0 if(defined $ch and $ch eq '/'){
    0 0        
1824 0   0     0 1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r");
      0        
1825             }
1826             elsif(defined $ch and $ch eq '*'){
1827 0         0 next_chr();
1828 0         0 while(1){
1829 0 0       0 if(defined $ch){
1830 0 0       0 if($ch eq '*'){
1831 0 0 0     0 if(defined(next_chr()) and $ch eq '/'){
1832 0         0 next_chr();
1833 0         0 last;
1834             }
1835             }
1836             else{
1837 0         0 next_chr();
1838             }
1839             }
1840             else{
1841 0         0 decode_error("Unterminated comment");
1842             }
1843             }
1844 0         0 next;
1845             }
1846             else{
1847 0         0 $at--;
1848 0         0 decode_error("malformed JSON string, neither array, object, number, string or atom");
1849             }
1850             }
1851             else{
1852 0 0 0     0 if ($relaxed and $ch eq '#') { # correctly?
1853 0         0 pos($text) = $at;
1854 0         0 $text =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g;
1855 0         0 $at = pos($text);
1856 0         0 next_chr;
1857 0         0 next;
1858             }
1859              
1860 0         0 last;
1861             }
1862             }
1863             }
1864              
1865              
1866             sub array {
1867 0   0 0   0 my $a = $_[0] || []; # you can use this code to use another array ref object.
1868              
1869 0 0       0 decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
1870             if (++$depth > $max_depth);
1871              
1872 0         0 next_chr();
1873 0         0 white();
1874              
1875 0 0 0     0 if(defined $ch and $ch eq ']'){
1876 0         0 --$depth;
1877 0         0 next_chr();
1878 0         0 return $a;
1879             }
1880             else {
1881 0         0 while(defined($ch)){
1882 0         0 push @$a, value();
1883              
1884 0         0 white();
1885              
1886 0 0       0 if (!defined $ch) {
1887 0         0 last;
1888             }
1889              
1890 0 0       0 if($ch eq ']'){
1891 0         0 --$depth;
1892 0         0 next_chr();
1893 0         0 return $a;
1894             }
1895              
1896 0 0       0 if($ch ne ','){
1897 0         0 last;
1898             }
1899              
1900 0         0 next_chr();
1901 0         0 white();
1902              
1903 0 0 0     0 if ($relaxed and $ch eq ']') {
1904 0         0 --$depth;
1905 0         0 next_chr();
1906 0         0 return $a;
1907             }
1908              
1909             }
1910             }
1911              
1912 0         0 decode_error(", or ] expected while parsing array");
1913             }
1914              
1915              
1916             sub object {
1917 0   0 0   0 my $o = $_[0] || {}; # you can use this code to use another hash ref object.
1918 0         0 my $k;
1919              
1920 0 0       0 decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
1921             if (++$depth > $max_depth);
1922 0         0 next_chr();
1923 0         0 white();
1924              
1925 0 0 0     0 if(defined $ch and $ch eq '}'){
1926 0         0 --$depth;
1927 0         0 next_chr();
1928 0 0       0 if ($F_HOOK) {
1929 0         0 return _json_object_hook($o);
1930             }
1931 0         0 return $o;
1932             }
1933             else {
1934 0         0 while (defined $ch) {
1935 0 0 0     0 $k = ($allow_barekey and $ch ne '"' and $ch ne "'") ? bareKey() : string();
1936 0         0 white();
1937              
1938 0 0 0     0 if(!defined $ch or $ch ne ':'){
1939 0         0 $at--;
1940 0         0 decode_error("':' expected");
1941             }
1942              
1943 0         0 next_chr();
1944 0         0 $o->{$k} = value();
1945 0         0 white();
1946              
1947 0 0       0 last if (!defined $ch);
1948              
1949 0 0       0 if($ch eq '}'){
1950 0         0 --$depth;
1951 0         0 next_chr();
1952 0 0       0 if ($F_HOOK) {
1953 0         0 return _json_object_hook($o);
1954             }
1955 0         0 return $o;
1956             }
1957              
1958 0 0       0 if($ch ne ','){
1959 0         0 last;
1960             }
1961              
1962 0         0 next_chr();
1963 0         0 white();
1964              
1965 0 0 0     0 if ($relaxed and $ch eq '}') {
1966 0         0 --$depth;
1967 0         0 next_chr();
1968 0 0       0 if ($F_HOOK) {
1969 0         0 return _json_object_hook($o);
1970             }
1971 0         0 return $o;
1972             }
1973              
1974             }
1975              
1976             }
1977              
1978 0         0 $at--;
1979 0         0 decode_error(", or } expected while parsing object/hash");
1980             }
1981              
1982              
1983             sub bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition
1984 0     0   0 my $key;
1985 0         0 while($ch =~ /[^\x00-\x23\x25-\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]/){
1986 0         0 $key .= $ch;
1987 0         0 next_chr();
1988             }
1989 0         0 return $key;
1990             }
1991              
1992              
1993             sub word {
1994 0     0   0 my $word = substr($text,$at-1,4);
1995              
1996 0 0       0 if($word eq 'true'){
    0          
    0          
1997 0         0 $at += 3;
1998 0         0 next_chr;
1999 0         0 return $Test::ModuleVersion::JSON::PP::true;
2000             }
2001             elsif($word eq 'null'){
2002 0         0 $at += 3;
2003 0         0 next_chr;
2004 0         0 return undef;
2005             }
2006             elsif($word eq 'fals'){
2007 0         0 $at += 3;
2008 0 0       0 if(substr($text,$at,1) eq 'e'){
2009 0         0 $at++;
2010 0         0 next_chr;
2011 0         0 return $Test::ModuleVersion::JSON::PP::false;
2012             }
2013             }
2014              
2015 0         0 $at--; # for decode_error report
2016              
2017 0 0       0 decode_error("'null' expected") if ($word =~ /^n/);
2018 0 0       0 decode_error("'true' expected") if ($word =~ /^t/);
2019 0 0       0 decode_error("'false' expected") if ($word =~ /^f/);
2020 0         0 decode_error("malformed JSON string, neither array, object, number, string or atom");
2021             }
2022              
2023              
2024             sub number {
2025 0     0   0 my $n = '';
2026 0         0 my $v;
2027              
2028             # According to RFC4627, hex or oct digts are invalid.
2029 0 0       0 if($ch eq '0'){
2030 0         0 my $peek = substr($text,$at,1);
2031 0         0 my $hex = $peek =~ /[xX]/; # 0 or 1
2032              
2033 0 0       0 if($hex){
2034 0         0 decode_error("malformed number (leading zero must not be followed by another digit)");
2035 0         0 ($n) = ( substr($text, $at+1) =~ /^([0-9a-fA-F]+)/);
2036             }
2037             else{ # oct
2038 0         0 ($n) = ( substr($text, $at) =~ /^([0-7]+)/);
2039 0 0 0     0 if (defined $n and length $n > 1) {
2040 0         0 decode_error("malformed number (leading zero must not be followed by another digit)");
2041             }
2042             }
2043              
2044 0 0 0     0 if(defined $n and length($n)){
2045 0 0 0     0 if (!$hex and length($n) == 1) {
2046 0         0 decode_error("malformed number (leading zero must not be followed by another digit)");
2047             }
2048 0         0 $at += length($n) + $hex;
2049 0         0 next_chr;
2050 0 0       0 return $hex ? hex($n) : oct($n);
2051             }
2052             }
2053              
2054 0 0       0 if($ch eq '-'){
2055 0         0 $n = '-';
2056 0         0 next_chr;
2057 0 0 0     0 if (!defined $ch or $ch !~ /\d/) {
2058 0         0 decode_error("malformed number (no digits after initial minus)");
2059             }
2060             }
2061              
2062 0   0     0 while(defined $ch and $ch =~ /\d/){
2063 0         0 $n .= $ch;
2064 0         0 next_chr;
2065             }
2066              
2067 0 0 0     0 if(defined $ch and $ch eq '.'){
2068 0         0 $n .= '.';
2069              
2070 0         0 next_chr;
2071 0 0 0     0 if (!defined $ch or $ch !~ /\d/) {
2072 0         0 decode_error("malformed number (no digits after decimal point)");
2073             }
2074             else {
2075 0         0 $n .= $ch;
2076             }
2077              
2078 0   0     0 while(defined(next_chr) and $ch =~ /\d/){
2079 0         0 $n .= $ch;
2080             }
2081             }
2082              
2083 0 0 0     0 if(defined $ch and ($ch eq 'e' or $ch eq 'E')){
      0        
2084 0         0 $n .= $ch;
2085 0         0 next_chr;
2086              
2087 0 0 0     0 if(defined($ch) and ($ch eq '+' or $ch eq '-')){
    0 0        
      0        
2088 0         0 $n .= $ch;
2089 0         0 next_chr;
2090 0 0 0     0 if (!defined $ch or $ch =~ /\D/) {
2091 0         0 decode_error("malformed number (no digits after exp sign)");
2092             }
2093 0         0 $n .= $ch;
2094             }
2095             elsif(defined($ch) and $ch =~ /\d/){
2096 0         0 $n .= $ch;
2097             }
2098             else {
2099 0         0 decode_error("malformed number (no digits after exp sign)");
2100             }
2101              
2102 0   0     0 while(defined(next_chr) and $ch =~ /\d/){
2103 0         0 $n .= $ch;
2104             }
2105              
2106             }
2107              
2108 0         0 $v .= $n;
2109              
2110 0 0 0     0 if ($v !~ /[.eE]/ and length $v > $max_intsize) {
    0          
2111 0 0       0 if ($allow_bigint) { # from Adam Sussman
2112 0         0 require Math::BigInt;
2113 0         0 return Math::BigInt->new($v);
2114             }
2115             else {
2116 0         0 return "$v";
2117             }
2118             }
2119             elsif ($allow_bigint) {
2120 0         0 require Math::BigFloat;
2121 0         0 return Math::BigFloat->new($v);
2122             }
2123              
2124 0         0 return 0+$v;
2125             }
2126              
2127              
2128             sub is_valid_utf8 {
2129              
2130 0 0   0   0 $utf8_len = $_[0] =~ /[\x00-\x7F]/ ? 1
    0          
    0          
    0          
2131             : $_[0] =~ /[\xC2-\xDF]/ ? 2
2132             : $_[0] =~ /[\xE0-\xEF]/ ? 3
2133             : $_[0] =~ /[\xF0-\xF4]/ ? 4
2134             : 0
2135             ;
2136              
2137 0 0       0 return unless $utf8_len;
2138              
2139 0         0 my $is_valid_utf8 = substr($text, $at - 1, $utf8_len);
2140              
2141 0 0       0 return ( $is_valid_utf8 =~ /^(?:
2142             [\x00-\x7F]
2143             |[\xC2-\xDF][\x80-\xBF]
2144             |[\xE0][\xA0-\xBF][\x80-\xBF]
2145             |[\xE1-\xEC][\x80-\xBF][\x80-\xBF]
2146             |[\xED][\x80-\x9F][\x80-\xBF]
2147             |[\xEE-\xEF][\x80-\xBF][\x80-\xBF]
2148             |[\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]
2149             |[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]
2150             |[\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF]
2151             )$/x ) ? $is_valid_utf8 : '';
2152             }
2153              
2154              
2155             sub decode_error {
2156 0     0   0 my $error = shift;
2157 0         0 my $no_rep = shift;
2158 0 0       0 my $str = defined $text ? substr($text, $at) : '';
2159 0         0 my $mess = '';
2160 0 0       0 my $type = $] >= 5.008 ? 'U*'
    0          
    0          
2161             : $] < 5.006 ? 'C*'
2162             : utf8::is_utf8( $str ) ? 'U*' # 5.6
2163             : 'C*'
2164             ;
2165              
2166 0         0 for my $c ( unpack( $type, $str ) ) { # emulate pv_uni_display() ?
2167 0 0       0 $mess .= $c == 0x07 ? '\a'
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2168             : $c == 0x09 ? '\t'
2169             : $c == 0x0a ? '\n'
2170             : $c == 0x0d ? '\r'
2171             : $c == 0x0c ? '\f'
2172             : $c < 0x20 ? sprintf('\x{%x}', $c)
2173             : $c == 0x5c ? '\\\\'
2174             : $c < 0x80 ? chr($c)
2175             : sprintf('\x{%x}', $c)
2176             ;
2177 0 0       0 if ( length $mess >= 20 ) {
2178 0         0 $mess .= '...';
2179 0         0 last;
2180             }
2181             }
2182              
2183 0 0       0 unless ( length $mess ) {
2184 0         0 $mess = '(end of string)';
2185             }
2186              
2187             Carp::croak (
2188 0 0       0 $no_rep ? "$error" : "$error, at character offset $at (before \"$mess\")"
2189             );
2190              
2191             }
2192              
2193              
2194             sub _json_object_hook {
2195 0     0   0 my $o = $_[0];
2196 0         0 my @ks = keys %{$o};
  0         0  
2197              
2198 0 0 0     0 if ( $cb_sk_object and @ks == 1 and exists $cb_sk_object->{ $ks[0] } and ref $cb_sk_object->{ $ks[0] } ) {
      0        
      0        
2199 0         0 my @val = $cb_sk_object->{ $ks[0] }->( $o->{$ks[0]} );
2200 0 0       0 if (@val == 1) {
2201 0         0 return $val[0];
2202             }
2203             }
2204              
2205 0 0       0 my @val = $cb_object->($o) if ($cb_object);
2206 0 0 0     0 if (@val == 0 or @val > 1) {
2207 0         0 return $o;
2208             }
2209             else {
2210 0         0 return $val[0];
2211             }
2212             }
2213              
2214              
2215             sub PP_decode_box {
2216             {
2217 0     0   0 text => $text,
2218             at => $at,
2219             ch => $ch,
2220             len => $len,
2221             depth => $depth,
2222             encoding => $encoding,
2223             is_valid_utf8 => $is_valid_utf8,
2224             };
2225             }
2226              
2227             } # PARSE
2228              
2229              
2230             sub _decode_surrogates { # from perlunicode
2231 0     0   0 my $uni = 0x10000 + (hex($_[0]) - 0xD800) * 0x400 + (hex($_[1]) - 0xDC00);
2232 0         0 my $un = pack('U*', $uni);
2233 0         0 utf8::encode( $un );
2234 0         0 return $un;
2235             }
2236              
2237              
2238             sub _decode_unicode {
2239 0     0   0 my $un = pack('U', hex shift);
2240 0         0 utf8::encode( $un );
2241 0         0 return $un;
2242             }
2243              
2244             #
2245             # Setup for various Perl versions (the code from Test::ModuleVersion::JSON::PP58)
2246             #
2247              
2248             BEGIN {
2249              
2250 1 50   1   5052 unless ( defined &utf8::is_utf8 ) {
2251 0         0 require Encode;
2252 0         0 *utf8::is_utf8 = *Encode::is_utf8;
2253             }
2254              
2255 1 50       5 if ( $] >= 5.008 ) {
2256 1         4 *Test::ModuleVersion::JSON::PP::JSON_PP_encode_ascii = \&_encode_ascii;
2257 1         4 *Test::ModuleVersion::JSON::PP::JSON_PP_encode_latin1 = \&_encode_latin1;
2258 1         2 *Test::ModuleVersion::JSON::PP::JSON_PP_decode_surrogates = \&_decode_surrogates;
2259 1         8 *Test::ModuleVersion::JSON::PP::JSON_PP_decode_unicode = \&_decode_unicode;
2260             }
2261              
2262 1 50 33     16 if ($] >= 5.008 and $] < 5.008003) { # join() in 5.8.0 - 5.8.2 is broken.
2263             package Test::ModuleVersion::JSON::PP;
2264 0         0 require subs;
2265 0         0 subs->import('join');
2266 0         0 eval q|
2267             sub join {
2268             return '' if (@_ < 2);
2269             my $j = shift;
2270             my $str = shift;
2271             for (@_) { $str .= $j . $_; }
2272             return $str;
2273             }
2274             |;
2275             }
2276              
2277              
2278             sub Test::ModuleVersion::JSON::PP::incr_parse {
2279 0     0   0 local $Carp::CarpLevel = 1;
2280 0   0     0 ( $_[0]->{_incr_parser} ||= Test::ModuleVersion::JSON::PP::IncrParser->new )->incr_parse( @_ );
2281             }
2282              
2283              
2284             sub Test::ModuleVersion::JSON::PP::incr_skip {
2285 0   0 0   0 ( $_[0]->{_incr_parser} ||= Test::ModuleVersion::JSON::PP::IncrParser->new )->incr_skip;
2286             }
2287              
2288              
2289             sub Test::ModuleVersion::JSON::PP::incr_reset {
2290 0   0 0   0 ( $_[0]->{_incr_parser} ||= Test::ModuleVersion::JSON::PP::IncrParser->new )->incr_reset;
2291             }
2292              
2293 1 50 0 0   626 eval q{
  0 0       0  
  0         0  
  0         0  
  0         0  
2294             sub Test::ModuleVersion::JSON::PP::incr_text : lvalue {
2295             $_[0]->{_incr_parser} ||= Test::ModuleVersion::JSON::PP::IncrParser->new;
2296              
2297             if ( $_[0]->{_incr_parser}->{incr_parsing} ) {
2298             Carp::croak("incr_text can not be called when the incremental parser already started parsing");
2299             }
2300             $_[0]->{_incr_parser}->{incr_text};
2301             }
2302             } if ( $] >= 5.006 );
2303              
2304             } # Setup for various Perl versions (the code from Test::ModuleVersion::JSON::PP58)
2305              
2306              
2307             ###############################
2308             # Utilities
2309             #
2310              
2311             BEGIN {
2312 1     1   76 eval 'require Scalar::Util';
2313 1 50       6 unless($@){
2314 1         3 *Test::ModuleVersion::JSON::PP::blessed = \&Scalar::Util::blessed;
2315 1         3 *Test::ModuleVersion::JSON::PP::reftype = \&Scalar::Util::reftype;
2316 1         321 *Test::ModuleVersion::JSON::PP::refaddr = \&Scalar::Util::refaddr;
2317             }
2318             else{ # This code is from Sclar::Util.
2319             # warn $@;
2320 0         0 eval 'sub UNIVERSAL::a_sub_not_likely_to_be_here { ref($_[0]) }';
2321             *Test::ModuleVersion::JSON::PP::blessed = sub {
2322 0         0 local($@, $SIG{__DIE__}, $SIG{__WARN__});
2323 0 0       0 ref($_[0]) ? eval { $_[0]->a_sub_not_likely_to_be_here } : undef;
  0         0  
2324 0         0 };
2325 0         0 my %tmap = qw(
2326             B::NULL SCALAR
2327             B::HV HASH
2328             B::AV ARRAY
2329             B::CV CODE
2330             B::IO IO
2331             B::GV GLOB
2332             B::REGEXP REGEXP
2333             );
2334             *Test::ModuleVersion::JSON::PP::reftype = sub {
2335 0         0 my $r = shift;
2336              
2337 0 0       0 return undef unless length(ref($r));
2338              
2339 0         0 my $t = ref(B::svref_2object($r));
2340              
2341             return
2342 0 0       0 exists $tmap{$t} ? $tmap{$t}
    0          
2343             : length(ref($$r)) ? 'REF'
2344             : 'SCALAR';
2345 0         0 };
2346             *Test::ModuleVersion::JSON::PP::refaddr = sub {
2347 0 0       0 return undef unless length(ref($_[0]));
2348              
2349 0         0 my $addr;
2350 0 0       0 if(defined(my $pkg = blessed($_[0]))) {
2351 0         0 $addr .= bless $_[0], 'Scalar::Util::Fake';
2352 0         0 bless $_[0], $pkg;
2353             }
2354             else {
2355 0         0 $addr .= $_[0]
2356             }
2357              
2358 0         0 $addr =~ /0x(\w+)/;
2359 0         0 local $^W;
2360             #no warnings 'portable';
2361 0         0 hex($1);
2362             }
2363 0         0 }
2364             }
2365              
2366              
2367             # shamely copied and modified from JSON::XS code.
2368              
2369             $Test::ModuleVersion::JSON::PP::true = do { bless \(my $dummy = 1), "Test::ModuleVersion::JSON::PP::Boolean" };
2370             $Test::ModuleVersion::JSON::PP::false = do { bless \(my $dummy = 0), "Test::ModuleVersion::JSON::PP::Boolean" };
2371              
2372 0 0   0   0 sub is_bool { defined $_[0] and UNIVERSAL::isa($_[0], "Test::ModuleVersion::JSON::PP::Boolean"); }
2373              
2374 0     0   0 sub true { $Test::ModuleVersion::JSON::PP::true }
2375 0     0   0 sub false { $Test::ModuleVersion::JSON::PP::false }
2376 0     0   0 sub null { undef; }
2377              
2378             ###############################
2379              
2380             package Test::ModuleVersion::JSON::PP::Boolean;
2381              
2382             use overload (
2383 0     0   0 "0+" => sub { ${$_[0]} },
  0         0  
2384 0     0   0 "++" => sub { $_[0] = ${$_[0]} + 1 },
  0         0  
2385 0     0   0 "--" => sub { $_[0] = ${$_[0]} - 1 },
  0         0  
2386 1         18 fallback => 1,
2387 1     1   6 );
  1         2  
2388              
2389              
2390             ###############################
2391              
2392             package Test::ModuleVersion::JSON::PP::IncrParser;
2393              
2394 1     1   130 use strict;
  1         2  
  1         50  
2395              
2396 1     1   6 use constant INCR_M_WS => 0; # initial whitespace skipping
  1         2  
  1         78  
2397 1     1   5 use constant INCR_M_STR => 1; # inside string
  1         2  
  1         58  
2398 1     1   5 use constant INCR_M_BS => 2; # inside backslash
  1         3  
  1         49  
2399 1     1   5 use constant INCR_M_JSON => 3; # outside anything, count nesting
  1         1  
  1         52  
2400 1     1   6 use constant INCR_M_C0 => 4;
  1         2  
  1         51  
2401 1     1   5 use constant INCR_M_C1 => 5;
  1         2  
  1         1461  
2402              
2403             $Test::ModuleVersion::JSON::PP::IncrParser::VERSION = '1.01';
2404              
2405             my $unpack_format = $] < 5.006 ? 'C*' : 'U*';
2406              
2407             sub new {
2408 0     0   0 my ( $class ) = @_;
2409              
2410 0         0 bless {
2411             incr_nest => 0,
2412             incr_text => undef,
2413             incr_parsing => 0,
2414             incr_p => 0,
2415             }, $class;
2416             }
2417              
2418              
2419             sub incr_parse {
2420 0     0   0 my ( $self, $coder, $text ) = @_;
2421              
2422 0 0       0 $self->{incr_text} = '' unless ( defined $self->{incr_text} );
2423              
2424 0 0       0 if ( defined $text ) {
2425 0 0 0     0 if ( utf8::is_utf8( $text ) and !utf8::is_utf8( $self->{incr_text} ) ) {
2426 0         0 utf8::upgrade( $self->{incr_text} ) ;
2427 0         0 utf8::decode( $self->{incr_text} ) ;
2428             }
2429 0         0 $self->{incr_text} .= $text;
2430             }
2431              
2432              
2433 0         0 my $max_size = $coder->get_max_size;
2434              
2435 0 0       0 if ( defined wantarray ) {
2436              
2437 0 0       0 $self->{incr_mode} = INCR_M_WS unless defined $self->{incr_mode};
2438              
2439 0 0       0 if ( wantarray ) {
2440 0         0 my @ret;
2441              
2442 0         0 $self->{incr_parsing} = 1;
2443              
2444 0         0 do {
2445 0         0 push @ret, $self->_incr_parse( $coder, $self->{incr_text} );
2446              
2447 0 0 0     0 unless ( !$self->{incr_nest} and $self->{incr_mode} == INCR_M_JSON ) {
2448 0 0       0 $self->{incr_mode} = INCR_M_WS if $self->{incr_mode} != INCR_M_STR;
2449             }
2450              
2451             } until ( length $self->{incr_text} >= $self->{incr_p} );
2452              
2453 0         0 $self->{incr_parsing} = 0;
2454              
2455 0         0 return @ret;
2456             }
2457             else { # in scalar context
2458 0         0 $self->{incr_parsing} = 1;
2459 0         0 my $obj = $self->_incr_parse( $coder, $self->{incr_text} );
2460 0 0       0 $self->{incr_parsing} = 0 if defined $obj; # pointed by Martin J. Evans
2461 0 0       0 return $obj ? $obj : undef; # $obj is an empty string, parsing was completed.
2462             }
2463              
2464             }
2465              
2466             }
2467              
2468              
2469             sub _incr_parse {
2470 0     0   0 my ( $self, $coder, $text, $skip ) = @_;
2471 0         0 my $p = $self->{incr_p};
2472 0         0 my $restore = $p;
2473              
2474 0         0 my @obj;
2475 0         0 my $len = length $text;
2476              
2477 0 0       0 if ( $self->{incr_mode} == INCR_M_WS ) {
2478 0         0 while ( $len > $p ) {
2479 0         0 my $s = substr( $text, $p, 1 );
2480 0 0 0     0 $p++ and next if ( 0x20 >= unpack($unpack_format, $s) );
2481 0         0 $self->{incr_mode} = INCR_M_JSON;
2482 0         0 last;
2483             }
2484             }
2485              
2486 0         0 while ( $len > $p ) {
2487 0         0 my $s = substr( $text, $p++, 1 );
2488              
2489 0 0       0 if ( $s eq '"' ) {
2490 0 0       0 if (substr( $text, $p - 2, 1 ) eq '\\' ) {
2491 0         0 next;
2492             }
2493              
2494 0 0       0 if ( $self->{incr_mode} != INCR_M_STR ) {
2495 0         0 $self->{incr_mode} = INCR_M_STR;
2496             }
2497             else {
2498 0         0 $self->{incr_mode} = INCR_M_JSON;
2499 0 0       0 unless ( $self->{incr_nest} ) {
2500 0         0 last;
2501             }
2502             }
2503             }
2504              
2505 0 0       0 if ( $self->{incr_mode} == INCR_M_JSON ) {
2506              
2507 0 0 0     0 if ( $s eq '[' or $s eq '{' ) {
    0 0        
    0          
2508 0 0       0 if ( ++$self->{incr_nest} > $coder->get_max_depth ) {
2509 0         0 Carp::croak('json text or perl structure exceeds maximum nesting level (max_depth set too low?)');
2510             }
2511             }
2512             elsif ( $s eq ']' or $s eq '}' ) {
2513 0 0       0 last if ( --$self->{incr_nest} <= 0 );
2514             }
2515             elsif ( $s eq '#' ) {
2516 0         0 while ( $len > $p ) {
2517 0 0       0 last if substr( $text, $p++, 1 ) eq "\n";
2518             }
2519             }
2520              
2521             }
2522              
2523             }
2524              
2525 0         0 $self->{incr_p} = $p;
2526              
2527 0 0 0     0 return if ( $self->{incr_mode} == INCR_M_STR and not $self->{incr_nest} );
2528 0 0 0     0 return if ( $self->{incr_mode} == INCR_M_JSON and $self->{incr_nest} > 0 );
2529              
2530 0 0       0 return '' unless ( length substr( $self->{incr_text}, 0, $p ) );
2531              
2532 0         0 local $Carp::CarpLevel = 2;
2533              
2534 0         0 $self->{incr_p} = $restore;
2535 0         0 $self->{incr_c} = $p;
2536              
2537 0         0 my ( $obj, $tail ) = $coder->PP_decode_json( substr( $self->{incr_text}, 0, $p ), 0x10000001 );
2538              
2539 0         0 $self->{incr_text} = substr( $self->{incr_text}, $p );
2540 0         0 $self->{incr_p} = 0;
2541              
2542 0 0       0 return $obj or '';
2543             }
2544              
2545              
2546             sub incr_text {
2547 0 0   0   0 if ( $_[0]->{incr_parsing} ) {
2548 0         0 Carp::croak("incr_text can not be called when the incremental parser already started parsing");
2549             }
2550 0         0 $_[0]->{incr_text};
2551             }
2552              
2553              
2554             sub incr_skip {
2555 0     0   0 my $self = shift;
2556 0         0 $self->{incr_text} = substr( $self->{incr_text}, $self->{incr_c} );
2557 0         0 $self->{incr_p} = 0;
2558             }
2559              
2560              
2561             sub incr_reset {
2562 0     0   0 my $self = shift;
2563 0         0 $self->{incr_text} = undef;
2564 0         0 $self->{incr_p} = 0;
2565 0         0 $self->{incr_mode} = 0;
2566 0         0 $self->{incr_nest} = 0;
2567 0         0 $self->{incr_parsing} = 0;
2568             }
2569              
2570             package
2571             Test::ModuleVersion::ModuleURL;
2572             our @ISA = ('Test::ModuleVersion::Object::Simple');
2573 1     1   7 use strict;
  1         1  
  1         41  
2574 1     1   6 use warnings;
  1         1  
  1         765  
2575 4     4   18 sub has { __PACKAGE__->Test::ModuleVersion::Object::Simple::attr(@_) }
2576              
2577             has distnames => sub { {} };
2578             has privates => sub { {} };
2579             has 'error';
2580             has lwp => 'auto';
2581              
2582             sub get {
2583 0     0   0 my ($self, $module, $version, $opts) = @_;
2584            
2585 0   0     0 $opts ||= {};
2586 0         0 my $distnames = $self->distnames;
2587 0         0 my $privates = $self->privates;
2588 0         0 my $lwp = $self->lwp;
2589              
2590             # Module
2591 0         0 my $module_dist = $module;
2592 0 0       0 $module_dist = $distnames->{$module} if defined $distnames->{$module};
2593 0         0 $module_dist =~ s/::/-/g;
2594            
2595 0         0 my $url;
2596 0 0       0 if ($url = $privates->{$module}) {
2597 0         0 $url =~ s/%M/"$module_dist-$version"/e;
  0         0  
2598             }
2599             else {
2600            
2601             # Get dounload URL using metaCPAN api
2602 0         0 my $metacpan_api = 'http://api.metacpan.org/v0';
2603 0         0 my $search = "release/_search?q=name:$module_dist-$version"
2604             . "&fields=download_url,name";
2605 0         0 my $module_info = "$metacpan_api/$search";
2606 0         0 my $res = {};
2607 0         0 my $agent;
2608 0 0 0     0 if ($lwp eq 'use' || $lwp eq 'auto' && eval { require LWP::UserAgent; LWP::UserAgent->VERSION(5.802) })
  0   0     0  
  0         0  
2609             {
2610 0         0 require LWP::UserAgent;
2611 0         0 $agent = 'LWP::UserAgent';
2612 0         0 my $ua = LWP::UserAgent->new(
2613             parse_head => 0,
2614             env_proxy => 1,
2615             agent => "Test::ModuleVersion/$VERSION",
2616             timeout => 30
2617             );
2618 0         0 my $r = $ua->get($module_info);
2619 0         0 $agent = 'LWP::UserAgent';
2620 0         0 $res->{success} = $r->is_success;
2621 0         0 $res->{status_line} = $r->status_line;
2622 0         0 $res->{content} = $r->content;
2623             }
2624             else {
2625 0         0 $agent = 'HTTP::Tiny';
2626 0         0 my $ua = Test::ModuleVersion::HTTP::Tiny->new;
2627 0         0 my $r = $ua->get($module_info);
2628 0         0 $res->{success} = $r->{success};
2629 0         0 $res->{status_line} = "$r->{status} $r->{reason}";
2630 0         0 $res->{content} = $r->{content};
2631             }
2632            
2633 0         0 my $error;
2634 0 0 0     0 if ($res->{success} && !$ENV{TEST_MODULEVERSION_REQUEST_FAIL}) {
2635 0         0 my $release = Test::ModuleVersion::JSON::PP::decode_json $res->{content};
2636 0         0 $url = $release->{hits}{hits}[0]{fields}{download_url};
2637 0 0       0 $error = "$module_dist-$version is unknown" unless defined $url;
2638             }
2639             else {
2640 0         0 $error = "Request to metaCPAN fail($res->{status_line}):$agent:$module_info";
2641             }
2642 0         0 $self->error($error);
2643             }
2644            
2645 0         0 return $url;
2646             }
2647              
2648              
2649             package Test::ModuleVersion;
2650             our @ISA = ('Test::ModuleVersion::Object::Simple');
2651 1     1   6 use strict;
  1         3  
  1         29  
2652 1     1   5 use warnings;
  1         2  
  1         33  
2653 1     1   1080 use ExtUtils::Installed;
  1         151403  
  1         50  
2654 1     1   10 use Carp 'croak';
  1         3  
  1         69  
2655 1     1   1219 use Data::Dumper;
  1         6370  
  1         1143  
2656              
2657 6     6 0 22 sub has { __PACKAGE__->Test::ModuleVersion::Object::Simple::attr(@_) }
2658             has before => '';
2659             has distnames => sub { {} };
2660             has default_ignore => sub { ['Perl', 'Test::ModuleVersion'] };
2661             has lib => sub { [] };
2662             has modules => sub { [] };
2663             has privates => sub { {} };
2664              
2665             sub detect {
2666 0     0 1 0 my ($self, %opts) = @_;
2667 0   0     0 my $ignore = $opts{ignore} || [];
2668            
2669             # Detect installed modules
2670 0         0 my $ei = ExtUtils::Installed->new;
2671 0         0 my @modules;
2672 0         0 for my $module (sort $ei->modules) {
2673 0 0       0 next if grep { $module eq $_ } @$ignore;
  0         0  
2674 0         0 my $version = $ei->version($module);
2675 0 0       0 push @modules, [$module => $version] if length $version;
2676             }
2677              
2678 0         0 return \@modules;
2679             }
2680              
2681             sub test_script {
2682 4     4 1 18 my ($self, %opts) = @_;
2683            
2684             # Code
2685 4         7 my $code;
2686              
2687             # Library path
2688 4 50       15 my $libs = ref $self->lib ? $self->lib : [$self->lib];
2689 4         23 $code .= "use FindBin;\n";
2690 4         18 $code .= qq|use lib "\$FindBin::Bin/$_";\n| for @$libs;
2691            
2692             # Before
2693 4         19 $code .= $self->before . "\n";
2694            
2695             # Reffer this module
2696 4         13 $code .= "# Created by Test::ModuleVersion $Test::ModuleVersion::VERSION\n";
2697              
2698             # Test code
2699 4         7 $code .= <<'EOS';
2700             use Test::More;
2701             use strict;
2702             use warnings;
2703             use ExtUtils::Installed;
2704             EOS
2705            
2706             # Main
2707 4         8 $code .= <<'EOS';
2708              
2709             sub main {
2710             my $command = shift;
2711             my @options = @_;
2712            
2713             die qq/command "$command" is unkonwn command/
2714             if defined $command && $command ne 'list';
2715            
2716             my $list_failed;
2717             my $lwp = 'auto';
2718             for my $option (@options) {
2719             if ($option eq '--fail') { $list_failed = 1 }
2720             elsif ($option eq '--lwp') { $lwp = 'use' }
2721             elsif ($option eq '--no-lwp') { $lwp = 'no' }
2722             else { die qq/list $option is unknown option/ }
2723             }
2724            
2725             if (defined $command) {
2726             my $builder = Test::More->builder;
2727             open my $out_fh, '>', undef;
2728             $builder->output($out_fh);
2729             $builder->failure_output($out_fh);
2730             $builder->todo_output($out_fh);
2731             }
2732              
2733             my $modules = [];
2734             my $failed = [];
2735             my $require_ok;
2736             my $version_ok;
2737             my $version;
2738            
2739             plan tests => <%%%%%% test_count %%%%%%>;
2740              
2741             EOS
2742            
2743             # Module and version check
2744 4         8 my $test_count = 0;
2745 4         7 for my $m (@{$self->modules}) {
  4         12  
2746 10         19 my ($module, $version) = @$m;
2747 10         65 $code .= " # $module\n"
2748             . " \$require_ok = require_ok('$module');\n"
2749             . " \$version_ok = is(\$${module}::VERSION, '$version', '$module version: $version');\n"
2750             . " push \@\$modules, ['$module' => '$version'];\n"
2751             . " push \@\$failed, ['$module' => '$version'] unless \$require_ok && \$version_ok;\n\n";
2752 10         24 $test_count += 2;
2753             }
2754            
2755             # Print module URLs
2756 4         9 $code .= <<'EOS';
2757             # Print module URLs
2758             if (defined $command) {
2759             my $distnames = <%%%%%% distnames %%%%%%>
2760             ;
2761             my $privates = <%%%%%% privates %%%%%%>
2762             ;
2763             my $tm = Test::ModuleVersion->new;
2764             my @ms = $command eq 'list' && $list_failed ? @$failed
2765             : $command eq 'list' ? @$modules
2766             : [];
2767             for my $m (@ms) {
2768             my ($module, $version) = @$m;
2769             my $mu = Test::ModuleVersion::ModuleURL->new;
2770             $mu->distnames($distnames);
2771             $mu->privates($privates);
2772             $mu->lwp($lwp);
2773             my $url = $mu->get($module, $version);
2774             if (defined $url) { print "$url\n" }
2775             else { print STDERR $mu->error . "\n" }
2776             }
2777             }
2778             }
2779              
2780             EOS
2781            
2782             # Embbed Test::ModuleVersion
2783 4         14 $code .= $self->_source . "\n";
2784            
2785             # Run
2786 4         35 $code .= "package main;\n"
2787             . "main(\@ARGV);\n";
2788            
2789             # Test count
2790 4         41 $code =~ s/<%%%%%% test_count %%%%%%>/$test_count/e;
  4         200  
2791            
2792             # Distribution names
2793 4         24 my $distnames_code = Data::Dumper->new([$self->distnames])->Terse(1)->Indent(2)->Dump;
2794 4         404 $code =~ s/<%%%%%% distnames %%%%%%>/$distnames_code/e;
  4         247  
2795              
2796             # Private repositories
2797 4         17 my $privates_code = Data::Dumper->new([$self->privates])->Terse(1)->Indent(2)->Dump;
2798 4         220 $code =~ s/<%%%%%% privates %%%%%%>/$privates_code/e;
  4         237  
2799            
2800 4 50       17 if (my $file = $opts{output}) {
2801 0 0       0 open my $fh, '>', $file
2802             or die qq/Can't open file "$file": $!/;
2803 0         0 print $fh $code;
2804             }
2805 4         58 return $code;
2806             }
2807              
2808             sub _source {
2809 4     4   6 my $self = shift;
2810            
2811             # Source
2812 4         7 my $class = __PACKAGE__;
2813 4         16 $class =~ s/::/\//g;
2814 4         6 $class .= '.pm';
2815 4         8 my $path = $INC{$class};
2816 4 50       259 open my $fh, '<', $path
2817             or croak qq/Can't open "$path": $!/;
2818 4         6 my $source;
2819 4         106 while (my $line = <$fh>) {
2820 11312 100       17501 last if $line =~ /^=head1/;
2821 11308         23293 $source .= $line;
2822             }
2823 4         814 return $source;
2824             }
2825              
2826             1;
2827              
2828             =head1 NAME
2829              
2830             Test::ModuleVersion - Module version test generator
2831              
2832             =head1 CAUTION
2833              
2834             (2013/3/20)
2835              
2836             Sorry. This module is DEPRECATED because L and L is much better.
2837              
2838             If you want to install moudles, use L and L instead.
2839              
2840             See L
2841              
2842             If you want to test module version, you write test by yourself.
2843              
2844             is($DBIx::Custom::VERSION, '0.2108');
2845              
2846             This module will be removed from CPAN on 2018/3/1
2847              
2848             =head1 SYNOPSIS
2849              
2850             use Test::ModuleVersion;
2851             my $tm = Test::ModuleVersion->new;
2852             $tm->modules([
2853             ['DBIx::Custom' => '0.2108'],
2854             ['Validator::Custom' => '0.1426']
2855             ]);
2856             $tm->test_script(output => 't/module.t');
2857              
2858             =head1 DESCRIPTION
2859              
2860             L is test generator for module version check.
2861             If you run the test generated by L,
2862             you can check the module version.
2863              
2864             If module version test is failed, you can list module URLs.
2865              
2866             =head2 Create version test
2867              
2868             Let's create version test.
2869              
2870             # mvt.pl
2871             my $tm = Test::ModuleVersion->new;
2872             $tm->modules([
2873             ['DBIx::Custom' => '0.2108'],
2874             ['Validator::Custom' => '0.1426']
2875             ]);
2876             $tm->test_script(output => 't/module.t');
2877              
2878             C attribute is set to the pairs of module and version.
2879             C method print version test into C file.
2880              
2881             Run C
2882              
2883             $ perl mvt.pl
2884              
2885             Test script C is created.
2886              
2887             ...
2888             $require_ok = require_ok('DBIx::Custom');
2889             $version_ok = is($DBIx::Custom::VERSION, '0.2108', 'DBIx::Custom version: 0.2108');
2890              
2891             $require_ok = require_ok('Validator::Custom');
2892             $version_ok = is($Validator::Custom::VERSION, '0.1426', 'DBIx::Custom version: 0.1426');
2893             ...
2894              
2895             =head2 Run version test
2896              
2897             Run version test.
2898              
2899             $ perl t/module.t
2900              
2901             If module is not installed or version is different,
2902             test fail.
2903              
2904             ok 1 - require DBIx::Custom;
2905             not ok 2 - DBIx::Custom version: 0.2108
2906             # Failed test 'DBIx::Custom version: 0.2108'
2907             # at t/module.t.pl line 13.
2908             # got: '0.2106'
2909             # expected: '0.2108'
2910              
2911             ok 2 - require Validator::Custom;
2912             ok 3 - Validator::Custom version: 0.1426
2913              
2914             =head2 List module URLs
2915              
2916             You can list moudle URLs by C command
2917              
2918             $ perl t/module.t list
2919              
2920             All module URLs in version test is output to C.
2921              
2922             http://cpan.metacpan.org/authors/id/K/KI/KIMOTO/DBIx-Custom-0.2108.tar.gz
2923             ...
2924              
2925             You can list only test failed module URLs by C<--fail> option
2926              
2927             $ perl t/module.t list --fail
2928              
2929             =head1 Advanced
2930              
2931             =head2 Module installation by L
2932              
2933             $ perl t/module.t list --fail | perl cpanm -L extlib
2934              
2935             Module installation is very easy. Test failed module
2936             is installed into C directory by L.
2937              
2938             =head2 HTTP client
2939              
2940             L version switch two HTTP client as necessary.
2941              
2942             =over 2
2943              
2944             =item 1. LWP::UserAgent
2945              
2946             =item 2. HTTP::Tiny
2947              
2948             =back
2949              
2950             These module is used to get module URLs from metaCPAN.
2951              
2952             If L 5.802+ is installed, L
2953             is seleced. If not, L is selected.
2954              
2955             C<--lwp> option force L.
2956              
2957             $ perl t/module.t list --lwp
2958              
2959             C<--no-lwp> option force L.
2960              
2961             $ perl t/module.t list --no-lwp
2962              
2963             =head2 HTTP proxy
2964              
2965             export http_proxy=http://hostname:3001
2966              
2967             C environment variable enable you to use proxy server.
2968              
2969             =head2 HTTP proxy authentication
2970              
2971             export http_proxy=http://username:password@hostname:3001
2972              
2973             If L 5.802+ is installed,
2974             proxy authentication is available.
2975             L don't support proxy authentication.
2976              
2977             =head1 EXAMPELS
2978              
2979             =head2 Basic1
2980              
2981             # Directory
2982             t / mvt.pl
2983             / module.t
2984            
2985             extlib / lib / perl5 / Object / Simple.pm
2986             / Validator / Custom.pm
2987              
2988             features:
2989              
2990             =over 2
2991              
2992             =item 1. Module is installed in C
2993              
2994             =item 2. Perl 5.008007+ is required
2995              
2996             =item 3. Object::Simple 3.625, Validator::Custom 0.1401
2997              
2998             =back
2999              
3000             use Test::ModuleVersion;
3001             use FindBin;
3002             my $tm = Test::ModuleVersion->new;
3003             $tm->lib('../extlib/lib/perl5');
3004             $tm->before(<<'EOS');
3005             use 5.008007;
3006            
3007             =pod
3008              
3009             run mvt.pl to create this module version test(t/module.t).
3010              
3011             perl mvt.pl
3012            
3013             =cut
3014             EOS
3015             $tm->modules([
3016             ['Object::Simple' => '3.0625'],
3017             ['Validator::Custom' => '0.1401']
3018             ]);
3019             $tm->test_script(output => "$FindBin::Bin/t/module.t");
3020              
3021             =head2 Basic2
3022              
3023             # Directory
3024             t / mvt.pl
3025             / module.t
3026            
3027             extlib / lib / perl5 / LWP.pm
3028              
3029             features:
3030              
3031             =over 2
3032              
3033             =item 1. LWP 6.03
3034              
3035             LWP module distribution name is C.
3036             If module name is different from distribution name,
3037             you can use C attribute.
3038              
3039             =back
3040              
3041             use Test::ModuleVersion;
3042             use FindBin;
3043             my $tm = Test::ModuleVersion->new;
3044             $tm->lib('../extlib/lib/perl5');
3045             $tm->distnames({
3046             'LWP' => 'libwww-perl',
3047             });
3048             $tm->modules([
3049             ['LWP' => '6.03'],
3050             ]);
3051             $tm->test_script(output => "$FindBin::Bin/t/module.t");
3052            
3053             =head2 Basic3
3054              
3055             # Directory
3056             t / mvt.pl
3057             / module.t
3058            
3059             extlib / lib / perl5 / SomeModule.pm
3060              
3061             features:
3062              
3063             =over 2
3064              
3065             =item 1. SomeModule 0.03 don't exist in CPAN
3066              
3067             =item 2. SomeModule exist in http://myhost/SomeModule-0.03.tar.gz
3068              
3069             SomeModule is private module.
3070             If module exist in some URL,
3071             you can use C attribute.
3072              
3073             =back
3074              
3075             use Test::ModuleVersion;
3076             use FindBin;
3077             my $tm = Test::ModuleVersion->new;
3078             $tm->lib('../extlib/lib/perl5');
3079             $tm->privates({
3080             'SomeModule' => 'http://myhost/%M.tar.gz',
3081             });
3082             $tm->modules([
3083             ['SomeModule' => '0.03'],
3084             ]);
3085             $tm->test_script(output => "$FindBin::Bin/t/module.t");
3086              
3087             =head1 ATTRIBUTES
3088              
3089             =head2 C
3090              
3091             my $code = $self->before;
3092             $tm = $tm->before($code);
3093              
3094             You can add some code before version test.
3095              
3096             $tm->before(<<'EOS');
3097             use 5.008007;
3098            
3099             =pod
3100            
3101             You can create this script(t/module.t) by the following command.
3102              
3103             perl mvt.pl
3104            
3105             =cut
3106            
3107             EOS
3108              
3109             =head2 C
3110              
3111             my $distnames = $self->distnames;
3112             $tm = $tm->distnames({
3113             'LWP' => 'libwww-perl',
3114             'IO::Compress::Base' => 'IO-Compress',
3115             'Cwd' => 'PathTools',
3116             'File::Spec' => 'PathTools',
3117             'List::Util' => 'Scalar-List-Utils',
3118             'Scalar::Util' => 'Scalar-List-Utils'
3119             ...
3120             });
3121              
3122             Module distribution name corresponding to module name.
3123             Some module have different distribution name.
3124             For example, L module distribution name is C.
3125              
3126             you must set C attribute to get module URL.
3127              
3128             =head2 C
3129              
3130             my $lib = $self->lib;
3131             $tm = $tm->lib('../extlib/lib/perl5');
3132             $tm = $tm->lib(['../extlib/lib/perl5', ...]);
3133              
3134             Module including pass from version test directory.
3135             C is added to version test.
3136              
3137             use lib "$FindBin::Bin/../extlib/lib/perl5";
3138              
3139             =head2 C
3140              
3141             my $modules = $tm->modules;
3142             $tm = $tm->modules($modules);
3143              
3144             Pairs of module and version.
3145              
3146             $tm->modules([
3147             ['DBIx::Custom' => '0.2108'],
3148             ['Validator::Custom' => '0.1426']
3149             ]);
3150              
3151             Note that version must be string(C<'0.1426'>), not number(C<0.1426>).
3152              
3153             =head2 C
3154              
3155             my $privates = $tm->privates;
3156             $tm = $tm->privates({
3157             'SomeModule' => 'http://localhost/~kimoto/%M.tar.gz'
3158             });
3159              
3160             Private module URLs.
3161             you can get module URL if the module don't exist in CPAN.
3162             C<%M> is replaced by C like C.
3163              
3164             =head1 METHODS
3165              
3166             =head2 C
3167              
3168             my $modules = $tm->detect;
3169             my $modules = $tm->detect(ignore => ['Perl', 'Test::ModuleVersion']);
3170              
3171             Get all installed module.
3172             If you set C option, the module is ignored.
3173              
3174             Note that L is used internally.
3175             This information will be not accurate in some cases.
3176              
3177             =head2 C
3178              
3179             my $test_script = $tm->test_script;
3180             $tm->test_script(output => 't/module.t');
3181              
3182             Return version test as string.
3183             If C option is set, test is output to the file.
3184              
3185             =head1 BACKWARDS COMPATIBILITY POLICY
3186              
3187             If a functionality is DEPRECATED, you can know it by DEPRECATED warnings
3188             except for attribute method.
3189             You can check all DEPRECATED functionalities by document.
3190             DEPRECATED functionality is removed after five years,
3191             but if at least one person use the functionality and tell me that thing
3192             I extend one year each time he tell me it.
3193              
3194             EXPERIMENTAL functionality will be changed without warnings.
3195              
3196             =head1 AUTHOR
3197              
3198             Yuki Kimoto, C<< >>
3199              
3200             =head1 LICENSE AND COPYRIGHT
3201              
3202             Copyright 2012 Yuki Kimoto.
3203              
3204             This program is free software; you can redistribute it and/or modify it
3205             under the terms of either: the GNU General Public License as published
3206             by the Free Software Foundation; or the Artistic License.
3207              
3208             See http://dev.perl.org/licenses/ for more information.
3209              
3210             =cut