Fix incorrect handling of exotic fieldnames
Peter Rabbitson [Fri, 2 Nov 2012 16:20:24 +0000 (17:20 +0100)]
Changes
lib/Class/Accessor/Grouped.pm
t/accessors.t
t/accessors_ro.t
t/accessors_wo.t
t/lib/AccessorGroups.pm
t/lib/AccessorGroupsRO.pm
t/lib/AccessorGroupsWO.pm

diff --git a/Changes b/Changes
index 6a39c87..45b9eb1 100644 (file)
--- a/Changes
+++ b/Changes
@@ -6,6 +6,7 @@ Revision history for Class::Accessor::Grouped.
     - Switch all module loading to Module::Runtime and lose
       dependency on Class::Inspector
     - Simplify superclass traversal done by the 'inherited' group type
+    - Fix incorrect quoting of unusual hash keys (fieldnames)
 
 0.10006 2011-12-30 03:52 (UTC)
     - Silence warnings resulting from incomplete can() overrides
index 35d21de..c60ef7f 100644 (file)
@@ -571,58 +571,73 @@ if (! defined $USE_XS) {
   $xsa_autodetected++;
 }
 
+my $perlstring;
+if ($] < '5.008') {
+  require Data::Dumper;
+  my $d = Data::Dumper->new([])->Indent(0)->Purity(0)->Pad('')->Useqq(1)->Terse(1)->Freezer('')->Toaster('');
+  $perlstring = sub { $d->Values([shift])->Dump };
+}
+else {
+  require B;
+  $perlstring = \&B::perlstring;
+}
+
+
 my $maker_templates = {
   rw => {
     xs_call => 'accessors',
     pp_code => sub {
-      my $set = "set_$_[0]";
-      my $get = "get_$_[0]";
-      my $field = $_[1];
-      $field =~ s/'/\\'/g;
-
-      "
-        \@_ != 1
-          ? shift->$set('$field', \@_)
-          : shift->$get('$field')
-      "
+      # my ($group, $fieldname) = @_;
+      my $quoted_fieldname = $perlstring->($_[1]);
+      sprintf <<'EOS', ($_[0], $quoted_fieldname) x 2;
+
+@_ > 1
+  ? shift->set_%s(%s, @_)
+  : shift->get_%s(%s)
+EOS
+
     },
   },
   ro => {
     xs_call => 'getters',
     pp_code => sub {
-      my $get = "get_$_[0]";
-      my $field = $_[1];
-      $field =~ s/'/\\'/g;
-
-      "
-        \@_ == 1
-          ? shift->$get('$field')
-          : do {
-            my \$caller = caller;
-            my \$class = length( ref(\$_[0]) ) ? ref(\$_[0]) : \$_[0];
-            Carp::croak(\"'\$caller' cannot alter the value of '$field' \".
-                        \"(read-only attributes of class '\$class')\");
-          }
-      "
+      # my ($group, $fieldname) = @_;
+      my $quoted_fieldname = $perlstring->($_[1]);
+      sprintf  <<'EOS', $quoted_fieldname, $_[0], $quoted_fieldname;
+
+@_ > 1
+  ? do {
+    my $caller = caller;
+    my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
+    Carp::croak(sprintf
+      "'%%s' cannot alter the value of '%%s' (read-only attribute of class '%%s')",
+      $caller, %s, $class
+    );
+  }
+  : shift->get_%s(%s)
+EOS
+
     },
   },
   wo => {
     xs_call => 'setters',
     pp_code => sub {
-      my $set = "set_$_[0]";
-      my $field = $_[1];
-      $field =~ s/'/\\'/g;
-
-      "
-        \@_ != 1
-          ? shift->$set('$field', \@_)
-          : do {
-            my \$caller = caller;
-            my \$class = length ( ref(\$_[0]) ) ? ref(\$_[0]) : \$_[0];
-            Carp::croak(\"'\$caller' cannot access the value of '$field' \".
-                        \"(write-only attributes of class '\$class')\");
-          }
-      "
+      # my ($group, $fieldname) = @_;
+      my $quoted_fieldname = $perlstring->($_[1]);
+      sprintf  <<'EOS', $_[0], ($quoted_fieldname) x 2;
+
+@_ > 1
+  ? shift->set_%s(%s, @_)
+  : do {
+    my $caller = caller;
+    my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
+    Carp::croak(sprintf
+      "'%%s' cannot access the value of '%%s' (write-only attribute of class '%%s')",
+      $caller, %s, $class
+    );
+  }
+EOS
+
     },
   },
 };
index a7f7b00..a525715 100644 (file)
@@ -1,4 +1,4 @@
-use Test::More tests => 117;
+use Test::More tests => 137;
 use strict;
 use warnings;
 use lib 't/lib';
@@ -61,6 +61,10 @@ my $test_accessors = {
   lr2name => {
     custom_field => "lr2'field",
   },
+  fieldname_torture => {
+    custom_field => join ('', map { chr($_) } (0..255) ),
+    is_xs => $use_xs,
+  },
 };
 
 for my $name (sort keys %$test_accessors) {
index 6834fb9..7b385a2 100644 (file)
@@ -1,4 +1,4 @@
-use Test::More tests => 48;
+use Test::More tests => 58;
 use Test::Exception;
 use strict;
 use warnings;
@@ -52,6 +52,10 @@ my $test_accessors = {
   lr2name => {
     custom_field => "lr2'field",
   },
+  fieldname_torture => {
+    custom_field => join ('', map { chr($_) } (1..255) ), # FIXME after RT#80569 is fixed 0..255 should work
+    is_xs => $use_xs,
+  },
 };
 
 for my $name (sort keys %$test_accessors) {
index 68c3eea..39c5d7a 100644 (file)
@@ -1,4 +1,4 @@
-use Test::More tests => 38;
+use Test::More tests => 46;
 use Test::Exception;
 use strict;
 use warnings;
@@ -51,6 +51,10 @@ my $test_accessors = {
   lr2name => {
     custom_field => "lr2'field",
   },
+  fieldname_torture => {
+    custom_field => join ('', map { chr($_) } (1..255) ), # FIXME after RT#80569 is fixed 0..255 should work
+    is_xs => $use_xs,
+  },
 };
 
 for my $name (sort keys %$test_accessors) {
index a8e3b97..10801c8 100644 (file)
@@ -18,6 +18,7 @@ __PACKAGE__->mk_group_accessors('simple', 'singlefield');
 __PACKAGE__->mk_group_accessors('multiple', qw/multiple1 multiple2/);
 __PACKAGE__->mk_group_accessors('listref', [qw/lr1name lr1;field/], [qw/lr2name lr2'field/]);
 __PACKAGE__->mk_group_accessors('simple', 'runtime_around');
+__PACKAGE__->mk_group_accessors('simple', [ fieldname_torture => join ('', map { chr($_) } (0..255) ) ]);
 
 sub get_simple {
   my $v = shift->SUPER::get_simple (@_);
index 1f88a47..d023275 100644 (file)
@@ -6,6 +6,7 @@ use base 'Class::Accessor::Grouped';
 __PACKAGE__->mk_group_ro_accessors('simple', 'singlefield');
 __PACKAGE__->mk_group_ro_accessors('multiple', qw/multiple1 multiple2/);
 __PACKAGE__->mk_group_ro_accessors('listref', [qw/lr1name lr1;field/], [qw/lr2name lr2'field/]);
+__PACKAGE__->mk_group_ro_accessors('simple', [ fieldname_torture => join ('', map { chr($_) } (1..255) ) ]);
 
 sub new {
   return bless {}, shift;
index 2ea6887..b8b8c56 100644 (file)
@@ -6,6 +6,7 @@ use base 'Class::Accessor::Grouped';
 __PACKAGE__->mk_group_wo_accessors('simple', 'singlefield');
 __PACKAGE__->mk_group_wo_accessors('multiple', qw/multiple1 multiple2/);
 __PACKAGE__->mk_group_wo_accessors('listref', [qw/lr1name lr1;field/], [qw/lr2name lr2'field/]);
+__PACKAGE__->mk_group_wo_accessors('simple', [ fieldname_torture => join ('', map { chr($_) } (1..255) ) ]);
 
 sub new {
   return bless {}, shift;