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 30     30   83019 use strict;
  30         85  
  30         901  
3 30     30   196 use warnings qw(FATAL all NONFATAL misc);
  30         62  
  30         944  
4 30     30   161 use Carp;
  30         70  
  30         1634  
5 30     30   603 use mro 'c3';
  30         17332  
  30         161  
6              
7 30     30   1679 use fields;
  30         49299  
  30         119  
8              
9 30     30   12410 use YATT::Lite::XHF qw(read_file_xhf);
  30         101  
  30         43432  
10              
11             require YATT::Lite::Util;
12              
13             sub new {
14 7781     7781 1 50087 my $self = fields::new(shift);
15 7781 100       1156229 if (@_) {
16 7719         22052 my @task = $self->configure(@_);
17 7719         21959 $self->_before_after_new;
18 7719         20274 $self->after_new;
19 7719         18706 $$_[0]->($self, $$_[1]) for @task;
20             } else {
21 62         238 $self->_before_after_new;
22 62         169 $self->after_new;
23             }
24              
25             # To tolerate ``forgotten ->SUPER::after_new() bug'' in user class.
26 7781         20620 $self->_after_after_new;
27              
28 7780         25261 $self;
29             }
30              
31             sub just_new {
32 84     84 0 368 my $self = fields::new(shift);
33             # To delay configure_zzz.
34 84         20894 ($self, $self->configure(@_));
35             }
36              
37             # General initialization hook for each user class.
38       7677 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       7693     sub _before_after_new {}
45              
46             # Called after all configure_ZZZ hook is called.
47       7693     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 20     20   69 my ($self, $fn, $method) = @_[0 .. 2];
56 20         39 local $loading_file = $fn;
57 20 50       62 if (ref $method eq 'CODE') {
58 20         67 $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 90     90 1 2310 my ($self, $key, $default) = @_;
73 90         211 my $name = "cf_$key";
74 90         250 my $fields = YATT::Lite::Util::fields_hash($self);
75 90 50       324 unless (not exists $fields->{"cf_$name"}) {
76 0         0 confess $NO_SUCH_CONFIG_ITEM->($self, $name);
77             }
78 90   66     443 $self->{$name} // $default;
79             }
80              
81             sub configure {
82 8801     8801 1 15006 my $self = shift;
83 8801         13057 my (@task);
84 8801         23710 my $fields = YATT::Lite::Util::fields_hash($self);
85 8801 50 33     36504 my @params = @_ == 1 && ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
  0         0  
86 8801         27193 while (my ($name, $value) = splice @params, 0, 2) {
87 26319 50       55449 unless (defined $name) {
88 0         0 croak "Undefined name given for @{[ref($self)]}->configure(name=>value)!";
  0         0  
89             }
90 26319         43320 $name =~ s/^-//;
91 26319 100       115327 if (my $sub = $self->can("configure_$name")) {
    50          
92 1565         7207 push @task, [$sub, $value];
93             } elsif (not exists $fields->{"cf_$name"}) {
94 0         0 confess $NO_SUCH_CONFIG_ITEM->($self, $name);
95             } else {
96 24754         87335 $self->{"cf_$name"} = $value;
97             }
98             }
99 8801 100       18603 if (wantarray) {
100             # To delay configure_zzz.
101 7803         17638 @task;
102             } else {
103 998         2079 $$_[0]->($self, $$_[1]) for @task;
104 998         2800 $self;
105             }
106             }
107              
108             sub cf_list {
109 2     2 0 4 my $obj_or_class = shift;
110 2   66     13 my $pat = shift || qr{^cf_(.*)};
111 2         7 my $fields = YATT::Lite::Util::fields_hash($obj_or_class);
112 2 100       7 sort map {($_ =~ $pat) ? $1 : ()} keys %$fields;
  6         45  
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 753     753 0 1524 my MY $self = shift;
128 753         2160 my $fields = YATT::Lite::Util::fields_hash($self);
129             map {
130 753 100       1558 my ($from, $to) = ref $_ ? @$_ : ($_, $_);
  3179         7324  
131 3179 50       8048 unless (exists $fields->{"cf_$from"}) {
132 0         0 confess $NO_SUCH_CONFIG_ITEM->($self, $from);
133             }
134 3179         10413 $to => $self->{"cf_$from"}
135             } @_;
136             }
137              
138             sub cf_delegate_defined {
139 302     302 0 662 my MY $self = shift;
140 302         1127 my $fields = YATT::Lite::Util::fields_hash($self);
141 302         1308 $self->cf_delegate_known(1, $fields, @_);
142             }
143              
144             sub cf_delegate_known {
145 369     369 0 1186 (my MY $self, my ($raise_err, $fields)) = splice @_, 0, 3;
146             map {
147 369 50       793 my ($from, $to) = ref $_ ? @$_ : ($_, $_);
  3778         7759  
148 3778 100       8132 if (not exists $fields->{"cf_$from"}) {
149 171 50       393 $raise_err ? (confess $NO_SUCH_CONFIG_ITEM->($self, $from)) : ();
150             } else {
151 3607 100       10194 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 285     285 0 788 (my MY $self, my ($binding, $task)) = splice @_, 0, 3;
160 285         697 my ($keys, $values) = $self->cf_bindings(@$binding);
161 285         544 local @{$self}{@$keys} = @$values;
  285         525  
162 285 50       693 if (ref $task) {
163 285         760 $task->($self, @_);
164             } else {
165 0         0 $self->$task(@_);
166             }
167             }
168              
169             sub cf_bindings {
170 285     285 0 470 my MY $self = shift;
171 285 50       757 carp "Odd number of key value bindings" if @_ % 2;
172 285         486 my (@keys, @values);
173 285         873 while (my ($key, $value) = splice @_, 0, 2) {
174             # XXX: key check!
175             # XXX: task extraction!
176 12         29 push @keys, "cf_$key"; push @values, $value;
  12         40  
177             }
178 285         725 (\@keys, \@values);
179             }
180              
181              
182             sub cf_unknowns {
183 67     67 0 140 my $self = shift;
184 67   33     298 my $class = ref $self || $self;
185 67         185 my $fields = YATT::Lite::Util::fields_hash($class);
186 67         129 my @unknown;
187 67         289 while (my ($name, $value) = splice @_, 0, 2) {
188 6 50       33 next if $fields->{"cf_$name"};
189 0 0       0 next if $self->can("configure_$name");
190 0         0 push @unknown, $name;
191             }
192 67         276 @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 19     19 0 88 my ($class, @names) = @_;
219 19         91 my $fields = YATT::Lite::Util::fields_hash($class);
220 19         109 foreach my $name (@names) {
221 19         68 my $cf = "cf_$name";
222 19 50       94 unless ($fields->{$cf}) {
223 0         0 croak "No such config: $name";
224             }
225 19         81 *{YATT::Lite::Util::globref($class, $name)} = sub {
226 1     1   16 shift->{$cf};
227 19         92 };
228             }
229             }
230             1;