File Coverage

blib/lib/Thrift/Parser/FieldSet.pm
Criterion Covered Total %
statement 93 97 95.8
branch 20 24 83.3
condition 6 9 66.6
subroutine 15 15 100.0
pod 7 9 77.7
total 141 154 91.5


line stmt bran cond sub pod time code
1             package Thrift::Parser::FieldSet;
2              
3             =head1 NAME
4              
5             Thrift::Parser::FieldSet - A set of fields in a structure
6              
7             =cut
8              
9 6     6   33 use strict;
  6         10  
  6         201  
10 6     6   33 use warnings;
  6         13  
  6         181  
11 6     6   34 use Params::Validate qw(validate_with);
  6         13  
  6         607  
12 6     6   38 use Data::Dumper;
  6         12  
  6         377  
13 6     6   36 use Scalar::Util qw(blessed);
  6         12  
  6         294  
14 6     6   32 use base qw(Class::Accessor::Grouped);
  6         12  
  6         7795  
15             __PACKAGE__->mk_group_accessors(simple => qw(fields));
16              
17             =head1 USAGE
18              
19             =head2 fields
20              
21             Returns an array ref of all the fields in this set.
22              
23             =cut
24              
25             sub new {
26 6     6 0 17 my $class = shift;
27 6         176 my %self = validate_with(
28             params => shift,
29             spec => {
30             fields => 1,
31             },
32             );
33 6         92 return bless \%self, $class;
34             }
35              
36             =head2 named
37              
38             my $value = $field_set->named('id');
39              
40             Searches the fields in the set for the field named $name. Returns the value of that field.
41              
42             =cut
43              
44             sub named {
45 3     3 1 1515 my ($self, $name) = @_;
46 3         5 foreach my $field (@{ $self->{fields} }) {
  3         23  
47 6 100       235 if ($field->name eq $name) {
48 2         202 return $field->value;
49             }
50             }
51 1         17 return;
52             }
53             *field_named = \&named;
54              
55             =head2 id
56              
57             my $value = $field_set->id(2);
58              
59             Searches the fields in the set for the field with id $id. Returns the value of that field.
60              
61             =cut
62              
63             sub id {
64 2     2 1 506 my ($self, $id) = @_;
65 2         4 foreach my $field (@{ $self->{fields} }) {
  2         8  
66 3 100       113 if ($field->id eq $id) {
67 1         44 return $field->value;
68             }
69             }
70 1         20 return;
71             }
72              
73             =head2 ids
74              
75             Returns an array ref of the ids of this field set.
76              
77             =cut
78              
79             sub ids {
80 1     1 1 4 my $self = shift;
81 1         121 my @ids = sort { $a <=> $b } map { $_->id } @{ $self->{fields} };
  1         23  
  2         77  
  1         5  
82 1         10 return \@ids;
83             }
84              
85             =head2 field_values
86              
87             Returns an array ref of the values of the fields in the set.
88              
89             =cut
90              
91             sub field_values {
92 1     1 1 3 my $self = shift;
93 1         3 my @values = map { $_->value } @{ $self->{fields} };
  2         78  
  1         4  
94 1         20 return \@values;
95             }
96              
97             =head2 keyed_field_values
98              
99             Returns a hashref where the keys are the names of the fields and the values are the values of the fields.
100              
101             =cut
102              
103             sub keyed_field_values {
104 1     1 1 15531 my $self = shift;
105 1         4 my %hash = map { $_->name => $_->value } @{ $self->{fields} };
  2         128  
  1         6  
106 1         57 return \%hash;
107             }
108              
109             =head2 keyed_field_values_plain
110              
111             Returns a hashref where the keys are the names of the fields and the values are the plain values of the fields.
112              
113             =cut
114              
115             sub keyed_field_values_plain {
116 1     1 1 10764 my $self = shift;
117 1         3 my %hash = map { $_->name => $_->value->value_plain } @{ $self->{fields} };
  2         277  
  1         3  
118 1         23 return \%hash;
119             }
120              
121             =head2 compose
122              
123             Used internally by L and L. Given a list of key/value pairs, returns a FieldSet object informed by the IDL.
124              
125             =cut
126              
127             sub compose {
128 6     6 1 9719 my ($self_class, $class, %args) = @_;
129              
130 6 50       122 if (! $class->idl) {
131 0         0 die "Requires an IDL";
132             }
133              
134 6 100       162 if (! $class->idl->can('field_id')) {
135 1         32 Thrift::Parser::InvalidArgument->throw(
136             key => 'class', value => $class, error => "Doesn't support field_id()",
137             );
138             }
139              
140             # Check for missing non-optional fields
141              
142 5         78 foreach my $field (@{ $class->idl->fields }) {
  5         73  
143 13         69 my $default_value = $field->default_value;
144              
145             # User may pass '_:id' or the name of the field
146 13 100       138 my $key = defined $args{ '_' . $field->id } ? '_' . $field->id : $field->name;
147              
148 13 50 33     356 if (defined $default_value && ! defined $args{$key}) {
149 0         0 $args{$key} = $default_value;
150 0         0 next;
151             }
152              
153 13 100 100     98 if (! defined $default_value && ! defined $args{$key} && ! $field->optional && $class->isa('Thrift::Parser::Type::Struct')) {
      66        
154 1         38 Thrift::Parser::InvalidArgument->throw("Missing value for field '".$field->name."' in $class compose()");
155             }
156             }
157              
158 4         249 my @fields;
159 4         20 foreach my $key (keys %args) {
160             # Determine the IDL type of the field
161 8         13 my $idl_field;
162 8 100       36 if (my ($id) = $key =~ m{^_(\d+)$}) {
163 1         5 $idl_field = $class->idl->field_id($id);
164             }
165             else {
166 7         152 $idl_field = $class->idl->field_named($key);
167             }
168 8 100       236 if (! $idl_field) {
169 1         12 Thrift::Parser::InvalidArgument->throw(
170             error => "Failed to find referenced field '$key' in the $class IDL spec",
171             key => $key, value => $args{$key},
172             );
173             }
174 7         112 my $type = $idl_field->type;
175              
176             # Cast into the new value
177              
178 7         60 my $type_class;
179 7 100       228 if ($type->isa('Thrift::IDL::Type::Custom')) {
180 3         14 my $type_name = $type->full_name;
181 3         63 my $referenced_type = $class->idl_doc->object_full_named($type_name);
182 3 50       384 if (! $referenced_type) {
183 0         0 Thrift::Parser::InvalidSpec->throw("Couldn't find definition of custom type '".$type_name."'");
184             }
185 3         29 my $namespace = $referenced_type->{header}->namespace('perl');
186 3 50       20 $type_class = join '::', (defined $namespace ? ($namespace) : ()), $type->local_name;
187             }
188             else {
189 4         17 $type_class = 'Thrift::Parser::Type::' . $type->name;
190             }
191              
192 7         122 my $value = $type_class->compose_with_idl($type, $args{$key});
193              
194 7         108 my $field = Thrift::Parser::Field->new({
195             id => $idl_field->id,
196             value => $value,
197             name => $idl_field->name,
198             });
199 7         26 push @fields, $field;
200             }
201              
202 3         31 return $self_class->new({ fields => \@fields });
203             }
204              
205             sub write {
206 1     1 0 237 my ($self, $output) = @_;
207              
208 1         8 $output->writeStructBegin();
209 1         2 foreach my $field (@{ $self->{fields} }) {
  1         10  
210 2         9 $field->write($output);
211             }
212 1         6 $output->writeFieldStop();
213 1         5 $output->writeStructEnd();
214             }
215              
216             =head1 COPYRIGHT
217              
218             Copyright (c) 2009 Eric Waters and XMission LLC (http://www.xmission.com/). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
219              
220             The full text of the license can be found in the LICENSE file included with this module.
221              
222             =head1 AUTHOR
223              
224             Eric Waters
225              
226             =cut
227              
228             1;