/[Frey]/trunk/lib/Frey/Introspect.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/lib/Frey/Introspect.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 59 - (show annotations)
Tue Jul 8 12:19:04 2008 UTC (15 years, 9 months ago) by dpavlin
File size: 5705 byte(s)
don't hide load_class dies
1 package Frey::Introspect;
2
3 use Moose;
4 use Carp;
5 use Class::MOP;
6 use Moose::Meta::Role;
7 use Moose::Meta::Class;
8 use Scalar::Util qw/blessed/;
9 use Data::Dump qw/dump/;
10 use File::Slurp;
11 use List::Util;
12
13 use Continuity::Widget::DomNode;
14 use lib 'lib';
15
16 extends 'Frey';
17
18 has 'package' => (
19 is => 'rw',
20 isa => 'Str',
21 required => 1,
22 );
23
24 has 'path' => (
25 is => 'rw',
26 );
27
28 =head2 load_package
29
30 my ( $class, $meta, $is_role ) = $o->load_package( 'Some::Package' );
31
32 =cut
33
34 sub load_package {
35 my ( $self ) = @_;
36
37 my $package = $self->package;
38
39 #intercept role application so we can accurately generate
40 #method and attribute information for the parent class.
41 #this is fragile, but there is not better way that i am aware of
42 my $rmeta = Moose::Meta::Role->meta;
43 $rmeta->make_mutable if $rmeta->is_immutable;
44 my $original_apply = $rmeta->get_method("apply")->body;
45 $rmeta->remove_method("apply");
46 my @roles_to_apply;
47 $rmeta->add_method("apply", sub{push(@roles_to_apply, [@_])});
48 #load the package with the hacked Moose::Meta::Role
49
50 #eval { Class::MOP::load_class($package); };
51 #confess "Failed to load package ${package} $@" if $@;
52 Class::MOP::load_class($package);
53
54 my $meta = $package->meta;
55
56 my ($class, $is_role);
57 if($package->meta->isa('Moose::Meta::Role')){
58 $is_role = 1;
59 # we need to apply the role to a class to be able to properly introspect it
60 $class = Moose::Meta::Class->create_anon_class;
61 $original_apply->($meta, $class);
62 } else {
63 #roles don't have superclasses ...
64 $class = $meta;
65 }
66 return ( $class, $meta, $is_role );
67 }
68
69 =head2 joose
70
71 my $js = $o->joose( 'Some::Package' );
72
73 =cut
74
75 sub joose {
76 my ($self) = @_;
77
78 my ( $class, $meta, $is_role ) = $self->load_package;
79
80 if ( ! $is_role ) {
81 my @superclasses = map{ $_->meta->name }
82 grep { $_ ne 'Moose::Object' } $meta->superclasses;
83 warn "superclasses ",dump( @superclasses );
84 }
85
86 my $out;
87
88 my ( $m, $c ) = split(/::/, $class->name, 2);
89 my $filename = $m . '.' . ( $c ? "$c." : '' ) . 'js';
90
91 $out .= "Module(\"$m\", function (m) {\n\tClass(\"$c\", {\n\t\thas: {\n";
92
93 foreach ( $class->get_attribute_list ) {
94 $out .= "\t\t\t$_: {\n";
95
96 my $attr = $class->get_attribute($_);
97 my $is = $attr->_is_metadata;
98 $out .= "\t\t\t\tis: \"$is\",\n" if defined $is;
99 $out .= "\t\t\t\tlazy: true,\n" if $attr->is_lazy;
100 $out .= "\t\t\t\trequired: true,\n" if $attr->is_required;
101 $out .= "\t\t\t\tinit: \"" . $attr->init_arg . "\",\n" if $attr->init_arg; # FIXME
102
103 if( defined(my $isa = $attr->_isa_metadata) ){
104 if( blessed $isa ){
105 while( blessed $isa ){
106 $isa = $isa->name;
107 }
108 }
109 $isa =~ s/\s+\|\s+undef//gi;
110 $out .= "\t\t\t\tisa: Moose.$isa,\n";
111 }
112
113
114 $out .= "\t\t\t},\n";
115
116 }
117
118 $out .= "\t\t},\n\t\tmeta: Frey.HTML,
119 classMethods: {
120 renderHTML: function () {
121 return new Joose.SimpleRequest().getText(\"/~/${m}::${c}\")
122 },\n";
123
124 $out .= "\t\t},\n";
125
126 $out .= "\t}),\n";
127
128 $out =~ s/,\n$/\n/;
129 $out .= "});\n";
130
131 $out .= "\nconsole.log( 'loaded " . $class->name . " from $filename' );\n";
132
133 warn $class->dump(2);
134
135 warn "method_list = ",dump( $class->get_method_list );
136 warn dump( map{ $class->get_method($_)->name } sort $class->get_method_list );
137
138 # print $out;
139 my $path = "static/blib/$filename";
140 write_file( $path, $out );
141 warn "# created $path\n";
142 $self->path( $path );
143
144 return $out;
145 }
146
147 =head2 methods
148
149 my @methods = $o->methods;
150
151 =cut
152
153 sub methods {
154 my $self = shift;
155
156 my ( $class, $meta, $is_role ) = $self->load_package;
157
158 my $attr;
159 $attr->{$_}++ foreach $class->get_attribute_list;
160 my @methods = grep { ! defined($attr->{$_}) } $class->get_method_list;
161 warn "# methods = ",dump( @methods );
162
163 return @methods;
164 }
165
166 =head1 OUTPUT GENERATION
167
168 =head2 html
169
170 $o->html( $request );
171
172 =cut
173
174 our @javascript = ( qw'
175 ../lib/Joose.js
176 ');
177
178 sub html {
179 my ( $self, $request ) = @_;
180
181 while (1) {
182
183 my $js = Continuity::Widget::DomNode->create(
184 map {
185 ( script => { type => 'text/javascript', src => $_ } )
186 } @javascript
187 )->to_string;
188
189 $js .= << '__END_OF_JS__';
190 <script type="text/javascript">
191 joose.loadComponents("../lib")
192
193 function $(id) {
194 return document.getElementById(id)
195 }
196
197 </script>
198 __END_OF_JS__
199
200 warn "# >>> js\n$js\n";
201
202 my $methods;
203
204 my ( $class, $meta, $is_role );
205 eval { ( $class, $meta, $is_role ) = $self->load_package(); };
206 if ( $@ ) {
207 warn "ERROR: $@";
208 $request->conn->send_status_line( 500, $@ );
209 $request->print( $@ );
210 $request->next;
211 return;
212 }
213
214 if ( $class->can('meta') ) {
215 $methods = Continuity::Widget::DomNode->create(
216 ul => [
217 map { (
218 li => [ a => { href => '/~/' . $self->package . '/' . $_ } => [ $_ ] ]
219 ) } $self->methods
220 ]
221 )->to_string;
222 } else {
223 $methods = '<b>not introspectable</b>';
224 }
225
226 my $attributes = Continuity::Widget::DomNode->create(
227 ul => [
228 map {
229 my $attr = $class->get_attribute($_);
230 warn "## $_ ", $attr->is_required ? 'required' : 'optional';
231 ( li => [ a => { href => '/~/' . $self->package . '/' . $_ } => [ $_ ], ( $attr->is_required ? ' <b>required</b>' : '' ) ] )
232 } $class->get_attribute_list
233 ],
234 )->to_string;
235
236 my $doc = Continuity::Widget::DomNode->create(
237 html => [
238 head => [
239 link => { rel=>"stylesheet", href=>"/static/app.css", type=>"text/css", media=>"screen" },
240 $js,
241 title => [ 'Introspect ', $self->package ],
242 ],
243 body => [
244 h1 => [ $self->package ],
245 h2 => [ 'Methods' ],
246 $methods,
247 h2 => [ 'Atrributes' ],
248 $attributes,
249 ],
250 ]
251 );
252
253 $request->print($doc->to_string);
254 warn "# >>> html\n", $doc->to_string, "\n";
255 $request->next;
256 }
257 warn "# exit html";
258 }
259
260 =head1 SEE ALSO
261
262 L<MooseX::AutoDoc> on which this code is based
263
264 =cut
265
266 1;

  ViewVC Help
Powered by ViewVC 1.1.26