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