X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=lib%2FLaTeX%2FTikZ%2FFunctor%2FRule.pm;fp=lib%2FLaTeX%2FTikZ%2FFunctor%2FRule.pm;h=efaff7b1cc73078b012ff9b7499ec87feacad17f;hb=a44105abc490869376ff448faa654f429324abe2;hp=0000000000000000000000000000000000000000;hpb=1055a774ea694509df09ea6bf90747b81699af85;p=perl%2Fmodules%2FLaTeX-TikZ.git diff --git a/lib/LaTeX/TikZ/Functor/Rule.pm b/lib/LaTeX/TikZ/Functor/Rule.pm new file mode 100644 index 0000000..efaff7b --- /dev/null +++ b/lib/LaTeX/TikZ/Functor/Rule.pm @@ -0,0 +1,216 @@ +package LaTeX::TikZ::Functor::Rule; + +use strict; +use warnings; + +=head1 NAME + +LaTeX::TikZ::Functor::Rule - An object that specifies how functors should handle a certain kind of set or mod. + +=head1 VERSION + +Version 0.01 + +=cut + +our $VERSION = '0.01'; + +=head1 DESCRIPTION + +A rule specifies how functors should handle a certain kind of set or mod. +A functor is basically an ordered collection of rules. + +=cut + +use Carp (); + +use Any::Moose; +use Any::Moose 'Util' => [ qw[find_meta does_role] ]; +use Any::Moose 'Util::TypeConstraints'; + +=head1 ATTRIBUTES + +=head2 C + +=cut + +has 'target' => ( + is => 'ro', + isa => 'ClassName|RoleName', + required => 1, +); + +=head2 C + +=cut + +has 'handler' => ( + is => 'ro', + isa => 'CodeRef', + required => 1, +); + +=head2 C + +=cut + +has 'is_role' => ( + is => 'ro', + isa => 'Bool', + required => 1, +); + +=head2 C + +=cut + +has 'is_set' => ( + is => 'ro', + isa => 'Bool', + required => 1, +); + +my $ltfrl_tc = subtype 'LaTeX::TikZ::Functor::RuleList' + => as 'ArrayRef[LaTeX::TikZ::Functor::Rule]'; + +=head1 METHODS + +=head2 C<< new target => $target, handler => $handler >> + +=cut + +around 'BUILDARGS' => sub { + my ($orig, $class, %args) = @_; + + my $target = $args{target}; + __PACKAGE__->meta->find_attribute_by_name('target') + ->type_constraint->assert_valid($target); + + (my $pm = $target) =~ s{::}{/}g; + $pm .= '.pm'; + require $pm; + + my $meta = find_meta($target); + Carp::confess("No meta object associated with target $target") + unless defined $meta; + $args{is_role} = $meta->isa(any_moose('Meta::Role')); + + my $is_set; + if (does_role($target, 'LaTeX::TikZ::Set')) { + $is_set = 1; + } elsif (does_role($target, 'LaTeX::TikZ::Mod')) { + $is_set = 0; + } else { + Carp::confess("Target $target is neither a set nor a mod"); + } + $args{is_set} = $is_set; + + $class->$orig(%args); +}; + +=head2 C<< insert into => \@list, overwrite => $overwrite, replace => $replace >> + +Inserts the current rule into the list of rules C<@list>. + +If C<$replace> is false, then the rule will be appended to the C<@list> ; except if there already is an existent entry for the same target, in which case it will be overwritten if C<$overwrite> is true, or an exception will be thrown if it is false. + +If C<$replace> is true, then the rule will replace the first rule in the list that is a subclass or that consumes the role denoted by the target. +All the subsequent rules in the list that inherit or consume the target will be removed. + +=cut + +sub insert { + my ($rule, %args) = @_; + + my $list = $args{into}; + $ltfrl_tc->assert_valid($list); + + my $overwrite = $args{overwrite}; + my $replace = $args{replace}; + + my $target = $rule->target; + my $is_role = $rule->is_role; + + if ($replace) { + my @remove; + + for my $i (0 .. $#$list) { + my $old_target = $list->[$i]->target; + if ($rule->handles($old_target)) { + if (defined $rule) { + splice @$list, $i, 1, $rule; + $rule = undef; + } else { + push @remove, $i; + } + } + } + + my $shift; + for (@remove) { + splice @$list, $_ - $shift, 1; + ++$shift; + } + return 1 unless defined $rule; + + } else { # Replace only an existent rule + + for my $i (0 .. $#$list) { + my $old_target = $list->[$i]->target; + if ($old_target eq $target) { + Carp::confess("Default rule already defined for target $target") + unless $overwrite; + splice @$list, $i, 1, $rule; + return 1; + } + } + } + + push @$list, $rule; + return 0; +} + +=head2 C + +Returns true if and only if the current rule can handle the object or class/role name C<$obj>. + +=cut + +sub handles { + my ($rule, $obj) = @_; + + $rule->is_role ? does_role($obj, $rule->target) : $obj->isa($rule->target); +} + +__PACKAGE__->meta->make_immutable; + +=head1 SEE ALSO + +L, L. + +=head1 AUTHOR + +Vincent Pit, C<< >>, L. + +You can contact me by mail or on C (vincent). + +=head1 BUGS + +Please report any bugs or feature requests to C, or through the web interface at L. +I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc LaTeX::TikZ + +=head1 COPYRIGHT & LICENSE + +Copyright 2010 Vincent Pit, all rights reserved. + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=cut + +1; # End of LaTeX::TikZ::Functor::Rule