sandbox

Scala, Android, Architecture, Management, Service Design あたりを主戦場としております

LaunchBar から Google Calendar のイベントを登録する

予定を登録するのに Google Calendar を開くのが面倒だったので、下記の様な感じで LaunchBar から Google Calendar の QuickAdd 機能を使って予定を登録できる様にしてみました。


f:id:tlync:20110205205556p:image

必要な環境

  • python (Mac であれば標準でインストールされているはず)
  • gcalcli
    • GData
    • dateutil

おおまかな手順

  1. GData のインストール
  2. dateutil のインストール
  3. gcalcli のダウンロード、編集
  4. LaunchBar の設定

GData をインストール

gcalcli の依存モジュールの GData をインストールします。

wget http://gdata-python-client.googlecode.com/files/gdata-2.0.13.tar.gz
tar -zxvf gdata-2.0.13.tar.gz  
cd gdata-2.0.13
./setup.py install

dateutil をインストール

同じく依存モジュールの dateutil もインストールします。

wget http://labix.org/download/python-dateutil/python-dateutil-1.5.tar.gz 
tar -zxvf python-dateutil-1.5.tar.gz
cd python-dateutil-1.5.tar.gz
./setup.py install

gcalcli のダウンロード

予定登録を行う為の gcalcli スクリプトをお好きなディレクトリにダウンロードします。

cd ~/Scripts #お好きなディレクトリに
wget http://gcalcli.googlecode.com/files/gcalcli-1.4.tgz
tar -zxvf gcalcli-1.4.tgz

アカウント名、パスワードの入力

ダウンロードした gcalcli の48、49行目のユーザー名とパスワードを自分の Google アカウントのメールアドレスとパスワードに変更します。

__username__ = '*********@gmail.com'
__password__ = '*********'

文字コード指定の変更(問題が発生した人のみ)

自分の環境では OSX を英語で使っているせいか、gcalcli の予定登録をしようとすると UnicodeDecodeError が発生した為、下記の様にエンコード指定部分を変更しました。
もしかすると、日本語環境の人は不要かもしれないので、一旦この手順は無視して問題が発生したら試してみるといいかもしれません。

--- gcalcli.orig	2011-02-05 21:26:48.000000000 +0900
+++ gcalcli	2011-02-05 21:26:25.000000000 +0900
@@ -1087,7 +1087,7 @@
             Usage()
 
         # allow unicode strings for input
-        uniArg = unicode(args[1], locale.getpreferredencoding())
+        uniArg = unicode(args[1], 'utf-8')
         gcal.QuickAdd(uniArg)
         return

LaunchBar の SearchTemplate の設定

LaunchBar をショートカットで呼びだしたら、Alt + Cmd + I でインデックス画面を表示。
f:id:tlync:20110205215149p:image

SearchTemplate(UTF-8) を選択し Add をクリック。
f:id:tlync:20110205215425p:image

名前はお好みで入力し、URL を下記の様に入力。
※パスは自分がダウンロードしたディレクトリを入力する。またチルダ(~)を含めると登録できないので、フルパスで入力する。

x-launchbar:execute?path=/Users/takuya/Scripts/gcalcli&arguments=quick+%22*%22

f:id:tlync:20110205215107p:image

上記で手順は完了です。

予定の登録

あとは SearchTemplate の登録時にした任意のキーワード(Google Canedar 等)で呼び出し、QuickAdd のフォーマットで予定を入力すると、自動的に Google Calendar に予定が登録されています。便利!!


f:id:tlync:20110205215815p:image
f:id:tlync:20110205215814p:image

Firefox 4 & Vimperator 3.0 用のシンプルな colorscheme 書いた

たいした事も書かずに放置しっぱなしのこのブログですが、新しく場所作るのも面倒だったのここで。。
今日、Firefox 4 にメインブラウザを切りかえたので、vimperator 3.0 のデフォルトテーマをベースにシンプルに、でも美しくを目標に colorscheme を作成しました。


GitHub
https://github.com/tlync/vimperator-addons/blob/master/colors/vimpwhite.vimp


起動後はこんな感じ。ほぼデフォルトテーマのまま。
f:id:tlync:20110204232427p:image


結果領域は Mac OS X ネイティブっぽく。
f:id:tlync:20110204232425p:image


Hint も CSS3 で綺麗に。
f:id:tlync:20110204232422p:image


