Dot
view release on metacpan or search on metacpan
};
}
} elsif ($q eq 'sane') {
($^H, ${^WARNING_BITS}, %^H) = @H;
} else {
confess("unknown request $q");
}
}
}
}
Dot->import(iautoload => [[qw/Scalar::Util weaken/],
[qw/Carp confess/]]);
sub add {
my $o = shift;
while (@_) {
my ($k, $v) = splice @_, 0, 2;
$o->{$k} = $v;
}
}
sub mod {
my $o = shift;
weaken($o);
add($o,
weaken => \&weaken,
add => sub {
unshift @_, $o;
goto &add;
},
del => sub {
map { $_ => delete $o->{$_} } @_;
});
$o;
}
1;
sub class {
my $obj = shift;
$obj->{method1} = sub {
# I need to access another public method called method0 of
# this object, but oops, circular reference.
$obj->{method0}(...);
};
$obj;
}
You must say C<weaken(my $obj = shift)> when this happens, and C<weaken> (from
C<Scalar::Util>) is the only thing that's necessary (sometimes) to use C<Dot>,
everything else is optional, you don't even need C<Dot> itself.
=head2 Inheritance
In C<Dot>, when a class has been called to modify an object then this object
inherits from that class, and when a class calls another class to help it
modify an object then the former class inherits from the latter. And
multiple inheritance happens when more than one classes are called directly.
As you will see, inheritance in C<Dot> is pretty different, it's dividable,
does provides two functionalities for convenience: a class named C<mod>
and an import subroutine to be C<use>d by other modules.
=head2 C<Dot::mod>
C<Dot::mod> is a C<Dot> class, we call it C<Dot> for short, it's convenient to always inherit from
it since it provides three methods that're used frequently:
=over 4
=item weaken
Not a method exactly, but as explained previously, C<weaken> is the only thing that's sometimes
necessary to use C<Dot>, thus it's important, so instead of loading
C<Scalar::Util> everywhere, C<Dot> exports it and when you have an object
that's been modified by C<Dot> you can just call C<weaken> using C<< $obj->{weaken}($obj) >>.
=item add
Add key-value pairs to this object so that they could be accessed publicly.
It just does hash assignment and entirely for readability purpose:
$obj->{add}(... => ...,
... => ...,
...);
t/attribute-method.t view on Meta::CPAN
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
=cut
use Dot 'sane', iautoload => [qw'Scalar::Util Carp', [qw'Test::More 0ok']];
# Class for the ability to add attribute.
sub mod {
Dot::mod(my $o = shift);
$o->{weaken}($o);
$o->{attr} = sub {
my $attr = shift;
for my $k (keys %$attr) {
my ($c, $t, $f) = $attr->{$k};
if (exists $o->{$k}) { $t = delete $o->{$k} }
elsif (exists $c->{default}) { $t = $c->{default} }
elsif ($c->{defcref}) { $t = $c->{defcref}() }
elsif ($c->{required}) { confess("Attribute $k is required.") }
else { $f = 1 }
$o->{$k} = sub {
t/attribute-tie.t view on Meta::CPAN
}
for my $n (qw/store fetch/) {
no strict 'refs';
*{uc $n} = sub {
goto &{shift->{$n}};
};
}
# Class for the ability to add attribute.
sub mod1 {
Dot::mod(my $o = shift);
$o->{weaken}($o);
$o->{add}(#
attr => sub {
my $attr = shift;
# It's nasty here that we can't use each.
for my $k (keys %$attr) {
my ($v, $t, $f) = $attr->{$k};
if (exists $o->{$k}) { $t = delete $o->{$k} }
elsif (exists $v->{default}) { $t = $v->{default} }
elsif ($v->{defcref}) { $t = $v->{defcref}() }
elsif ($v->{required}) { confess("Attribute $k is required.") }
( run in 0.809 second using v1.01-cache-2.11-cpan-65fba6d93b7 )