]> git.vpit.fr Git - perl/modules/LaTeX-TikZ.git/blob - lib/LaTeX/TikZ/Meta/TypeConstraint/Autocoerce.pm
cdbc69c083c71a60cd759e7019a45bba4e137e45
[perl/modules/LaTeX-TikZ.git] / lib / LaTeX / TikZ / Meta / TypeConstraint / Autocoerce.pm
1 package LaTeX::TikZ::Meta::TypeConstraint::Autocoerce;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 LaTeX::TikZ::Meta::TypeConstraint::Autocoerce - Type constraint metaclass that autoloads type coercions.
9
10 =head1 VERSION
11
12 Version 0.01
13
14 =cut
15
16 our $VERSION = '0.01';
17
18 use Scalar::Util qw/blessed/;
19
20 use Sub::Name ();
21
22 use Any::Moose;
23 use Any::Moose 'Util' => [ 'find_meta' ];
24
25 extends any_moose('Meta::TypeConstraint');
26
27 =head1 ATTRIBUTES
28
29 =head2 C<mapper>
30
31 A code reference that maps an object class name to the name of the package in which the coercion can be found, or C<undef> to disable coercion for this class name.
32 It is called with the type constraint object as first argument, followed by the class name.
33
34 =cut
35
36 has 'mapper' => (
37  is  => 'ro',
38  isa => 'CodeRef',
39 );
40
41 =head2 C<parent>
42
43 =cut
44
45 has 'parent' => (
46  is       => 'ro',
47  isa      => any_moose('Meta::TypeConstraint'),
48  required => 1,
49 );
50
51 =head2 C<user_constraint>
52
53 =cut
54
55 has 'user_constraint' => (
56  is       => 'ro',
57  isa      => 'Maybe[CodeRef]',
58  required => 1,
59 );
60
61 =head1 METHODS
62
63 =cut
64
65 around 'new' => sub {
66  my ($orig, $class, %args) = @_;
67
68  unless (exists $args{mapper}) {
69   $args{mapper} = sub { join '::', $_[0]->parent->name, $_[1] };
70  }
71
72  my $parent = delete $args{parent};
73  unless (blessed $parent) {
74   $parent = find_meta($parent)->type_constraint;
75  }
76  __PACKAGE__->meta->find_attribute_by_name('parent')
77                   ->type_constraint->assert_valid($parent);
78  $args{parent} = $parent;
79
80  $args{user_constraint} = delete $args{constraint};
81
82  if (any_moose() eq 'Moose') {
83   $args{coercion} = Moose::Meta::TypeCoercion->new;
84  }
85
86  my $tc;
87  $args{constraint} = Sub::Name::subname('_constraint' => sub {
88   my ($thing) = @_;
89
90   # Remember that when ->check is called inside coerce, a return value of 0
91   # means that coercion should take place, while 1 signifies that the value is
92   # already OK.
93
94   # First, try a possible user defined constraint
95   my $user = $tc->user_constraint;
96   if (defined $user) {
97    my $ok = $user->($thing);
98    return 1 if $ok;
99   }
100
101   # Then, it's valid if and only if it passes the parent type constraint
102   return $tc->parent->check($thing);
103  });
104
105  $tc = $class->$orig(%args);
106 };
107
108 around 'coerce' => sub {
109  my ($orig, $tc, $thing) = @_;
110
111  # The original coerce gets an hold onto the type coercions *before* calling
112  # the constraint. Thus, we have to force the loading before recalling into
113  # $orig.
114
115  # First, check whether $thing is already of the right kind.
116  return $thing if $tc->check($thing);
117
118  # If $thing isn't even an object, don't bother trying to autoload a coercion
119  my $class = blessed($thing);
120  if (defined $class) {
121   $class = $tc->mapper->($tc, $class);
122
123   if (defined $class) {
124    # Find the file to autoload
125    (my $pm = $class) =~ s{::}{/}g;
126    $pm .= '.pm';
127
128    unless ($INC{$pm}) { # Not loaded yet
129     local $@;
130     eval {
131      # We die often here, even though we're not really interested in the error.
132      # However, if a die handler is set (e.g. to \&Carp::confess), this can get
133      # very slow. Resetting the handler shows a 10% total time improvement for
134      # the geodyn app.
135      local $SIG{__DIE__};
136      require $pm;
137     };
138    }
139   }
140  }
141
142  $tc->$orig($thing);
143 };
144
145 __PACKAGE__->meta->make_immutable(
146  inline_constructor => 0,
147 );
148
149 =head1 AUTHOR
150
151 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
152
153 You can contact me by mail or on C<irc.perl.org> (vincent).
154
155 =head1 BUGS
156
157 Please report any bugs or feature requests to C<bug-latex-tikz at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=LaTeX-TikZ>.
158 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
159
160 =head1 SUPPORT
161
162 You can find documentation for this module with the perldoc command.
163
164     perldoc LaTeX::TikZ
165
166 =head1 COPYRIGHT & LICENSE
167
168 Copyright 2010 Vincent Pit, all rights reserved.
169
170 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
171
172 =cut
173
174 1; # End of LaTeX::TikZ::Meta::TypeConstraint::Autocoerce