#!/usr/local/bin/perl -w # # stem2pod # # takes filename (a stem module) arguments and it updates their # pod from their attribute descriptions. it also will insert pod # templates for methods, subs and standard pod sections. # # if a file is changed, it is written out over itself. unchanged # files are not touched. use strict; use Carp qw( carp cluck ) ; use Data::Dumper; #use Test::More tests => 1 ; #$SIG{__WARN__} = sub { cluck } ; my $changed ; my $package ; my %is_attr_part = map { $_ => 1 } qw( name type help default required class class_args ) ; foreach my $file_name ( @ARGV ) { process_source_file( $file_name ) ; } exit ; sub process_source_file { my ( $file_name ) = @_ ; my $code_text = read_file( $file_name ) ; my $new_code_text = process_code_text( $file_name, $code_text ) ; #print $new_code_text ; if ( $new_code_text eq $code_text ) { print "$file_name SAME\n" ; return ; } print "$file_name CHANGED\n" ; write_file( "$file_name.new, $new_code_text ) ; # write_file( "$file_name.bak, $code_text ) ; # write_file( $file_name, $new_code_text ) ; } sub process_code_text { my ( $file_name, $text ) = @_ ; $text =~ s{ ( ^package # start at package line .+? # the middle stuff ^sub # start of constructor ) } { update_attr_spec( $1, $file_name ) }mgsex ; $text =~ s{ (.{0,20}?) ^sub \s+ (\w+) \s* } { update_sub_pod( $1, $2 ) }mgsex ; unless( $text =~ /^=cut\s*^\s*1\s*;\s*/m ) { $text =~ s{^\s*1\s*;\s*$}{ update_trailing_pod() }mex ; } return $text ; } sub update_attr_spec { my( $attr_text, $file_name ) = @_ ; #print "U1 <$attr_text>\n" ; ( $package ) = $attr_text =~ /^package\s+([\w:]+)/ ; $attr_text =~ s/\n*^\#{5,}\n.+?^\#{5,}\n*//ms ; # and print "DELETED OLD POD\n" ; #print "U3 <$attr_text>\n" ; $attr_text =~ s{ (^my\s+\$attr_spec.+?^]\s*;\s*) } { attr_spec_to_pod( $1, $file_name ) }gmsex ; #dump_attr( 'ATTR', $attr_text ) ; #print "ATTR [", substr( $attr_text, -40 ), "]\n" ; #print "U2 [$attr_text]\n" ; return $attr_text ; } sub attr_spec_to_pod { my ( $attr_text, $file_name ) = @_ ; my $pod ; #print "ATTR [$attr_text]\n" ; #print "ATTR END1 [", substr( $attr_text, -30), "]\n" ; $attr_text =~ s/\s*\z// ; my( $attr_list_text ) = $attr_text =~ /^my\s+\$attr_spec.+?=(.+?^\])/ms ; $attr_list_text or die "can't parse out attr list from file $file_name class $package" ; #print "ATTR2 [$attr_list_text]\n" ; my $attr_list = eval $attr_list_text ; $pod .= <{name} ; if ( $name ) { $pod .= < =over 4 POD } else { warn <{help} ; if ( defined( $help ) ) { $pod .= <{class} ) { my $class_args = '<' . join( ', ', @{$attr_ref->{class_args} || []} ) . '>' ; $pod .= <{type} ) and $pod .= <{type} POD if ( exists( $attr_ref->{default} ) ) { my $default = $attr_ref->{default} ; if( ref($default) eq "ARRAY" ) { $default = '(' . join( ', ', @{$default} ) . ')' ; } $pod .= < value: $default POD } exists( $attr_ref->{required} ) and $pod .= <. POD foreach my $attr ( sort keys %{ $attr_ref } ) { next if $is_attr_part{ $attr } ; $pod .= "Unknown attribute $attr\n" ; } $pod .= < The B method creates an object of the class B<$package>. POD return < The B method is effectively a default method for message delivery. If any message to this cell can't be delivered to another method, then it will be delivered to the B method. If a command message is delivered and a value is returned by B, a response message is sent back to the originating cell with that value. POD return < type messages are delivered to this method. Its return value is ignored by the message delivery system. POD return < command messages are delivered to this method. If any value is returned, the message delivery system will create a response type message and dispatch it back to the sending cell. POD return <uri\@stemsystems.comE =cut 1 ; POD } sub read_file { my( $file_name ) = shift ; local( *FH ) ; open( FH, $file_name ) || carp "can't open $file_name $!" ; return if wantarray ; my $buf ; sysread( FH, $buf, -s FH ) ; return $buf ; } sub write_file { my( $file_name ) = shift ; local( *FH ) ; open( FH, ">$file_name" ) || carp "can't create $file_name $!" ; print FH @_ ; } sub dump_attr { my( $key, $text ) = @_ ; $text =~ /(;\s+#{3,})/s or return ; print "$key [$1]\n" ; } __END__