Hello community,

here is the log from the commit of package perl-JSON-Validator for 
openSUSE:Factory checked in at 2019-09-30 16:01:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-JSON-Validator (Old)
 and      /work/SRC/openSUSE:Factory/.perl-JSON-Validator.new.2352 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-JSON-Validator"

Mon Sep 30 16:01:28 2019 rev:8 rq:733997 version:3.15

Changes:
--------
--- /work/SRC/openSUSE:Factory/perl-JSON-Validator/perl-JSON-Validator.changes  
2019-08-13 13:20:17.505433742 +0200
+++ 
/work/SRC/openSUSE:Factory/.perl-JSON-Validator.new.2352/perl-JSON-Validator.changes
        2019-09-30 16:01:43.768844493 +0200
@@ -1,0 +2,10 @@
+Fri Sep 27 08:43:15 UTC 2019 -  <timueller+p...@suse.de>
+
+- updated to 3.15
+   see /usr/share/doc/packages/perl-JSON-Validator/Changes
+
+  3.15 2019-09-27T09:28:32+0900
+   - Add JSON::Validator::Error->details() #133
+   - Reversed the checksum and nice name for generated definitions #173
+
+-------------------------------------------------------------------

Old:
----
  JSON-Validator-3.14.tar.gz

New:
----
  JSON-Validator-3.15.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-JSON-Validator.spec ++++++
--- /var/tmp/diff_new_pack.CzGEex/_old  2019-09-30 16:01:44.488842577 +0200
+++ /var/tmp/diff_new_pack.CzGEex/_new  2019-09-30 16:01:44.488842577 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           perl-JSON-Validator
-Version:        3.14
+Version:        3.15
 Release:        0
 %define cpan_name JSON-Validator
 Summary:        Validate data against a JSON schema

++++++ JSON-Validator-3.14.tar.gz -> JSON-Validator-3.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/Changes 
new/JSON-Validator-3.15/Changes
--- old/JSON-Validator-3.14/Changes     2019-08-09 23:52:24.000000000 +0200
+++ new/JSON-Validator-3.15/Changes     2019-09-27 02:28:32.000000000 +0200
@@ -1,5 +1,9 @@
 Revision history for perl distribution JSON-Validator
 
+3.15 2019-09-27T09:28:32+0900
+ - Add JSON::Validator::Error->details() #133
+ - Reversed the checksum and nice name for generated definitions #173
+
 3.14 2019-08-09T23:52:24+0200
  - Fix failing tests #169
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/MANIFEST 
new/JSON-Validator-3.15/MANIFEST
--- old/JSON-Validator-3.14/MANIFEST    2019-08-09 23:52:25.000000000 +0200
+++ new/JSON-Validator-3.15/MANIFEST    2019-09-27 02:28:34.000000000 +0200
@@ -106,6 +106,7 @@
 t/spec/person.json
 t/spec/petstore.json
 't/spec/space bundle.json'
+t/spec/test-definitions-key.json
 t/spec/with-deep-mixed-ref.json
 t/spec/with-relative-ref.json
 t/stack/Some.pm
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/META.json 
new/JSON-Validator-3.15/META.json
--- old/JSON-Validator-3.14/META.json   2019-08-09 23:52:25.000000000 +0200
+++ new/JSON-Validator-3.15/META.json   2019-09-27 02:28:34.000000000 +0200
@@ -61,6 +61,6 @@
       },
       "x_IRC" : "irc://irc.freenode.net/#mojo"
    },
-   "version" : "3.14",
-   "x_serialization_backend" : "JSON::PP version 2.97001"
+   "version" : "3.15",
+   "x_serialization_backend" : "JSON::PP version 4.02"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/META.yml 
new/JSON-Validator-3.15/META.yml
--- old/JSON-Validator-3.14/META.yml    2019-08-09 23:52:25.000000000 +0200
+++ new/JSON-Validator-3.15/META.yml    2019-09-27 02:28:33.000000000 +0200
@@ -30,5 +30,5 @@
   homepage: https://mojolicious.org
   license: http://www.opensource.org/licenses/artistic-license-2.0
   repository: https://github.com/mojolicious/json-validator.git
-version: '3.14'
+version: '3.15'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/lib/JSON/Validator/Error.pm 
new/JSON-Validator-3.15/lib/JSON/Validator/Error.pm
--- old/JSON-Validator-3.14/lib/JSON/Validator/Error.pm 2019-06-04 
21:37:12.000000000 +0200
+++ new/JSON-Validator-3.15/lib/JSON/Validator/Error.pm 2019-09-27 
02:18:23.000000000 +0200
@@ -3,16 +3,92 @@
 
 use overload q("") => \&to_string, bool => sub {1}, fallback => 1;
 