ちなみに Mac でしか確認していません。
黒背景ベースも作りたい。


3/23 追記:
最新の Firefox 4 & vimperator 3 で試すとスクリーンショットと異なりアドオンバーが表示される様になっているかもしれません。
その場合は、アドオンバーを消す場合はこちらのエントリを参考に。
http://d.hatena.ne.jp/tlync/20110225/1298600213

LINQ to Entities で _ , % を使ったワイルドカード検索

たまにはブログ書こう。。という事で。

背景

SQL で使える _(アンダースコア), %(パーセント) のワイルドカードがあります。
このワイルドカードを使ったパラメトリックなクエリを LINQ to Entities (以下 L2E) で純粋に実現しようと思うと、StartsWith, EndsWith, Contains と Expression Tree & Lambda Expression を使って面倒な実装をする必要があります。
まだワイルドカードはひとつまでとかだったらいいですが、複数となるといちいちパースして、Expression Tree 組み立てて、というのは暇な時しかやる気がおきません。


そこでなんとか簡単に実現する方法がないかと調べていたのですが、ある方法ですぐ実現できました。

結論

Object Query を使う です。
以下、例。

// 実は ObjectQuery.Where が使えるので、IQueryable.Where でなく ObjectQuery.Where で。
ObjectQuery<Products> query = e.Products.Where("It.ProductNumber like 'AA%%-00%%'");

// ObjectQuery は IQueryable を実装しているのでそのままキャスト。
IQueryable<Products> products = (IQueryable<Products>) query;

※最初から ObjectQuery でいいじゃん、と言われるかもしれませんが、ADO.NET Data Services を使っているので L2E 上で実現する必要がありました。

なんで使えるの?

何かソースがあって使えると判断した理由ではないので、明確に何故には答えられません。。
気づいたのはデバッグをしている時で、L2E のクエリにブレイクポイントを設定して、クエリ処理中のデータ型を見てみると IQueryable ではなくて ObjectQuery となっていました。
であれば、ObjectQuery.Where が使えるんじゃないかと思って使ってみたら使えた、という流れです。

詳細は Entity Framework のアーキテクチャを追わないとはっきり分からないかもしれませんが、おそらく L2E のクエリが ObjectService によって処理される際に、内部的に ObjectQuery が使われてるんだろうと思ってます。

まとめ

L2E のタイプセーフさはなくなりますが、ADO.NET Data Services の Service Operation の様に IQueryable を返す必要があって、パラメトリックなクエリに対応したい場合に役立つと思います。


なんかドキュメント見落しているだけなのかもしれませんが、ふつう気づかないよなぁ、と思ったので公開メモでした。

Firefox デフォルトテーマにぴったりの vimperator の colorscheme 書いた

最近 2.0 に移行してから vimp 中毒度が増している今日この頃だけど、
これだ! という colorscheme がなかったので作ってみました。


ポイントとしては、Firefox のデフォルトテーマ Firelight に外観を合わせている事と、
Hint が Safari の検索ライクな角丸になってます。


http://github.com/tlync/vimperator-addons/tree/master


ただ、mac でしか確認していないのと、Firefox 3 のデフォルトテーマ Firelight で使う事を想定してます。
また、全ての表示を確認している訳ではないので何らかの問題は抱えているかも…



追記:
Windows でも確認しましたが、一応基本的なところは崩れとかなく動いてる様です。
でも、Windows だとステータスバーに画像が使用されていないので見た目が微妙。


2009/06/06 追記:
Vimperator 2.1, Firefox 3.5 beta4 向けに少し変更しました。
TreeStyleTab ユーザでない人は Tab をコメントアウトした方が良いかもしれません。
また、Firefox 3 ユーザの人は、StatusLine のスタイルは for Firefox 3.0.x とコメントアウトしてあるスタイルを使用した方が良いです。


f:id:tlync:20090222235056p:image
f:id:tlync:20090222235053p:image

詳解 Objective-C 2.0

項目的には、今読んでいる Apple 公式の資料とかぶっているから、こちらを先に読み進めようかな。

詳解 Objective-C 2.0

詳解 Objective-C 2.0

Objective-C 2.0 プログラミング言語を読む #4 プロパティ

出張三昧で時間が空いてしまった。。
iPhone の発売を心待ちにしつつ、勉強再開。

プロパティとは

オブジェクトのプロパティを宣言によって実装する方法。
また、アクセサメソッドを記述せずにオブジェクトのプロパティにアクセス出来る構文も用意されている。
プロパティには2つの側面があり、プロパティを宣言する為の構文要素と、アクセスする為の構文要素がある。

プロパティの目的

アクセサの記述が面倒なので、宣言で簡単に記述できるようにした。
例えば、

  • 宣言により、アクセサメソッドの動作方法を指定出来る。
  • 宣言で指定された仕様に基づき、コンパイラがアクセサメソッドを合成出来る。
  • 宣言されていないプロパティの使用の検出。
  • プロパティの実行時のインストロペクション。

プロパティの宣言

@property を使用してプロパティを宣言する。
宣言はメソッド宣言リスト内の任意の場所に置くことが出来、プロトコルやカテゴリ宣言のなかにも置くことが出来る。

@interface MyClass:NSObject 
{ 
  NSString*value; 
} 
//@property(attributes) type name と宣言する
@property(copy, readwrite) NSString *value;
@end 

@implementationMyClass 
@synthesize value; 
@end 

プロパティの実装ディレクティブ

@implementation ブロックでは、@synthesize と @dynamic を使用して、コンパイラの動作を指定出来る。

ディレクティブ 意味
@synthesize 関連するアクセサを合成する
@dynamic 実行時に自分自身でメソッド用意する(つまり合成しない)。デフォルト

こんな風に一度に宣言することも出来る。

//各プロパティのアクセサを合成し、age プロパティはインスタンス変数 yearsOld によって表すことを指定。
@synthesizefirstName, lastName, age = yearsOld;

プロパティ宣言属性

必要に応じて @property(attributes) の形式で、プロパティを属性で修飾することが出来る。

属性 意味
getter=gtterName
,setter=setterName
アクセサの名前を指定したい時に指定する。デフォルトではキー値コーディングの表記規約に従う。
readonly 読み取り専用であることを示す。ドット構文を使用して値を代入しようとするとコンパイル警告が発生する。
readwrite 読み書き可能であることを示す。デフォルト。
assign setter で単純代入を使用することを指定する。デフォルト。GC を使用していない環境では適切ではない為、コンパイラ警告が発生する。
retain 代入時に retain を呼び出すことを指定する。Objective-C オブジェクトに対してのみ有効。
copy 代入時にオブジェクトのコピーを使用することを指定する。NSCopying プロトコルを実装する必要がある。
nonatomic 合成されるアクセサが非アトミックになるように指定する。デフォルトでは全てアトミック。

assign, retain, copy でアクセサを合成した場合は、それぞれ下記の様な実装になる。

// assign 
property = newValue; 

// retain 
if (property != newValue) 
{ 
  [property release]; 
  property = [newValue retain]; 
}

// copy 
if (property != newValue) 
{ 
  [property release]; 
  property = [newValue copy]; 
} 

プロパティの再宣言

サブクラス、カテゴリ、プロトコルでプロパティで再宣言出来る。
その場合は、そのサブクラス、カテゴリ、プロトコル全体でプロパティの属性を繰り返す必要がある。
#これは同じ属性を宣言しとけってことか?

1つ例外として readonly と readwrite は、readonly で宣言したプロパティを、
サブクラス、カテゴリ、プロトコル で readwrite として再宣言出来る。

プロパティへのアクセス

ドット構文

Java などと同様にドット構文でアクセス出来る。

MyClass *myInstance = [[MyClassalloc] init]; 
myInstance.value = @"Newvalue"; 
NSLog(@"myInstancevalue:%@", myInstance.value); 

ただ、これはシンタックスシュガーでしかなく、実際はコンパイラによってアクセサメソッドの呼び出しに変換される。

MyClass *myInstance = [[MyClassalloc] init]; 
[myInstancesetValue:@"Newvalue"]; 
NSLog(@"myInstancevalue:%@", [myInstancevalue]); 

また自身のインスタンス変数にアクセスする場合は self を用いる。
self を指定しないと直接インスタンス変数にアクセスすることになる。

self.age = 10; //setter が呼びだされる
age = 10; //インスタンス変数へ直接アクセスされる
キー値コーティング

定義したプロパティにはキー値コーディングでもアクセス出来る。
キー値コーディングとは、 NSObject で定義されている valueForKey:, setValue:forKey: でアクセサメソッドを
呼ぶことが出来る仕組みである。
何が嬉しいのかというと、引数には文字列でプロパティ名を渡せる為、実行時に呼ぶアクセサを動的に変えることが出来る。
#これは Java とか JavaScript のリフレクションみたいだな。

@interface Person
{
  NSString *name;
  NSInteger age;
}

@property(copy) NSString *name;
@property NSInteger age;

@end

...

Person *person = [[Person alloc] init];
NSString *name = [person valueForKey:@"name"]; //person.name
[person setValue:20 forKey:@"age"] //person.age = 20;
プロパティのサブクラス化

readonly な属性をサブクラスで readwrite にするなどの様に、プロパティもオーバーライドすることができる。

プロパティのインストロペクション

class_getProperty(Class cls, const char *name) の様にプロパティを取得でき、
property_info(Property *property, const char **name, const char **type) でプロパティの情報を取得出来る。

他にも class_copyPropertyList や、 property_copyAttributeList 関数などもある。

ランタイムの相違

32bit 環境では、@interface 宣言ブロックにインスタンス変数を宣言しなければならない。
64bit 環境では、自動でインスタンス変数を合成してくれる。

Objective-C 2.0 プログラミング言語を読む #3 カテゴリ

カテゴリのところ。コード書く時に体に染みこませればいいので理解だけさらっと。

カテゴリとは

既存のビルトインクラスなどにメソッドを追加出来る。
また、自身のクラスにおいても実装を複数のファイルに分ける、つまりカテゴリ化することも出来る。

メソッドのクラスへの追加

インタフェース名の後にカテゴリ名を指定する。
中括弧がなく、インスタンス変数は定義できないことに注意。

#import "SampleClass.h"

@interface SampleClass(CategoryName)
//method declarations
@end

このカテゴリを定義したインターフェースファイルは命名規則により、
ClassName+CategoryName.h とする。

なので、これをインポートする実装ファイルは以下の様になる。

#import "SampleClass+CategoryName.h"

@implementation SampleClass(CategoryName)
//method implementations
@end

カテゴリの使いかた

  • クラスが継承している、また宣言されているメソッドをオーバーライドすることが出来る。
  • 同じクラスの別カテゴリに宣言されているメソッドは確実にオーバーライドすることは出来ない。
  • @interface セクションで宣言されているメソッドをオーバーライドするのは避けるべき。

ルートクラスのカテゴリ

カテゴリはルートクラスにもメソッドを追加出来る。
その為、NSObject を継承するすべてのクラスでそのメソッドが利用可能になる。
役立つこともあるかもしれないが、かなり危険。

#これは JavaScript のビルトインオブジェクトを拡張する際の問題と一緒かな。

クラス拡張

上記で説明してきた様なカテゴリの定義では、追加したメソッドに対する実装を必須としたくても
コンパイラがチェックしてくれない為、実装がなくてもコンパイル出来てしまう。

これを実装を必須としてメソッドを追加する場合にクラス拡張を使用する。

普通にカテゴリを定義した場合

@interface MyObject:NSObject 
{ 
  NSNumber*number; 
} 

- (NSNumber *)number; 
@end 

@interface MyObject (Setter) 
- (void)setNumber:(NSNumber *)newNumber; 
@end 

@implementation MyObject 
- (NSNumber *)number 
{ 
  return number; 
} 

//setNumber メソッドがなくてもコンパイル出来てしまう
@end 

クラス拡張を使用した場合

@interface MyObject :NSObject 
{ 
NSNumber *number; 
} 
- (NSNumber *)number; 
@end 

@interface MyObject () //括弧内を空にする。匿名カテゴリの様なイメージ。
- (void)setNumber:(NSNumber *)newNumber; 
@end 

@implementation MyObject 
- (NSNumber *)number 
{ 
  return number; 
} 

- (void)setNumber(NSNumber *)newNumber //ちゃんと実装しないとコンパイラに怒られる
{ 
  number = newNumber; 
} 
@end 

上記の様にメソッドを追加した場合は、コンパイラが setNumber のメソッドがないかをちゃんとチェックしてくれる。

読破するつもりだったけど

会議が入ったので読み終わるのは全然無理になった。。
さくっと理解して早くアプリ作りたいなぁ。