2007年4月アーカイブ

404 Blog Not Found:perl - POO と goto

ちなみに,暇な人はdepthの指定を100以上にしてみよう。滅多にお目にかかれないものに巡り会える。

暇ではないが、気になったのでdepthを100以上にしてみた。

% perl sample.pl
Benchmark: running Goto, Noself, Return for at least 3 CPU seconds...
Recursive inheritance detected while looking for method '()' in package 'Goto::0' at aa.pl line 77.

お、なんだこれは。再帰継承じゃねーかと言われた。99まではオッケイで、100より上だとこうなる。
調べてみると答えは「perldiag」にあった。

% perldoc perldiag
       …
       Recursive inheritance detected while looking for method %s
           (F) More than 100 levels of inheritance were encountered while invoking a method.
           Probably indicates an unintended loop in your inheritance hierarchy.
       …
100以上の継承をするとそうでるみたい。

ってことはPerlでは100以上の継承ができないってことなのかな。
実際そんなクラス構造を作ることはないとは思うけど…。

Sledge::Engineで、テンプレートとそれに対応するクラスはあるけれど、そのテンプレートに対応したdispatch_***()がなかったときに、その関数を自動生成するlookup_staticっていう関数があって、これすごく便利なんです。ただ、対応するクラスすらなかったときは404になります。まぁ当たり前ですね。

でもクラスも自動生成してくれるようにな機能があったらいいなと思って、というか業務で必要だったのでlookup_static()を以下のようにしてみました。

追加したのは最後のelse節です。なかったらその場で動的にクラスを作っています。多分PerlSetVarとかで有効・無効を制御した方がいいかもしれません。

下にpatchも貼っておきます。作者のshebangさんにメールしてみる、というか直接話すw
sub lookup_static {
    my($self, $path) = @_;
    my($page, $dir, $suf) =
        File::Basename::fileparse($path, $StaticExtension);
    return if index($page, '.') >= 0;
    $page ||= 'index';
    my $class;
    if ($dir eq '/') {
        my $appname = ref $self;
        for my $subclass(qw(Root Index)) {
            $class = join '::', $appname, 'Pages', $subclass;
            last if $class->require;
        }
    }
    else {
        $dir =~ s{^/}{};
        $dir =~ s{/$}{};
        $class = join '::',
            ref($self), 'Pages', map { camelize($_) } split '/', $dir;
    }
    if ((Class::Inspector->loaded($class) || $class->require) &&
            -e $class->guess_filename($page)) {
        no strict 'refs';
        *{"$class\::dispatch_$page"} = sub {}
            unless $class->can("dispatch_$page");
        my %action = (class => $class, page => $page);
        $self->ActionMap->{$path} = \%action;
        return \%action;
    }
    else {
        no strict 'refs';
        push @{"$class\::ISA"}, "${appname}::Pages";
        *{"$class\::dispatch_$page"} = sub {}
            unless $class->can("dispatch_$page");
        $class->tmpl_dirname($dir);
        return unless -e $class->guess_filename($page);

        my %action = (class => $class, page => $page);
        $self->ActionMap->{$path} = \%action;
        return \%action;
    }
}
--- Sledge-Engine-0.03/lib/Sledge/Engine.pm     2006-11-16 17:53:53.000000000 +0900
+++ Sledge-Engine-0.03_new/lib/Sledge/Engine.pm 2007-04-19 10:39:02.310000000 +0900
@@ -140,6 +140,18 @@
         $self->ActionMap->{$path} = \%action;
         return \%action;
     }
