Paw XVI

Well I though I hit the correct fix when Paws does its XML parsing and drops the 'Root' node but I found I have to apply some sort 'trait' to my class rather than an attribute so I am going to start this time with my code for 'RestXMLResponse.pm' first and then work that fix back into boto and the templates.

What I want to do is this


 if ($ret_class->can('_stream_param')) {
      $unserialized_struct = {}
    } else {
      if (not defined $content or $content eq '') {
        $unserialized_struct = {}
      } else {
        my $keep_root = 0;
 ++    $keep_root = 1
 ++         if ($ret_class->can('_keep_root'));
 ++       $unserialized_struct = eval { $self->unserialize_response( $content,1 ) };
--       $unserialized_struct = eval { $self->unserialize_response( $content) };
…

and in my ' unserialize_response' sub I can just use that '$keep_root' scalar to flip the 'KeepRoot' option on the parser and I should be set.

Now to get that '_keep_root' in there will need a little code to the xml 'callresult_calss.tt' template in the same manner that is now done for '_stream_param'


...
   [%- IF (shape.members.$param_name.streaming == 1) %], traits => ['ParamInBody'][% stream_param = param_name %][% END %]
++[%- IF (shape.members.$param_name.keep_root == 1) %] [% keep_root = param_name%][% END %]
  [%- IF (c.required_in_shape(shape,param_name)) %], required => 1[% END %]);
[% END %]
--[%- IF (stream_param or shape.payload == param_name) %]
++[%- IF (stream_param or shape.payload == param_name or keep_root) %]
    
use MooseX::ClassAttribute;
++[%- IF (keep_root) %]
++ class_has _keep_root => (is => 'ro', default => 1);[% END %]
  [%- IF (stream_param) %]
…

I just check to see if the 'keep_root' is in the class set a tt var and then outside the loop add in the 'class_has'

Now to add that 'keep_root' to boto


    "GetBucketLocationOutput":{
      "type":"structure",
      "members":{
        "LocationConstraint":{
          "shape":"BucketLocationConstraint",
          "documentation":"<p/>",
++        "keep_root":true
        }
      }
    },

and a quick recompile and a check of my “GetBucketLocationOutput.pm” I see


package Paws::S3::GetBucketLocationOutput;
  use Moose;
  has LocationConstraint => (is => 'ro', isa => 'Str'
);

  use MooseX::ClassAttribute;
  class_has _keep_root => (is => 'ro', default => 1);
  has _request_id => (is => 'ro', isa => 'Str');
1;

So far so good (2 hours of wasted time getting the template correct edited out )

and on my first test run I get

not ok 10045 - Call S3->GetBucketLocation from t/10_responses/s3-get-bucket-location.response

# Failed test 'Call S3->GetBucketLocation from t/10_responses/s3-get-bucket-location.response'
# at t/10_responses.t line 108.
# died: Moose::Exception::ValidationFailedForTypeConstraint (Attribute (LocationConstraint) does not pass the type constraint because: Validation failed for 'Str' with value { content: "EU", xmlns: "http://s3.amazonaws.com/doc/2006-03-01/" } at /wwwveh/lib/x86_64-linux-thread-multi/Moose/Object.pm line 24
...
not ok 10046 - Can't test method access because something went horribly wrong in the call to GetBucketLocation

# Failed test 'Can't test method access because something went horribly wrong in the call to GetBucketLocation'
# at t/10_responses.t line 111.

This did not take long to fix as what is going on here is the XML is being serialized as


$VAR1 = {
          'LocationConstraint' => {
                                    'content' => 'eu-west-2',
                                    'xmlns' => 'http://s3.amazonaws.com/doc/2006-03-01/'
                                  }
        };

I really want this


$VAR1 = {
          'LocationConstraint' => 'eu-west-2'
        };

so a little adjustment to my code is in order, I need to get rid of that 'xmlns' key and pop the value of the 'content' key up the the 'LocationConstraint' keuy.

However there is no easy way to set this up in the 'response_to_object' sub as there is no link between the json and the end attributes. I will have to add that in the template with this small adjustment.


[%- IF (keep_root) %]
--  class_has _keep_root => (is => 'ro', default => 1);[% END %]
++class_has _keep_root => (is => 'ro', default =>'[% keep_root %]');[% END %]

Now when I re-generated my class I get;


se MooseX::ClassAttribute;
  class_has _keep_root => (is => 'ro', default => 'LocationConstraint');

so I have the link that I can now use here;


 my $keep_root = 0;
        $keep_root = 1
          if ($ret_class->can('_keep_root'));
        $unserialized_struct = eval { $self->unserialize_response( $content,$keep_root ) };

++      if ($keep_root){
++          $unserialized_struct->{$ret_class->_keep_root()} = $unserialized_struct->{$ret_class->_keep_root()}->{content};
++      }

and on my test run;

..10366 ok All tests successful.

Test Summary Report
-------------------
t/10_responses.t (Wstat: 0 Tests: 10366 Failed: 0)
TODO passed: 6364, 6370, 7896, 10052, 10137
Files=1, Tests=10366, 12 wallclock secs ( 0.85 usr 0.16 sys + 11.96 cusr 0.28 csys = 13.25 CPU)
Result: PASS

time for a little code clean up and a checkin. Maybe I will get my T-shirt this month after all?

6_to_21.jpg

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations