]> git.vpit.fr Git - perl/modules/LaTeX-TikZ.git/blobdiff - lib/LaTeX/TikZ/Functor.pm
Move most of the functor logic into a new LT::Functor::Role class
[perl/modules/LaTeX-TikZ.git] / lib / LaTeX / TikZ / Functor.pm
index eaf13cabed4a9b35bc7eb778cbc7977e8624ce47..efa66a095283d48de76a5c120eded45e40946d40 100644 (file)
@@ -26,21 +26,18 @@ use Carp ();
 
 use Sub::Name ();
 
+use LaTeX::TikZ::Functor::Rule;
+
 use LaTeX::TikZ::Interface;
 
 use LaTeX::TikZ::Tools;
 
-use Any::Moose 'Util' => [ qw[find_meta does_role] ];
-
 my $lts_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Set');
 
-my @default_set_rules;
-my @default_mod_rules;
-
-my ($validate_rule, $insert_rule);
+my $validate_spec;
 BEGIN {
- $validate_rule = Sub::Name::subname('validate_rule' => sub {
-  my ($spec, $handler) = @_;
+ $validate_spec = Sub::Name::subname('validate_spec' => sub {
+  my ($spec) = @_;
 
   my ($replace, $target);
   if (defined $spec and ref $spec eq ''
@@ -51,73 +48,7 @@ BEGIN {
    Carp::confess("Invalid rule spec $spec");
   }
 
-  (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;
-  my $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");
-  }
-
-  Carp::confess("Invalid handler for rule spec $spec")
-                             unless defined $handler and ref $handler eq 'CODE';
-
-  return [ $target, $handler, $replace, $is_role, $is_set ];
- });
-
- $insert_rule = Sub::Name::subname('insert_rule' => sub {
-  my ($rule, $list, $overwrite) = @_;
-
-  my ($target, $replace, $is_role) = @{$rule}[0, 2, 3];
-
-  if ($replace) {
-   my @remove;
-
-   for my $i (0 .. $#$list) {
-    my $old_target = $list->[$i]->[0];
-    if ($is_role ? does_role($old_target, $target)
-                 : $old_target->isa($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]->[0];
-    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;
+  return $target, $replace;
  });
 }
 
@@ -168,6 +99,9 @@ Thus, if you define your own L<LaTeX::TikZ::Set> or L<LaTeX::TikZ::Mod> object,
 
 =cut
 
+my @default_set_rules;
+my @default_mod_rules;
+
 sub new {
  my ($class, %args) = @_;
 
@@ -178,12 +112,21 @@ sub new {
  while (@user_rules) {
   my ($spec, $handler) = splice @user_rules, 0, 2;
 
-  my $rule = $validate_rule->($spec, $handler);
+  my ($target, $replace) = $validate_spec->($spec);
 
-  $insert_rule->($rule, $rule->[4] ? \@set_rules : \@mod_rules, 1);
+  my $rule = LaTeX::TikZ::Functor::Rule->new(
+   target  => $target,
+   handler => $handler,
+  );
+
+  $rule->insert(
+   into      => $rule->is_set ? \@set_rules : \@mod_rules,
+   overwrite => 1,
+   replace   => $replace,
+  );
  }
 
- my %dispatch  = map { $_->[0] => $_ } @set_rules, @mod_rules;
+ my %dispatch = map { $_->target => $_ } @set_rules, @mod_rules;
 
  my $self;
 
@@ -195,14 +138,14 @@ sub new {
   my $rule = $dispatch{ref($set)};
   unless ($rule) {
    for (@set_rules) {
-    if ($_->[2] ? $set->does($_->[0]) : $set->isa($_->[0])) {
+    if ($_->handles($set)) {
      $rule = $_;
      last;
     }
    }
-   $rule = [ undef, sub { $_[1] } ] unless $rule;
   }
-  my $new_set = $rule->[1]->($self, $set, @_);
+  my $new_set = $rule ? $rule->handler->($self, $set, @_)
+                      : $set;
   my $is_new  = $new_set ne $set;
 
   my @new_mods;
@@ -211,17 +154,14 @@ MOD:
    my $rule = $dispatch{ref($mod)};
    unless ($rule) {
     for (@mod_rules) {
-     if ($_->[2] ? $mod->does($_->[0]) : $mod->isa($_->[0])) {
+     if ($_->handles($mod)) {
       $rule = $_;
       last;
      }
     }
-    unless ($rule) {
-     push @new_mods, $mod;
-     next MOD;
-    }
    }
-   push @new_mods, $rule->[1]->($self, $mod, @_);
+   push @new_mods, $rule ? $rule->handler->($self, $mod, @_)
+                         : $mod;
   }
 
   $new_set->mod(@new_mods) if $is_new;
@@ -251,13 +191,19 @@ Returns true if and only if an existent rule was replaced.
 
 sub default_rule {
  shift;
+ my ($spec, $handler) = @_;
 
- my $rule = $validate_rule->(@_);
+ my ($target, $replace) = $validate_spec->($spec);
+
+ my $rule = LaTeX::TikZ::Functor::Rule->new(
+  target  => $target,
+  handler => $handler,
+ );
 
- $insert_rule->(
-  $rule,
-  $rule->[4] ? \@default_set_rules : \@default_mod_rules,
-  0,
+ $rule->insert(
+  into      => $rule->is_set ? \@default_set_rules : \@default_mod_rules,
+  overwrite => 0,
+  replace   => $replace,
  );
 }