Commit | Line | Data |
5964b3ca |
1 | package MooseX::Dependent; |
2 | |
3 | use 5.008; |
4 | |
5 | use strict; |
6 | use warnings; |
7 | |
8 | our $VERSION = '0.01'; |
9 | our $AUTHORITY = 'cpan:JJNAPIORK'; |
10 | |
11 | =head1 NAME |
12 | |
13 | MooseX::Dependent - Dependent L<MooseX::Types> constraints and L<Moose> attributes |
14 | |
15 | =head1 SYNOPSIS |
16 | |
17 | Given some L<MooseX::Types> declared as: |
18 | |
19 | package MyApp::Types; |
20 | |
21 | use MooseX::Types::Moose qw(Object, Int); |
22 | use MooseX::Dependent::Types qw(Dependent); |
23 | use Moosex::Types -declare => [qw(Set UniqueID)]; |
24 | |
25 | subtype Set, |
26 | as Object, |
27 | where { |
613e1e97 |
28 | shift->can('find'); |
5964b3ca |
29 | }; |
30 | |
31 | subtype UniqueID, |
32 | as Dependent[Int, Set], |
33 | where { |
613e1e97 |
34 | my ($int, $set) = @_; |
35 | return $set->find($int) ? 0:1; |
5964b3ca |
36 | }; |
37 | |
38 | Assuming 'Set' is a class that creates and manages sets of values (lists of |
39 | unique but unordered values) with a method '->find($n)', which returns true when |
40 | $n is a member of the set and which you instantiate like so: |
41 | |
613e1e97 |
42 | my $set_obj = Set->new(1,2,3,4,5); ## 1..5 are member of Set $set_obj' |
5964b3ca |
43 | |
44 | You can then use this $set_obj as a parameter on the previously declared type |
45 | constraint 'UniqueID'. This $set_obj become part of the constraint (you can't |
46 | actually use the constraint without it.) |
47 | |
6c67366e |
48 | UniqueID([$set_obj])->check(1); ## Not OK, since one isn't unique in $set_obj |
49 | UniqueID([$set_obj])->check('AAA'); ## Not OK, since AAA is not an Int |
50 | UniqueID([$set_obj])->check(100); ## OK, since 100 isn't in the set. |
613e1e97 |
51 | |
52 | You can assign the result of a parameterized dependent type to a variable or to |
53 | another type constraint, as like any other type constraint: |
54 | |
55 | ## As variable |
56 | my $unique = UniqueID[$set_obj]; |
57 | $unique->check(10); ## OK |
58 | $unique->check(2); ## Not OK, '2' is already in the set. |
59 | |
60 | ## As a new subtype |
61 | subtype UniqueInSet, as UniqueID[$set_obj]; |
62 | UniqueInSet->check(99); ## OK |
63 | UniqueInSet->check(3); ## Not OK, '3' is already in the set. |
64 | |
65 | However, you can't use a dependent type constraint to check or validate a value |
66 | until you've parameterized the dependent value: |
67 | |
68 | UniqueID->check(1000); ## Throws exception |
69 | UniqueID->validate(1000); ## Throws exception also |
70 | |
71 | This is a hard exception, rather than just returning a failure message (via the |
72 | validate method) or a false boolean (via the check method) since I consider an |
73 | unparameterized type constraint to be more than just an invalid condition. You |
74 | will have to catch these in an eval if you think you might have them. |
5964b3ca |
75 | |
613e1e97 |
76 | Afterward, you can use these dependent types on your L<Moose> based classes |
5964b3ca |
77 | and set the dependency target to the value of another attribute or method: |
78 | |
79 | TDB: Following is tentative |
80 | |
81 | package MyApp::MyClass; |
82 | |
83 | use Moose; |
84 | use MooseX::Dependent (or maybe a role, or traits...?) |
85 | use MooseX::Types::Moose qw(); |
86 | use MyApp::Types qw(UniqueID Set); |
87 | |
88 | has people => (is=>'ro', isa=>Set, required=>1); |
613e1e97 |
89 | has id => (is=>'ro', dependent_isa=>UniqueID, required=>1); |
9c319add |
90 | |
91 | TODO notes, coerce=>1 should coerce both check value and constraining value |
5964b3ca |
92 | |
93 | Please see the test cases for more examples. |
94 | |
95 | =head1 DESCRIPTION |
96 | |
97 | A dependent type is a type constraint whose validity is dependent on a second |
98 | value. You defined the dependent type constraint with a primary type constraint |
99 | (such as 'Int') a 'constraining' value type constraint (such as a 'Set' object) |
100 | and a coderef (such as a 'where' clause in your type constraint declaration) |
101 | which will compare the incoming value to be checked with a value that conforms |
102 | to the constraining type constraint. |
103 | |
104 | Once created, you can use dependent types directly, or in your L<Moose> based |
105 | attributes and methods (if you are using L<MooseX::Declare>). Attribute traits |
106 | are available to make it easy to assign the dependency to the value of another |
107 | attribute or another method. |
108 | |
109 | =head1 TYPE CONSTRAINTS |
110 | |
111 | All type constraints are defined in L<MooseX::Dependent::Types>. Please see |
112 | that class for more documentation and examples of how to create type constraint |
113 | libraries using dependent types. |
114 | |
115 | =cut |
116 | |
117 | =head1 ATTRIBUTE TRAITS |
118 | |
119 | TBD |
120 | |
121 | =head1 SEE ALSO |
122 | |
123 | L<Moose>, L<Moose::Meta::TypeConstraints>, L<MooseX::Types> |
124 | |
125 | =head1 AUTHOR |
126 | |
127 | John Napiorkowski, C<< <jjnapiork@cpan.org> >> |
128 | |
129 | =head1 COPYRIGHT & LICENSE |
130 | |
131 | This program is free software; you can redistribute it and/or modify |
132 | it under the same terms as Perl itself. |
133 | |
134 | =cut |
135 | |
136 | 1; |