+    else {
+        no strict 'refs';
+        push @{"$class\::ISA"}, "${appname}::Pages";
+        *{"$class\::dispatch_$page"} = sub {}
+            unless $class->can("dispatch_$page");
+        $class->tmpl_dirname($dir);
+        return unless -e $class->guess_filename($page);
+
+        my %action = (class => $class, page => $page);
+        $self->ActionMap->{$path} = \%action;
+        return \%action;
+    }
 }

 sub run {
twitter2snarl.jpg

Twitterで更新がけっこうおおくてメッセやIRCとかで見るのがめんどうなので、shebangさんのOSXのGrowlみたいなのをWindowsでできないのかなぁと調べたら、Snarlというアプリを発見。これ、Growlインスパイヤみたい。しかもRubyのインターフェイスがあるので、こりゃいいやということで、Rubyでプログラムを書いて更新情報を出せるようにしました。

このプログラムを使うには事前にgemでruby-snarlをインストールしておく必要があります。

コードは以下。使い方はSnarlを立ち上げておいて、以下のプログラムをDOSのコマンドラインで、引数にtwitterのidとpassを渡して実行するだけです。Rubyのコードこんなに書いたの初めて…。これでいいのかどうかわからんけど一応動いてます。でもSnarlのバグなのか日本語がちょっと微妙…。ちゃんとUTF8で指定してやってるのに文字化けするところがあります。これはSnarlのバージョンアップを待つしかないかも。

twitter2snarl.rb
require 'rubygems'
require 'snarl'
require 'net/http'
require 'time'
require 'rexml/document'
include REXML
require 'uri'

user = ARGV.shift
pass = ARGV.shift

CURDIR  = Dir.pwd
HOST    = "twitter.com"
LASTMOD = CURDIR + "/.twitter2snarl"

# make uri
u = URI::HTTP.build([ nil, HOST, nil, "/statuses/friends_timeline.xml", nil, nil]);

# load last update
begin
  f = File.open(LASTMOD, "r")
  lastupdate = f.gets
  f.close
  u.query = "since=" + URI.escape(lastupdate)
rescue => evar
  puts "You are first time using twitter2snarl. Thanx!"
end

# request xml to twitter
xml = nil
Net::HTTP.version_1_2
req = Net::HTTP::Post.new(u.request_uri)
req.basic_auth user, pass
Net::HTTP.start(HOST, 80) { |http|
  res = http.request(req)
  xml = res.body
}

# check icons dir
Dir.mkdir(CURDIR + "/icons") unless FileTest.exists?(CURDIR + "/icons")

# parse xml and send message to snarl
img_cache = Hash[]
doc = Document.new xml
doc.elements.each("statuses/status") { |s|
  text        = s.elements["text"].text
  screen_name = s.elements["user/screen_name"].text
  image_url   = s.elements["user/profile_image_url"].text
  ext         = image_url.gsub(/^.*\.(jpg|png|gif)\?\d+$/, '\1')
  icon        = CURDIR + "/icons/" + screen_name + "." + ext

  # fetch profile icon
  if !img_cache[image_url] && !FileTest.exist?(icon) then
    u = URI.parse(image_url);
    File.open(icon, 'wb') { |f|
      Net::HTTP.start(u.host, u.port) { |http|
        res = http.get(u.request_uri)
        f.write res.body
        f.close
      }
    }
    img_cache[image_url] = 1
  end

  Snarl.show_message("Twitter: " + screen_name, text, icon, 10)
}

# write last update to file
f = File.open(LASTMOD, "w");
f.write Time.now.httpdate
f.close
あと、いちいちコマンドラインで実行するのは面倒なので、以下のようにschtasksでスケジュール登録しておくとよいでしょう。
C:\> schtasks.exe /Create /tn "Twitter Friends Timeline" /tr "C:\Ruby\bin\rubyw.exe \"C:\path\to\twitter2snarl.rb\" username@example.com password" /sc minute /mo 10

malaが紹介していた「bluewindからtwitterを更新できるようにRubyでシンプルなクライアントを書いた」のRubyのスクリプトを使って、fenrirのインスタントコマンドからtwitterのステータスを更新できるようにしてみたら、すげー快適。

設定方法は、fenrirの設定ファイルのinstant.iniに以下の行を追加して保存。(rubyw.exeだとコンソールウィンドウが立ち上がらないらしい。知らなかった。)

/t=""C:\Ruby\bin\rubyw.exe" "C:\path\to\update.rb" username password %A"

そしてfenrirを開き、

/t ここにステータスを書く

とインスタントコマンドを実行するだけでステータスを更新できます。これは便利だ!mala++。
もし、Rubyなんて入れてねーYOって人は、http://wget.sunsite.dk/この辺からWindows版のwgetをもってくれば、

/t=""C:\path\to\wget.exe" --post-data="status=%A" -O- http://username:password@twitter.com/statuses/update.json""

って設定しておけば、英数字での更新はできます。ただし、コンソールウィンドウが立ち上がります。
wgetよりもっと簡単にPOSTリクエストが打てるWindows用のコマンドがありそうですが、みつかりませんでした。これよいコマンドを知っていたら教えてください><

ていうか、更新はいいんだけど、友達の更新情報を見る方が問題だよなー。今のところIRCが一番邪魔しなくてよさげだけど、なんかもっといい方法ないかなぁ。Plaggerで定期的に携帯にメールとかも個人的にはいいかも。

どうやってる人が多いんだろう。

ちょっと時間が経ってしまいましたが、先日2日に渡ってYAPC::Asia 2007が催されました。
自分も会場に2日間とも参加させて頂いたので感想を書こうと思います。

全部のトークについて書くのは大変なので、自分がぐっときたワードについて書きます。

弾さんがやってたのを見てmod_rewriteでもできるべと思い、試しにやってみた。
RewriteCond %{HTTP_REFERER} !^http://clouder\.jp/~yoshiki/nohotlinks/
RewriteRule ^/~yoshiki/nohotlinks/.*\.(gif|png|jpe?g|mov|wmv|avi|flv)$ - [F]
これでできた。

やっていることは、RewriteCondディレクティブでリファラーをチェックして、http://clouder.jp/~yoshiki/nohotlinks/でなかった場合には、RewriteRuleディレクティブで/~yoshiki/nohotlinks/以下の画像やメディアを403 Forbiddenに飛ばすだけです。

以下は実際の動作の様子です。
http://clouder.jp/~yoshiki/nohotlinks/から参照できる画像も、このページや直接アクセスすると見られなくなっています。

ホットリンクできる例

・ホットリンクできない例
↓は表示されない。


ちなみに自分もそのサイトが「ホットリンクしないで複製してね」という以外はホットリンクするというのが正しいやり方じゃないかと思います。


Apacheハンドブック
Apacheハンドブック
posted with amazlet on 07.04.08
Ben Laurie Peter Laurie 大川 佳織 田辺 茂也
オライリージャパン (2003/09)
売り上げランキング: 35539
おすすめ度の平均: 5.0
5 Apache使い必須

検索

広告

OpenID対応しています OpenIDについて
Powered by Movable Type 4.22-ja