以下「呼び出されるもの」をメソッドと書くこととする。サブルーチンも関数と呼んでもほぼ同じ。
実行が失敗する可能性のあるメソッドの呼び出し側は、メソッド呼び出し後に成功したか失敗したかをチェックして、失敗だった場合適切な処理を行う必要がある。
メソッドの実行が成功か失敗かどうかの情報がどのように得らるようになっているかは、メソッドによって様々である。
成功したかどうかが true か falseか、あるいは 0 か !0 などで返されるタイプ。
if (obj.run()) { // success }
失敗の場合はエラー番号などが返されるものがある。真偽値として評価できる値を返す場合はそのまま条件式などで使用できる。
エラー状態受け渡しのオブジェクトを呼び出し時に引数として指定するタイプもある。
失敗した場合に null を返すものや、通常0以上の値を返す時に失敗の場合は負の値を返すものなど。
Data result = obj.run(); if (result != null) { // success }
チェックを忘れると、誤った値で計算を続けてしまったりヌルポインタ例外を引き起したりする。
結果受け渡しオブジェクトを呼び出し時に指定するタイプもある。
obj.run(); if (globalStatusObject.isSuccess()) { // success }
obj.run(); if (obj.isSuccess()) { // success }
try { obj.run(); } catch (Exception x) { // error }
どこかで捕捉する必要がある。
困る。
Bobby Woolf による。
null のかわりに Null Object を使用して null チェックを不要にするパターン。
普段使っているノート PC は pdumpfs でバックアップをとっている。 任意のスナップショットから簡単にファイルを復元できるので、バックアップ用HDDを別に用意できる場合はこれが便利。
会社で使っている Windows デスクトップは、rsync でWindowsファイルサーバへ同期。 1世代しかバックアップが無い。 少なくとも数世代前のファイルが復元できるようにしておきたい。
某 Linux サーバはバックアップ無し! マズイ。 現状、たまに手動で tarball にして保存しているぐらい。
DAR というバックアップコマンドの紹介を見て興味をひかれた。 シンプルながらも使い勝手の良さそう。 Linux でも Windows でも動くというのも嬉しい。
Linux 上で試してみる。
/tmp の下にテスト用ディレクトリ dar を作成。 その下に home ディレクトリと var ディレクトリを作成する。
mkdir -p /tmp/dar/home/naney mkdir -p /tmp/dar/var/lib/dar echo 'abc' > /tmp/dar/home/naney/file1.txt
/tmp/dar/home 以下バックアップ対象として /tmp/dar/var/lib/dar 以下にバックアップファイルを作成してみることにする。
最初はフルバックアップ:
dar -c /tmp/dar/var/lib/dar/home-full \ -y9 \ -R /tmp/dar \ home
/tmp/dar/home をフルバックアップした home-full.1.1.dar が /tmp/dar/var/lib/dar にできる。
ファイルを1つ追加。
echo 'def' > /tmp/dar/home/naney/file2.txt
ここで差分バックアップをとる:
dar -c /tmp/dar/var/lib/dar/home-diff-1 \ -A /tmp/dar/var/lib/dar/home-full \ -y9 \ -R /tmp/dar \ home
home-full.1.dar に対する差分バックアップファイル home-diff-1.1.dar ができる。
もう1つファイルを追加。それから最初にあったファイルを削除してみる。
echo 'ghi' > /tmp/dar/home/naney/file3.txt rm /tmp/dar/home/naney/file1.txt
ここで差分バックアップ(2回目):
dar -c /tmp/dar/var/lib/dar/home-diff-2 \ -A /tmp/dar/var/lib/dar/home-full \ -y9 \ -R /tmp/dar \ home
home-full.1.dar に対する差分バックアップファイル home-diff-1.2.dar ができる。
またインクリメンタルバックアップもとってみる
dar -c /tmp/dar/var/lib/dar/home-inc-2 \ -A /tmp/dar/var/lib/dar/home-diff-1 \ -y9 \ -R /tmp/dar \ home
差分バックアップファイル home-diff-1.1.dar に対する差分バックアップファイル home-diff-2.1.dar ができる。
dar -x /tmp/dar/var/lib/dar/home-full
を実行。
home/naney/file1.txt
が復元される。
dar -x /tmp/dar/var/lib/dar/home-full dar -x /tmp/dar/var/lib/dar/home-diff-1
を実行。
home/naney/file1.txt home/naney/file2.txt
が復元される。
dar -x /tmp/dar/var/lib/dar/home-full dar -x /tmp/dar/var/lib/dar/home-diff-2
を実行。
home/naney/file2.txt home/naney/file3.txt
が復元される。
dar -x /tmp/dar/var/lib/dar/home-full dar -x /tmp/dar/var/lib/dar/home-diff-1 dar -x /tmp/dar/var/lib/dar/home-inc-2
を実行。
home/naney/file2.txt home/naney/file3.txt
が復元される。
前回は CPAN::Site を用いたオフライン用インストールセットを作成した。
今回は空の CPAN のミラーを作り、そこに野良パッケージを突っ込んで使用する形でインストールセットを作成してみる。
~/perl-5.8.8 以下にクリーンな Perl 5.8.8 をインストールしてインストールセットを作成していく。
perl -MCPAN -e shell cpan> install CPAN::Mini::Inject cpan> exit
CPAN::Mini::Inject は、インストールセットには必要ない。 ~/perl-5.8.8 にはインストールせずに、普段使っているほうにインストールしておく。
以下スクリプト例(エラー処理などは省略)
#!/usr/bin/perl -w use strict; use File::Path; use CPAN::Mini; use CPAN::Mini::Inject; my $remote = 'ftp://ftp.dti.ad.jp/pub/lang/CPAN/'; my $local = '/home/myname/public_html/CPAN'; my $repository = '/home/myname/repository'; mkpath([$local, $repository], 1, 0755); # module_filters で全てのモジュールを対象外にして、空の CPAN ミラーを作る CPAN::Mini->update_mirror(remote => $remote, local => $local, diremode => 0755, trace => 1, module_filters => [ qr/./ ]); my $injector = CPAN::Mini::Inject->new; $injector->{config}{remote} = $remote; $injector->{config}{local} = $local; $injector->{config}{repository} = $repository; $injector->{config}{diremode} = 0755; # CPAN::Mini::Inject リポジトリに追加したあと、 # CPAN ミラーへ 注入 $injector->add(repository => $repository, module => 'WiKicker', authorid => 'NANEY', version => '0.xx', file => 'WiKicker-0.xx.tar.gz') ->inject;
これで、~/public_html/CPAN に野良パッケージの追加された CPAN ミラーが作成される。
rm -rf ~/.cpan ~/perl-5.8.8/bin/perl -MCPAN -e shell cpan> o conf urllist pop cpan> o conf urllist push http://http://localhost/CPAN cpan> reload index cpan> o conf urllist push ftp://ftp.dti.ad.jp/pub/lang/CPAN/ cpan> install WiKicker cpan> exit
ここでローカル CPAN サーバを file:/// 等で指定すると、そこから読みとったファイルは ~/.cpan/sources/ 以下にコピーされないので一箇所にまとめることができないので注意。
またCPAN ではモジュールインデックスファイルは1組しか持てないようで、初期設定のままだと野良パッケージを含む CPAN ミラーのインデックスファイルが使われない。 そのため一旦 urllist を空にした後、 自分の CPAN ミラーを指定しインデックスファイルをロードする。 その後にソースパッケージを取得するセカンダリとして通常の CPAN (ミラー)を指定するようにしている。
これが終わると、WiKicker とそれに必要なファイルが ~/.cpan/sources にたまる。
これを適宜アーカイブして保存する。
別の環境で例えば /usr/local/perl-5.8.8 にインストールされた Perl に WiKicker をオフラインでインストールするとする。
先の工程で作成したファイルセットが /tmp/CPAN においてあるものとする。
/usr/local/perl-5.8.8/bin/perl -MCPAN -e shell # 初期化でオフラインのため CPAN ミラーの選択ができずに URL の入力を # 求められたところで file:///tmp/CPAN を指定 cpan> install WiKicker cpan> exit
これで /tmp/CPAN から芋蔓式に WiKicker がインストールされる。
CPAN::Site を利用して構築した場合は、インストール時にも CPAN::Site が必要だが、こちらはインストールセットの利用には CPAN.pm だけで良いというのが利点。
今回は CPAN::Mini で空の CPAN ミラーを作成し野良パッケージを追加した。
ここで最初から CPAN の最新パッケージの全ミラーを CPAN::Mini で作成し、これに野良パッケージを追加してインストールセットを作ってしまうという方法もある。 この場合は後で必要に応じてミラーからパッケージを入れられるというメリットがあるかわりに、ミラー作成のコストがかかるというデメリットがある。
2006年6月8日以来、3日ぶりのリリース。
zakwa 氏からの要望により、WikiPage のコピー直後に編集画面に移れる edit now オプションを追加。
また大きな改良として「添付機能」を追加した。 まだ最初のコードなのでエラー処理等が甘いが、それなりに動いているのでコミット。 まだ権限設定がないので、公開サーバでは使用しない方が良い。
添付ファイルのダウンロードを WiKicker 本体の CGI プログラムから行わせるか、独立の CGI プログラムにするか迷ったが、結局別物にした。
というのが大きな理由。
WiKicker のページにまだ設定方法を書いていないので、こちらへ。
例えば attachment というファイル名で以下のような Perl CGI プログラムを作り、Web サーバから実行できるように設定を行う。
#!/usr/bin/perl use strict; use warniings; use WiKicker::WikiCGI::AttachmentController; WiKicker::WikiCGI::AttachmentController ->new(properties_file => '対応する wiki の設定ファイル名')->run;
次に Wiki の設定ファイルに以下を追加。
param.NormalPage.attachment: enable param.NormalPage.attachment.uri: attachment
param.NormalPage.attachment.uri には上で作った CGI プログラムの URI (相対/絶対)を指定する。
これで各ページに attachment (添付)というリンクが表示され、添付機能が使えるようになる。
# リンクを作成 [[attachment:ファイル名]] [[attachment:ページ名/ファイル名]] <- 別のページの添付ファイル # 画像をインライン表示 [[image:attachment:ファイル名]] [[image:attachment:ページ名/ファイル名]]
Twitter の replies (mentions) をフィードリーダや Plagger で読めるようにするために、Basic 認証で Twitter にアクセスしてフィードをとってきてそのまま出力する Perl CGI スクリプトを書いて使っていたのだが、やはり Basic 認証が嫌なので OAuth 認証に書き換えた。
Net::Twitter モジュールだと取ってきたフィードが Perl のデータ構造になってしまいそのまま再度出力するのが面倒なので、Net::OAuth モジュールでリクエストを作って投げるようにした。
以下エラー処理等を省略したコード。
Web サイトに設置すれば(CGI スクリプト側で認証を済ませて)認証無しで replies のフィードが取れるようになるので簡単にフィードリーダで読めるようになる。
#!/usr/bin/perl -w use strict; use warnings; use CGI; use LWP::UserAgent; use Net::OAuth; use Data::Random qw(rand_chars); $Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A; my $consumer_key = 'YOUR CONSUMER KEY'; my $consumer_secret = 'YOUR CONSUMER SECRET'; my $access_token = 'YOUR ACCESS TOKEN'; my $access_token_secret = 'YOUR ACCESS TOKEN SECRET'; my $url = 'http://twitter.com/statuses/replies.atom'; my $method = 'GET'; my $query = CGI->new; my $request = Net::OAuth->request('protected resource')->new( consumer_key => $consumer_key, consumer_secret => $consumer_secret, request_url => $url, request_method => $method, signature_method => 'HMAC-SHA1', timestamp => time, nonce => join('', rand_chars(ssize => 16, set => 'alphanumeric')), token => $access_token, token_secret => $access_token_secret, extra_params => {count => '200'}); $request->sign; my $ua = LWP::UserAgent->new; my $response; if ($method eq 'GET') { $response = $ua->get($request->to_url); } else { $response = $ua->post($request->to_url); } print $query->header('application/atom+xml; charset=utf-8'); print $response->content;
リンクを複数のソーシャルメディアでシェアする仕組みを持ってなくて、そういう時は個別に投稿している。でも公開範囲とか細かく設定したい時以外はサクッと一発で終わらせた方がクールだ。あと今までほとんど Twitter ではリンクのブックマーク的シェアしていなかったんだけれど、まあ今後はちょっとしてもいいかなと。
ということで仕組み作り。はてなブックマークから Twitter 連携・外部サイト連携するのが国内的王道かな。でも他の人のリンク踏むとブックマーク先に飛んだりブックマークエントリーページに飛んだりっていう体験があってちょっとそういうの嫌だったりする。
代替案としては Facebook を一次投稿先にして IFTTT で他へ流す方法が思いついた。IFTTT 的に quick trigger になるのでタイムラグが無いのが良い。そのかわり非公開以外のリンク投稿について全て trigger してしまうようなのでちょっと怖い。URL・ページタイトル・コメントを IFTTT 側で分けて取れるのでいいんだけどね。
あとは Buffer を一次投稿先にして直接あるいは IFTTT で流す案も検討した。時間をばらしたい人はいいけどそうでない場合はあまり良くない。あとページタイトルは取得してくれない。
ということでやはりリンクの共有としては、はてなブックマークが便利なんだなぁ。PC からでも Android 端末からでもいけるし。なので一次投稿先ははてなブックマークに決定。全体公開ものをここにブックマークしているので、垂れ流れていくのも問題なし。ただ前述した点があるので、実際の連携にははてなブックマークの機能を使わないで、フィードを IFTTT に読ませて撒くことにした。
ただ IFTTT、はてなブックマークにつけたコメント部分をフィードから読みとれない。ということでちょこちょこっと Perl でフィルタを書いた。
#!/usr/bin/perl use warnings; use strict; use CGI; use LWP::UserAgent; use XML::RSS; my $ua = LWP::UserAgent->new; my $response = $ua->get('http://b.hatena.ne.jp/はてなID/rss'); my $rss = XML::RSS->new; $rss->parse($response->content); foreach my $item (@{$rss->{items}}) { my $description = $item->{description}; $item->{title} = $description if defined $description; } my $query = CGI->new; print $query->header('application/xml; charset=utf-8'); print $rss->as_string;
サーバに XML::RSS が入ってたのでそれを使った感じ。IFTTT からは15分に1回ぐらいのアクセスのはずなので、まあこんなもんで。エラー処理も端折り。
はてなブックマークにつけたコメントは IFTTT でエントリのタイトルとしてとれるようになるので、それを使うように。Facebook に投げる場合はページのタイトルは Facebook が自前で取得してくれるので使わないので、フィードではタイトルを上書きしてしまって問題ない。
ページのタイトルを取得しないソーシャルメディア向け(Twitter とか)には
foreach my $item (@{$rss->{items}}) { my $description = $item->{description}; $item->{title} = '“' . $item->{title} . '”'; $item->{title} = $description . ' / ' . $item->{title} if defined $description; }
と、タイトルとコメントをはてなブックマーク書式っぽくしてタイトルに設定してあげる。あとは IFTTT でいい感じに流してもらうと。
8月16日 (金) から配属されていたインターン、今日が最終日。 YAPC::Asia Tokyo 2013 に参加していて不在だったので今日は直接挨拶できなかったけど、お疲れさまでした。
インターンの中でも一番若く (未成年)、はたしてどこまで出来るのか、期待半分・心配半分でのスタートだったんだけれど、想像以上に飲み込みがはやくて大丈夫だった。若い吸収力ってすごいね。
前半は開発環境の構築と開発プロセスの理解、開発中の既存システムへの機能追加。後半はチーム内で新しく始まった Mojolicious ベースのシステム開発の中の問い合わせフォーム開発をお願いし、無事まとめあげてくれた。
普段、主に競技プログラミングに取り組んでいるというインターンなので、今回は実ソフトウェアにおける「オブジェクト指向」「MVC 的なこと」「責務の分離」「バリデーション」「エラー処理」「テスト」あたりの要所について都度伝えたつもりだったけど、ちょっとでも何か学びになれていればよいなと思う。
青春の夏休みに我々のインターンシップを選んでくれてありがとう!
あとマンツーマンでフォローしてくれたおとよさんもお疲れさま! 引き続き艦これをお楽しみください。
ちょっとしたメモを Alfred for Mac から一発で TaskPaper ファイルに挿入したい。Packal 上に TaskPaper のための多機能な Alfred Workflow があるので入れたんだけれど、うまくタスク追加ができないことがあるので、自前でスクリプトを作って Alfred から呼ぶことにした。
TaskPaper ファイルはテキストファイルなので書き慣れている Perl でスクリプトを書いてもいいんだけれど、 編集の競合が避けられるし parser も書かなくて済むしということで TaskPaper の API を使うことにした。
JavaScript for Automation (JXA) を使えば JavaScript コードで TaskPaper API を呼べるっぽい。
以下指定した TaskPaper ファイルに Inbox: プロジェクトがなければ追加した上でその子供としてノートを挿入するコード(エラー処理割愛。実際にはタイムスタンプとかもノートにつけるようにした)。
#!/usr/bin/env osascript -l JavaScript function TaskPaperContext(editor, options) { let inbox = editor.outline.evaluateItemPath("//Inbox:")[0]; if (!inbox) { inbox = editor.outline.createItem("Inbox:"); let projects = editor.outline.evaluateItemPath('@type = project') if (projects.length == 0) { editor.outline.root.appendChildren(inbox) } else { editor.outline.root.insertChildrenBefore(inbox, projects[0]); } } let items = ItemSerializer.deserializeItems(options.text, editor.outline, ItemSerializer.TEXTMimeType) editor.setCollapsed(items[0]) inbox.appendChildren(items, inbox.firstChild) } function run(argv) { Application('TaskPaper').open(argv[0]).evaluate({ script:TaskPaperContext.toString(), withOptions: {text: argv[1]} }) }
これを inbox.scpt というファイルで保存し実行権限を与えれば
./inbox.scpt $HOME/tmp/test.taskpaper こんにちはこんにちは!!
という感じで呼び出せるようになる。
あとは Alfred Workflow を作ってそこからこのスクリプトを実行すれば OK だ。
Naney (なにい) です。株式会社MIXIで SNS 事業の部長をしています。
※本サイトの内容は個人的見解であり所属組織とは関係ありません。