シェル機能をインプリメントしたいなら Term::ShellUI を使うと便利
Web::Scraperのshellをhistoryから補完できるようにしてみました。
shell系は使わないと忘れてしまうので、historyがあったほうがいいかなと思って作ってみました。
~/.scraperhistoryを作っておくと、historyが使えるようになります。
Web::Scraperのshellでhistory補完 - dann's blog - #
おお,たしかに history があると便利。Term::ReadLine ってちょろっと設定するだけでヒストリ保存とかしてくれなかったっけ?と思ったら,別のモジュールでした。
以前*1も使いましたが,Term::ShellUI という CPAN モジュールを使うと高度なシェル機能を簡単にインプリメントすることができます。
特色は,
- 各コマンドへのサブルーチンリファレンスを指定するだけ
- エイリアスも指定できる
desc
を指定しておくと,$term->help_call()
等でヘルプメッセージをだせるargs
を指定すると,コンテキスト依存な補完ができる(zsh みたいな感じで)history_file
を指定すると,履歴をよしなにファイルに保存してくれる- 自分で
Features
を調べる必要はない
これらの機能を実現するために自分の手でコードを書く必要はありません。設定子として書いておくだけです。
使い方は,
- Term::ShellUI を設定込みで
new()
するnew()
したあとにプロパティとして設定をいじることもできます
$term->run()
すると,シェルプロンプトループが開始する- EOD とかしない限り,基本的に戻ってきません
です。
diff 形式だと Perl のコードがみづらくなるので,抜粋で。
# ...... snip snip snip ...... use Config; use Term::ShellUI; use Data::Dumper; use HTML::Entities; use URI; use Web::Scraper; use YAML; # ...... snip snip snip ...... my $stuff = process_args($ARGV[0]) or die "Usage: scraper [URI-or-filename]\n"; my $scraper = scraper { exec_shellui($_[0]) }; $scraper->user_agent->env_proxy; my $result = $scraper->scrape($stuff); # ...... snip snip snip ...... sub exec_shellui { my ($tree) = @_; local $YAML::UseCode = $YAML::UseCode = 1; my $term_setting = Load(<<'END_SHELL_SETTING'); --- app: scraper prompt: !!perl/code | { 'scraper[' . shift->{term}->GetHistory() . ']> ' } history_file: "~/.scraperhistory" history_max: 1000 commands: dump: desc: "Dump result" proc: !!perl/code | { local $Data::Dumper::Indent = 1; warn Dumper result } d: alias: dump yaml: desc: "Dump result in YAML" proc: !!perl/code | { warn Dump result } y: alias: dump source: desc: "Show source" proc: !!perl/code | { $print->($tree->as_HTML(q('"&<>), q( ), {})); } s: alias: source quit: desc: "Exit" method: !!perl/code | { $_[0]->exit_requested(1); } q: alias: quit code: desc: "Dump your processing in perl code" proc: !!perl/code | { if (@_ == 1 && $_[0] eq 'all') { print generate_code($source, @stack); } else { print generate_code($source, $stack[-1]); } } c: alias: code # fallbacks "": method: !!perl/code | { my ($term, $param) = @_; my $res = eval $param->{rawline}; warn $@ if $@; push @stack, $param->{rawline} unless $@; } help: desc: "Show this help message" method: !!perl/code | { shift->help_call(undef, @_); } h: alias: help "?": alias: help END_SHELL_SETTING my $term = Term::ShellUI->new(%$term_setting); print 'Using ', $term->{term}->ReadLine, "\n"; $term->run(); } # ...... snip snip snip ......
YAML 形式で設定する必要はないんですが,短く見やすくなるのでそうしました :)
実行すると,
% scraper http://b.hatena.ne.jp/ Using Term::ReadLine::Perl scraper[0]> ? code -- Dump your processing in perl code dump -- Dump result help -- Show this help message quit -- Exit source -- Show source yaml -- Dump result in YAML scraper[1]>
履歴数も表示することができます。