+our $MESSAGES = {
+  allOf => {type => '/allOf Expected %3 - got %4.'},
+  anyOf => {type => '/anyOf Expected %3 - got %4.'},
+  array => {
+    additionalItems => 'Invalid number of items: %3/%4.',
+    maxItems        => 'Too many items: %3/%4.',
+    minItems        => 'Not enough items: %3/%4.',
+    uniqueItems     => 'Unique items required.',
+  },
+  const   => {const => 'Does not match const: %3.'},
+  enum    => {enum  => 'Not in enum list: %3.'},
+  integer => {
+    maximum    => '%3 > maximum(%4)',
+    minimum    => '%3 < minimum(%4)',
+    multipleOf => 'Not multiple of %3.',
+  },
+  not    => {not  => 'Should not match.'},
+  null   => {null => 'Not null.'},
+  number => {
+    maximum    => '%3 > maximum(%4)',
+    minimum    => '%3 < minimum(%4)',
+    multipleOf => 'Not multiple of %3.',
+  },
+  object => {
+    additionalProperties => 'Properties not allowed: %3.',
+    maxProperties        => 'Too many properties: %3/%4.',
+    minProperties        => 'Not enough properties: %3/%4.',
+    required             => 'Missing property.',
+  },
+  oneOf => {
+    all_rules_match => 'All of the oneOf rules match.',
+    type            => '/oneOf Expected %3 - got %4.',
+  },
+  string => {
+    pattern   => 'String does not match %3.',
+    maxLength => 'String is too long: %3/%4.',
+    minLength => 'String is too short: %3/%4.',
+  }
+};
+
+has details => sub { [qw(generic generic)] };
+
+has message => sub {
+  my $self    = shift;
+  my $details = $self->details;
+  my $message;
+
+  if (($details->[0] || '') eq 'format') {
+    $message = '%3';
+  }
+  elsif (($details->[1] || '') eq 'type' and @$details == 3) {
+    $message = 'Expected %1 - got %3.';
+  }
+  elsif (my $group = $MESSAGES->{$details->[0]}) {
+    $message = $group->{$details->[1] || 'default'};
+  }
+
+  return join ' ', Failed => @$details unless defined $message;
+
+  $message =~ s!\%(\d)\b!{$details->[$1 - 1] // ''}!ge;
+  return $message;
+};
+
+has path => '/';
+
 sub new {
-  my $self = bless {}, shift;
-  @$self{qw(path message)} = ($_[0] || '/', $_[1] || '');
-  $self;
+  my $class = shift;
+
+  # Constructed with attributes
+  return $class->SUPER::new($_[0]) if ref $_[0] eq 'HASH';
+
+  # Constructed with ($path, ...)
+  my $self = $class->SUPER::new;
+  $self->{path} = shift || '/';
+
+  # Constructed with ($path, $message)
+  $self->message(shift) unless ref $_[0];
+
+  # Constructed with ($path, \@details)
+  $self->details(shift) if ref $_[0];
+
+  return $self;
 }
 
-sub message   { shift->{message} }
-sub path      { shift->{path} }
-sub to_string { sprintf '%s: %s', @{$_[0]}{qw(path message)} }
-sub TO_JSON   { {message => $_[0]->{message}, path => $_[0]->{path}} }
+sub to_string { sprintf '%s: %s', $_[0]->path, $_[0]->message }
+sub TO_JSON { {message => $_[0]->message, path => $_[0]->path} }
 
 1;
 
@@ -34,11 +110,58 @@
 
 =head1 ATTRIBUTES
 
+=head2 details
+
+  my $error     = $error->details(["generic", "generic"]);
+  my $error     = $error->details([qw(array type object)]);
+  my $error     = $error->details([qw(format date-time Invalid)]);
+  my $array_ref = $error->details;
+
+Details about the error:
+
+=over 2
+
+=item 1.
+
+Often the category of tests that was run. Example values: allOf, anyOf, array,
+const, enum, format, integer, not, null, number, object, oneOf and string.
+
+=item 2.
+
+Often the test that failed. Example values: additionalItems,
+additionalProperties, const, enum, maxItems, maxLength, maxProperties, maximum,
+minItems, minLength.  minProperties, minimum, multipleOf, not, null, pattern,
+required, type and uniqueItems,
+
+=item 3.
+
+The rest of the list contains parameters for the test that failed. It can be a
+plain human-readable string or numbers indicating things such as max/min
+values.
+
+=back
+
 =head2 message
 
   my $str = $error->message;
 
-A human readable description of the error. Defaults to empty string.
+A human readable description of the error. Defaults to being being constructed
+from L</details>. See the C<$MESSAGES> variable in the source code for more
+details.
+
+As an EXPERIMENTAL hack you can localize C<$JSON::Validator::Error::MESSAGES>
+to get i18n support. Example:
+
+  sub validate_i18n {
+    local $JSON::Validator::Error::MESSAGES = {
+      allOf => {type => '/allOf Forventet %3 - fikk %4.'},
+    };
+
+    my @error_norwegian = $jv->validate({age => 42});
+  }
+
+Note that the error messages might contain a mix of English and the local
+language. Run some tests to see how it looks.
 
 =head2 path
 
@@ -50,7 +173,9 @@
 
 =head2 new
 
-  my $error = JSON::Validator::Error->new($path, $message);
+  my $error = JSON::Validator::Error->new(\%attributes);
+  my $error = JSON::Validator::Error->new($path, \@details);
+  my $error = JSON::Validator::Error->new($path, \@details);
 
 Object constructor.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/lib/JSON/Validator.pm 
new/JSON-Validator-3.15/lib/JSON/Validator.pm
--- old/JSON-Validator-3.14/lib/JSON/Validator.pm       2019-08-09 
23:52:24.000000000 +0200
+++ new/JSON-Validator-3.15/lib/JSON/Validator.pm       2019-09-27 
02:28:32.000000000 +0200
@@ -23,8 +23,7 @@
 use constant RECURSION_LIMIT   => $ENV{JSON_VALIDATOR_RECURSION_LIMIT} || 100;
 use constant SPECIFICATION_URL => 'http://json-schema.org/draft-04/schema#';
 
-our $DEFINITIONS = 'definitions';
-our $VERSION = '3.14';
+our $VERSION = '3.15';
 our $YAML_LOADER = eval q[use YAML::XS 0.67; YAML::XS->can('Load')];  # 
internal
 our @EXPORT_OK   = qw(joi validate_json);
 
@@ -60,51 +59,55 @@
 
 sub bundle {
   my ($self, $args) = @_;
-  my @topics = ([undef, my $bundle = {}]);
   my ($cloner, $tied);
 
-  $topics[0][0]
+  my $schema
     = $args->{schema} ? $self->_resolve($args->{schema}) : $self->schema->data;
-
-  local $DEFINITIONS = $args->{ref_key} || $DEFINITIONS;
-  Mojo::Util::deprecated('bundle({ref_key => "..."}) will be removed.')
-    if $args->{ref_key};
+  my @topics = ([$schema, my $bundle = {}, '']);    # ([$from, $to], ...);
 
   if ($args->{replace}) {
     $cloner = sub {
-      my $from = shift;
-      my $ref  = ref $from;
-      $from = $tied->schema if $ref eq 'HASH' and $tied = tied %$from;
-      my $to = $ref eq 'ARRAY' ? [] : $ref eq 'HASH' ? {} : $from;
-      push @topics, [$from, $to] if $ref;
+      my $from      = shift;
+      my $from_type = ref $from;
+      $from = $tied->schema if $from_type eq 'HASH' and $tied = tied %$from;
+      my $to = $from_type eq 'ARRAY' ? [] : $from_type eq 'HASH' ? {} : $from;
+      push @topics, [$from, $to] if $from_type;
       return $to;
     };
   }
   else {
-    my %seen;
-    $bundle->{$DEFINITIONS} = $topics[0][0]{$DEFINITIONS} || {};
     $cloner = sub {
       my $from      = shift;
       my $from_type = ref $from;
 
-      if ($from_type eq 'HASH' and my $ref = tied %$from) {
-        return $from
-          if !$args->{schema}
-          and $ref->fqn =~ m!^\Q$self->{root_schema_url}\E\#!;
-
-        my $k = $self->_definitions_key($bundle, $ref, \%seen);
-        push @topics, [$ref->schema, $bundle->{$DEFINITIONS}{$k} ||= {}]
-          unless $seen{$ref->fqn}++;
-        tie my %ref, 'JSON::Validator::Ref', $ref->schema, "#/$DEFINITIONS/$k";
-        return \%ref;
+      $tied = $from_type eq 'HASH' && tied %$from;
+      unless ($tied) {
+        my $to = $from_type eq 'ARRAY' ? [] : $from_type eq 'HASH' ? {} : 
$from;
+        push @topics, [$from, $to] if $from_type;
+        return $to;
       }
 
-      my $to = $from_type eq 'ARRAY' ? [] : $from_type eq 'HASH' ? {} : $from;
-      push @topics, [$from, $to] if $from_type;
-      return $to;
+      return $from
+        if !$args->{schema}
+        and $tied->fqn =~ m!^\Q$self->{root_schema_url}\E\#!;
+
+      my $p = $self->_definitions_path($bundle, $tied);
+      unless ($self->{bundled_refs}{$tied->fqn}) {
+        $self->{bundled_refs}{$tied->fqn} = $tied;
+        push @topics, [$schema->{$p->[0]} || {}, $bundle->{$p->[0]} ||= {}];
+        push @topics, [$tied->schema, $bundle->{$p->[0]}{$p->[1]} ||= {}];
+      }
+
+      tie my %ref, 'JSON::Validator::Ref', $tied->schema, "#/$p->[0]/$p->[1]";
+      return \%ref;
     };
   }
 
+  Mojo::Util::deprecated('bundle({ref_key => "..."}) will be removed.')
+    if $args->{ref_key};
+  local $self->{definitions_key} = $args->{ref_key};
+  local $self->{bundled_refs}    = {};
+
   while (@topics) {
     my ($from, $to) = @{shift @topics};
     if (ref $from eq 'ARRAY') {
@@ -119,7 +122,6 @@
     }
   }
 
-  delete $bundle->{$DEFINITIONS} unless keys %{$bundle->{$DEFINITIONS}};
   return $bundle;
 }
 
@@ -225,27 +227,34 @@
   };
 }
 
