File Coverage

blib/lib/ExtJS/AutoForm/Moose/Types.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package ExtJS::AutoForm::Moose::Types;
2              
3 1     1   4154 use warnings;
  1         2  
  1         31  
4 1     1   5 use strict;
  1         2  
  1         31  
5              
6 1     1   511 use Moose::Exporter;
  0            
  0            
7             use JSON::Any;
8             use Carp qw(confess);
9              
10             =head1 NAME
11              
12             ExtJS::AutoForm::Moose::Types - Manage extjs form generation for Moose types
13              
14             =cut
15              
16             =head1 SYNOPSIS
17              
18             Those are in fact the current type reflections implemented, except for enum, which is treated in a special way so far:
19              
20             reflect 'Any' => extjs { {
21             xtype => "displayfield",
22             fieldLabel=> "Unsupported field type"
23             } };
24              
25             reflect 'Str' => extjs { {
26             xtype => "textfield",
27             value => \&ExtJS::AutoForm::Moose::Types::value_or_default
28             } };
29              
30             reflect 'Num' => extjs { {
31             xtype => "numberfield",
32             allowDecimals => JSON::Any::true,
33             value => \&ExtJS::AutoForm::Moose::Types::value_or_default
34             } };
35              
36             reflect 'Int' => extjs { {
37             xtype => "numberfield",
38             allowDecimals => JSON::Any::false,
39             value => \&ExtJS::AutoForm::Moose::Types::value_or_default
40             } };
41              
42             reflect 'Bool' => extjs { {
43             xtype => "checkbox",
44             checked => \&ExtJS::AutoForm::Moose::Types::value_or_default_bool
45             } };
46              
47             =head1 DESCRIPTION
48              
49             This module does two things: hold the registry of known type contraints reflections, and provide a bit of
50             curry to ease adding reflections for new types based on their type name.
51              
52             =head2 Syntax curry
53              
54             =over
55              
56             =item reflect 'I<type_name>' => extjs { I<code returning a hash template> }
57              
58             Create a new moose type constraint to extjs field association.
59              
60             The template parameter must be specified as a perl function that returns a hash that will be,
61             at some point, encoded as JSON and sent to a browser. You can use callbacks as values on this
62             hash, which will be called and it's result used as the generated key value (See callbacks in
63             L</TEMAPLTE FORMAT> below).
64              
65             =back
66              
67             =head2 Template format
68              
69             The template format is the one used by ExtJS Component class creation. This means it does all
70             it's job using xtypes and does not use any javascript functions.
71              
72             =head2 Customizing tamplate values using callbacks
73              
74             Any template hash value can be a callback instead of a plain value, which allows further
75             customization of the generated extjs description.
76              
77             Those callbacks receive two parameters: the object instance (undef when generation has been
78             called statically), and the L<Moose::Meta::Attribute> instance for that attribute.
79              
80             Example:
81              
82             sub enum_values($$) {
83             my ($obj,$attribute) = @_;
84             return $attribute->type_constraint->values;
85             }
86              
87             See L</REFLECTION HELPERS> below for a list of helper callbacks provided by default.
88              
89             =head2 Javascript functions on the generated result?
90              
91             Using javascript isn't straight-forward because the generated result is usually encoded as
92             JSON, which by itself does not support javascript functions.
93              
94             In those cases you need to use javascript functions, you've got a few options:
95              
96             =over
97              
98             =item * Don't
99              
100             If you read the ExtJS API docs carefully, you'll notice there's really not that much that cannot
101             be controlled through config parameters.
102              
103             =item * Extend the base ExtJS components
104              
105             It's not difficult, and you can register those as a new xtype.
106              
107             =item * Encode the generated structure yourself
108              
109             This seems like a dirty hack to me, and you'll probably be meriting for a place in hell, but...
110              
111             Since JSON does not allow functions, you cannot use any of the available JSON modules supported
112             by JSON::Any. You can get around this by writing your own structure to JSON encoder that knows
113             how to handle that.
114              
115             You could also replace any functions on the whole structure with tokens and replace those tokens
116             on the resulting JSON.
117              
118             =back
119              
120             =cut
121              
122             #
123             # EXPORTING
124             #
125             Moose::Exporter->setup_import_methods(
126             as_is => [ qw(
127             reflect extjs
128             ) ],
129             );
130              
131             our %REGISTRY = ();
132              
133             #
134             # SYNTAX CURRY
135             #
136             sub extjs(&) { { template => $_[0] } }
137              
138             sub reflect($$;$) {
139             my $type_name = shift;
140             my %p = map { %{$_} } @_; #really useless here. done this way since I was hoping to extend own Moose (sub)type sugar
141              
142             unless(ref($p{template}) eq "CODE")
143             {
144             local $Carp::CarpLevel = $Carp::CarpLevel + 1;
145             confess("A callback must be provided for type reflection");
146             }
147              
148             my $test = $p{template}->();
149              
150             unless(ref($test) && ref($test) eq "HASH")
151             {
152             local $Carp::CarpLevel = $Carp::CarpLevel + 1;
153             confess("The callback provided for '$type_name' reflection does not return a hash structure");
154             }
155              
156             $REGISTRY{$type_name} = $p{template};
157             }
158              
159             #
160             # Base TypeConstraint reflections
161             #
162             reflect 'Any' => extjs { {
163             xtype => "displayfield",
164             fieldLabel=> "Unsupported field type"
165             } };
166              
167             reflect 'Str' => extjs { {
168             xtype => "textfield",
169             value => \&ExtJS::AutoForm::Moose::Types::value_or_default
170             } };
171              
172             reflect 'Num' => extjs { {
173             xtype => "numberfield",
174             allowDecimals => JSON::Any::true,
175             value => \&ExtJS::AutoForm::Moose::Types::value_or_default
176             } };
177              
178             reflect 'Int' => extjs { {
179             xtype => "numberfield",
180             allowDecimals => JSON::Any::false,
181             value => \&ExtJS::AutoForm::Moose::Types::value_or_default
182             } };
183              
184             reflect 'Bool' => extjs { {
185             xtype => "checkbox",
186             checked => \&ExtJS::AutoForm::Moose::Types::value_or_default_bool
187             } };
188              
189             reflect '__ENUM__' => extjs { {
190             xtype => "combo",
191             store => \&ExtJS::AutoForm::Moose::Types::enum_values,
192             } };
193              
194             =head1 REFLECTION HELPERS
195              
196             The following subroutines are provided as helpers for common checks and transformations used on
197             the ExtJS templates.
198              
199             =over
200              
201             =cut
202              
203             =item value_or_default
204              
205             Returns the current value of this attribute for the given object, or it's default value if reflection
206             was done directly on the class
207              
208             =cut
209             sub value_or_default($$) {
210             my ($obj,$attribute) = @_;
211             return $obj ? $attribute->get_value($obj) : $attribute->default(undef);
212             }
213              
214             =item value_or_default_bool
215              
216             Does the same as the previous helper, but it returns a JSON boolean value suitable for JSON::Any encoding
217              
218             =cut
219             sub value_or_default_bool($$) {
220             my ($obj,$attribute) = @_;
221             return JSON::Any::true if ( $obj ? $attribute->get_value($obj) : $attribute->default(undef) );
222             return JSON::Any::false;
223             }
224              
225             =item required_attribute_bool
226              
227             Returns a JSON true value when this attribute is required, false otherwise
228              
229             =cut
230             sub required_attribute_bool($$) {
231             my ($obj,$attribute) = @_;
232             return $attribute->is_required ? JSON::Any::true : JSON::Any::false;
233             }
234              
235             =item enum_values
236              
237             Returns an array containing the enum-type attribute values. See L<Moose::Meta::TypeConstraint::Enum>.
238              
239             =cut
240             sub enum_values($$) {
241             my ($obj,$attribute) = @_;
242             return $attribute->type_constraint->values;
243             }
244              
245             =back
246              
247             =cut
248              
249             =head1 AUTHOR
250              
251             Quim Rovira, C<< quim at rovira.cat >>
252              
253             =head1 BUGS
254              
255             Please report any bugs or feature requests to C<bug-moosex-extjs-reflection at rt.cpan.org>, or through
256             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Moosex-ExtJS-Reflection>. I will
257             be notified, and then you'll automatically be notified of progress on your bug as I make changes.
258              
259             =head1 SUPPORT
260              
261             You can find documentation for this module with the perldoc command.
262              
263             perldoc ExtJS::AutoForm::Moose::Types
264              
265              
266             You can also look for information at:
267              
268             =over 4
269              
270             =item * RT: CPAN's request tracker
271              
272             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=ExtJS-AutoForm-Moose>
273              
274             =item * AnnoCPAN: Annotated CPAN documentation
275              
276             L<http://annocpan.org/dist/ExtJS-AutoForm-Moose>
277              
278             =item * CPAN Ratings
279              
280             L<http://cpanratings.perl.org/d/ExtJS-AutoForm-Moose>
281              
282             =item * Search CPAN
283              
284             L<http://search.cpan.org/dist/ExtJS-AutoForm-Moose/>
285              
286             =back
287              
288              
289             =head1 ACKNOWLEDGEMENTS
290              
291              
292             =head1 LICENSE AND COPYRIGHT
293              
294             Copyright 2011 Quim Rovira.
295              
296             This program is free software; you can redistribute it and/or modify it
297             under the terms of either: the GNU General Public License as published
298             by the Free Software Foundation; or the Artistic License.
299              
300             See http://dev.perl.org/licenses/ for more information.
301              
302             ExtJS trademarks are property of Sencha Labs L<http://www.sencha.com>
303              
304             =cut
305              
306             1; # End of ExtJS::AutoForm::Moose::Types