File Coverage

blib/lib/YATT/Lite/Object.pm
Criterion Covered Total %
statement 101 130 77.6
branch 26 44 59.0
condition 6 14 42.8
subroutine 23 29 79.3
pod 4 17 23.5
total 160 234 68.3


line stmt bran cond sub pod time code
1             package YATT::Lite::Object; sub MY () {__PACKAGE__}
2 22     22   122354 use strict;
  22         39  
  22         699  
3 22     22   121 use warnings qw(FATAL all NONFATAL misc);
  22         40  
  22         769  
4 22     22   102 use Carp;
  22         38  
  22         2433  
5 22     22   911 use mro 'c3';
  22         34369  
  22         164  
6              
7 22     22   1655 use fields;
  22         53327  
  22         126  
8              
9 22     22   13672 use YATT::Lite::XHF qw(read_file_xhf);
  22         134  
  22         44189  
10              
11             require YATT::Lite::Util;
12              
13             sub new {
14 4627     4627 1 35599 my $self = fields::new(shift);
15 4627 100       656662 if (@_) {
16 4602         13105 my @task = $self->configure(@_);
17 4602         10597 $self->_before_after_new;
18 4602         10355 $self->after_new;
19 4602         12043 $$_[0]->($self, $$_[1]) for @task;
20             } else {
21 25         86 $self->_before_after_new;
22 25         74 $self->after_new;
23             }
24              
25             # To tolerate ``forgotten ->SUPER::after_new() bug'' in user class.
26 4627         9924 $self->_after_after_new;
27              
28 4626         17147 $self;
29             }
30              
31             sub just_new {
32 51     51 0 172 my $self = fields::new(shift);
33             # To delay configure_zzz.
34 51         10511 ($self, $self->configure(@_));
35             }
36              
37             # General initialization hook for each user class.
38       4530 1   sub after_new {};
39              
40             # Two more initialization hooks for framework writer.
41              
42             # Called just after parameter initialization.
43             # Good for private member initialization.
44       4574     sub _before_after_new {}
45              
46             # Called after all configure_ZZZ hook is called.
47       4627     sub _after_after_new {}
48              
49             our $loading_file;
50             sub _loading_file {
51 0 0   0   0 return "\n loaded from (unknown file)" unless defined $loading_file;
52 0         0 sprintf qq|\n loaded from file '%s'|, $loading_file;
53             }
54             sub _with_loading_file {
55 13     13   37 my ($self, $fn, $method) = @_[0 .. 2];
56 13         26 local $loading_file = $fn;
57 13 50       38 if (ref $method eq 'CODE') {
58 13         49 $method->(@_[3 .. $#_]);
59             } else {
60 0         0 $self->$method(@_[3 .. $#_]);
61             }
62             }
63              
64             # XXX: To hide from subclass. (Might harm localization)
65             my $NO_SUCH_CONFIG_ITEM = sub {
66             my ($self, $name) = @_;
67             "No such config item $name in class " . ref($self)
68             . $self->_loading_file;
69             };
70              
71             sub cget {
72 42     42 1 2384 my ($self, $key, $default) = @_;
73 42         93 my $name = "cf_$key";
74 42         124 my $fields = YATT::Lite::Util::fields_hash($self);
75 42 50       162 unless (not exists $fields->{"cf_$name"}) {
76 0         0 confess $NO_SUCH_CONFIG_ITEM->($self, $name);
77             }
78 42   66     237 $self->{$name} // $default;
79             }
80              
81             sub configure {
82 5266     5266 1 7724 my $self = shift;
83 5266         6107 my (@task);
84 5266         13220 my $fields = YATT::Lite::Util::fields_hash($self);
85 5266 50 33     24958 my @params = @_ == 1 && ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
  0         0  
86 5266         15940 while (my ($name, $value) = splice @params, 0, 2) {
87 15432 50       30882 unless (defined $name) {
88 0         0 croak "Undefined name given for @{[ref($self)]}->configure(name=>value)!";
  0         0  
89             }
90 15432         20768 $name =~ s/^-//;
91 15432 100       80652 if (my $sub = $self->can("configure_$name")) {
    50          
92 729         3755 push @task, [$sub, $value];
93             } elsif (not exists $fields->{"cf_$name"}) {
94 0         0 confess $NO_SUCH_CONFIG_ITEM->($self, $name);
95             } else {
96 14703         64095 $self->{"cf_$name"} = $value;
97             }
98             }
99 5266 100       9506 if (wantarray) {
100             # To delay configure_zzz.
101 4653         10926 @task;
102             } else {
103 613         1369 $$_[0]->($self, $$_[1]) for @task;
104 613         1950 $self;
105             }
106             }
107              
108             sub cf_list {
109 2     2 0 4 my $obj_or_class = shift;
110 2   66     14 my $pat = shift || qr{^cf_(.*)};
111 2         7 my $fields = YATT::Lite::Util::fields_hash($obj_or_class);
112 2 100       13 sort map {($_ =~ $pat) ? $1 : ()} keys %$fields;
  6         48  
113             }
114              
115             sub cf_pairs {
116 0     0 0 0 my ($obj) = shift;
117 0         0 my $fields = YATT::Lite::Util::fields_hash($obj);
118             map {
119 0         0 [substr($_, 3) => $obj->{$_}]
120 0         0 } grep {/^cf_/} keys %$fields;
  0         0  
121             }
122              
123             #
124             # util for delegate
125             #
126             sub cf_delegate {
127 548     548 0 838 my MY $self = shift;
128 548         1409 my $fields = YATT::Lite::Util::fields_hash($self);
129             map {
130 548 100       1029 my ($from, $to) = ref $_ ? @$_ : ($_, $_);
  2009         4908  
131 2009 50       6045 unless (exists $fields->{"cf_$from"}) {
132 0         0 confess $NO_SUCH_CONFIG_ITEM->($self, $from);
133             }
134 2009         7780 $to => $self->{"cf_$from"}
135             } @_;
136             }
137              
138             sub cf_delegate_defined {
139 98     98 0 174 my MY $self = shift;
140 98         314 my $fields = YATT::Lite::Util::fields_hash($self);
141 98         466 $self->cf_delegate_known(1, $fields, @_);
142             }
143              
144             sub cf_delegate_known {
145 130     130 0 372 (my MY $self, my ($raise_err, $fields)) = splice @_, 0, 3;
146             map {
147 130 50       262 my ($from, $to) = ref $_ ? @$_ : ($_, $_);
  1253         2853  
148 1253 100       3153 if (not exists $fields->{"cf_$from"}) {
149 86 50       209 $raise_err ? (confess $NO_SUCH_CONFIG_ITEM->($self, $from)) : ();
150             } else {
151 1167 100       4407 defined $self->{"cf_$from"} ? ($to => $self->{"cf_$from"}) : ();
152             }
153             } @_;
154             }
155              
156             # Or, say, with_option.
157             # XXX: configure_ZZZ hook is not applied.
158             sub cf_let {
159 271     271 0 625 (my MY $self, my ($binding, $task)) = splice @_, 0, 3;
160 271         701 my ($keys, $values) = $self->cf_bindings(@$binding);
161 271         445 local @{$self}{@$keys} = @$values;
  271         468  
162 271 50       581 if (ref $task) {
163 271         797 $task->($self, @_);
164             } else {
165 0         0 $self->$task(@_);
166             }
167             }
168              
169             sub cf_bindings {
170 271     271 0 341 my MY $self = shift;
171 271 50       661 carp "Odd number of key value bindings" if @_ % 2;
172 271         319 my (@keys, @values);
173 271         794 while (my ($key, $value) = splice @_, 0, 2) {
174             # XXX: key check!
175             # XXX: task extraction!
176 12         26 push @keys, "cf_$key"; push @values, $value;
  12         45  
177             }
178 271         609 (\@keys, \@values);
179             }
180              
181              
182             sub cf_unknowns {
183 32     32 0 60 my $self = shift;
184 32   33     155 my $class = ref $self || $self;
185 32         98 my $fields = YATT::Lite::Util::fields_hash($class);
186 32         56 my @unknown;
187 32         133 while (my ($name, $value) = splice @_, 0, 2) {
188 4 50       29 next if $fields->{"cf_$name"};
189 0 0       0 next if $self->can("configure_$name");
190 0         0 push @unknown, $name;
191             }
192 32         136 @unknown;
193             }
194              
195             sub cf_by_file {
196 0     0 0 0 (my MY $self, my $fn) = @_[0..1];
197 0         0 my ($ext) = $fn =~ m{\.(\w+)$};
198 0         0 $self->cf_by_filetype($ext, $fn, @_[3..$#_]);
199             }
200              
201             sub cf_by_filetype {
202 0     0 0 0 (my MY $self, my ($ext, $fn)) = @_[0..2];
203 0   0     0 $ext //= 'xhf';
204 0 0       0 my $sub = $self->can("read_file_$ext")
205             or croak "Unknown config file type: $fn";
206             $self->_with_loading_file
207             ($fn, sub {
208 0     0   0 $self->configure($sub->($self, $fn));
209 0         0 });
210             }
211              
212             sub define {
213 0     0 0 0 my ($class, $name, $sub) = @_;
214 0         0 *{YATT::Lite::Util::globref($class, $name)} = $sub;
  0         0  
215             }
216              
217             sub cf_mkaccessors {
218 13     13 0 40 my ($class, @names) = @_;
219 13         52 my $fields = YATT::Lite::Util::fields_hash($class);
220 13         102 foreach my $name (@names) {
221 13         40 my $cf = "cf_$name";
222 13 50       126 unless ($fields->{$cf}) {
223 0         0 croak "No such config: $name";
224             }
225 13         48 *{YATT::Lite::Util::globref($class, $name)} = sub {
226 1     1   7 shift->{$cf};
227 13         61 };
228             }
229             }
230             1;