-sub _definitions_key {
-  my ($self, $bundle, $ref, $seen) = @_;
+sub _definitions_path {
+  my ($self, $bundle, $ref) = @_;
+  my $definitions_key = $self->{definitions_key} || 'definitions';
+
+  # No need to rewrite, if it already has a nice name
+  if ($ref->fqn =~ m!#/$definitions_key/([^/]+)$!) {
+    my $key = $1;
+
+    if ( $self->{bundled_refs}{$ref->fqn}
+      or !$bundle->{$definitions_key}{$key}
+      or D($ref->schema) eq D($bundle->{$definitions_key}{$key}))
+    {
+      return [$definitions_key, $key];
+    }
+  }
 
-  # No need to rewrite, when it already has a nice name
-  return $1
-    if $ref->fqn =~ m!#/$DEFINITIONS/([^/]+)$!
-    and ($seen->{$ref->fqn}
-    or !$bundle->{$DEFINITIONS}{$1}
-    or D($ref->schema) eq D($bundle->{$DEFINITIONS}{$1}));
-
-  # Must mask path to file on disk
-  my $key       = $ref->fqn;
-  my $spec_path = (split '#', $key)[0];
+  # Generate definitions key based on filename
+  my ($spec_path, $fragment) = split '#', $ref->fqn;
+  my $key = $fragment;
   if (-e $spec_path) {
-    $key = sprintf '%s-%s', substr(sha1_sum($key), 0, 10),
-      path($spec_path)->basename;
+    $key = join '-', map { s!^\W+!!; $_ } grep {$_} path($spec_path)->basename,
+      $fragment, substr(sha1_sum($spec_path), 0, 10);
   }
 
   # Fallback or nicer path name
   $key =~ s![^\w-]!_!g;
-  $key;
+
+  return [$definitions_key, $key];
 }
 
 sub _get {
@@ -611,7 +620,7 @@
   if (my $rules = $schema->{not}) {
     push @errors, $self->_validate($to_json ? $$to_json : $_[1], $path, 
$rules);
     $self->_report_errors($path, 'not', \@errors) if REPORT;
-    return @errors ? () : (E $path, 'Should not match.');
+    return @errors ? () : (E $path, [not => 'not']);
   }
 
   if (my $rules = $schema->{allOf}) {
@@ -650,7 +659,7 @@
   }
 
   $self->_report_errors($path, 'allOf', \@errors) if REPORT;
-  return E $path, "/allOf Expected @{[join '/', _uniq(@expected)]} - got 
$type."
+  return E $path, [allOf => type => join('/', _uniq(@expected)), $type]
     if !@errors and @expected;
   return _add_path_to_error_messages(allOf => @errors) if @errors;
   return;
@@ -678,7 +687,7 @@
 
   $self->_report_errors($path, 'anyOf', \@errors) if REPORT;
   my $expected = join '/', _uniq(@expected);
-  return E $path, "/anyOf Expected $expected - got $type." unless @errors;
+  return E $path, [anyOf => type => $expected, $type] unless @errors;
   return _add_path_to_error_messages(anyOf => @errors);
 }
 
@@ -711,8 +720,8 @@
 
   return if @errors + @expected + 1 == @$rules;
   my $expected = join '/', _uniq(@expected);
-  return E $path, "All of the oneOf rules match." unless @errors + @expected;
-  return E $path, "/oneOf Expected $expected - got $type." unless @errors;
+  return E $path, [oneOf => 'all_rules_match'] unless @errors + @expected;
+  return E $path, [oneOf => type => $expected => $type] unless @errors;
   return _add_path_to_error_messages(oneOf => @errors);
 }
 
