added some docs about possible future syntaxes
[gitmo/MooseX-Dependent.git] / lib / MooseX / Dependent.pm
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 UniqueInt)];
24     
25     use Set::Scalar;
26
27         subtype Set,
28                 as class_type("Set::Scalar");
29
30         subtype UniqueInt,
31                 as Dependent[Int, Set],
32                 where {
33                     my ($int, $set) = @_;
34                     return !$set->has($int) ;
35                 };
36
37 Assuming 'Set' is a class that creates and manages sets of values (lists of
38 unique but unordered values) with a method '->has($n)', which returns true when
39 $n is a member of the set and which you instantiate like so:
40
41     my $set_obj = Set->new(1,2,3,4,5); ## 1..5 are member of Set $set_obj'
42
43 You can then use this $set_obj as a parameter on the previously declared type
44 constraint 'UniqueInt'.  This $set_obj become part of the constraint (you can't
45 actually use the constraint without it.)
46
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.
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
55     my $unique = UniqueInt[$set_obj];
56     $unique->check(10); ## OK
57     $unique->check(2); ## Not OK, '2' is already in the set.
58     
59     ## As a new subtype
60     subtype UniqueInSet, as UniqueInt[$set_obj];
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
67     UniqueInt->check(1000); ## Throws exception
68     UniqueInt->validate(1000); ## Throws exception also
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.
74
75 Afterward, you can use these dependent types on your L<Moose> based classes
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();
85     use MyApp::Types qw(UniqueInt Set);
86     
87     has people => (is=>'ro', isa=>Set, required=>1);
88     has id => (is=>'ro', dependent_isa=>UniqueInt, required=>1);
89     
90     TODO notes, coerce=>1 should coerce both check value and constraining value
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
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
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
135 Copyright 2009, John Napiorkowski C<< <jjnapiork@cpan.org> >>
136
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;