File Coverage

blib/lib/wxPerl/Constructors.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package wxPerl::Constructors;
2             $VERSION = eval{require version}?version::qv($_):$_ for(0.0.4);
3              
4 2     2   40830 use warnings;
  2         5  
  2         76  
5 2     2   12 use strict;
  2         4  
  2         72  
6 2     2   12 use Carp;
  2         9  
  2         215  
7              
8             =head1 NAME
9              
10             wxPerl::Constructors - parameterized constructors
11              
12             =head1 SYNOPSIS
13              
14             This package provides a mix of named and positional parameters which
15             mirrors the original C++ API, allowing you to omit default values, even
16             if you need to specify arguments which would otherwise follow them.
17              
18             By applying C (and some editing) to your
19             code:
20              
21             use wxPerl::Constructors;
22              
23             my $ctrl = wxPerl::TextCtrl->new($self, $label,
24             style => wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP);
25              
26             =head1 Usage
27              
28             Note the mixed positional/named arguments. Required values are
29             positional and must come before key-value pairs.
30              
31             my $ctrl = wxPerl::Foo->new($parent, $req_arg, key => $value);
32              
33             The exception is when there are no arguments. This goes directly to the
34             Wx::Foo->new() call with no intermediate processing.
35              
36             my $ctrl = wxPerl::Foo->new();
37              
38             All constructors also accept a C<($parent, \%params)> syntax, which may
39             be useful if you are building a data-driven class generator (or just
40             prefer to use named parameters for everything.)
41              
42             my $ctrl = wxPerl::Foo->new($parent,
43             {
44             req_arg => $req_arg,
45             key => $value,
46             }
47             );
48              
49             In this mode, you must still provide the required arguments because
50             there are no default values for them (they're, uh... required.)
51              
52             =head1 Advanced usage
53              
54             The constructors are also (well actually, not yet) available via this
55             longhand form (intended as infrastructure for other packages.)
56              
57             my $ctrl = wxPerl::Constructors->new(
58             'TextCtrl', $self, $label,
59             style => wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP);
60              
61             You may inherit from wxPerl::$foo as follows:
62              
63             use wxPerl::Constructors;
64             use base 'wxPerl::Frame';
65              
66             CAVEAT: There will probably be no way to deduce that you've
67             accidentally called a wxPerl::foo->new() with the Wx::foo-style
68             positional arguments. Though it might be possible later, for now you
69             have to take care to change the calls.
70              
71             =head1 Methods
72              
73             See L for available classes and details on
74             the argument syntax.
75              
76             =cut
77              
78             =begin Notes
79              
80             Some issue to do with custom classes which derive from our constructors.
81             They should C, but need to have a new() which
82             comes from here? This implies that we need to discover their underlying
83             Wx::Perl type. I suppose we could either traverse their @ISA until we
84             find a m/Wx::/, and/or we could require/allow them to define a WxType
85             method?
86              
87             Bah. The classes are all setup to inherit from the Wx::Thingy. That
88             still leaves the "I don't want to be a wxPerl::Frame" issue, but maybe
89             that's not really desired?
90              
91             use wxPerl::Constructors qw(override);
92             use base qw(wxPerl::Frame Wx::Frame);
93              
94             I'm going to let some of that slide until I see how I want to use it.
95              
96             =end Notes
97              
98             =cut
99              
100 2     2   833 use Wx ();
  0            
  0            
101             use wxPerl::Constructors::argmap;
102              
103             # load the definitions and define the classes
104             {
105             my $ARGPOS = wxPerl::Constructors::argmap->ARGPOS;
106             my $DEFAULTS = wxPerl::Constructors::argmap->DEFAULTS;
107              
108             foreach my $class_base (keys(%$ARGPOS)) {
109             my $argpos = $ARGPOS->{$class_base};
110             my $defaults = $DEFAULTS->{$class_base};
111             my $super_method = 'Wx::' . $class_base . '::new';
112              
113             my $constructor = sub {
114             my @argpos = @$argpos; # need a fresh copy each time
115              
116             my $class = shift;
117              
118             unless(scalar(@_)) { # go directly to Foo->new()
119             @_ = ($class);
120             goto &$super_method;
121             }
122              
123             my @args = shift(@_); # parent
124              
125             push(@args, '-1'); # id
126              
127             # then the positional args
128             # unless it is a hashref
129             if(@_ and ((ref($_[0])||'') eq 'HASH')) {
130             my %opts = %{shift(@_)};
131             # id is special
132             $args[1] = delete($opts{id}) if(exists($opts{id}));
133             while(my $arg = shift(@argpos)) {
134             exists($defaults->{$arg}) and last;
135             exists($opts{$arg}) or
136             croak("required argument '$arg' not given");
137             push(@args, delete($opts{$arg}));
138             }
139             foreach my $arg (@argpos) { # these all have defaults
140             %opts or last;
141             push(@args, (exists($opts{$arg}) ?
142             delete($opts{$arg}) : $defaults->{$arg}));
143             }
144             } # end hashref wrangling
145             else { # standard usage
146             if(@_) { # first collect the required positional arguments
147             while(my $arg = shift(@argpos)) {
148             if(exists($defaults->{$arg})) {
149             unshift(@argpos, $arg); # put it back
150             last;
151             }
152             push(@args, shift(@_));
153             }
154             }
155              
156             if(@_) {
157             (@_ % 2) and croak("odd number of elements in options list");
158             my %opts = @_;
159              
160             # id is special
161             $args[1] = delete($opts{id}) if(exists($opts{id}));
162             foreach my $arg (@argpos) { # these all have defaults
163             %opts or last;
164             push(@args, (exists($opts{$arg}) ?
165             delete($opts{$arg}) : $defaults->{$arg}));
166             }
167             }
168             } # end argument wrangling
169             @_ = ($class, @args);
170             # TODO there's a problem with dangling args, so we'll need to do
171             # something like remove any trailing undef arguments
172             # (XXX the trailing undef comes from Wx.pm Frame->defaultname I
173             # think.)
174             #warn "$super_method ", join(',', @_), "\n";
175             goto &$super_method;
176             # vs:
177             #$class->$super_method(@args);
178             }; # end $constructor
179              
180             my $class_name = 'wxPerl::' . $class_base;
181             no strict 'refs';
182             @{$class_name . '::ISA'} = ('Wx::' . $class_base); # TODO careful?
183             *{$class_name . '::new'} = $constructor;
184             }
185              
186             } # end auto-define
187              
188              
189              
190              
191             =head1 AUTHOR
192              
193             Eric Wilhelm @
194              
195             http://scratchcomputing.com/
196              
197             =head1 BUGS
198              
199             If you found this module on CPAN, please report any bugs or feature
200             requests through the web interface at L. I will be
201             notified, and then you'll automatically be notified of progress on your
202             bug as I make changes.
203              
204             If you pulled this development version from my /svn/, please contact me
205             directly.
206              
207             =head1 COPYRIGHT
208              
209             Copyright (C) 2007 Eric L. Wilhelm, All Rights Reserved.
210              
211             =head1 NO WARRANTY
212              
213             Absolutely, positively NO WARRANTY, neither express or implied, is
214             offered with this software. You use this software at your own risk. In
215             case of loss, no person or entity owes you anything whatsoever. You
216             have been warned.
217              
218             =head1 LICENSE
219              
220             This program is free software; you can redistribute it and/or modify it
221             under the same terms as Perl itself.
222              
223             =cut
224              
225             # vi:ts=2:sw=2:et:sta
226             1;