#!/usr/bin/perl use strict; use base 'LEOCHARRE::CLI'; #use warnings; my $o = gopts('OC'); sub usage { return qq{ OPTION FLAGS: -O print as pod -C print as perl code }; } # INIT SOURCE # open(FILE,'<','./t/xmlrpc.php') or die; my @src_lines = ; close FILE; debug("got $#src_lines lines."); my $src_code = join( "\n", @src_lines); debug('length'.length $src_code ); my($POD,$CODE,$OUT) = ( q{ =pod =head1 NAME name =head1 DESCRIPTION =head1 XML RPC METHODS }, q{package name; use strict; use Carp; }, undef ); # EXAMINE SOURCE my @perl_method_names; my @external_method_names; my $external_method_names={}; my $_imethod=qr/\w+\.\w+/o; while( $src_code=~/'($_imethod)'\s*=>\s*'this:(\w+)'/g ){ #\s*=>\s*'$ismethod'/ ){ push @external_method_names, $1; $external_method_names->{$1} = $2; } my $functs = __init_functions(\@src_lines); my $functs_args = __init_function_args(); # choose which we want to view my @interesting_methods = grep { /^wp\.|^metaWeblog/ } @external_method_names; for (@interesting_methods) { _analize_method($_); } # close the outputs $CODE.= sprintf q/ sub server { my $self = shift; unless( $self->{_server} ){ $self->proxy or croak('missing proxy'); require XMLRPC::Lite; $self->{_server} ||= XMLRPC::Lite->proxy( $self->proxy ); } return $self->{_server}; } sub _call_has_fault { my $call = shift; my $err = $call->fault or return 0; for( keys %$err ){ print STDERR "ERROR:$_ $$err{$_}\n"; } return 1; } sub server_methods { my $self = shift; return qw(%s); } sub xmlrpc_methods { my $self = shift; return qw(%s); } /, join(' ',@external_method_names), join(' ',@perl_method_names); $CODE.="\n1;\n\n__END__\n\n"; $POD.= ' =head1 METHODS =head2 server_methods() returns array of server methods accessible via xmlrpc. =head2 xmlrpc_methods() returns array of methods in this package that make calls via xmlrpc '. "\n=head1 AUTHOR\n\n=head1 BUGS\n\n=head1 CAVEATS\n\n=head1 SEE ALSO\n\n=cut\n"; no warnings; print $OUT if !($o->{O} + $o->{C}); print $CODE if $o->{C}; print $POD if $o->{O}; exit; sub _analize_method { my ($external_method_name) = shift; my $internal_method_name = $external_method_names->{$external_method_name} or die; my $suggested_perl_name = $external_method_name; $suggested_perl_name=~s/^.+\.//; push @perl_method_names, $suggested_perl_name; if( !$o->{O} and !$o->{C} ){ my $args; my $argcount; if( my $_args = $functs_args->{$internal_method_name} ){ $args = join ', ',@$_args; $argcount = scalar @$_args; } $OUT.= "external name: '$external_method_name'\n"; $OUT.= "internal name: function $internal_method_name()\n"; $OUT.= " perl name: $suggested_perl_name\n"; $OUT.=(sprintf " %s args: %s\n", $argcount, $args ) if $args; if (DEBUG){ my $code = $functs->{$internal_method_name}; if($code and scalar @$code){ $OUT.= "code:yes\n"; $OUT.= "@$code\n"; } } } elsif ($o->{O} or $o->{C}){ # if P(O)D or CODE OO my $_all_args = $functs_args->{$internal_method_name}; my @_args = grep { ! _call_arg_should_be_method($_) } @{$functs_args->{$internal_method_name}}; # leave out args fed by oo if($o->{C}){ my $code = "# xmlrpc.php: function $internal_method_name\nsub $suggested_perl_name {\n"; $code.= "\tmy \$self = shift;\n"; my @call_args; for my $_argname ( @$_all_args ){ my $argname= lc($_argname); push @call_args, $argname; if (my $object_method = _call_arg_should_be_method($_argname)){ $code.= "\tmy \$$argname = \$self->$object_method;\n"; } else { $code.= "\tmy \$$argname = shift;\n"; } } $code.="\n"; # the call $code.="\tmy \$call = \$self->server->call(\n\t\t'$external_method_name',\n"; for my $a (@call_args){ $code.="\t\t\$$a,\n"; } $code.="\t);\n\n"; $code.="\tif (_call_has_fault(\$call)){\n"; $code.="\t\treturn;\n"; $code.="\t}\n\n"; $code.="\tmy \$result = \$call->result;\n"; $code.="\tdefined \$result\n\t\tor die('no result');\n\n"; $code.="\treturn \$result;\n"; $code.="}\n\n"; $CODE.= $code; } if($o->{O}){ $POD.= "=head2 $suggested_perl_name()\n\n"; $POD.=(sprintf "takes %s args: %s\n\n", scalar @_args, join(', ',@_args) ) if @_args; #$POD.= "\n";#=cut\n\n"; } } $OUT.= "\n\n"; } sub _call_arg_should_be_method { my $name = shift; return 'blog_id' if $name=~/blog_id/i; return 'username' if $name=~/user_login|username/i; return 'password' if $name=~/user_pass|password/i; return; } sub _functions { # the internal function names my @inames = keys %$functs; #internal php function names return @inames; } sub _function_lines { # name in php file my $imethod = shift; my $codelines = $functs->{$imethod} or return; scalar @$codelines or return; return @$codelines; } sub __init_function_args { my $hash={}; METHOD: for my $imethod (_functions()){ my @codelines = _function_lines($imethod) or next METHOD; my @args; for my $line (@codelines){ if( $line=~/\$(\w+)\s*\=\s*.+\$args\[(\d)\];/ ){ my $argname = $1; my $num= $2; #debug("$argname $num"); push @args, $argname; #$args[$num] = $argname; } } $hash->{$imethod} = \@args; } # what type of arg is it?? return $hash; } sub __init_functions { my $src_lines = shift; my $hash={}; my $function_lines; my $function_name; LINE: for my $_line (@$src_lines){ if($_line=~/function (\w+)\(/){ $function_name = $1; } if(defined $function_name){ push @{$hash->{$function_name}}, $_line; } } return $hash; } __END__ for(@src_lines){ }