Class-MOP-Browser need to be a bulky Catalyst App, a single file script will suffice
Stevan Little [Tue, 12 Sep 2006 14:17:33 +0000 (14:17 +0000)]
scripts/class_browser.pl [new file with mode: 0644]

diff --git a/scripts/class_browser.pl b/scripts/class_browser.pl
new file mode 100644 (file)
index 0000000..b79d9b0
--- /dev/null
@@ -0,0 +1,310 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Class::MOP;
+use Data::Dumper;
+use B::Deparse;
+use Template;
+use Getopt::Long;
+
+my $DATA = join "" => <DATA>;
+
+my $stand_alone = 0;
+
+GetOptions(
+    "s" => \$stand_alone,
+);
+
+if ($stand_alone) {
+    {
+        package Class::MOP::Browser::Server;
+        use strict;
+        use warnings;
+        use base qw(HTTP::Server::Simple::CGI);
+
+        sub handle_request {
+            my ($self, $cgi) = @_;
+            Template->new->process(
+                \$DATA,
+                {
+                    'get_all_metaclasses'   => \&::get_all_metaclasses,
+                    'get_metaclass_by_name' => \&::get_metaclass_by_name,
+                    'deparse_method'        => \&::deparse_method,
+                    'deparse_item'          => \&::deparse_item,
+                }
+            ) or warn Template->error;
+        }
+    }    
+
+    my $server = Class::MOP::Browser::Server->new();
+    $server->run();    
+}
+else {
+    
+    print CGI::header();
+    
+    Template->new->process(
+        \$DATA,
+        {
+            'get_all_metaclasses'   => \&::get_all_metaclasses,
+            'get_metaclass_by_name' => \&::get_metaclass_by_name,
+            'deparse_method'        => \&::deparse_method,
+            'deparse_item'          => \&::deparse_item,
+        }
+    ) or warn Template->error;    
+}
+
+
+
+sub get_all_metaclasses { 
+    sort { $a->name cmp $b->name } Class::MOP::get_all_metaclass_instances() 
+}
+    
+sub get_metaclass_by_name { 
+    Class::MOP::get_metaclass_by_name(@_); 
+}
+
+sub deparse_method {
+    my ($method) = @_;
+
+    my $deparse = B::Deparse->new("-d");
+    my $body = $deparse->coderef2text($method->body());
+
+    my @body = split /\n/ => $body;
+    my @cleaned;
+
+    foreach (@body) {
+        next if /^\s+use/;
+        next if /^\s+BEGIN/;        
+        next if /^\s+package/;        
+        push @cleaned => $_;
+    }
+
+    return "sub " . $method->name . ' ' . (join "\n" => @cleaned);
+}
+
+sub deparse_item {
+    my ($item) = @_;
+    return $item unless ref $item;
+    local $Data::Dumper::Deparse = 1;
+    local $Data::Dumper::Indent  = 1;
+    my $dumped = Dumper $item;    
+    $dumped =~ s/^\$VAR1\s=\s//;
+    $dumped =~ s/\;$//;    
+
+    my @body = split /\n/ => $dumped;
+    my @cleaned;
+
+    foreach (@body) {
+        next if /^\s+use/;
+        next if /^\s+BEGIN/;        
+        next if /^\s+package/;        
+        push @cleaned => $_;
+    }    
+
+    return (join "\n" => @cleaned);
+}
+
+1;
+
+## This is the template file to be used
+
+__DATA__
+[% USE q = CGI %]
+[% area = 'attributes' %]
+[% IF q.param('area') %]
+    [% area = q.param('area') %]
+[% END %]
+<html>
+<head>
+<title>Class::MOP Browser</title>
+<style type='text/css'>
+
+body {
+    font-family: arial;
+}
+
+td { font-size: 12px; }
+b  { font-size: 12px; }
+
+pre {
+    font-family: courier;
+    font-size:   12px;
+    width:       330px;
+    padding:     10px;
+    overflow:    auto;
+    border:      1px dotted green;
+}
+
+A { 
+    font-family: arial;
+    font-size:   12px;    
+    color: black;
+    text-decoration: none;
+}
+
+A:hover {
+    text-decoration: underline;    
+}
+                                
+td.lightblue  { 
+    background-color: #99BBFF; 
+    border-right:  1px solid #336699; 
+    border-bottom: 1px solid #336699; 
+    border-top:    1px solid #BBDDFF; 
+    border-left:   1px solid #BBDDFF;        
+}
+
+td.grey       { 
+    background-color: #CCCCCC; 
+    border-right:  1px solid #888888; 
+    border-bottom: 1px solid #888888;  
+    border-top:    1px solid #DDDDDD; 
+    border-left:   1px solid #DDDDDD;       
+}
+
+td.manila     { 
+    background-color: #FFDD99;
+    border-right:  2px solid #CC9933; 
+    border-bottom: 2px solid #CC9933; 
+    border-top:    2px solid #FFFFBB; 
+    border-left:   2px solid #FFFFBB;        
+}
+
+td.darkgreen  { 
+    background-color: #33CC33; 
+    border-right:  1px solid #009900; 
+    border-bottom: 1px solid #009900; 
+    color: #CCFFCC;    
+}
+
+td.lightgreen { 
+    background-color: #AAFFAA; 
+    border-right:  1px solid #33FF33; 
+    border-bottom: 1px solid #33FF33;     
+}
+
+</style>
+</head>
+<body>
+<h1>Class::MOP Browser</h1>
+<table bgcolor='#CCCCCC' cellpadding='0' cellspacing='0' border='0' align='center' height='400'>
+<tr valign='top'>
+    
+<td rowspan='2' width='200'><table cellspacing='0' cellpadding='5' border='0' width='100%'>
+    [% FOREACH metaclass IN get_all_metaclasses() %]
+        <tr>
+        [% IF q.param('class') == metaclass.name %]
+            <td class='lightblue'><b>[% metaclass.name %]</b</td>
+        [% ELSE %]
+            <td class='grey'><a href='?class=[% metaclass.name %]'>[% metaclass.name %]</a></td>
+        [% END %]
+        </tr>
+    [% END %]
+    </table></td>
+<td height='10' width='250'><table cellspacing='0' cellpadding='5' border='0' width='100%'>
+    <tr align='center'>    
+    [% FOREACH area_name IN [ 'attributes', 'methods', 'superclasses' ] %]
+        [% IF q.param('class') %]
+            [% IF area == area_name %]            
+                <td class='manila'><b>[% area_name %]</b></td>
+            [% ELSE %]
+                <td class='lightblue'><a href='?class=[% q.param('class') %]&area=[% area_name %]'>[% area_name %]</a></td>
+            [% END %]
+        [% ELSE %]
+            <td class='lightblue' style="color: #336699;">[% area_name %]</td>
+        [% END %]
+    [% END %]
+    </tr>
+    </table></td>
+
+<td valign='top' rowspan='2' class='lightgreen' width='450'>
+    <table cellspacing='0' cellpadding='3' border='0'>
+    <tr>                    
+    <td class='darkgreen' width='100'></td> 
+    <td class='darkgreen' width='350'></td>     
+    </tr>    
+    [% IF q.param('class') && area == 'attributes' && q.param('attr') %]
+
+    [% 
+        meta = get_metaclass_by_name(q.param('class'))
+        attr = meta.get_attribute(q.param('attr'))
+    %]
+
+        [% FOREACH aspect IN [ 'name', 'init_arg', 'reader', 'writer', 'accessor', 'predicate', 'default' ]%]
+            [% item = attr.$aspect() %]
+            <tr>
+            <td class='darkgreen' align='right' valign='top'>[% aspect %]</td>
+            <td class='lightgreen'>[% IF item == undef %]&mdash;[% ELSE %]<pre>[% deparse_item(item) %]</pre>[% END %]</td>
+            </tr>
+        [% END %]
+
+    [% ELSIF q.param('class') && area == 'methods' && q.param('method') %]
+
+    [% 
+        meta = get_metaclass_by_name(q.param('class'))
+        method = meta.get_method(q.param('method'))
+    %]
+
+        [% FOREACH aspect IN [ 'name', 'package_name', 'fully_qualified_name' ]%]
+            <tr>
+            <td class='darkgreen' align='right' valign='top'>[% aspect %]</td>
+            <td class='lightgreen'>[% method.$aspect() %]</td>
+            </tr>
+        [% END %]
+            <tr>
+            <td class='darkgreen' align='right' valign='top'>body</td>
+            <td class='lightgreen'><pre>[% deparse_method(method) %]</pre></td>
+            </tr>    
+
+    [% END %]
+    </table></td>
+
+</tr>
+<tr>
+
+[% IF q.param('class') && area %]
+
+[% meta = get_metaclass_by_name(q.param('class')) %]
+
+<td class='lightblue' valign='top'><div style='height: 100%; overflow: auto;'><table cellspacing='0' cellpadding='5' border='0' width='100%'>
+
+    [% IF area == 'methods' %]
+        [% FOREACH method IN meta.get_method_list.sort %]
+            <tr>
+                [% IF q.param('method') == method %]
+                    <td class='darkgreen'><b>[% method %]</b></td>                
+                [% ELSE %]
+                    <td class='manila'><a href='?class=[% q.param('class') %]&area=[% q.param('area') %]&method=[% method %]'>[% method %]</a></td>
+                [% END %]
+            </tr>
+        [% END %]    
+    [% END %]
+    [% IF area == 'attributes' %]
+        [% FOREACH attr IN meta.get_attribute_list.sort %]
+            <tr>
+                [% IF q.param('attr') == attr %]
+                    <td class='darkgreen'><b>[% attr %]</b></td>                
+                [% ELSE %]
+                    <td class='manila'><a href='?class=[% q.param('class') %]&area=[% q.param('area') %]&attr=[% attr %]'>[% attr %]</a></td>
+                [% END %]
+            </tr>
+        [% END %]    
+    [% END %] 
+    [% IF area == 'superclasses' %]
+        [% FOREACH super IN meta.superclasses.sort %]
+            <tr>
+                <td class='manila'><a href='?class=[% super %]'>[% super %]</a></td>
+            </tr>
+        [% END %]    
+    [% END %]       
+    </table></div></td>
+[% END %]
+
+</tr>
+</table>
+</body>
+</html>
+