@@ -725,9 +734,9 @@
     return if $m eq S $i;
   }
 
-  local $" = ', ';
-  return E $path, sprintf 'Not in enum list: %s.', join ', ',
+  $enum = join ', ',
     map { (!defined or ref) ? Mojo::JSON::encode_json($_) : $_ } @$enum;
+  return E $path, [enum => enum => $enum];
 }
 
 sub _validate_type_const {
@@ -736,8 +745,7 @@
   my $m     = S $data;
 
   return if $m eq S $const;
-  return E $path, sprintf 'Does not match const: %s.',
-    Mojo::JSON::encode_json($const);
+  return E $path, [const => const => Mojo::JSON::encode_json($const)];
 }
 
 sub _validate_format {
@@ -746,7 +754,7 @@
   return do { warn "Format rule for '$schema->{format}' is missing"; return }
     unless $code;
   return unless my $err = $code->($value);
-  return E $path, $err;
+  return E $path, [format => $schema->{format}, $err];
 }
 
 sub _validate_type_any { }
@@ -756,21 +764,21 @@
   my @errors;
 
   if (ref $data ne 'ARRAY') {
-    return E $path, _expected(array => $data);
+    return E $path, [array => type => _guess_data_type($data)];
   }
   if (defined $schema->{minItems} and $schema->{minItems} > @$data) {
-    push @errors, E $path, sprintf 'Not enough items: %s/%s.', int @$data,
-      $schema->{minItems};
+    push @errors, E $path,
+      [array => minItems => int(@$data), $schema->{minItems}];
   }
   if (defined $schema->{maxItems} and $schema->{maxItems} < @$data) {
-    push @errors, E $path, sprintf 'Too many items: %s/%s.', int @$data,
-      $schema->{maxItems};
+    push @errors, E $path,
+      [array => maxItems => int(@$data), $schema->{maxItems}];
   }
   if ($schema->{uniqueItems}) {
     my %uniq;
     for (@$data) {
       next if !$uniq{S($_)}++;
-      push @errors, E $path, 'Unique items required.';
+      push @errors, E $path, [array => 'uniqueItems'];
       last;
     }
   }
