忘れそうだったのでメモ
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / balancer://hogehoge/ timeout=2
ProxyPassReverse / balancer://hogehoge/
<Proxy balancer://hogehoge>
BalancerMember http://192.168.1.1 loadfactor=10 keepalive=Off
BalancerMember http://192.168.1.2 loadfactor=10 keepalive=Off
</Proxy>
ポイントは ProxyPreserveHost On ってところ。
ProxyPassReverse だけだと proxy 先に header の Host: をそのまま送ってくれるようになる。
参考資料
タイトルの通り今回したかったのはファイルハンドルを使って
ファイルへ出力していたコードの出力先を変数にしたかった。
そういうことをしてくれる小粋なモジュール IO::Scalar を使って対応しました。
これがまた便利で、数行書き換えるだけでよくてパフォーマンスは使う前と後で、それほど差異はありませんでした。
通常の FileHandle を使ったコード
#!/usr/bin/perl
use strict;
use warnings;
open my $fh, '>', 'file' or die $!
print $fh 'hoge'; #この時点で file とう名前のファイルがカレントディレクトリにつくられます。
1;
IO::Scalar を使って出力先を変数にしたコード
#!/usr/bin/perl
use strict;
use warnings;
use IO::Scalar;
my $file;
my $out;
{
my $fh = IO::Scalar->new(\$out);
local *F = $fh;
$file = *F;
print $file "hoge\n";
}
warn $out;
1;
で、調べていくと IO::String というモジュールも同じようなことをしてくれることを知った。
ちょっと試してみたけどインターフェースはさほどかわりない感じ。
というわけでベンチ。
Rate IO_STRING IO_SCALAR
IO_STRING 210/s -- -44%
IO_SCALAR 373/s 77% --
見た通り IO::Scalar の方がはやいですね。
試したコードはこれ。
#!/usr/bin/perl
use strict;
use warnings;
use IO::String;
use IO::Scalar;
use Benchmark qw/cmpthese/;
my @data = map { int rand 1000 } 1..1000;
cmpthese(10000, {
IO_STRING => \&with_io_string,
IO_SCALAR => \&with_io_scalar,
});
sub with_io_scalar {
my $output;
my $ios = IO::Scalar->new(\$output);
local *STDOUT = $ios;
print $_ for @data;
# warn $output;
}
sub with_io_string {
my $output;
my $ios = IO::String->new(\$output);
local *STDOUT = $ios;
print $_ for @data;
# warn $output;
}
1;
参考資料
IO::Scalarで色々
IO::scalarでIOのキャプチャ
id:dann さんの記事 「snipMateのsnippetが書きやすい件」で snipMate.vim が紹介されてて試してみた。
snipettsEmu.vim は snippets の追加がめんどくさかったってのもあるし
入力がタイポしてたりすると編集後に次の場所に移動できなかったりとか
(1)入力後 => (2)に移動といったことをしようとすると html_snippets.vim を書き直す必要があった。
snipMate は sunppets の追加が簡単そうだったので乗り換えてみた。
インストール
snipMate.vim をダウンロードしてきて
.vim ディレクトリ以下で解凍すれば終了。
使い方は snipettsEmu と同じです。
snippetsの構造
$ tree html
snippets
|-- html.snippet <- filetype
$ tree html
snippets
|-- html <- filetype
|-- body.snippet <- trigger
`-- h1.snippet
html.snippets
snippet body <- trigger
<body>
${1}
</body>
snippet h1 <- trigger
<h1>${1}</h1>
${2}
body.snippet
h1.snippet
この2つの構造は全く同じ意味です。
つまりは filetype ベースで trigger を作成しておけば良いということですね。
少しだけ .snippets の書き方の説明をしておきます。
${1} : 最初に入力する単語。デフォルトのままだと <tab> を入力すると ${2} に移動します。
${1:hoge} : デフォルトで hoge という単語が入力されている状態になります。
$1 : ${1} で入力された値と同期されます。
このように最初のインデントが必須。
trigger.snippets の場合は
このように実際に補完される文字をファイルに書いておけばいいから分かりよい。
ただ、ファイルが増えまくるのもどうかとも思うが。
自分の好きな方で filetype.sunippet もしくはディレクトリ構造に分ければいいと思う。
snippetが複数マッチする場合
この機能がかなり便利。
[dealforest@imac-local] tree html
snippets
|– html
|– doctype
|– HTML.snippet
`– XHTML.snippet
といった構造だとする。
この場合に hoge.html を開き doctype を入力し を実行すると
1. HTML
2. XHTML
Type number and <enter> or click with mouse (empty cancels):
とう画面が表示されるので 2 と入力すると XHTML の snippet が補完される。
ちなみにこれは html.snippets でいうと
snippets doctype HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""
"http://www.w3.org/TR/html4/loose.dtd">
snippets doctype XHTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
と同じこと。
補完を tab から c-b に変更
.vim/after/plugin/snipMate.vim
-ino <silent> <tab> <c-r>=TriggerSnippet()<cr>
-snor <silent> <tab> <esc>i<right><c-r>=TriggerSnippet()<cr>
+ino <silent> <c-b> <c-r>=TriggerSnippet()<cr>
+snor <silent> <c-b> <esc>i<right><c-r>=TriggerSnippet()<cr>
.vim/plugin/snipMate.vim
document には.vim/after/plugin/snipMate.vim だけ変更するといけるって書いてるけどそれだけじゃ駄目。
.vim/plugin/snipMate.vim の方も変更してやらないとたまに動かなくなるので注意。
<tab> ってハードコードされてた。。。。
tips
コマンド実行
snippet date
`system("date +%Y-%m-%d")`
ファイル名に変換
snippet constructor
public `Filename()`() {
}
こんなことも可能。おほー
TT, perl の snippet を移行した
snippetsEmu で使わせてもらってた snippet を、せっかくなんでそのまま snipMate に移行しました。
ちなみに使用していた snippet は CatalystとTT用snippetsEmu.vim設定 です。
id:spiritloose さんのスニペットには本当にいつも助けられていました。感謝感謝。
tt2.snippet
snippet class
[% USE ${1:class} = Class('${2:ClassName}') %]
${3}
snippet url
[% USE ${1:name} = url('${2:path}') %]
${3}
snippet linkto
<a href="[% c.uri_for('${1:path}', ${2:param}) %]¥">${3:label}</a>
${4}
snippet if
[% IF ${1:condition} -%]"
${2}
[% END -%]
${3}
snippet ife
[% IF ${1:condition} -%]
${2}
[% ELSE -%]
${3}
[% END -%]
${4}
snippet ifee
[% IF ${1:condition1} -%]
${2}
[% ELSIF ${3:condition2} -%]
${4}
[% ELSE -%]
${5}
[% END -%]
${6}
snippet unless
[% UNLESS ${1:condition} -%]
${2}
[% END -%]
${3}
snippet for
[% FOR ${1:var} = ${2:list} %]
${3}
[% END -%]
${4}
snippet foreach
[% FOREACH ${1:var} = ${2:list} %]
${3}
[% END -%]
${4}
snippet while
[% WHILE (${1:var} = ${2:rs}.next) -%]
${3}
[% END -%]
${4}
snippet switch
[% SWITCH ${1:var} -%]
${2}
[% END -%]
${3}
snippet case
[% CASE ${1:var} -%]
${2}
snippet include
[% INCLUDE '${1:file}' %]
${2}
snippet process
[% PROCESS '${1:file}' %]
${2}
snippet macro
[% MACRO ${1:name}(${2:arg}) BLOCK %]
${3}
[% END %]
${4}
snippet var
[% ${1:var} %]
${2}
snippet hvar
[% ${1:var} | html %]
${2}
snippet hlvar
[% ${1:var} | html | html_line_break %]
${2}
snippet null
[%- FILTER null -%]
${1}
[%- END -%]
${2}
perl.snippet
#perl
snippet dump
use Data::Dumper; warn Dumper ${1:$var};
${2}
snippet say
print ${1:$var}, "¥n";
${2}
snippet self
my $self = shift;
${2}
snippet data
my $data = do {
local $/;
<data>
};
${1}
snippet argf
while (<>) {
chomp;
${1}
}
${2}
snippet isa
if (blessed ${1:$var} and ${2:$var}->isa('${3:Class}')) {
${4}
}
${5}
snippet readcsv
use IO::File;
use Text::CSV_XS;
my $fh = IO::File->new('${1:filename}') or die 'cannot open file.';
my $csv = Text::CSV_XS->new({ sep_char => "¥t", binary => 1 });
until ($fh->eof) {
my $cols = $csv->getline($fh);
unless ($cols) {
warn $csv->error_diag;
next;
}
my (${2}) = @$cols;
}
$fh->close;
${3}
#class-C3
snippet next
$self->next::method(@_);
${1}
snippet maybe
$self->maybe::next::method(@_);
${1}
#Catalyst
snippet debug
$c->log->debug('${1:[ debug ]}: '. ${2:$var});
${3}
snippet warn
$c->log->warn('${1:[ warn ]}: '. ${2:$var});
${3}
snippet dumper
$c->log->dumper('${1:[ dumper ]}: '. ${2:$var});
${3}
snippet model
$c->model('${1:model}')
${2}
snippet view
$c->view('${1:view}')
${2}
snippet template
$c->view('View::TT')->template('${1:name}');
${2}
snippet config
$c->config->{${1:name}}
${2}
snippet controller
sub ${1:func} : ${2:Attribute} {
my ($self, $c) = @_;
${3}
}
${4}
snippet begin
sub begin : Private {
my ($self, $c) = @_;
${1}
1;
}
${2}
snippet auto
sub auto : Private {
my ($self, $c) = @_;
${1}
1;
}
${2}
snippet detach
$c->detach('${1:name}');
${2}
snippet forward
$c->forward('${1:name}');
${2}
snippet stash
$c->stash->{${1:var}}${2}
snippet flash
$c->flash->{${1:var}}${2}
snippet session
$c->session->{${1:var}}${2}
snippet sstash
$c->stash->{${1:var}} = ${2};
${3}
snippet sflash
$c->flash->{${1:var}} = ${2};
${3}
snippet ssession
$c->session->{${1:var}} = ${2};
${3}
snippet rs
$c->model('DBIC::${1:Source}')
${2}
snippet redirect
$c->res->redirect($c->uri_for('${1:uri}'));
${2}
snippet param
$c->req->param('${1:param}')
${2}
snippetsEmu の不便だったとこがなくなったー
相当快適になった。
ただどうしても分からなかったのが外部で定義した snippet を include するやり方がわからなかった。
そのため .tt の場合には filetype を tt2.html とすることで回避した。
Perl でシリアライズの方法が色々あるのでちょっとベンチマークをとってみた。
ちなみに試したのは Storable, FreezeThaw, Data::Dumper, XML::Dumper の4つ。
結果だけを先にいうと一番のおすすめは Data::Dumper でファイルに出力し、eval するのが一番よさげ。
ベンチマークをとったコード(シリアライズ)
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw/cmpthese/;
use Storable;
use FreezeThaw;
use Data::Dumper;
use XML::Dumper;
$| = 1;
package Human;
use base qw/Class::Accessor::Fast/;
__PACKAGE__->mk_accessors( qw/name email key/ );
package main;
my $human = new Human();
$human->name('dealforest');
$human->email('dealforest.net@gmail.com');
open my $store, '>', 'store';
open my $dumper, '>', 'dumper';
open my $freezethaw, '>', 'freezethaw';
open my $xml, '>', 'xmldumper.xml';
my $dump = new XML::Dumper;
cmpthese(50000000 ,{
dumper => &data_dumper,
store_fd => &storable_store,
freeze => &freezethaw_freeze,
pl2xml => &xmldumper_pl2xml,
});
close $store;
close $xml;
close $dumper;
close $freezethaw;
sub storable_store {
Storable::store_fd $human, $store;
}
sub data_dumper {
print $dumper Dumper $human;
}
sub freezethaw_freeze {
print $freezethaw FreezeThaw::freeze $human;
}
sub xmldumper_pl2xml {
print $xml $dump->pl2xml($human);
}
1;
ベンチマークの結果(シリアライズ)
Rate pl2xml freeze dumper store_fd
pl2xml 68493151/s -- -29% -41% -51%
freeze 96153846/s 40% -- -17% -31%
dumper 116279070/s 70% 21% -- -16%
store_fd 138888889/s 103% 44% 19% --
(※)ベンチの結果はカオスなくらい毎回かわりますw
そのためどらが一概にはやいのか良くわからいです。。。
平均的にみたらこれかなってのをだしてます。
ベンチマークをとったコード(デシリアライズ)
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw/cmpthese/;
use Storable;
use FreezeThaw;
use Data::Dumper;
use XML::Dumper;
$| = 1;
my $xmldump = new XML::Dumper;
cmpthese(100000, {
dumper => sub {
open my $fh, '<', 'dumper';
my @a = <$fh>;
my $VAR1;
eval(join '', @a);
close $fh;
},
fd_retrieve => sub {
open my $fh, '<', 'store';
Storable::fd_retrieve($fh);
},
freeze => sub {
open my $fh, '<', 'freezethaw';
my $a = <$fh>;
FreezeThaw::thaw($a);
close $fh;
},
pl2xml => sub {
open my $fh, '<', 'xmldumper.xml';
my @a = <$fh>;
$xmldump->xml2pl(join '', @a);
close $fh;
},
}
);
1;
ベンチマークの結果(デシリアライズ)
Rate pl2xml freeze dumper fd_retrieve
pl2xml 2703/s -- -71% -81% -90%
freeze 9183/s 240% -- -35% -66%
dumper 14025/s 419% 53% -- -47%
fd_retrieve 26667/s 886% 190% 90% --
まとめ
シリアライズするコストはどれも似たような感じ。
デシリアライズのコストは意外に XML::Dumper がはやかった。
Storable がおそかったのは少しびっくりした。
デシリアライズのコストは Storable が一番。その次に Data::Dumper がはやかった。
ただ XML::Dumper は文字データしか扱えない。バイナリ絡むと無理。
FreezeThaw も若干微妙。
その辺で一番便利だったのが Data::Dumper だった。
swfをパースしたインスタンスでも復元できた。
つまりは Data::Dumepr を選んどくとが一番幸せになれそう。
追記: 2009-04-10T03:18:27+00:00
Storable は GLOB をシリアライズできないみたい。
ってエラーがでた。