PHP5.2以下のPHPを使ってアレしてる人なんか、なんだかんだでcreate_function でアレしたりしてアレするでしょう?
でも、これって調子こいてJavaScriptやLISPのノリや、Perl のサブルーチンのリファレンスのつもりで使ってるとアレしちゃうんですよ。そもそもそこまで便利じゃないので、そのノリで使えないっていうのはアレしちゃってください。で、create_functionをよくアレしてる人は、以下のコード実行してみてください。
for ( $i = 0; $i < 1000000; $i++ ){
hoge ('$x', 'return $x;' );
}
function hoge ( $x, $y ) { return create_function ( $x, $y ); }
スコープぬけようがcreate_functionした関数は破棄しないし、同じコードだろうが問答無用で新しい関数定義するという男らしい仕様でアレしているので使用可能メモリを一瞬でオーバーして男らしく散り際をわきまえてアレしちゃうんですね。でも、そんなアホみたいな回数をcreate_functionするような場所で回さないもんへへーんとかアレしてる方、
// バッチコントローラの階層
for ( $i = 0; $i < 10; $i++ ) {
// モデルの階層
for ( $j = 0; $j < 100; $j++ ) {
// そのモデルの下請けモデルの階層
for ( $k = 0; $k < 1000; $k++ ){
hoge ('$x', 'return $x;' );
}
}
}
function hoge ( $x, $y ) { return create_function ( $x, $y ); }
これ位の計算量は普通に有り得るでしょう。うげーやべぇって思ってアレしました? 思ってないなら思った方が良いです。どう考えても思えないなら、ここでは先に進まなくてアレしちゃうので思ってください。
で、こうしてみることにしました。
function create_function_ex ( $args, $code ) {
return LambdaFactory::create ( $args, $code );
}
class LambdaFactory {
private static $_Cache = array ();
public function create ( $args, $code ) {
if ( !self::$_Cache[$args . "\x0b" . $code] ) self::$_Cache[$args."\x0b". $code] = create_function ( $args, $code );
return self::$_Cache[$args . "\x0b" . $code];
}
}
です。
じゃあ、これと同じファイルに
for ( $i = 0; $i < 10000000; $i++ ){
$fnc = create_function_ex ( '$x', 'print "$x\n";' );
$fnc ( $i );
}
を追記して実行してみてください。
PHPさん、ここでは男らしく踏ん張ってくださいましたね。
これで安心してcreate_function 多用した可読性の低いコードを
ハッピーに書けますね!
※勿論、5.3以降のPHPなら create_function なんか使わずに。 function ( $x ) { return $x; } というようにしましょう。
SVNクライアントのラッパーが使っているうちに大きくなりましたので、晒します。使い方はソース読んでください。
正直、ここまで大きくなるなら、pm にしてhelpとコマンドをセットと略式コマンドに対応出来たほうが良かったんじゃないかって思ってます。
#!/usr/bin/perl
use File::Basename;
use strict;
## 環境設定
sub say { print @_ , "\n" }
my $SVN = 'svn';
my %HOSTS = (
host1 => {
host => 'http://svn-server.domain/path/to/repostiry',
local_dir => '/local/working/copy/dir/home',
server_host => 'user@domain.com',
server_key => "/path/to/server-key/id_rsa",
server_dir => '/path/to/dir',
default => 1,
},
host2 => {
host => 'http://svn-server.domain/path/to/repostiry',
local_dir => '/local/working/copy/dir/home',
server_host => 'user@domain.com',
server_key => "/path/to/server-key/id_rsa",
server_dir => '/path/to/dir',
default => 0,
},
);
my $SVN_ENV = {};
## ここからロジック
our %COMMANDS = (
##
## 対象リポジトリのブランチのリストを表示
##
ls => sub {
`$SVN list '$SVN_ENV->{host}/branches'`
},
##
## 対象ブランチのベースリビジョンを取得
##
base_rev => sub {
`$SVN log '$SVN_ENV->{host}/branches/$_[0]' --stop-on-copy --quiet`
},
##
## update
##
update => sub {
if ( $_[0] ) { `$SVN update $SVN_ENV->{local_dir}/branches/$_[0]` }
else { `$SVN update` }
},
##
## ブランチの削除
##
del => sub {
`$SVN del -m 'del $_[0]' $SVN_ENV->{host}/branches/$_[0]`
},
##
## ブランチの移動
##
mv => sub {
`$SVN mv -m 'mv $_[0]' '$SVN_ENV->{host}/branches/$_[0]' '$SVN_ENV->{host}/branches/$_[1]'`
},
##
## ブランチを作成してチェックアウトしてくる
##
create => sub {
my $branch_name = shift;
if ( `$SVN log $SVN_ENV->{host}/branches/$branch_name 2>&1` =~ /not +found/ ){
print 'creating branch ' . $branch_name . '.....' . "\n";
print `$SVN cp -m 'make $branch_name' $SVN_ENV->{host}/trunk $SVN_ENV->{host}/branches/$branch_name`;
}
if ( !-d "$SVN_ENV->{local_dir}/branches/$branch_name" ) {
print 'checking out branch ' . $branch_name . '.....' . "\n";
print `$SVN co $SVN_ENV->{host}/branches/$branch_name $SVN_ENV->{local_dir}/branches/$branch_name` ;
} else {
print 'updating branch ' . $branch_name . '.....' . "\n";
print `$SVN update $SVN_ENV->{local_dir}/branches/$branch_name`;
}
if ( !-f "$SVN_ENV->{local_dir}/branches/$branch_name/.aurc" ) {
print 'making dot_aurc_copy ' . $branch_name . '.....' . "\n";
my $TMPL = "$SVN_ENV->{server_host}\n" .
"$SVN_ENV->{server_key}\n".
"$SVN_ENV->{server_dir}\n";
my $path = "$SVN_ENV->{local_dir}/branches/$branch_name";
$path =~ s#(?:/$)##;
if ( $path ) { -d $path or die 'ディレクトリが無いような気がしますよ' . $path; }
else { $path = '.' }
open F, '> ' . $path . '/.aurc'; print F $TMPL; close F;
print $path . 'に.aurcを作りました'. "\n";
}
'created';
},
##
## mergeコマンド(対象の作業ディレクトリで実行してください)
##
merge => sub {
our %COMMANDS;
my ( $path, $dry_run ) = @_;
my $rev = undef;
print $COMMANDS{update}->() . "\n";
$path or die 'パスの指定がありません' ;
my $stat = `$SVN stat $SVN_ENV->{local_dir}/branches/$path`;
if ( $stat ) {
my @adds = map { /(\S+)$/ } grep { /^\?/ } split /\n/, $stat;
my @changes = map { /(\S+)$/ } grep { /^m/i } split /\n/, $stat;
say 'コミット漏れ、追加漏れあったけどどうする? 追加漏れ:' .@adds . ' コミット漏れ:' . @changes . ' [y/n]';
my $answer = <STDIN>;
chomp $answer;
say;
if ( $answer ne 'n' ){
say `$SVN update $SVN_ENV->{local_dir}/branches/$path`;
for ( @adds ) {
say '追加する?[y/n]:' . $_ ;
my $answer = <STDIN>;
chomp $answer;
say;
say `$SVN add $_` if $answer ne 'n';
}
say `$SVN ci -m 'prepared for merging by svn_branch.pl' $SVN_ENV->{local_dir}/branches/$path`;
}
}
my @log = map { /(\d+)/ } grep { /\S/ }
split /^\s*-+$/m, $COMMANDS{base_rev}->( $path );
$rev = pop @log or die 'ブランチ間違ってない?';
my $MERGE_COMMAND = "$SVN merge -x -w ";
$dry_run and $MERGE_COMMAND .= ' --dry-run ';
`$MERGE_COMMAND -r $rev:HEAD $SVN_ENV->{host}/branches/$path`;
},
##
## ひとつ前のリビジョンに戻す
##
rollback => sub {
if ( $_[0] ) { `$SVN merge -x -w -r HEAD:PREV $SVN_ENV->{host}/branches/$_[0]` }
else { `$SVN merge -x -w -r HEAD:PREV` }
},
);
## パラメータ処理(一個目はいつでもコマンド)
my $cmd = shift @ARGV;
$COMMANDS{$cmd} or die '指定のコマンド無いっす';
## 対象ホストの解析とか
my %params = @ARGV;
if ( $params{-h} && $HOSTS{$params{-h}} ) {
$SVN_ENV = $HOSTS{$params{-h}};
}
else {
my ( $key ) = grep { $HOSTS{$_}->{default} } keys %HOSTS;
$SVN_ENV = $HOSTS{$key};
}
/^-/ and delete $params{$_} for keys %params;
## 実行
say $COMMANDS{$cmd}->( %params );
また、svnクライアントのラッパ。
ブランチ操作に特化したもの。
ブランチ作ってチェックアウトしてくる奴とか、
マージする奴とかと統合したい。
#!/usr/bin/perl
## 環境設定
sub say { print @_ , "\n" }
my $SVN = 'svn';
my %HOSTS = (
user => {
host => 'http://hoge.fuga',
default => 1,
},
admin => {
host => 'http://hoge.fuga',
default => 0,
},
);
## ここからロジック
my $HOST = '';
my %COMMANDS = (
ls => sub {
`$SVN list '$HOST/branches'`
},
base_rev => sub {
`$SVN log '$HOST/branches/$_[0]' --stop-on-copy --quiet`
},
del => sub {
`$SVN del -m 'del $_[0]' '$HOST/branches/$_[0]'`
},
mv => sub {
`$SVN mv -m 'mv $_[0]' '$HOST/branches/$_[0]' '$HOST/branches/$_[1]'`
}
);
## パラメータ処理(一個目はいつでもコマンド)
my $cmd = shift @ARGV;
$COMMANDS{$cmd} or die '指定のコマンド無いっす';
## 対象ホストの解析とか
my %params = @ARGV;
if ( $params{-h} && $HOSTS{$params{-h}} ) {
$HOST = $HOSTS{$params{-h}}->{host};
}
else {
( $HOST ) =
map { $HOSTS{$_}->{host} }
grep { $HOSTS{$_}->{default} }
keys %HOSTS;
}
/^-/ and delete $params{$_} for keys %params;
## 実行
say $COMMANDS{$cmd}->( %params );
1;
よくあるtrunkをブランチに切るパターンを自動化。
さらに前に紹介したdot_aurc_copy.plもついでにキック。
ディスク勿体無いけど、switchは経験上危険なので問答無用でチェックアウト。
#!/usr/bin/perl -w
use File::Basename;
my $ROOT
= '[svnのリポジトリのパス]';
my $LOCAL_ROOT
= '[ローカルのパス]';
my $SVN
= 'svn';
my $DOT_AURC_COPY
= dirname ( $0 ) . '/dot_aurc_copy.pl';
my $branch_name = shift ( @ARGV )
or die 'ブランチ名が無い';
if ( `$SVN log $ROOT/branches/$branch_name 2>&1` =~ /not +found/ ){
print 'creating branch ' . $branch_name . '.....' . "\n";
print `$SVN cp -m 'make $branch_name' $ROOT/trunk $ROOT/branches/$branch_name`;
}
if ( !-d "$LOCAL_ROOT/branches/$branch_name" ) {
print 'checking out branch ' . $branch_name . '.....' . "\n";
print `$SVN co $ROOT/branches/$branch_name $LOCAL_ROOT/branches/$branch_name` ;
} else {
print 'updating branch ' . $branch_name . '.....' . "\n";
print `$SVN update $LOCAL_ROOT/branches/$branch_name`;
}
if ( !-f "$LOCAL_ROOT/branches/$branch_name/.aurc" ) {
print 'making dot_aurc_copy ' . $branch_name . '.....' . "\n";
print `perl $DOT_AURC_COPY branches/$branch_name`;
}
NetBeansが遅くてどうにもならないので、
svnのよくあるブランチのBASEからマージする作業を自動化してみた。
これでvimdiffへの繋ぎ込みとか出来るようになれば、
大体大丈夫になるが。
#!/usr/bin/perl
##
## 環境設定
##
my $ROOT
= 'http://svn-server.domain/path/to/branches';
my $SVN
= 'svn';
my $LOG_COMMAND
= "$SVN log --stop-on-copy --quiet";
my $MERGE_COMMAND
= "$SVN merge ";
## 未実装
my $DIFF_COMMAND
= "$SVN diff diff-cmd svndiff";
##
## ロジック
##
my ( $path, $dry_run ) = @ARGV;
$path or die 'ブランチ名の指定がありません' ;
my @log =
map { ($_) = $_ =~ /(\d+)/; }
grep { $_=~/\S/ }
split /^\s*-+$/m, `$LOG_COMMAND ${ROOT}/${path}`;
my $rev = pop @log;
$dry_run and $MERGE_COMMAND .= ' --dry-run ';
$MERGE_COMMAND .= "-r ${rev}:HEAD ${ROOT}/${path}";
print `$MERGE_COMMAND`;
能書き
会社のマシンがMacになったので環境を試行錯誤してきたので一旦まとめてメモ。SKKとvim以外は昔Mac使ってたのとあんまり変わってないような。今回はCarbon Emacsは敢えて入れてない。
MacVim
MacVimです。テキストエディタです。元々Emacs系統のテキストエディタを使っていた(主にxyzzy)のですがMacではxyzzyが真っ当には使えない訳なので、いっそ・・・という極端な方針転換をしてみた訳です。多くのEmacs使う人と同じようにviもそこそこ不便無く使えてたので余り戸惑いは無かったです。さて、このリンク先の香り屋版は日本語環境のオールインワンパッケージです。入れた瞬間から日本語を戸惑い無く使えるようになりmigemoとかも予め入っていて助かります。
AquaSKK
AquaSKKです。IMEですね。文節変換ではなくて変換対象の漢字の部分に着目して高速に変換することを目的としています。操作体系が特殊なので使う人を選ぶかも知れませんが慣れれば速く日本語入力できるようになってくるので試してみるのも良いかも知れません。
scplugin
WindowsでいうところのでTortoise SVNのようなもの。あれほど高機能ではないですがGUIでディレクトリの構成を見ながらチェックアウトしたりブランチ切ったりできるのは便利です。
DIFFMERGE
DIFFMERGE
あんまり使う機会が無かったからなんとも言えませんが入れたので列挙
iTerm
iTerm
Terminal.appより綺麗でタブ機能とブックマーク機能があるので沢山のサーバーに繋ぐ必要のある人にはお勧め
Evernote
説明不要ですね。Microsoft OneNoteより機能は弱いけどサーバー上にデータが保存されるので共有とかされて便利なヤツです。最近のOneNoteはサーバー上に保存されてて携帯とかでも見れるっぽいけど。
Quicksilver
Quicksilver
しょっちゅうは使わないけどまあまあ使うソフトを呼びだす時に便利なやつです。プラグイン入れて色々できるみたいですが使ってないです。プラグインで出来そうなことはvimから:!commandとかで出来そうだし、そこにPerlとか噛ませば大概のことは出来るので
FileZilla
FileZilla
Cyberduckが重過ぎて使いものにならなかったので、こっち入れた。編集したファイルのアップロードとかはvimからPerl実行してやってるので、あんまり使わない。
NetBeans
NetBeans
始めはソース書くのに使ってたけれど、恐らくMacのJavaVMが酷いためだと思うけど、あまりに重くて使いものにななかったのでvimを使いはじめたきっかけになったのです。今はSVNのマージに使ってるだけ。SVNのマージツールで良いものがあれば一切使わなくなるかも。やはり僕にIDEは向かないんだなーと思いました。ただIDE使うならば、これが良い。プロジェクトをスキャンしてますが、もっと短かければ使うメリットも多い。
OpenOffice.org
Excelとか開くのに使う。
Xcode
コンパイルするのに
Mac Ports
GNUなソフト入れるのに。遅いけど。/opt とか嫌だけど。
Opera
Mac版は酷いので入れただけ
Afficheur
Afficheurです。Wassrのクライアントですね。なかなか高機能で良い。
能書き
取り急ぎ作ってみた。ローカルで編集したファイルをSFTPでリモートの目的のディレクトリにアップロードするためのスクリプト。
テキストエディタの保存に引っ掛けて使うイメージ
使い方
以下みたいな適当な感じで
- プロジェクトルートに”.aurc”というファイルを作る( .aurcのレイアウトはまた後で)
- 以下のスクリプトを適当なファイルに保存する(ex:~/auto_upload.pl)
- perl ~/auto_upload.pl “上げたいファイルのパス”
- ファイルが適当にSFTPでアップされる
vimの場合
.vimrcに以下のように記述してwrで保存する
cmap wr w<Bar>!perl ~/auto_upload.pl "%:p"
保存した時に適当に実行される。
上がったかどうかを適当に目視確認してエンターを叩かないとダメ。
.aurcのレイアウト
1行目:user_name@hostname
2行目:/path/to/identity_file
3行目:リモートホストでのプロジェクトルート
ソース
適当に直してください
諸々
- 自分しか使うイメージが無かったのでクイックハック的なあんま考えてないソースなので汎用的に使う時には直す必要がある
- Mac + vim + 一回以上パスワードが保存されている環境またはidentity_file だけでパスワードが無い環境しか想定されていないのでパスワードとか必要であれば直す必要がある
- FTPとか他のプロトコルとか使うのであれば直す必要がある
今のところ僕自身はこれで困らない感じですが、万が一使ってみようと思っている人が居て何か要望あればコメントとかに書いてくれると嬉しいです。※やれるかどうかはともかくとして
#/usr/bin/perl
use strict;
my ( $target_file ) = @ARGV;
## 設定ファイルの検索
my $tmp = $target_file;
my $host = '';
my $identity = '';
my $local_root = '';
my $remote_root = '';
while ( $tmp =~ s#/[^/]+$## ){
opendir DIR, $tmp;
while ( my $fn = readdir ( DIR ) ){
$fn eq '.aurc' or next;
$local_root = $tmp;
open F, $tmp . '/' . $fn;
( $host, $identity, $remote_root ) = <F>;
chomp $host;
chomp $identity;
chomp $remote_root;
last;
}
close DIR;
$remote_root and last;
}
$remote_root or die '設定ファルなくね?';
## リモートのパスを算出
my $remote_file = $target_file;
$remote_file =~ s#$local_root##e;
$remote_root =~ s#/$##;
$remote_file =~ s#^/##;
$remote_file = $remote_root . '/' .$remote_file;
## SFTPコマンド
my $cmd = 'sftp ';
$identity and $cmd .= ' -oIdentityFile="' . $identity . '" ';
$cmd .= $host;
open SFTP, '| ' . $cmd;
print SFTP 'put "' . $target_file . '" "' . $remote_file . '"' . "\n";
print SFTP "quit\n";
close SFTP;
能書き
モニプラでやってるEC STUDIOさんのイベントに参加してみた。
ちなみに僕は7個
【超簡単アンケート!】あなたのIT活用度についてお聞かせください♪
アンケートの内容は以下のような内容
Q.下記の設問の中からあてはまるものをすべて選んでください。
1つもあてはまるものがない場合は「どれも無理」を選んでください。
- ブラインドタッチができる
- Twitterで毎日つぶやいている
- ショートカットキーを駆使している
- スマートフォン(iPhoneなど)を持っている
- パソコンのセキュリティソフトは検出率と速さに重点をおいて選んでいる
- パスワードの管理は専用のソフトを使っている
- スケジュールは、手帳よりもオンラインで利用できるもので管理している
- パソコンのモニタを2台以上使用している
- 外出先から、自宅のパソコンを遠隔操作できる
- パソコンのデータを自動でバックアップしている
- どれも無理
◆0個の方
この機会に入門生レベルを目指しましょう♪
◆1~3個
<IT活用入門生>
できそうなものをひとつでも多く増やしていきましょう♪
◆4~6個
<IT活用見習生>
自分なりの活用方法を身につけているところですね。
IT活用の楽しさがわかる「アイカ★ガール」無料メルマガを
購読してスキルアップに励みましょう♪
http://www.itkeiei.jp/girl/
◆7~9個
<IT活用師範>
素晴らしい!さらにスキルアップするために
クラウドの王様 Google Apps(グーグルアップス)をとことん
学びましょう♪
http://www.master-apps.jp/
◆10個
<IT活用名誉師範>
お見事!
件名についてですが、諸般の事情により
happy_ryoに全権委譲してhappy_ryoのプロジェクトになりました。
まず居ないと思いますが、これについて興味があって訪れていた方は、
happy_ryoのアナウンスを待ってください。
それに伴い、このページからは固定ページを無くしました。
happy_ryoについてはググれば出てくると思います。
この結果ってどうなると思います?
<?php print '*' == 0 ? 'true' : 'false' . "\n";
実はtrueですね、
数値 0 と文字列を比較すると、trueが返ってくるっぽいです。
こうするか
<?php print '*' === 0 ? 'true' : 'false' . "\n";
こうしましょう
<?php print '*' === 0 . '' ? 'true' : 'false' . "\n";
