「rand」を含む日記 RSS

はてなキーワード: randとは

2009-12-10

PHPのあの関数Perlでやるには?

元ネタ http://phpspot.org/blog/archives/2009/12/phpjavascriptph_1.html



面白そうだと思ったので僕もやってみた。モジュールPerl5.8系の標準モジュールのみ利用可という制限。

全部はキツイので関数処理関係の関数(http://php.benscom.com/manual/ja/ref.funchand.php)だけ実装してみた。

use strict;
use warnings;

=head2 call_user_func

 $ret = call_user_func($function,@param);
 $ret = call_user_func([$class,$method],@param);

example1

 sub plus { $_[0] + $_[1] }
 print call_user_func('plus',10,20); # 30

example2

 package Foo;
 sub plus { $_[1] + $_[2] }
 package main;
 print call_user_func(['Foo','plus'],10,20); # 30

=cut

sub call_user_func {
    my $proto = shift;
    if ( ref $proto eq 'ARRAY' ) {
        return $$proto[0]->${\$$proto[1]}(@_);
    }
    else {
        require Pod::Functions;
        if ( $Pod::Functions::Flavor{$proto} ) {
            return eval qq{$proto(\@_)};
        }
        else {
            no strict 'refs';
            return $proto->(@_);
        }
    }
}

=head2 call_user_func_array

 $ret = call_user_func_array($function,\@param);
 $ret = call_user_func_array([$class,$method],\@param);

example

 sub plus { $_[0] + $_[1] }
 print call_user_func_array('plus',[10,20]); # 30

=cut

sub call_user_func_array {
    return call_user_func(shift,@{+shift});
}

=head2 create_function

 $code = create_function($args_str,$code_str);

example

 $code = create_function('$c,$d=1','print $c+$d');
 $code->(10); # 11

=cut

sub create_function {
    my $args = shift;
    my $code = shift;
    my $default = 0;
    my @args = split /,/,$args;
    my $code_str = 'sub {';
    for my $arg (@args) {
        if ( $arg =~ /^\s*(\$[a-zA-Z][\w]*)\s*(?:=\s*(.+))?\s*$/ ) {
            my $val = $1;
            my $def = $2;
            if ( defined $def ) {
                $default = 1;
                $code_str .= qq{my $val = \@_ ? shift : $def;\n};
            }
            else {
                die 'parse error' if $default;
                $code_str .= qq{my $val = shift;\n};
            }
        }
    }
    $code_str .= $code . '}';
    my $sub = eval $code_str;
    die $@ if $@;
    return $sub;
}

=head2 forward_static_call

 $ret = forward_static_call($function,@param);
 $ret = forward_static_call([$class,$method],@param);

=cut

sub forward_static_call {
    call_user_func(@_);
}

=head2 forward_static_call_array

 $ret = forward_static_call_array($function,\@param);
 $ret = forward_static_call_array([$class,$method],\@param);

=cut

sub forward_static_call_array {
    call_user_func_array(@_);
}

=head2 func_get_arg

 $arg = func_get_arg($no)

example

 sub foo { print func_get_arg(1) }
 foo(100,200); # 200

=cut

sub func_get_arg {
    my $n = shift;
    package DB;
    @DB::args = ();
    () = caller(1);
    return defined $DB::args[$n] ? $DB::args[$n] : undef;
}

=head2 func_get_args

 @args = func_get_args()

example

 sub foo { print join ':', func_get_args() }
 foo(11,22,33); # 11:22:33

=cut

sub func_get_args {
    my $n = shift;
    package DB;
    @DB::args = ();
    () = caller(1);
    return @DB::args;
}

=head2 func_num_args

 $arg_count = func_num_args()

example

 sub foo { print func_num_args() }
 foo(11,22,33); # 3

=cut

sub func_num_args {
    my $n = shift;
    package DB;
    @DB::args = ();
    () = caller(1);
    return scalar @DB::args;
}

=head2 function_exists

 $bool = function_exists($func)

example

 sub foo {}
 print function_exists('foo');  # 1
 print function_exists('bar');  # 0
 print function_exists('rand'); # 1

=cut

sub function_exists {
    my $func = shift;
    return 1 if exists &$func;
    require Pod::Functions;
    return $Pod::Functions::Flavor{$func} ? 1 : 0;
}

=head2 get_defined_functions

 $funcs = get_defined_functions()

=cut

sub get_defined_functions {
    require Pod::Functions;
    return {
        internal => [ keys %Pod::Functions::Flavor ],
        user     => [ grep { exists &$_ } keys %:: ],
    };
}

=head2 register_shutdown_function

 register_shutdown_function($func,@param);
 register_shutdown_function([$class,$method],@param);

=cut

{
    my $REGISTER_SHUTDOWN_FUNCTION = [];
    sub register_shutdown_function {
        my $proto = shift;
        push @$REGISTER_SHUTDOWN_FUNCTION, [
            do {
                if ( ref $proto eq 'ARRAY' ) {
                    $$proto[0]->can($$proto[1]);
                }
                else {
                    require Pod::Functions;
                    if ( $Pod::Functions::Flavor{$proto} ) {
                        sub { eval qq{$proto(\@_)} };
                    }
                    else {
                        no strict 'refs';
                        \&$proto;
                    }
                }
            },
            [@_]
        ]
    }
    END {
        $_->[0]->(@{$_->[1]}) for @$REGISTER_SHUTDOWN_FUNCTION;
    }
}

思ったよりも難しかった。標準関数一覧を取る手段がなかったので標準モジュールを利用して標準関数の一覧を取得した。

あと文字列から標準関数を呼び出すスマートな手段が思いつかなかったのでeval便りに。

create_functionはかなりゴリ押し。myを勝手に付けたりデフォルト引数にも対応してたり細かい芸が光る(自分で言うな)

forward_static_callはぶっちゃけPerl的にcall_user_funcと殆ど処理が変わらないのでそのまま利用。

func_get_arg系は結構クリティカルだなー。@DB::argsをリアルに使ったの初めてだよ。

register_shutdown_functionはちょっとねー。ENDブロックを利用してるわけなんだけど当然mod_perlとかではうまく動かない。あとシグナルとか使った方が良いのかもしれない。

ヒマがあったら他の関数とかも実装してみたいかも。



プログラ増田のあなぐら

2009-10-04

グーグルマップ壁紙にしてみる

10/18 改訂



グーグルマップ航空写真をつなげて一枚にするスクリプト

なお、取得した画像著作権グーグル他各社が保持しています。

ご利用は計画的に私的範囲でどうぞご利用ください。

#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use LWP::UserAgent;
use GD;

my $cmdline = join(" ", $0, @ARGV);
my $usage = "usage: $0 -sx=116423 -sy=51603 -ex=116426 -ey=51605 -dx=4 -dy=3 -z=17 -size=300 -get=30 -dir=cache -output=output.jpg -nodebug";
my ($sx, $sy) = (0, 0);
my ($ex, $ey) = (0, 0);
my ($dx, $dy) = (4, 3);
my $z = 17;
my $size = 300;
my $get = 30;
my $dir = "cache";
my $output = "output.jpg";
my $debug = 0;
GetOptions("sx=i" => \$sx, "sy=i" => \$sy,
	   "ex=i" => \$ex, "ey=i" => \$ey,
	   "dx=i" => \$dx, "dy=i" => \$dy,
	   "z=i" => \$z,
	   "size=i" => \$size, "get=i" => $get,
	   "dir=s" => \$dir, "output=s" => \$output,
	   "debug!" => \$debug) or die "$usage\nDied";
if ($ex == 0) {
    $ex = $sx + $dx;
} else {
    $ex++;
    $dx = $ex - $sx;
}
if ($ey == 0) {
    $ey = $sy + $dy;
} else {
    $ey++;
    $dy = $ey - $sy;
}
$sx>0 and $dx>0 and $sy>0 and $dy>0 and $z>0 and $dir and $output
    or die "$usage\nBad arguments";
$dx*$dy > $size and die "Getting too large.";

$debug and print "debug: mkdir $dir\n";
mkdir $dir;
-d $dir or die "can't make dir $dir: $!";

my $base = sprintf("http://khm%d.google.co.jp/kh/v=46&z=%d", int(rand(4)), $z);
my $ua = LWP::UserAgent->new;
printf "now get %d images...\n", $dx*$dy;
for (my $x=$sx; $x < $ex; $x++) {
    for (my $y=$sy; $y < $ey; $y++) {
	my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y);
	$debug and print "debug: check of $file\n";
	-s $file and next;
	--$get < 0 and last;
	my $req = HTTP::Request->new(GET=>+"$base&x=$x&y=$y");
	$debug and print "debug: fetch from ".$req->uri."\n";
	my $res = $ua->request($req);
	unless ($res->is_success) {
	    print "fail fetch from $file: ", $res->status_line, "\n";
	    next;
	}
	if (open(my $fh, ">", $file)) {
	    $debug and print "debug: write of $file\n";
	    binmode $fh;
	    print $fh $res->content;
	    close $fh;
	} else {
	    print "fail open in $file: $!\n";
	}
    }
}
$get < 0 and print "reach the getting limit, skip after all.\n";

printf "creating %dX%d image...\n", 256*$dx, 256*$dy;
my $image = new GD::Image(256*$dx, 256*$dy);
for (my $x=$sx; $x < $ex; $x++) {
    for (my $y=$sy; $y < $ey; $y++) {
	my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y);
	$debug and print "debug: check of $file\n";
	-s $file or next;
	$debug and print "debug: read of $file\n";
	my $part = GD::Image->newFromJpeg($file);
	$debug and print "debug: image copy\n";
	$image->copy($part, 256*($x-$sx), 256*($y-$sy), 0, 0, 256, 256);
    }
}
#$image->string(gdSmallFont, 0, 0, $cmdline, $image->colorAllocate(255, 255, 255));
open(my $fh, ">", $output) or die "fail open $output: $!";
$debug and print "debug: write of $output\n";
binmode $fh;
print $fh $image->jpeg();
close $fh;

例えば秋葉原とか

perl gmwall.pl -sx=116423 -sy=51603 -ex=116427 -ey=51606

駅だけとか

perl gmwall.pl -sx=465701 -sy=206420 -ex=465705 -ey=206423 -z=19

使う数値はfirebugなどで拾ってください。

- 転職ならen
- 派遣ならen
 
1ページ中1ページ目を表示(合計:2件)