2009年3月17日火曜日

GTDで己の無知の知を知る

OmniFocusを導入していちばん大事だと思ったことなのですが、
GTDを実践していると、「実はびっくりするぐらい自分は何も分かっていない」ということが明らかになります。

どういうことか?
と申しますと、

たとえば今開発しているアプリに新機能を追加したので、テストしたいと考えています。
ですからまずはOmniFocusに「〜をテストする」という考えを追加します。

これだけでは行動に落とし込めないので
「テストクラスを書く」
「テストクラスをTextMateから実行する」
といった行動レベルに分解する必要があるのですが、

ここでふと「テストクラスを書くって、どうやるんだっけ」とか
「TextMateからテストを実行するショートカットってどうだったっけ」とか
そういう疑問が次々にわいてくるわけです。

だからそれらの本筋アクションを実行する前に、
「Pythonのunittestの使い方をネットで調べる」
「サンプルコードを動かして学ぶ」
「TextMateのショートカットを調べてEvernoteにメモする」
というような雑用作業が次々に出てきてしまいます。

今までの自分は、こういう「調べる」とか「学ぶ」というアクションを
全く思考に入れずにプログラムを作ったり仕事をしたりしていました。
これが今までずっと「なぜか知らないが、たったこれだけしか仕事の量がないのにどうしてこんなに時間がかかるのか」と思っていた原因なんだなぁと独り合点しています。

おかげさまで、今では「自分は何も知らないのだから時間がかかる」という風に考えられるようになり、仕事が進まないストレスも減ったかなーと。

pythonで、Objective-Cのカテゴリのように、あるクラスのソースを変更せずに任意のメソッドを追加する方法

■結論
すべてのクラスには__bases__という隠しフィールドがあるので、そこに任意のスーパークラスを作って追加する


■何がしたいか
たとえば以下のようなクラスがあります。
class Foo:
def do_something(self, x):
  print x
  return

このクラスのソースコードに指一本触れずに以下のメソッドを追加したい。
  def another_method(self, x, y):
  print x+y
  return

って将軍様が言っていたので、一⑨さんは考えました。


■チーン!ひらめいた!
まずは以下のようにスーパークラスになるクラスを作ります。
class SampleCategory:
def another_method(self, x, y):
  print x+y
  return

そしてここからがポイント。__bases__というTupleに、今作ったスーパークラスのtype型を追加します。
スーパークラスを宣言した後で・・・
from com.akisute.example import Foo
Foo.__bases__ += (SampleCategory,)

これだけです。
なぜかこれでうまくいくのがPythonのふしぎ。

実際のソースコードの例は以下のようになります(以下、拙作のプログラムから抜粋)
#!/usr/bin/env python
# encoding: utf-8
"""Login Authentication plugin.
Extends BasicController to give it an additional function for authentication
using Google account.
"""
import sys
import os

class LoginAuthPlugin:
    def is_login(self):
        """Returns True if requesting user is logged in."""
        #Do some work here
        return false

from gaeo.controller import BaseController
BaseController.__bases__ += (LoginAuthPlugin,)


JavaScriptのprototype書き換えにも似ていますね。
ただしprototype書き換えに比べて優れているのは、__bases__はTupleなので、簡単に好きなだけスーパークラスを追加することが出来ます。
(prototypeだと複数のスーパークラスを追加するのがきわめて困難)
from com.akisute.example import Foo
Foo.__bases__ += (SampleCategory,)
Foo.__bases__ += (AnotherCategory,)


■元ネタ
GAEOでpluginを読み込んでBaseControllerを拡張するときにこのテクが使われていました。
GAEO作った人は凄い。

2009年3月14日土曜日

Firebugのconsole APIを使ってLoggerもどきを作ってみた

突然ですが、Firebugのconsole APIは凄く便利です。
console.log("abesi");
console.debug("object:%o, decimal:%d, float:%f", anObject, count, Math.PI);

問題はこれ、Firebugがインストールされていて、かつコンソールが有効になっているとき以外は
エラーになってしまいます。
(consoleというオブジェクトがないから)
これをなんとかしたい。
それからついでに、せっかくlog, debug, info, warn, errorと5つも種類があるので、ログレベル制御もしてみたい。

ということで思い立ったが吉日、車輪の再発明をしようということで、ちょっとLoggerもどきを書いてみました。
http://gist.github.com/79018

使い方はこんな感じです。
    //Get logger
    var logger = new Logger(Logger.LEVEL_DEBUG);

    logger.debug($("abesi"));
    logger.info(hidebu);
    logger.warn("tawaba=%d", 100);

ログレベル制御をしているので、ログレベルをInfoにするとdebugログが出なくなる・・・はずです。
JavaScriptのprototypeなんて触ったのは実は人生初なので問題点が多々あるかと思いますが、まぁ、せっかくですから、どうぞお使いください。