@@ -797,8 +805,8 @@
       }
     }
     elsif (!$additional_items) {
-      push @errors, E $path, sprintf "Invalid number of items: %s/%s.",
-        int(@$data), int(@rules);
+      push @errors, E $path,
+        [array => additionalItems => int(@$data), int(@rules)];
     }
   }
   elsif (UNIVERSAL::isa($schema->{items}, 'HASH')) {
@@ -832,7 +840,7 @@
     return;
   }
 
-  return E $path, _expected(boolean => $value);
+  return E $path, [boolean => type => _guess_data_type($value)];
 }
 
 sub _validate_type_integer {
@@ -841,14 +849,14 @@
 
   return @errors if @errors;
   return if $value =~ /^-?\d+$/;
-  return E $path, "Expected integer - got number.";
+  return E $path, [integer => type => _guess_data_type($value)];
 }
 
 sub _validate_type_null {
   my ($self, $value, $path, $schema) = @_;
 
-  return E $path, 'Not null.' if defined $value;
-  return;
+  return unless defined $value;
+  return E $path, ['null', 'null'];
 }
 
 sub _validate_type_number {
@@ -858,10 +866,10 @@
   $expected ||= 'number';
 
   if (!defined $value or ref $value) {
-    return E $path, _expected($expected => $value);
+    return E $path, [$expected => type => _guess_data_type($value)];
   }
   unless (_is_number($value)) {
-    return E $path, "Expected $expected - got string."
+    return E $path, [$expected => type => _guess_data_type($value)]
       if !$self->{coerce}{numbers}
       or $value !~ /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
     $_[1] = 0 + $value;    # coerce input value
@@ -873,16 +881,16 @@
   if (my $e
     = _cmp($schema->{minimum}, $value, $schema->{exclusiveMinimum}, '<'))
   {
-    push @errors, E $path, "$value $e minimum($schema->{minimum})";
+    push @errors, E $path, [$expected => minimum => $value, 
$schema->{minimum}];
   }
   if (my $e
     = _cmp($value, $schema->{maximum}, $schema->{exclusiveMaximum}, '>'))
   {
-    push @errors, E $path, "$value $e maximum($schema->{maximum})";
+    push @errors, E $path, [$expected => maximum => $value, 
$schema->{maximum}];
   }
   if (my $d = $schema->{multipleOf}) {
     if (($value / $d) =~ /\.[^0]+$/) {
-      push @errors, E $path, "Not multiple of $d.";
+      push @errors, E $path, [$expected => multipleOf => $d];
     }
   }
 
@@ -895,17 +903,17 @@
   my ($additional, @errors, %rules);
 
   if (ref $data ne 'HASH') {
-    return E $path, _expected(object => $data);
+    return E $path, [object => type => _guess_data_type($data)];
   }
 
   my @dkeys = sort keys %$data;
   if (defined $schema->{maxProperties} and $schema->{maxProperties} < @dkeys) {
-    push @errors, E $path, sprintf 'Too many properties: %s/%s.', int @dkeys,
-      $schema->{maxProperties};
+    push @errors, E $path,
+      [object => maxProperties => int(@dkeys), $schema->{maxProperties}];
   }
   if (defined $schema->{minProperties} and $schema->{minProperties} > @dkeys) {
-    push @errors, E $path, sprintf 'Not enough properties: %s/%s.', int @dkeys,
-      $schema->{minProperties};
+    push @errors, E $path,
+      [object => minProperties => int(@dkeys), $schema->{minProperties}];
   }
   if (my $n_schema = $schema->{propertyNames}) {
     for my $name (keys %$data) {
@@ -942,12 +950,12 @@
   }
   elsif (my @k = grep { !$rules{$_} } @dkeys) {
     local $" = ', ';
-    return E $path, "Properties not allowed: @k.";
+    return E $path, [object => additionalProperties => join '/', @k];
   }
 
   for my $k (sort keys %required) {
     next if exists $data->{$k};
-    push @errors, E _path($path, $k), 'Missing property.';
+    push @errors, E _path($path, $k), [object => 'required'];
     delete $rules{$k};
   }
 
@@ -974,13 +982,13 @@
   my @errors;
 
   if (!defined $value or ref $value) {
-    return E $path, _expected(string => $value);
+    return E $path, [string => type => _guess_data_type($value)];
   }
   if (  B::svref_2object(\$value)->FLAGS & (B::SVp_IOK | B::SVp_NOK)
     and 0 + $value eq $value
     and $value * 0 == 0)
   {
-    return E $path, "Expected string - got number."
+    return E $path, [string => type => _guess_data_type($value)]
       unless $self->{coerce}{strings};
     $_[1] = "$value";    # coerce input value
   }
@@ -989,21 +997,19 @@
   }
   if (defined $schema->{maxLength}) {
     if (length($value) > $schema->{maxLength}) {
-      push @errors, E $path, sprintf "String is too long: %s/%s.",
-        length($value), $schema->{maxLength};
+      push @errors, E $path,
+        [string => maxLength => length($value), $schema->{maxLength}];
     }
   }
   if (defined $schema->{minLength}) {
     if (length($value) < $schema->{minLength}) {
-      push @errors, E $path, sprintf "String is too short: %s/%s.",
-        length($value), $schema->{minLength};
+      push @errors, E $path,
+        [string => minLength => length($value), $schema->{minLength}];
     }
   }
   if (defined $schema->{pattern}) {
     my $p = $schema->{pattern};
-    unless ($value =~ /$p/) {
-      push @errors, E $path, "String does not match '$p'";
-    }
+    push @errors, E $path, [string => pattern => $p] unless $value =~ /$p/;
   }
 
   return @errors;
@@ -1018,7 +1024,7 @@
   for my $e (@errors_with_index) {
     my $index = shift @$e;
     push @errors, map {
-      my $msg = sprintf '/%s/%s %s', $type, $index, $_->{message};
+      my $msg = sprintf '/%s/%s %s', $type, $index, $_->message;
       $msg =~ s!(\d+)\s/!$1/!g;
       E $_->path, $msg;
     } @$e;
@@ -1034,12 +1040,6 @@
   return "";
 }
 
-sub _expected {
-  my $type = _guess_data_type($_[1], []);
-  return "Expected $_[0] - got different $type." if $_[0] =~ /\b$type\b/;
-  return "Expected $_[0] - got $type.";
-}
-
 # _guess_data_type($data, [{type => ...}, ...])
 sub _guess_data_type {
   my $ref     = ref $_[0];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/t/bundle.t 
new/JSON-Validator-3.15/t/bundle.t
--- old/JSON-Validator-3.14/t/bundle.t  2019-06-01 11:27:46.000000000 +0200
+++ new/JSON-Validator-3.15/t/bundle.t  2019-09-27 02:18:23.000000000 +0200
@@ -21,57 +21,61 @@
   $bundled = $jv->bundle({
     replace => 1,
     schema  => {
-      name        => {'$ref' => '#/definitions/name'},
-      definitions => {name   => {type => 'string'}}
+      definitions => {name   => {type => 'string'}},
+      surname     => {'$ref' => '#/definitions/name'},
     },
   });
 
-  is $bundled->{name}{type}, 'string', "[$n] replace=1";
+  is $bundled->{surname}{type}, 'string', "[$n] replace=1";
 
   note "[$n] replace=0";
   $bundled = $jv->schema({
-    name        => {'$ref' => '#/definitions/name'},
-    age         => {'$ref' => 'b.json#/definitions/age'},
+    surname     => {'$ref' => '#/definitions/name'},
+    age         => {'$ref' => 'b.json#/definitions/years'},
     definitions => {name   => {type => 'string'}},
-    B => {id => 'b.json', definitions => {age => {type => 'integer'}}},
+    B => {id => 'b.json', definitions => {years => {type => 'integer'}}},
   })->bundle;
+  ok $bundled->{definitions}{name},
+    "[$n] definitions/name still in definitions";
   is $bundled->{definitions}{name}{type}, 'string',
-    "[$n] name still in definitions";
-  is $bundled->{definitions}{age}{type}, 'integer', "[$n] added to 
definitions";
-  isnt $bundled->{age}, $jv->schema->get('/age'),  "[$n] new age ref";
-  is $bundled->{name},  $jv->schema->get('/name'), "[$n] same name ref";
-  is $bundled->{age}{'$ref'}, '#/definitions/age',
-    "[$n] age \$ref point to /definitions/age";
-  is $bundled->{name}{'$ref'}, '#/definitions/name',
-    "[$n] name \$ref point to /definitions/name";
+    "[$n] definitions/name/type still in definitions";
+  is $bundled->{definitions}{years}{type}, 'integer',
+    "[$n] added to definitions";
+  isnt $bundled->{age},   $jv->schema->get('/age'),     "[$n] new age ref";
+  is $bundled->{surname}, $jv->schema->get('/surname'), "[$n] same surname 
ref";
+  is $bundled->{age}{'$ref'}, '#/definitions/years',
+    "[$n] age \$ref point to /definitions/years";
+  is $bundled->{surname}{'$ref'}, '#/definitions/name',
+    "[$n] surname \$ref point to /definitions/name";
 }
 
-is $jv->get([qw(name type)]), 'string', 'get /name/$ref';
-is $jv->get('/name/type'), 'string', 'get /name/type';
-is $jv->get('/name/$ref'), undef,    'get /name/$ref';
-is $jv->schema->get('/name/type'), 'string', 'schema get /name/type';
-is $jv->schema->get('/name/$ref'), '#/definitions/name',
-  'schema get /name/$ref';
+is $jv->get([qw(surname type)]), 'string', 'get /surname/$ref';
+is $jv->get('/surname/type'), 'string', 'get /surname/type';
+is $jv->get('/surname/$ref'), undef,    'get /surname/$ref';
+is $jv->schema->get('/surname/type'), 'string', 'schema get /surname/type';
+is $jv->schema->get('/surname/$ref'), '#/definitions/name',
+  'schema get /surname/$ref';
 
 $bundled = $jv->schema('data://main/bundled.json')->bundle;
 is_deeply [sort keys %{$bundled->{definitions}}], ['objtype'],
   'no dup definitions';
 
-my @pathlists = (
-  ['spec', 'with-deep-mixed-ref.json'],
-  ['spec', File::Spec->updir, 'spec', 'with-deep-mixed-ref.json'],
-);
-for my $pathlist (@pathlists) {
-  my $file = path $workdir, @$pathlist;
+for my $path (
+  ['test-definitions-key.json'],
+  ['with-deep-mixed-ref.json'],
+  ['with-deep-mixed-ref.json'],
+  [File::Spec->updir, 'spec', 'with-deep-mixed-ref.json'],
+  )
+{
+  my $file = path $workdir, 'spec', @$path;
+
+  my @expected = qw(age_json-SHA height unit_json-SHA weight_json-SHA);
+  $expected[0] = 'age_json-type-SHA'
+    if $path->[0] eq 'test-definitions-key.json';
+
   $bundled = $jv->schema($file)->bundle;
-  is_deeply [sort map { s!^[a-z0-9]{10}!SHA!; $_ }
-      keys %{$bundled->{definitions}}],
-    [qw(
-      SHA-age_json
-      SHA-unit_json
-      SHA-weight_json
-      height
-      )],
+  is_deeply [sort map { s!-[a-z0-9]{10}$!-SHA!; $_ }
+      keys %{$bundled->{definitions}}], \@expected,
     'right definitions in disk spec'
     or diag explain $bundled->{definitions};
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/t/coerce-default.t 
new/JSON-Validator-3.15/t/coerce-default.t
--- old/JSON-Validator-3.14/t/coerce-default.t  2019-06-04 21:37:12.000000000 
+0200
+++ new/JSON-Validator-3.15/t/coerce-default.t  2019-09-27 02:18:23.000000000 
+0200
@@ -30,11 +30,11 @@
 
 $jv->schema({
   type       => 'object',
-  properties => {tos => {type => 'boolean', default => 'invalid'}},
+  properties => {age => {type => 'number', default => 'invalid'}},
 });
 
 @errors = $jv->validate({});
-is $errors[0]{message}, 'Expected boolean - got string.',
+is $errors[0]->message, 'Expected number - got string.',
   'default values must be valid';
 
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/t/more-bundle.t 
new/JSON-Validator-3.15/t/more-bundle.t
--- old/JSON-Validator-3.14/t/more-bundle.t     2019-08-09 23:48:57.000000000 
+0200
+++ new/JSON-Validator-3.15/t/more-bundle.t     2019-09-27 02:18:23.000000000 
+0200
@@ -150,23 +150,20 @@
         return 1
           if (eq_deeply($got->{dupe_name}, {type => 'integer'})
           and eq_deeply($got->{$other_key}, {type => 'string'})
-          and eq_deeply($other_key, re(qr/-more-bundle2_yaml$/)))
-          or ((
-              eq_deeply($got->{dupe_name},  {type => 'string'})
+          and $other_key =~ qr/\bmore-bundle2_yaml-definitions_dupe_name-\w+$/)
+          or (eq_deeply($got->{dupe_name}, {type => 'string'})
           and eq_deeply($got->{$other_key}, {type => 'integer'})
-          and eq_deeply($other_key, re(qr/-more-bundle_yaml$/))
-          ));
+          and $other_key =~ qr/\bmore-bundle_yaml-definitions_dupe_name-\w+$/);
         return (0, 'uh oh, got: ' . (Test::More::explain($got))[0]);
       }),
 
       # begin i_contain_refs_to_same_named_definitions definition
       type       => 'object',
       properties => {
-        foo => {
-          '$ref' => re(qr/^#\/definitions\/(dupe_name|\w+-more-bundle_yaml)$/)
-        },
+        foo =>
+          {'$ref' => 
re(qr/^#\/definitions\/(dupe_name|more-bundle_yaml-.*)$/)},
         bar => {
-          '$ref' => re(qr/^#\/definitions\/(dupe_name|\w+-more-bundle2_yaml)/)
+          '$ref' => re(qr/^#\/definitions\/(dupe_name|more-bundle2_yaml-.*)$/)
         },
       },
     },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/JSON-Validator-3.14/t/spec/test-definitions-key.json 
new/JSON-Validator-3.15/t/spec/test-definitions-key.json
--- old/JSON-Validator-3.14/t/spec/test-definitions-key.json    1970-01-01 
01:00:00.000000000 +0100
+++ new/JSON-Validator-3.15/t/spec/test-definitions-key.json    2019-09-27 
02:18:23.000000000 +0200
@@ -0,0 +1,11 @@
+{
+  "type": "object",
+  "properties": {
+    "age": { "type": { "$ref": "../definitions/age.json#type" } },
+    "weight": { "$ref": "../definitions/weight.json" },
+    "height": { "$ref": "#/definitions/height" }
+  },
+  "definitions": {
+    "height": { "type": "integer" }
+  }
+}


Reply via email to