| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
############# |
|
2
|
|
|
|
|
|
|
# Created By: setitesuk@gmail.com |
|
3
|
|
|
|
|
|
|
# Created On: 2009-11-03 |
|
4
|
|
|
|
|
|
|
# Last Updated: 2009-11-09 |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package MooseX::AttributeCloner; |
|
7
|
1
|
|
|
1
|
|
3401982
|
use Moose::Role; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
9
|
|
|
8
|
1
|
|
|
1
|
|
4743
|
use Carp qw{carp cluck croak confess}; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
80
|
|
|
9
|
1
|
|
|
1
|
|
6
|
use English qw{-no_match_vars}; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
9
|
|
|
10
|
1
|
|
|
1
|
|
1248
|
use Readonly; |
|
|
1
|
|
|
|
|
2924
|
|
|
|
1
|
|
|
|
|
43
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
6
|
use JSON; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
8
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = 0.27; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Readonly::Scalar our $ATTRIBUTE_METACLASS_TO_SKIP => q[MooseX::Getopt::Meta::Attribute::NoGetopt]; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
MooseX::AttributeCloner |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 VERSION |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
0.27 |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
package My::Class; |
|
29
|
|
|
|
|
|
|
use Moose; |
|
30
|
|
|
|
|
|
|
with qw{MooseX::AttributeCloner}; |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my $NewClassObject = $self->new_with_cloned_attributes(q{New::Class}, {}); |
|
33
|
|
|
|
|
|
|
1; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
The purpose of this Role is to take all the attributes which have values in the current class, |
|
38
|
|
|
|
|
|
|
and populate them directly into a new class object. The purpose of which is that if you have data |
|
39
|
|
|
|
|
|
|
inputted on the command line that needs to propagate through to later class objects, you shouldn't |
|
40
|
|
|
|
|
|
|
need to do the following |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $oNewClass = New::Class->new({ |
|
43
|
|
|
|
|
|
|
attr1 => $self->attr1, |
|
44
|
|
|
|
|
|
|
attr2 => $self->attr2, |
|
45
|
|
|
|
|
|
|
... |
|
46
|
|
|
|
|
|
|
}); |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Which is going to get, quite frankly, tedious in the extreme. Particularly when you have more 2 class |
|
49
|
|
|
|
|
|
|
objects in your chain. |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head2 new_with_cloned_attributes |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
This takes a package name as the first argument, plus an optional additional $arg_refs hash. It will |
|
56
|
|
|
|
|
|
|
return a class object of the package populated with any matching attribute data from the current object, |
|
57
|
|
|
|
|
|
|
plus anything in the $arg_refs hash. |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=cut |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub new_with_cloned_attributes { |
|
62
|
4
|
|
|
4
|
1
|
3847
|
my ($self, $package, $arg_refs) = @_; |
|
63
|
4
|
|
100
|
|
|
368
|
$arg_refs ||= {}; |
|
64
|
|
|
|
|
|
|
|
|
65
|
4
|
100
|
66
|
|
|
25
|
if (!ref$self && ref$package) { |
|
66
|
1
|
|
|
|
|
2
|
my $temp = $self; |
|
67
|
1
|
|
|
|
|
2
|
$self = $package; |
|
68
|
1
|
|
|
|
|
2
|
$package = $temp; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
eval { |
|
72
|
4
|
|
|
|
|
12
|
my $package_file_name = $package; |
|
73
|
4
|
|
|
|
|
10
|
$package_file_name =~ s{::}{/}gxms; |
|
74
|
4
|
50
|
|
|
|
18
|
if ($package_file_name !~ /[.]pm\z/xms) { |
|
75
|
4
|
|
|
|
|
9
|
$package_file_name .= q{.pm}; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
4
|
|
|
|
|
42
|
require $package_file_name; |
|
78
|
4
|
50
|
|
|
|
8
|
} or do { |
|
79
|
0
|
|
|
|
|
0
|
confess $EVAL_ERROR; |
|
80
|
|
|
|
|
|
|
}; |
|
81
|
4
|
|
|
|
|
21
|
$self->_hash_of_attribute_values($arg_refs); |
|
82
|
4
|
|
|
|
|
126
|
return $package->new($arg_refs); |
|
83
|
|
|
|
|
|
|
} |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head2 attributes_as_command_options |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
returns all the built attributes that are not objects as a string of command_line options |
|
88
|
|
|
|
|
|
|
only the first level of references will be passed through, multi-dimensional data structures |
|
89
|
|
|
|
|
|
|
should use the json serialisation option and deserialise it on object construction or script |
|
90
|
|
|
|
|
|
|
running |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
my $command_line_string = $class->attributes_as_command_options(); |
|
93
|
|
|
|
|
|
|
--attr1 val1 --attr2 val2 |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
By default, it returns the options with a double dash, space separated, and not quoted (as above). These can be switched by submitting a hash_ref as follows |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
my $command_line_string = $class->attributes_as_command_options({ |
|
98
|
|
|
|
|
|
|
equal => 1, |
|
99
|
|
|
|
|
|
|
quotes => 1, |
|
100
|
|
|
|
|
|
|
single_dash => 1, |
|
101
|
|
|
|
|
|
|
}); |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Although, if you are passing a hash_ref, this will always be space separated attr val. |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
You may exclude some values if you wish. To do this, use the example below |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
my $command_line_string = $class->attributes_as_command_options({ |
|
108
|
|
|
|
|
|
|
excluded_attributes => [ qw( init_arg1 init_arg2 init_arg3 ) ], |
|
109
|
|
|
|
|
|
|
}); |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Note here you are using the init_arg, rather than any reader/accessor method names to exclude the option, as it is the init_arg which will be used in the command_line string generated |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Sometimes you may have floating attributes for argv and ARGV (we have discovered this with MooseX::Getopt). As such, these are being treated as 'special', and these will be excluded by default. You can request them to be included as follows. |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
my $command_line_string = $class->attributes_as_command_options({ |
|
116
|
|
|
|
|
|
|
included_argv_attributes => [ qw( argv ARGV ) ], |
|
117
|
|
|
|
|
|
|
}); |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
No additional command_line params can be pushed into this, it only deals with the attributes already set in the current object |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
Note, it is your responsibility to know where you may need any of these to be on or off, unless they have no init_arg (init_arg => undef) |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
From v0.25, any attributes with a metaclass of NoGetopt will not be translated to a command line as they would cause a failure to any new_with_options with MooseX::Getopt. You can override this by passing an additional argument 'include_no_getopt' |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
my $command_line_string = $class->attributes_as_command_options({ |
|
126
|
|
|
|
|
|
|
included_argv_attributes => [ qw( argv ARGV ) ], |
|
127
|
|
|
|
|
|
|
include_no_getopt => 1, |
|
128
|
|
|
|
|
|
|
}); |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=cut |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub attributes_as_command_options { |
|
133
|
11
|
|
|
11
|
1
|
7950
|
my ($self,$arg_refs) = @_; |
|
134
|
11
|
|
100
|
|
|
47
|
$arg_refs ||= {}; |
|
135
|
|
|
|
|
|
|
|
|
136
|
11
|
|
|
|
|
49
|
my $attributes = $self->_hash_of_attribute_values({command_options => 1}); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# exclude any specified init_args |
|
139
|
11
|
|
|
|
|
111
|
$self->_exclude_args($attributes, $arg_refs); |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# remove any objects from the hash |
|
142
|
7
|
|
|
|
|
26
|
$self->_traverse_hash($attributes); |
|
143
|
|
|
|
|
|
|
|
|
144
|
7
|
|
|
|
|
9
|
my @command_line_options; |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# version 0.21 - force this to be in a sorted order, so that results can be consistent should operating systems return keys in a different order |
|
147
|
7
|
|
|
|
|
12
|
foreach my $key (sort keys %{$attributes}) { |
|
|
7
|
|
|
|
|
43
|
|
|
148
|
|
|
|
|
|
|
|
|
149
|
31
|
100
|
66
|
|
|
124
|
if (! ref $attributes->{$key} |
|
|
|
|
66
|
|
|
|
|
|
150
|
|
|
|
|
|
|
&& |
|
151
|
|
|
|
|
|
|
( (ref( $self->meta()->get_attribute($key) ) ne $ATTRIBUTE_METACLASS_TO_SKIP ) || $arg_refs->{include_no_getopt} ) ) { |
|
152
|
18
|
|
|
|
|
563
|
my $string = $self->_create_string($key, $attributes->{$key}, $arg_refs); |
|
153
|
18
|
|
|
|
|
28
|
push @command_line_options, $string; |
|
154
|
18
|
|
|
|
|
41
|
next; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
13
|
100
|
|
|
|
74
|
if (ref $attributes->{$key} eq q{HASH}) { |
|
158
|
|
|
|
|
|
|
|
|
159
|
5
|
|
|
|
|
8
|
foreach my $h_key (sort {$a cmp $b} keys %{$attributes->{$key}}) { |
|
|
5
|
|
|
|
|
14
|
|
|
|
5
|
|
|
|
|
28
|
|
|
160
|
|
|
|
|
|
|
|
|
161
|
10
|
50
|
33
|
|
|
81
|
if (defined $attributes->{$key}->{$h_key} && ! ref $attributes->{$key}->{$h_key}) { # don't pass through empty strings or references |
|
162
|
10
|
|
|
|
|
39
|
my $string = $self->_create_string($key, qq{$h_key=$attributes->{$key}->{$h_key}}, $arg_refs, 1); |
|
163
|
10
|
|
|
|
|
24
|
push @command_line_options, $string; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
13
|
100
|
|
|
|
44
|
if (ref $attributes->{$key} eq q{ARRAY}) { |
|
171
|
|
|
|
|
|
|
|
|
172
|
7
|
|
|
|
|
9
|
foreach my $value (@{$attributes->{$key}}) { |
|
|
7
|
|
|
|
|
19
|
|
|
173
|
|
|
|
|
|
|
|
|
174
|
30
|
100
|
100
|
|
|
126
|
if (defined $value && ! ref $value) { # don't pass through empty strings or references |
|
175
|
18
|
|
|
|
|
43
|
my $string = $self->_create_string($key, $value, $arg_refs); |
|
176
|
18
|
|
|
|
|
65
|
push @command_line_options, $string; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
7
|
|
|
|
|
13
|
my $clo_string; |
|
186
|
7
|
100
|
|
|
|
17
|
if ($arg_refs->{single_dash}) { |
|
187
|
2
|
|
|
|
|
8
|
$clo_string = join q{ -}, @command_line_options; |
|
188
|
2
|
|
|
|
|
7
|
$clo_string = q{-} . $clo_string; |
|
189
|
|
|
|
|
|
|
} else { |
|
190
|
5
|
|
|
|
|
16
|
$clo_string = join q{ --}, @command_line_options; |
|
191
|
5
|
|
|
|
|
12
|
$clo_string = q{--} . $clo_string; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
7
|
|
|
|
|
59
|
return $clo_string; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head2 attributes_as_json |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
returns all the built attributes that are not objects as a JSON string |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
my $sAttributesAsJSON = $class->attributes_as_json(); |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=head2 attributes_as_escaped_json |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
as attributes_as_json, except it is an escaped JSON string, so that this could be used on a command line |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
my $sAttributesAsEscapedJSON = $class->attributes_as_escaped_json(); |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
This uses JSON to generate the string, removing any objects before stringifying, and then parses it through a regex to generate a string with escaped characters |
|
209
|
|
|
|
|
|
|
Note, because objects are removed, arrays will remain the correct length, but have null in them |
|
210
|
|
|
|
|
|
|
=cut |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub attributes_as_escaped_json { |
|
213
|
1
|
|
|
1
|
1
|
1482
|
my ($self) = @_; |
|
214
|
1
|
|
|
|
|
5
|
my $json = $self->attributes_as_json(); |
|
215
|
1
|
|
|
|
|
90
|
$json =~ s{([^\w\d-])}{\\$1}gmxs; |
|
216
|
1
|
|
|
|
|
6
|
return $json; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub attributes_as_json { |
|
220
|
2
|
|
|
2
|
1
|
3734
|
my ($self) = @_; |
|
221
|
|
|
|
|
|
|
|
|
222
|
2
|
|
|
|
|
10
|
my $attributes = $self->_hash_of_attribute_values(); |
|
223
|
|
|
|
|
|
|
# remove any objects from the hash |
|
224
|
2
|
|
|
|
|
9
|
$self->_traverse_hash($attributes); |
|
225
|
2
|
|
|
|
|
11
|
my $json = to_json($attributes); |
|
226
|
2
|
|
|
|
|
84
|
return $json; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 attributes_as_hashref |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Returns a hashref of the attributes this object has built, |
|
232
|
|
|
|
|
|
|
optionally excluding any specified attributes. |
|
233
|
|
|
|
|
|
|
Includes objects which may have been built. |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
my $hAttributesAsHashref = $class->attributes_as_hashref({ |
|
236
|
|
|
|
|
|
|
excluded_attributes => [ qw( init_arg1 init_arg2 init_arg3 ) ], |
|
237
|
|
|
|
|
|
|
}); |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
Note here you are using the init_arg, rather than any reader/accessor method names to exclude the option |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub attributes_as_hashref { |
|
244
|
1
|
|
|
1
|
1
|
2
|
my ( $self, $arg_refs ) = @_; |
|
245
|
1
|
|
50
|
|
|
4
|
$arg_refs ||= {}; |
|
246
|
1
|
|
|
|
|
4
|
my $attributes = $self->_hash_of_attribute_values(); |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# exclude any specified init_args |
|
249
|
1
|
|
|
|
|
3
|
$self->_exclude_args($attributes, $arg_refs); |
|
250
|
1
|
|
|
|
|
3
|
return $attributes; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
############### |
|
254
|
|
|
|
|
|
|
# private methods |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# a hash_ref of attribute values from $self, where built |
|
258
|
|
|
|
|
|
|
# either acts on a provided hash_ref, or will return a new one |
|
259
|
|
|
|
|
|
|
sub _hash_of_attribute_values { |
|
260
|
18
|
|
|
18
|
|
32
|
my ($self, $arg_refs) = @_; |
|
261
|
18
|
|
100
|
|
|
52
|
$arg_refs ||= {}; |
|
262
|
|
|
|
|
|
|
|
|
263
|
18
|
|
|
|
|
31
|
my $command_options = $arg_refs->{command_options}; |
|
264
|
18
|
|
|
|
|
29
|
delete$arg_refs->{command_options}; |
|
265
|
|
|
|
|
|
|
|
|
266
|
18
|
|
|
|
|
78
|
my @attributes = $self->meta->get_all_attributes(); |
|
267
|
18
|
|
|
|
|
1177
|
foreach my $attr (@attributes) { |
|
268
|
276
|
|
66
|
|
|
9777
|
my $reader = $attr->reader() || $attr->accessor(); |
|
269
|
276
|
|
|
|
|
833
|
my $init_arg = $attr->init_arg(); |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# if there is no reader/accessor method, then we can't read the attribute value, so skip |
|
272
|
276
|
50
|
|
|
|
539
|
next if (!$reader); |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# if the reader/accessor are private, then we don't want to pass it around |
|
275
|
276
|
50
|
|
|
|
557
|
next if ($reader =~ /\A_/xms); |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# if lazy_build, then will only propagate data if it is built, saving any expensive build routines. |
|
278
|
|
|
|
|
|
|
# obviously, this has the effect that you may need to do it twice, or force a build before the cloning of data |
|
279
|
|
|
|
|
|
|
# NOTE: this doesn't account for those which are lazy, and have a builder, but no predicate (generated by lazy_build flag only) |
|
280
|
276
|
100
|
|
|
|
660
|
if ($attr->{predicate}) { |
|
281
|
18
|
|
|
|
|
28
|
my $pred = $attr->{predicate}; |
|
282
|
18
|
100
|
|
|
|
556
|
next if !$self->$pred(); |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
|
|
285
|
274
|
100
|
33
|
|
|
9286
|
if ($init_arg && !exists$arg_refs->{$init_arg} && defined $self->$reader()) { |
|
|
|
|
66
|
|
|
|
|
|
286
|
100
|
50
|
100
|
|
|
3947
|
next if ( $attr->type_constraint() eq q{Bool} && $command_options && ! $self->$reader ); |
|
|
|
|
66
|
|
|
|
|
|
287
|
100
|
100
|
100
|
|
|
10385
|
$arg_refs->{$init_arg} = $attr->type_constraint() eq q{Bool} && $command_options ? q{} : $self->$reader(); |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
|
|
291
|
18
|
|
|
|
|
337
|
return $arg_refs; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# remove any objects from a hash |
|
295
|
|
|
|
|
|
|
sub _traverse_hash { |
|
296
|
24
|
|
|
24
|
|
36
|
my ($self, $hash) = @_; |
|
297
|
24
|
|
|
|
|
27
|
my @keys_to_delete; |
|
298
|
24
|
|
|
|
|
27
|
foreach my $key (keys %{$hash}) { |
|
|
24
|
|
|
|
|
72
|
|
|
299
|
78
|
100
|
|
|
|
193
|
next if (!ref $hash->{$key}); |
|
300
|
25
|
100
|
|
|
|
66
|
if (ref$hash->{$key} eq q{HASH}) { |
|
301
|
7
|
|
|
|
|
27
|
$self->_traverse_hash($hash->{$key}); |
|
302
|
7
|
|
|
|
|
10
|
next; |
|
303
|
|
|
|
|
|
|
} |
|
304
|
18
|
100
|
|
|
|
51
|
if (ref$hash->{$key} eq q{ARRAY}) { |
|
305
|
9
|
|
|
|
|
30
|
$hash->{$key} = $self->_traverse_array($hash->{$key}); |
|
306
|
9
|
|
|
|
|
16
|
next; |
|
307
|
|
|
|
|
|
|
} |
|
308
|
9
|
|
|
|
|
51
|
push @keys_to_delete, $key; |
|
309
|
|
|
|
|
|
|
} |
|
310
|
24
|
|
|
|
|
54
|
foreach my $key (@keys_to_delete) { |
|
311
|
9
|
|
|
|
|
22
|
delete $hash->{$key}; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
24
|
|
|
|
|
41
|
return $hash; |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# remove any objects from an array |
|
317
|
|
|
|
|
|
|
sub _traverse_array { |
|
318
|
9
|
|
|
9
|
|
15
|
my ($self, $array) = @_; |
|
319
|
9
|
|
|
|
|
15
|
my @wanted_items; |
|
320
|
9
|
|
|
|
|
14
|
foreach my $item (@{$array}) { |
|
|
9
|
|
|
|
|
20
|
|
|
321
|
40
|
100
|
|
|
|
81
|
if (!ref $item) { |
|
322
|
24
|
|
|
|
|
33
|
push @wanted_items, $item; |
|
323
|
24
|
|
|
|
|
30
|
next; |
|
324
|
|
|
|
|
|
|
} |
|
325
|
16
|
100
|
|
|
|
37
|
if (ref$item eq q{HASH}) { |
|
326
|
8
|
|
|
|
|
20
|
$self->_traverse_hash($item); |
|
327
|
8
|
|
|
|
|
13
|
push @wanted_items, $item; |
|
328
|
8
|
|
|
|
|
9
|
next; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
8
|
50
|
|
|
|
19
|
if (ref$item eq q{ARRAY}) { |
|
331
|
0
|
|
|
|
|
0
|
$item = $self->_traverse_array($item); |
|
332
|
0
|
|
|
|
|
0
|
push @wanted_items, $item; |
|
333
|
0
|
|
|
|
|
0
|
next; |
|
334
|
|
|
|
|
|
|
} |
|
335
|
8
|
|
|
|
|
27
|
push @wanted_items, undef; |
|
336
|
|
|
|
|
|
|
} |
|
337
|
9
|
|
|
|
|
25
|
return \@wanted_items; |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
############ |
|
341
|
|
|
|
|
|
|
# remove any unwanted options by the init_arg they would have |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub _exclude_args { |
|
344
|
12
|
|
|
12
|
|
22
|
my ($self, $attributes, $arg_refs) = @_; |
|
345
|
12
|
|
100
|
|
|
68
|
my $excluded_attributes = $arg_refs->{excluded_attributes} || []; |
|
346
|
12
|
|
|
|
|
21
|
delete $arg_refs->{excluded_attributes}; |
|
347
|
12
|
|
100
|
|
|
53
|
my $included_argv_attributes = $arg_refs->{included_argv_attributes} || []; |
|
348
|
12
|
|
|
|
|
20
|
delete $arg_refs->{included_argv_attributes}; |
|
349
|
12
|
0
|
33
|
|
|
32
|
if (!$excluded_attributes && !$included_argv_attributes) { |
|
350
|
0
|
|
|
|
|
0
|
return 1; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
12
|
100
|
100
|
|
|
74
|
if ( ! ref$excluded_attributes || ref$excluded_attributes ne q{ARRAY} ) { |
|
354
|
2
|
|
|
|
|
39
|
croak qq{Your excluded_attributes are not in an arrayref - $excluded_attributes}; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
|
|
357
|
10
|
100
|
100
|
|
|
64
|
if ( ! ref$included_argv_attributes || ref$included_argv_attributes ne q{ARRAY} ) { |
|
358
|
2
|
|
|
|
|
24
|
croak qq{Your included_argv_attributes are not in an arrayref - $included_argv_attributes}; |
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
|
|
361
|
8
|
|
|
|
|
15
|
foreach my $exclusion (@{$excluded_attributes}) { |
|
|
8
|
|
|
|
|
40
|
|
|
362
|
3
|
|
|
|
|
6
|
delete $attributes->{$exclusion}; |
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
|
|
365
|
8
|
|
|
|
|
18
|
my $wanted_argv = {}; |
|
366
|
8
|
|
|
|
|
11
|
foreach my $inclusion (@{$included_argv_attributes}) { |
|
|
8
|
|
|
|
|
17
|
|
|
367
|
2
|
|
|
|
|
7
|
$wanted_argv->{$inclusion}++; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
8
|
|
|
|
|
15
|
foreach my $argv ( qw{ argv ARGV }) { |
|
371
|
16
|
100
|
|
|
|
44
|
if (!$wanted_argv->{$argv}) { |
|
372
|
14
|
|
|
|
|
28
|
delete $attributes->{$argv}; |
|
373
|
|
|
|
|
|
|
} |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
8
|
|
|
|
|
24
|
return 1; |
|
377
|
|
|
|
|
|
|
} |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# create a command line string |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
sub _create_string { |
|
382
|
46
|
|
|
46
|
|
66
|
my ($self, $attr, $value, $arg_refs, $hash) = @_; |
|
383
|
46
|
|
|
|
|
54
|
my $string = $attr; |
|
384
|
|
|
|
|
|
|
|
|
385
|
46
|
100
|
100
|
|
|
330
|
if ($value ne q{} && !$hash && $arg_refs->{equal}) { |
|
|
|
|
100
|
|
|
|
|
|
386
|
10
|
|
|
|
|
19
|
$string .= q{=}; |
|
387
|
|
|
|
|
|
|
} else { |
|
388
|
36
|
|
|
|
|
59
|
$string .= q{ }; # default attr value separator |
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
|
|
391
|
46
|
100
|
100
|
|
|
172
|
if ($value ne q{} && $arg_refs->{quotes}) { |
|
392
|
14
|
|
|
|
|
24
|
$string .= qq{"$value"}; |
|
393
|
|
|
|
|
|
|
} else { |
|
394
|
32
|
|
|
|
|
39
|
$string .= qq{$value}; # default no quote of value |
|
395
|
|
|
|
|
|
|
} |
|
396
|
46
|
|
|
|
|
94
|
return $string; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
1; |
|
400
|
|
|
|
|
|
|
__END__ |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=head1 DIAGNOSTICS |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head1 CONFIGURATION AND ENVIRONMENT |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=over |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=item Moose::Role |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=item Carp |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=item English -no_match_vars |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=item Readonly |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=item JSON |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=back |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=head1 INCOMPATIBILITIES |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 BUGS AND LIMITATIONS |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
This is more than likely to have bugs in it. Please contact me with any you find (or submit to RT) |
|
427
|
|
|
|
|
|
|
and any patches. |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=head1 AUTHOR |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
setitesuk |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Copyright (C) 2011 Andy Brown (setitesuk@gmail.com) |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify |
|
438
|
|
|
|
|
|
|
it under the terms of the GNU General Public License as published by |
|
439
|
|
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or |
|
440
|
|
|
|
|
|
|
(at your option) any later version. |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
|
443
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
444
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
445
|
|
|
|
|
|
|
GNU General Public License for more details. |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
|
448
|
|
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |