File Coverage

blib/lib/Class/Accessor/Constructor.pm
Criterion Covered Total %
statement 90 96 93.7
branch 24 32 75.0
condition 10 19 52.6
subroutine 18 18 100.0
pod 3 3 100.0
total 145 168 86.3


line stmt bran cond sub pod time code
1 2     2   66689 use 5.008;
  2         9  
  2         83  
2 2     2   11 use strict;
  2         4  
  2         51  
3 2     2   9 use warnings;
  2         4  
  2         125  
4              
5             package Class::Accessor::Constructor;
6             BEGIN {
7 2     2   37 $Class::Accessor::Constructor::VERSION = '1.111590';
8             }
9              
10             # ABSTRACT: Constructor generator
11 2     2   16 use Carp 'cluck';
  2         4  
  2         149  
12 2         14 use parent qw(
13             Class::Accessor
14             Class::Accessor::Installer
15             Data::Inherited
16 2     2   11 );
  2         3  
17 2     2   34286 use constant NO_DIRTY => 0;
  2         5  
  2         173  
18 2     2   11 use constant WITH_DIRTY => 1;
  2         4  
  2         1022  
19              
20             sub mk_singleton_constructor {
21 1     1 1 2 my ($self, @args) = @_;
22 1   33     8 my $class = ref $self || $self;
23 1 50       4 @args = ('new') unless @args;
24 1         1 my $singleton;
25 1         2 for my $name (@args) {
26 1         4 my $instance_method = "${name}_instance";
27             $self->install_accessor(
28             name => $name,
29             code => sub {
30 2 50 33 2   1446 local $DB::sub = local *__ANON__ = "${class}::${name}"
        2      
31             if defined &DB::DB && !$Devel::DProf::VERSION;
32 2         3 my $self = shift;
33 2   66     9 $singleton ||= $self->$instance_method(@_);
34             },
35 1         10 );
36 1         28 $self->document_accessor(
37             name => $name,
38             purpose => <<'EODOC',
39             Creates and returns a new object. The object will be a singleton, so repeated
40             calls to the constructor will always return the same object. The constructor
41             will accept as arguments a list of pairs, from component name to initial
42             value. For each pair, the named component is initialized by calling the
43             method of the same name with the given value. If called with a single hash
44             reference, it is dereferenced and its key/value pairs are set as described
45             before.
46             EODOC
47             examples => [
48             "my \$obj = $class->$name;",
49             "my \$obj = $class->$name(\%args);",
50             ],
51             );
52 1         402 $class->mk_constructor($instance_method);
53             }
54 1         2 $self; # for chaining
55             }
56              
57             sub mk_constructor {
58 3     3 1 23 my $self = shift;
59 3         22 $self->_make_constructor(NO_DIRTY, @_);
60 3         1141 $self; # for chaining
61             }
62              
63             sub mk_constructor_with_dirty {
64 1     1 1 20 my $self = shift;
65 1         8 $self->_make_constructor(WITH_DIRTY, @_);
66 1         425 $self; # for chaining
67             }
68              
69             sub _make_constructor {
70 4     4   11 my ($self, $should_dirty, @args) = @_;
71 4   33     30 my $target_class = ref $self || $self;
72 4 100       15 @args = ('new') unless @args;
73              
74             # We generate a method into package $class which uses methods it needs to
75             # inherit from Class::Accessor::Constructor::Base (which in turn inherits
76             # from Data::Inherited), so we need to make sure that $class actually
77             # inherits from Class::Accessor::Constructor::Base.
78 4 100       35 unless (UNIVERSAL::isa($target_class, 'Class::Accessor::Constructor::Base'))
79             {
80 3         1435 require Class::Accessor::Constructor::Base;
81 2     2   16 no strict 'refs';
  2         10  
  2         1816  
82 3         54 push @{"${target_class}::ISA"}, 'Class::Accessor::Constructor::Base';
  3         65  
83             }
84 4         12 for my $name (@args) {
85              
86             # n00bs getting pwned here
87             $self->install_accessor(
88             name => $name,
89             code => sub {
90 5 50   5   1122 local $DB::sub = local *__ANON__ = "${target_class}::${name}"
        5      
        5      
91             if defined &DB::DB;
92 5         8 my $class = shift;
93 5         8 my $self;
94              
95             # If we're given a reference, don't tie() it. Only tie()
96             # completely new objects.
97 5 50       13 if (ref $class) {
98 0         0 $self = $class;
99             } else {
100 5         8 my %self = ();
101 5 100       23 tie %self, 'Class::Accessor::Constructor::Base'
102             if $should_dirty;
103 5         19 $self = bless \%self, $class;
104 5 100       13 if ($should_dirty) {
105              
106             # set the results of every_list() from here, because
107             # a tied class' STORE() method is given a $self with a ref
108             # of the tied class, not the original class.
109 1         11 $self->hygienic(scalar $self->every_list('HYGIENIC'));
110 1         27 $self->unhygienic(
111             scalar $self->every_list('UNHYGIENIC'));
112              
113             # Reset dirty flag because setting the above will cause
114             # the dirty flag to be set.
115 1         457 $self->clear_dirty;
116             }
117             }
118 5         8 our %cache;
119 5         7 my %args;
120              
121             # The following should be equivalent to
122             #
123             # my $munger = $cache{MUNGE_CONSTRUCTOR_ARGS}{ref $self} //=
124             # $self->can('MUNGE_CONSTRUCTOR_ARGS');
125             #
126             # but we want this to run under perl 5.8.8 as well. Can't use ||=
127             # with can() because if the object "can't", then can will return
128             # undef so it will check again the next time.
129             my $munger;
130 5 100       20 unless (exists $cache{MUNGE_CONSTRUCTOR_ARGS}{ ref $self }) {
131 4         89 $cache{MUNGE_CONSTRUCTOR_ARGS}{ ref $self } =
132             $self->can('MUNGE_CONSTRUCTOR_ARGS');
133             }
134 5         9 $munger = $cache{MUNGE_CONSTRUCTOR_ARGS}{ ref $self };
135 5 50       12 if ($munger) {
136 0         0 %args = $munger->($self, @_);
137             } else {
138 0         0 %args =
139             (scalar(@_ == 1) && ref($_[0]) eq 'HASH')
140 5 50 33     25 ? %{ $_[0] }
141             : @_;
142             }
143              
144             # Note: DEFAULTS are cached, so they have to be static.
145 5   100     120 my $defaults = $cache{DEFAULTS}{ ref $self } ||=
146             [ $self->every_hash('DEFAULTS') ];
147 5         3225 %args = (@$defaults, %args);
148              
149             # If a class wants to order some args first, it can define a
150             # FIRST_CONSTRUCTOR_ARGS list (will be cumulative over inheritance
151             # tree due to NEXT.pm magic)
152             # my @first = $self->every_list('FIRST_CONSTRUCTOR_ARGS');
153 5   100     44 my $first = $cache{FIRST_CONSTRUCTOR_ARGS}{ ref $self } ||=
154             [ $self->every_list('FIRST_CONSTRUCTOR_ARGS') ];
155 5         1556 my %seen;
156 5         16 for (@$first, keys %args) {
157 5 50       18 next if $seen{$_}++;
158 5         4 my $setter;
159 5 100       21 unless (exists $cache{setter}{$_}{ ref $self }) {
160 4         20 $cache{setter}{$_}{ ref $self } = $self->can($_);
161             }
162 5         16 $setter = $cache{setter}{$_}{ ref $self };
163 5 50       13 unless ($setter) {
164 0         0 my $error = sprintf "%s: no setter method for [%s]\n",
165             ref($self), $_;
166 0         0 cluck $error;
167 0         0 die $error;
168             }
169 5         26 $setter->($self, $args{$_});
170             }
171 5         60 my $init;
172 5 100       24 unless (exists $cache{INIT}{ ref $self }) {
173 4         46 $cache{INIT}{ ref $self } = $self->can('init');
174             }
175 5         10 $init = $cache{INIT}{ ref $self };
176 5 100       17 $self->init(%args) if $init;
177 5         24 $self;
178             },
179 4         50 );
180 4         111 $self->document_accessor(
181             name => $name,
182             purpose => <<'EODOC',
183             Creates and returns a new object. The constructor will accept as arguments a
184             list of pairs, from component name to initial value. For each pair, the named
185             component is initialized by calling the method of the same name with the given
186             value. If called with a single hash reference, it is dereferenced and its
187             key/value pairs are set as described before.
188             EODOC
189             examples => [
190             "my \$obj = $target_class->$name;",
191             "my \$obj = $target_class->$name(\%args);",
192             ]
193             );
194             }
195             }
196             1;
197              
198              
199             __END__