2009年12月25日金曜日

TwiVox | Twitter × Amazon | Twitterを使ってお気に入りの本やCDを管理できるサイトを作りました

Twitterを利用したWebサービスはいろいろありますが、Amazonと連携したサービスは意外とないようなので作ってみました。


TwiVox
http://jp.twivox.com


機能はごくごく単純で、TwiVoxからTwitterに投稿された本やCDのつぶやきを、ユーザーごとアイテムごとにまとめます。



使い方はいたって簡単です。

1. 自分の好きなアイテムを検索

2. つぶやく!

以上です。


TwiVox経由で投稿されたつぶやきはTwiVox内でも公開されます。
自分のつぶやき一覧は下記のURLから確認できます。

http://jp.twivox.com/u/あなたのTwitterユーザー名




Twitterのアカウントを持っている方は新しくユーザー登録をする必要はありません。
お持ちのTwitterアカウントで認証後すぐにご利用いただけます。


基本的にできることはこれだけですが、本やCDのつぶやきを一箇所にまとめたい!という時にお使いください。


Amazonを見ながらつぶやきたいという方向けにツールを用意しています。

Firefox向け (Jetpack)
TwiVox :: Jetpack

Google Chrome向け (extension)
Google Chrome Extensions: TwiVox

2009年12月13日日曜日

Google Chromeがとってもイイ感じ

これまでずっとFirefoxをメインブラウザとして利用してきましたが、Google Chromeがイイ感じなので完全に乗り換えるのも時間の問題になりそうです。


理由はなんといっても「軽さ」です。


とにかくページ描画がおそろしく速いです。

Webサイトを閲覧していて重い/軽いと感じるの原因のひとつに「Javascriptの処理速度」が挙げられますが、Chromeはこの点で競合のブラウザを圧倒しています。

グーグル「Chrome」、JavaScriptベンチマークで競合ブラウザを圧倒
http://japan.cnet.com/marketing/story/0,3800080523,20379766,00.htm


この処理速度のデモサイトもGoogleは用意しています。
Chrome Experiments
http://www.chromeexperiments.com/
3DアニメーションをJavascriptで描画するコンテンツなど、ブラウザごとに比べてみれば処理速度の違いを如実に体感できます。


それに、これまたすごいのが、起動の速さ

Firefoxの起動時間とくらべると段違いです。
急いでいる朝などは特にChromeの起ち上がりの速さは重宝します。



また、多くの人が感じているFirefoxの不満をChromeは解消しています。

Firefoxは長時間使うと極端に重くなることがあります。

Firefoxが重いのでなんとかしたい
http://okwave.jp/qa4736138.html?ans_count_asc=20

重いFirefoxをなんとかして速くしたい
http://c-brains.jp/blog/wsg/09/07/30-201110.php

Chromeは長時間起ち上げても重くなることがありません。
ずっと軽快。

しかも、タブごとに別プロセスで動いているので、あるタブで極端に重い処理をしていても他のタブでは影響を受けません。


とにかく、Chromeは快適なブラウジングのために欠かせないツールです。



じゃあ、なんで未だにFirefox使っているの?ってことなのですが

それはやっぱりFirefoxのアドオン(拡張機能)の存在です。


日々のブラウジングやWebアプリの開発などで、Firefoxアドオンは欠かせない存在です。
たぶんほとんどのFirefoxユーザーも同じでしょう。


しかし


この点でもChromeにぬかりはありません。
予告通り着々と準備はすすめられています。

安定版ではまだですが、開発版ではExtension(拡張機能)を使うことが可能になっています


つい先日、ついにエクステンションのポータルサイトがオープンしました。

Google Chrome Extensions
https://chrome.google.com/extensions/


すでに数百個のエクステンションが登録されているようですが、これから爆発的に増えるのではないでしょうか。
現在Firefoxで使っているアドオンをChromeでも探せるようになるのも時間の問題でしょう。

そうなったら、もうFirefoxにこだわる理由がなにひとつなくなりますね。




Google Chromeのおすすめエクステンション17本+
http://jp.listcamp.com/list/aghsaXN0Y2FtcHIMCxIETGlzdBjLtgUM/

2009年12月10日木曜日

Windowsにgettextをインストールする

Djangoで国際化するのはけっこう簡単なのですが、Windowsでやろうとしたらつまづいたところがあったのでメモしておきます。


何も知らず、おもむろにコマンドプロントで以下のコマンドを叩いたらエラーが返ってきました。

django-admin.py makemessages -l ja


どうもgettextがないよ、ということらしいです。


マニュアルを読んだらそのものずばりの対処法がありました。

Django | Internationalization
http://docs.djangoproject.com/en/dev/topics/i18n/#gettext-on-windows



1. 必要なライブラリをインストール

とりあえず フォルダを作る。
C:\Program Files\gettext-utils\bin

http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/
このサイトから以下のライブラリをダウンロード

gettext-runtime-X.zip
gettext-tools-X.zip
(Xはバージョン番号)

解凍するとそれぞれbinフォルダがあるので、その中の全てのファイルをさきほど作ったC:\Program Files\gettext-utils\binにつっこむ。


2. Pathを通す
(以下Windows XPの場合)

マイ コンピュータ右クリック => プロパティ
「システムのプロパティ」 =>詳細設定 => 「環境変数」
「システム環境変数」の Path を選択 => 「編集」
「変数値」の一番末尾に ;C:\Program Files\gettext-utils\bin


以上です。
コマンドプロントが起ち上がっている場合は一度閉じて、もう一度起ちあげてください。

2009年12月6日日曜日

Rubyで変数を動的に取得/設定する方法

Rubyで変数の名前を動的に設定したり取得するやり方をまとめてみました。


ローカル変数

ローカル変数は専用のリフレクションメソッドはないようです。

かわりにevalメソッドを使って実現できます。

varname = "foo"
x = "ABC"
eval("#{varname} = x") # foo に ABC をセット


インスタンス変数

インスタンス変数 (@varname)を動的に設定/取得する場合はinstance_variable_*メソッドが使えます。
class Foo
def initialize
@foo = 1
end
end

obj = Foo.new
p obj.instance_variable_get("@foo") # => 1
p obj.instance_variable_get(:@foo) # => 1
p obj.instance_variable_set(:@foo, 2) # => 2
p obj.instance_variable_get(:@foo) # => 2
p obj.instance_variable_get(:@bar) # => nil
p obj.instance_variable_set(:@bar, 100) # => 100
p obj.instance_variable_set("@#{baz}", 500) # => 500
p obj.instance_variable_get("@baz") # => 500

例えばこんな使い方...
class Foo
attr_accessor :foo, :bar, :baz

def initialize(opts = {})
opts.each {|k, v| instance_variable_set("@#{k}", v) }
end
end

obj = Foo.new({:foo => 1, :bar => 5, :baz => 10})
p obj.foo # => 1
p obj.bar # => 5
p obj.baz # => 10




クラス変数

クラス変数 (@@varname)にもclass_variable_*メソッドがあります。
(ただし、Ruby1.8ではprivateメソッドです!)
class Fred
@@foo = 1
@@foo = 5
@@foo = 99
end

def Fred.get_var(varname)
class_variable_get("@@#{varname}")
end

Fred.get_var(:foo) # => 1

Ruby1.9では上のクラスに対して次のように書ける (publicだから)
Fred.class_variable_get(:foo)

Ruby1.8ではclass_evalを使って同じようなことを実現できる。
Fred.class_eval { class_variable_get(:foo) }



参考:

Module - Ruby リファレンスマニュアル
http://www.ruby-lang.org/ja/man/html/Module.html#class_variables

Object - Rubyリファレンスマニュアル
http://www.ruby-lang.org/ja/man/html/Object.html


2009年12月1日火曜日

Androidのアプリを探す時に便利なサイトまとめ

Googleが主催するAndroidのアプリコンテスト Android Developer Challenge の第2回目の勝者が決定したようですね。

そういうわけで、というわけではないのですが
Androidアプリを探すのに便利そうなサイトをまとめてみました。
(Android端末を持っていないけれど、来るべき日のために!)

Androidのアプリを探す時に便利なサイト | ListCamp
http://jp.listcamp.com/list/aghsaXN0Y2FtcHIMCxIETGlzdBiTlwUM/

2009年11月29日日曜日

ListCampの使い方をまとめてみた

個人でWebサービスを作ってて何が面倒って、自分ででヘルプページとかプライバシーポリシーを用意しなければならないところです。

面倒だなあと思いつつも軽くまとめたのがこちら

ListCampの使い方
http://jp.listcamp.com/list/aghsaXN0Y2FtcHIMCxIETGlzdBjXhwUM/

リストの作成

わざわざWikiを用意するまでもないし、別ページを作るのもなんだかなあという感じだったので、せっかくだからListCampのリストでまとめてみました。


こういうヘルプページって、書かなければいけないことがいくらでもあるような気がして作る側としては気が滅入りますね。

Google App Engineで不要なインデックスを削除する方法

Google App Engineのストレージシステム(Datastore)は一般的なRDBMSのようにインデックスを貼ることが可能です。
(というか、インデックスを貼っていないクエリを本番環境で発行すると例外が投げられます)

以下、Python Datastore APIの話


インデックスの設定はきわめて簡単で、基本的にはすべて自動で行われます。

開発 Web サーバーを使用している場合、インデックス設定は容易に実行できます。必要なインデックスが存在しないクエリを実行すると、操作は失敗しませんが、逆に開発 Web サーバーがクエリを成功させるために必要なインデックス設定を生成します。アプリケーションのローカルテスト時に、アプリケーションが作成する可能性のあるクエリ(種類、祖先、フィルタ、並び替え順序のすべての組み合わせ)をすべて呼び出す場合、生成されたエンティティはインデックスの完全なセットを表します。テストですべての可能性のあるクエリ形式を実行しない場合、アプリケーションをアップロードする前にインデックス設定を見直し、調整することもできます。
クエリとインデックス - Google App Engine

例えば下のような場合
from google.appengine.ext import db

class Person(db.Model):
nickname = db.StringProperty()
age = db.IntegerProperty()
query = Person.all()
query.filter('nickname =', 'Foo')
query.('age =', 30)
query.fetch(10)

開発環境で上のコードを実行すると、index.ymlに次のようなインデックスが自動で設定されます。
- kind: Person
properties:
- name: age
- name: nickname

上のモデルにaddress(住所)を追加するとどうなるでしょう
class Person(db.Model):
nickname = db.StringProperty()
age = db.IntegerProperty()
address = db.StringProperty()

query = Person.all()
query.filter('nickname =', 'Foo')
query.('age =', 30)
query.('address =', 'Tokyo')
query.fetch(10)

index.ymlに新しいインデックスが追加されます。
- kind: Person # (1)
properties:
- name: age
- name: nickname


- kind: Person # (2)
properties:
- name: address
- name: age
- name: nickname

では、最初に設定したインデックス(1)を削除するにはどうすればいいでしょう?

index.ymlから該当部分を消しただけでは、デプロイしてもインデックスが削除されることはありません。
index.yaml からインデックスを変更または削除する場合、元のインデックスは App Engine から自動的には削除されません。そのため、新しいインデックスの作成中に古いバージョンのアプリケーションを実行させることや、新しいバージョンで問題が発生した場合、すぐに古いバージョンに戻すことができます。
使用していないインデックスの削除

index.ymlから使わなくなったインデックスを消去して、appcfg.pyを叩けばインデックスを削除することができます。
古いインデックスが不要になった場合は、次のコマンドを使用して App Engine から削除できます。
appcfg.py vacuum_indexes myapp/

このコマンドは、最近アップロードされたバージョンの index.yaml で指定されていない、すべてのアプリケーションのインデックスを削除します。
使用していないインデックスの削除

appcfg.py vacuum_indexesを叩くと削除候補のインデッックスを本当に削除するか確認してくるので、削除する場合は「y」を入力。
DashboardのDatastore - indexesのステータスがdeletingに変わります。


インデックスを削除してしまうとバージョンの互換性が失われる恐れがあります。
(先述したように、インデックスのないクエリを発行すると例外が投げられる)

ですのでインデックスを削除する際は十分に注意する必要があります。


関連エントリー:
Google App Engineアプリでモデルを変更してデプロイするとエラーになることがある

2009年11月28日土曜日

Google App Engineアプリでモデルを変更してデプロイするとエラーになることがある

Google App Engineの何がいいって、デプロイがめちゃくちゃ簡単なところです。
GoogleAppEngineLauncherを使っていればボタン1発で本番環境にアップロードできます。

でも、いざ本番にアップしても500 Internal Server Errorが出る時があります。

個人的にちょくちょく遭遇するパターンがあるのでまとめてみます。
(Python版のGoogle App Engineの話です)


原因はログを確認すれば一発で判明します。(註1)

no matching index found.
This query needs this index:
- kind: ***
properties:
- name: ***
- name: ***

マッチするindexがないよと言われています。
App Engine はデフォルトでいくつかのシンプルなクエリのインデックスを構築します。その他のクエリに対しては、アプリケーションは必要なインデックスを index.yaml という名前の設定ファイルに指定する必要があります。App Engine で実行しているアプリケーションが、(デフォルトによって提供されるか index.yaml で記述されるかした)対応するインデックスがないクエリを実行しようとすると、クエリは失敗となります。
クエリとインデックス - Google App Engine

indexの指定は自動でやってくれるはずなのですが...
すべてのデータストア クエリはインデックスを使用します。インデックスは、希望する順に並べられたクエリ結果を含むテーブルです。App Engine アプリケーションは、index.yaml という名前の設定ファイルでインデックスを定義します。 開発用 Web サーバーは、インデックスが設定されていないクエリが発生すると、このファイルに自動的に候補を追加します。アプリケーションをアップロードする前に、手動でファイルを編集して、インデックスを調整できます。
クエリとインデックス - Google App Engine


DashboardのDatastore - indexes を確認してみます。



おそらくステータスが下のようになっているindexがあるはずです。



このページに詳しい説明があります。
インデックス作成の仕組み - Google App Engine
新しいインデックスを定義し、インデックスを作成するようユーザーが指示すると、次の手順が実行されます:

1. インデックス定義のメタデータをアプリケーションに追加します。
2. インデックス メタデータに Building のマークを付けます。これにより、データストアは、すべての書き込みでインデックスを更新するように、ただし、クエリではまだそのインデックスを使用しないように指示されます。
3. 既存のエンティティをマッピングし、インデックスに追加します。
4. インデックスに Serving のマークを付けます。これにより、クエリでインデックスを使用できることがデータストアに通知されます。

質問: 長い間インデックスの状態が Building または Deleting のままなのはなぜですか?
回答: 昔はこの現象がよく発生していました。ワーカー シャード が大きすぎて、リース期間内に完了できなかったからです。この問題に対処するには、まず、リース期間を増やします。次に、個々のタブレットをシャードに分割します。引き続きインデックス作成に時間がかかることもありますが、以前に比べるとかなり速くなっています。

かなり速くなっていますといっても或る程度データを蓄積している場合は相当な時間(1時間〜)かかることがあるようです。
そんな時はあわてずあせらずしばらく待ってみましょう、というか、待つ以外に解決方法はなさそうです。



回避方法

indexの構築時間中はどうしようもなさそうです。
根本的な解決策ではないのですが、個人的に実践している方法を紹介しておきます。


Versionを活用する


例えばversion 2 で稼働しているアプリケーションの場合
# app.yml
application: myapp
version: 2
runtime: python
api_version: 1

デプロイする際にversionを上げます。
application: myapp
version: 3
runtime: python
api_version: 1


indexesを確認してbuildingservingに変わったらVersion3にチェックをいれてMake Defaultをクリック。

これでユーザーに対して500 Internal Server Errorを出さなくてすみます。

デプロイするたびにversion番号を上げたくない!という場合はversion: 2-0-testのように指定するといいかもしれません。


註1:
Dashboard でログを確認しようとしてもリアルタイムで表示されないことがあります。
なのでエラー情報などを直接ブラウザで確認できるように設定する必要があるかもしれません。
Djangoを使っている場合はsettings.pyのDebugをTrueにするなど。

2009年11月25日水曜日

ListCamp リニューアルしました

一年以上前に作ってそれから放置していたサービスに久しぶりに手を入れてみました。



ListCamp
http://jp.listcamp.com

いろんな情報をまとめてリスト化できるサービスです。

作れるリストは例えばこんな感じ
パワーポイントやPDFを共有できるWebサービスまとめ | ListCamp


新しく追加/修正したもの

OpenIDに対応
画像の指定が簡単にできるようになった
YouTube ニコニコ動画などのURLが指定された場合は自動でembed
コメントの許可/不許可設定ができるようになった



このサービスを作っている当初はAmazonのUnSpun(すでに閉鎖)みたいにラインキングをフィーチャーしたリスト作成サービスみたいなものを目指してましたが、それだと「人が集まってなんぼ」なんですよね。
そういうわけで、ランキングもあるけれどシンプルに「情報をまとめられるツール」っていう方向で行こうと思います (漠然としすぎてますが)。

ソーシャルブックマークで管理するとおさまりがつかなくなるけどまとめておきたい情報 (好きな映画のレビュー記事とか) をコンパクトにまとめられるサービスができたらいいな。
TwitterのつぶやきをまとめられるTogetterの汎用版みたいな感じで。

2009年11月9日月曜日

Jetpackが熱い!Greasemonkey終わったな

数ヶ月前にローンチされてから音沙汰がなかった(わけではないけれど、Googleで検索して出てくるのは当時のニュースやブログばかり)Jetpackですが、先日リリースされたversion0.6の解説ビデオを見て興味を持ったのでご紹介

Jetpack Menu API Tutorial from Aza Raskin on Vimeo.




軽く触ってみた感想ですが、こりゃ作り心地も使い勝手もいいです!

FirefoxのURLバーにabout:jetpackと打てばそのまま実行環境ができるし、Firebugとの連携ばっちし。
なによりjQueryを使えるってのが心強い。
インストールする時も再起動する必要ないのがうれしい。

ブラウザをちょっと便利にしたいな〜って時に重宝しそうです。



ちなみに、Jetpackは現在Firefox3.5のみに対応するアドオンとして提供されていますが、Firefoxの次期バージョンには正式に搭載されるそうです。

Mozilla Labsのユーザーエクスペリエンスチーフに聞く--FirefoxとWebの未来


Mozilla Labs Jetpack

https://jetpack.mozillalabs.com/

2009年10月27日火曜日

[LibroSpot] OpenIDに対応しました

LibroSpotOpenIDに対応しました。

OpenIDって何?という方はこちらのページをどうぞ。
OpenIDとは? - Yahoo! Japan
YahooのOpenID解説ページですが他サービスも理屈は同じです。


もともとOpenIDには対応していたのですが、ちょっと分かりにくかったので日本のサービスを並べてみました。

Yahoo! Japan
mixi
livedoor
こちらの3サイトはリンクをクリックするだけでOpenID用の認証ページに遷移します。
(それぞれのサイトで未ログインの場合、お持ちのIDとパスワードを入力してログインしてください)


もちろんその他のサービスにも対応しています。

例えば はてな のアカウントをお持ちの方は
http://www.hatena.ne.jp/[あなたのはてなID]/
というURLを入力するだけです。


めんどうな登録も不要でもちろん無料ですので、是非ご利用下さい。

LibroSpot
http://jp.librospot.com

2009年10月26日月曜日

[2ちゃんねるまとめのまとめ] 人気の記事順に並べる機能を追加しました

2ちゃんねるまとめのまとめ は腕利きの2chまとめ職人さんたちが選りすぐったエントリーが並んでいるので、どのエントリーを見てもおもしろいのですが、「人気」順にならべる機能を追加しました。


人気順って?

ぶっちゃけてしまうと、はてなブックマークの被ブックマーク数順です。

被ブックマーク数のチェックははてなブックマーク件数取得APIGETリクエストでのシンプルなAPIってやつを利用しています。

本当にシンプルに数字だけを返してくるので

import urllib, urllib2
url = "http://foo.com"
response = urllib2.urlopen('http://api.b.st-hatena.com/entry.count?' + urllib.urlencode({'url': url}))
count = response.read() # => 50

これだけで被ブックマークが確認できるので楽ちんです。
(エラーとか考えなければ)

今回は、エントリー別の詳細ページに上のコードを仕込んで、キャッシュの期限を適度に設定してみました。
アクセスがあってキャッシュが効いてなければ、はてなにリクエストを投げる仕組みになっています。
返ってきた数字をストレージに保存しておけば被ブックマーク順に並べられるというわけです。


ただ、これだとアクセスがなければずーっと更新されないままになってしまうですよね。

Google App Engineを利用しているのでTask Queueなんかを使えばいいのかもしれませんが、まんべんなくリクエストを投げるのは難しい感じがする。

エントリーの投稿日とか被ブックマーク数の増加率とかを勘案してスケジュールを組めばいけるのかな。
めんどいけど。

2009年10月25日日曜日

Google AJAX Feed APIを使ってAmazonのベストセラー/ニューリリース商品を表示するガジェットを作ってみる

amazonのアソシエイトに参加している方向け。

amazonアソシエイトのサイトでも色々ウィジェットを提供してくれていますが、既成のものだと「見慣れた感」が強くて目に止まりにくいかと思われます。

そういうわけで、シンプル & カスタマイズしやすいものがあれば便利かなと思ってソースコードを公開してみます。

プログラミングとかJavascriptとかよく知らねという方はこちらをどうぞ
iGoogle: amazon.co.jp ベストセラーズ
iGoogle: 新刊本情報




» デモ


商品情報:
amazonが配信しているRSS (本のベストセラーとか)を利用

商品情報の取得:
Google AJAX Feed APIを利用。
これを利用するとサーバーにスクリプトを置かなくてもJavascriptだけでRSSフィードをパースできます。

Google AJAX Feed API
http://code.google.com/intl/ja/apis/ajaxfeeds/


商品を表示したい箇所に次のように書いておきます。
<div id="amazon_items"></div>


実際に商品RSSを取得して表示するJavascript。
head内とかHTMLの一番下(body閉じタグの直前など)に貼付けてみてください。
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('feeds', '1');
google.setOnLoadCallback(drawItems);

// フィードの読み込みと描画を行う関数
function drawItems() {
var
tracking_id = 'aaaaa-22', // あなたのトラッキングID
thumb = 75, // サムネイル画像の1辺の長さ(px)
num = 5, // 表示する商品数
feed_url = 'http://www.amazon.co.jp/rss/new-releases/books/466280/ref=pd_nr_rss_link', // 表示したいカテゴリーのRSSフィードURL
feed = new google.feeds.Feed(feed_url + '?tag=' + tracking_id);
feed.setNumEntries(num);
feed.load(function(res) {
if (res.error) {
return false;
}
var h = '';
for (var i = 0; i < res.feed.entries.length; i++) {
var
e = res.feed.entries[i],
title = e.title.match(/#\d{1,2}:\s(.+)/),
img = e.content.match(/http:\/\/ecx\.images-amazon\.com\/.+\.jpg/),
author = e.content.match(/<span>([^<]+)/);
h += '<div style="clear:left;border-top:solid 1px #ccc;padding:5px 0;">';
if (img)
h +=
'<div style="float:left;">' +
'<a href="' + e.link + '" style="text-decoration:none;">' +
'<img src="' + img[0] + '" alt="" height="' + thumb + '" width="' + thumb + '" style="padding:0 12px 6px 0;border:none;" />' +
'</a>' +
'</div>';
h +=
'<div style="margin-left:' + (thumb+12) + 'px;">' +
'<a href="' + e.link + '" style="font-weight:bold;">' + ((title) ? title[1]: e.title) + '</a>';
if (author) h += ' &nbsp; <span>' + author[1] + '</span>';
h += '</div></div>';
}
h += '<div style="clear:left;"></div>';
document.getElementById('amazon_items').innerHTML = h;
});
}



GoogleのJavascript系APIを利用したことがない人のために軽く補足しておきます。
(太字がGoogle AJAX Feed APIを利用しているところです。)

最初におまじないをします。
<script type="text/javascript" src="http://www.google.com/jsapi"></script>

Google AJAX Feed API用のライブラリを読み込みます。
google.load('feeds', '1');

ライブラリの読み込みが完了してから実行するコールバック関数をセットします。
google.setOnLoadCallback(drawItems);

初期化します。引数は読み込みたいフィードのURLです。
feed_url = 'http://feeds.digg.com/digg/popular.rss';
feed = new google.feeds.Feed(feed_url);

デフォルトでは4件しかエントリーを返してくれません。
それ以上のエントリーを取得したい場合は明示的に指定する必要があります。
feed.setNumEntries(num);

feed.loadは実際にフィードの読み込み処理を行い、引数に指定したコールバック関数にフィードを操作する処理を書きます。
feed.load(function(res) {
// do something.
});



※ このスクリプトを使ってトラブルが発生しても当方は一切関知しません。

2009年10月20日火曜日

JaikuEngineでお手軽にTwitterクローンを作ってみる

作るというか、まあ、JaikuというTwitterのクローンサービスがありますが、それのクローンをGoogle App Engineに簡単にインストールできるよという話です。



Jaikuは2007年10月にGoogleが買収後、2009年1月に開発打ち切りが発表されました。

それはそれでザンネンなニュースなのですが
Google App Engineで動くオープンソースソフトとしてソースコードが公開されて、そちらで開発が進められています。

JaikuEngine
http://code.google.com/p/jaikuengine/


ローカル環境で動かしてみたのがこちら。


Jaikuの完コピです。
APIまで提供できます。


ちなみに、開発環境で
Google App Engine LauncherRunボタンとか dev_appserver.py app でサーバーを起動すると、上手く起動できませんでした。

アプリケーションのディレクトリで
python manage.py runserver 8080

とDjango流に起動させる必要があるようです。(初回だけ?)
(JaikuEngineはDjango製です)


8080以外のポートで起動させたい場合は
local_settings.py (dev_settings.pyをリネーム)
# 下の2行を修正
GAE_DOMAIN = 'localhost:8081'
DOMAIN = 'localhost:8081'



システム的にはこれだけです。
appcfg.py update app

すれば、公開完了!


ただ、対応言語が英語オンリーなので日本語化するとなると骨ですが。。。

このまま公開して無問題という方であれば、Python知らなくてもGoogle App Engineに不慣れでもサクっといけると思います。

2009年10月5日月曜日

jQueryのホットな記事をつぶやくTwitter botを作ってみた

以前作ったjQuery専門のニュースサイトを利用してjQueryのホットな記事をつぶやくbotを作ってみました。


@jquerybuzz
twitter.com/jquerybuzz





つぶやくのは多くて1時間に1度だけです。





ちなみに、このブログ名義のアカウントもTwitterにあります。
こちらもよろしく
http://twitter.com/mudaimemo

2009年9月30日水曜日

[Ruby on Rails]will_paginateで集計関数を使う場合の注意

will_paginateはページングを行うのに非常に便利なruby on railsのプラグインですが、ちょっと意図しない挙動があったのでご報告。

順番に追っていきます。

一番ベーシックな書法

@posts = Post.paginate({
:page => params[:page],
:order => 'created_at DESC'
})


条件をつけてみる
@posts = Post.paginate({
:conditions => ["posts.id = ?", params[:id]],
:page => params[:page],
:order => 'created_at DESC'
})


取得するカラムを指定してみる
@posts = Post.paginate({
:select => "posts.id, posts.title, posts.created_at",
:conditions => ["posts.id = ?", params[:id]],
:page => params[:page],
:order => 'created_at DESC'
})


データベース(MySQL)の集計関数(COUNT)を使ってみる
ここでひっかかった
@posts = Post.paginate({
:select => "COUNT(comments.id) as cnt, posts.id, posts.title, posts.created_at",
:joins => "LEFT JOIN comments ON posts.id = comments.post_id",
:conditions => ["posts.id = ?", params[:id]],
:group => "posts.id, posts.title, posts.created_at",
:page => params[:page],
:order => 'created_at DESC'
})

※ 全体の件数を返すクエリがなんかおかしい
SELECT
count(*) AS count_all,
posts.id,
posts.title,
posts.created_at
FROM
posts
LEFT JOIN comments ON posts.id = comments.post_id
WHERE
posts.id = '9999'
GROUP BY
posts.id,
posts.title,
posts.created_at

どう見ても全体の件数を返すクエリにはなっていません。
どうも、select やら joins やら group やらを指定するとうまく処理してくれない模様です。

それでいて全体件数 (@posts.total_entries) はちゃんとした値が入ってたりするので分かりにくいです。



これは自分で全体の件数を指定するしかないようですが、ちょっと書き直すだけで対応できるようなので一安心。

http://gitrdoc.com/mislav/will_paginate/tree/master/
@entries = WillPaginate::Collection.create(1, 10) do |pager|
result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset)
# inject the result array into the paginated collection:
pager.replace(result)

unless pager.total_entries
# the pager didn't manage to guess the total count, do it manually
pager.total_entries = Post.count
end
end

createメソッドの第3引数には全体の件数(total)を指定できるので、ここに自分で集計した件数を指定してやればいいわけです。


以上をふまえて書き換えたのがこちら

[改良版] データベース(MySQL)の集計関数(COUNT)を使ってみる

total = Post.count({:conditions => ["posts.id = ?", params[:id]]})

@posts = WillPaginate::Collection.create((params[:page] || 1), 10, total) do |pager|
result = Post.find(:all, {
:select => "COUNT(comments.id) as cnt, posts.id, posts.title, posts.created_at",
:joins => "LEFT JOIN comments ON posts.id = comments.post_id",
:conditions => ["posts.id = ?", params[:id]],
:group => "posts.id, posts.title, posts.created_at",
:limit => pager.per_page,
:offset => pager.offset
})
pager.replace(result)
end




[関連記事]
ActiveRecord以外でwill_paginateを使う方法
will_paginateの便利なViewヘルパー

2009年9月23日水曜日

最近気になったjQueryプラグイン7選

実用性の高いものから実験的なものまで


jquery.path

曲線&多次元のアニメーションを実行できるプラグイン
http://github.com/weepy/jquery.path


jquery.trace.js

jQueryのセレクタの挙動を確認できるプラグイン。
下記サイトにはFirebugを利用したデモビデオがあります。
http://www.bennadel.com/blog/1710-jQuery-Plugin-Tracing-Your-Selector-Paths.htm


CSS Exchanger

CSSを丸ごと動的に変更できるプラグイン。
http://tympanus.net/codrops/2009/09/09/switching-styles-jquery-css-exchanger/


jQuery Image Overlay Plugin

オーバーレイで画像にタイトルやキャプションをつけられるプラグイン
http://www.ferretarmy.com/files/jQuery/ImageOverlay/ImageOverlay.html


jQuery (mb)Gallery

ものすごく凝った感じの画像ギャラリー用プラグイン
http://pupunzi.wordpress.com/2009/02/28/mbgallery/


jQuery maxImage plugin

画像の大きさをちょうどいい感じに自動でリサイズしてくれるプラグイン。
http://www.aaronvanderzwan.com/maximage/


history plugin
Ajaxばりばりのページでもブラウザの「戻る」ボタンや「ブックマーク」を効かせられるプラグイン。
http://www.mikage.to/jquery/jquery_history.html

2009年9月20日日曜日

2ちゃんねるまとめのまとめ - 2ちゃんのまとめブログをまとめたサイト

前々から作ろう作ろうと思いつつ先延ばしになってたものの何とか形になったのでご報告します。

2ちゃんねるまとめのまとめ
http://2chfeed.appspot.com


1年くらい前にGoogle Gadgetsの勉強として作成した「2ちゃんねるまとめのまとめ」ですが、Google Analyticsによると3万人以上の方が利用してくれているようです (ありがとうございます!)。

これはそのWebサイト版という位置づけです。


Webサイト版の特長は...
実は、ガジェット版とそんなに変わってません(!!)
しいて言えば、まとめブログさんの数を 20 に増やしたくらいでしょうか。


とはいえ、ガジェットでは実現できなかった機能をいろいろ妄想しています。

これから追加したい機能

・ しおり (ここまで読んだ)
・ Twitterのbot
・ ランキング


とりあえずはRSSリーダー代わりに使っていただければと思います。
こんなことやって欲しいということがあれば是非是非コメントしてください。
よろしくお願いします。

2009年9月2日水曜日

Twitterのつぶやきを表示するmixiアプリを作ってみました

正式公開前にはなんかしらのアプリを作ろうと思っていましたがいつのまにか正式公開していました。

遅れちゃなんめえってことで
とりあえずお勉強という目的で、Twitterのつぶやきを表示するアプリを作ってみました。

Twitter@mixi: mixiアプリ
http://mixi.jp/view_appli.pl?id=7254

説明することはほんとんどありません。
本当にただtweetsを表示するだけですので…


自分の中では

jQueryプラグイン => Google Gadgets => OpenSocialアプリ (mixiアプリ)

という流れで、プラットフォームに合わせて再生産した感じです。

OpenSocialアプリはGoogle Gadgetsを作ったことがある人には馴染みやすいですね。
XMLのフォーマットが同じですし。
gadgets APIも共通です。

opensocial APIもgadgets APIと書式が似ているのでとっつきやすいのですが、
mixi Platformだとサポートされていないものがちらほらあります。

あれ、opensocialの仕様どおりなのに思った通りに動かないぞ!?
という時は下のサイトを舐めるように確認する必要があるかと。面倒ですが。

mixi Developer Center
http://developer.mixi.co.jp/appli

2009年8月28日金曜日

jQuery Buzz - jQuery関連の記事をまとめるニュースサイト

特定の分野の新しい記事を追いかける時、どういう手段をとりますか?

信頼できるブログのフィードをRSSリーダーに登録してチェックする人はけっこう多いかと思います。

ただ、個々のブログを追いかけるだけだととりこぼしも多いので、合わせてソーシャルブックマークをチェックするという人も多いのではないでしょうか。


自分の場合はDeliciousのjQueryタグのフィードをGoogleリーダーに登録しているのですが、とにかく数が多すぎて1日見ないと軽く1000件を超えてしまいます。

もっとサクっと注目の記事をチェックできたら便利だろうなと思って、こちらを作りました。

jQuery Buzz
http://www.jquerybuzz.com

仕組みはごく単純で、DeliciousでjQueryタグの付いているページをブックマークの多い順にまとめて並べているだけです。

それでも、フィードを単純に購読するより、短時間で注目記事が分かります。

タグ別に表示することができるので、
jQuery + AJAX
jQuery + PHP
jQuery + Plugin
jQUery + Gallery
のような絞り込みも可能です。

jQuery + Pluginを見れば、今注目のプラグインが一目瞭然ですよ。



jQuery Buzzを作るのに利用したサービス


Delicious

情報の供給元です


Google App Engine

インフラ。Python + Djangoを利用しています。


Yahoo Pipes

本番にデプロイしてから分かったのですが、DeliciousはGoogle App Engine(GAE)からのリクエストをIPで弾いているようです。

とりあえずプロキシかまさなきゃGAEでこのアプリを使えないってことで、Yahoo Pipesを利用することに。

http://pipes.yahoo.com/pipes/

[追記]
なんかPipesでも蹴られるようになってしまったようなのでheroku を利用することにしました。


bit.lyのAPI

それぞれの記事がどれくらいクリックされているのか分かります。

2009年8月27日木曜日

[Twit] TwitterのつぶやきをブログやWebページに簡単に貼付けられるガジェット

先日戯れに作ったjQueryのプラグインですが、ガジェットで提供したほうが気軽に使ってもらえるような気がしたので気まぐれで作ってみました。
Google Gadgetsを利用しています。

» ガジェット版 Twit: Add to Google

このガジェットを埋め込む」というリンクからガジェットの設定を行い、好きなページにコードを貼付けてください。


Bloggerを利用している方はもっと簡単に貼付けることができます。

1. 貼付けたいブログのレイアウトページを開きます

2. 「ガジェットを追加」をクリックしてガジェット追加用の小窓を開きます。

3. 左側にある「独自に追加」をクリックします。

4. URLの入力欄に下記のURLを入力します。

http://jquery-twit.googlecode.com/svn/trunk/gadget/content.xml

5.「Screen name」にあなたのTwitterのスクリーン名を入力します。 http://twitter.com/[scree name]

6. 「保存」をクリックして完了です。

2009年8月26日水曜日

[Twit] TwitterのつぶやきをブログやWebページに簡単に貼付けられるjQueryプラグイン

Twitterが大人気です。

Twiiterとブログを両方やっているなら、ブログにもTwitterのつぶやきをのせたい!という人は多いかもしれません。

というわけで、ブログやWebページにさくっとTwitterのつぶやきを貼付けられるjQueryのプラグインを作りました。

Google Code: jquery-twit
http://code.google.com/p/jquery-twit/

上のGoogle Codeのページに必要なCSSとJavascriptのファイルをzipで固めたものが置いてありますので
ダウンロードしてお使い下さい。


こんな感じです。

Loading Twitter...



使い方はいたって簡単です。

はじめに必要なファイルをインクルードします。
<link href="jquery.twit.css" type="text/css" rel="stylesheet" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
<script src="jquery.twit.js" type="text/javascript"></script>

つぶやきを表示したい場所に次のように書きます。
<script type="text/javascript">
$(document).ready(function () {
$('#twitter').twit('mudaimemo', {limit: 5});
});
</script>
<div id="twitter">Twitterを読み込み中...</div>

$('#twitter').twit(username, options);

usernameにあなたのTwitterのスクリーン名
http://twitter.com/[スクリーン名]
を指定するだけで利用可能です。

他にいくつかオプションを指定することが可能です。
詳しくはこちらをご覧下さい。


試してみたいけど、JavascriptとかjQueryとか全然分からないよ、という方向けにGoogle Gadgetsでガジェット版も作りました。

[Twit] TwitterのつぶやきをブログやWebページに簡単に貼付けられるガジェット

2009年8月21日金曜日

[jQuery] 画像をあらかじめ読み込む方法

Javascriptで動的に画像要素を生成する時の話です。

jQuery Gallery Pluginを作っててちょっとハマったのは、「画像をいつ読み込むか & どう読み込むか」という点でした。

画像ギャラリーなどのように、動的に画像要素を生成して、大きめの画像を一枚ずつ表示させようとすると、読み込みの遅延に悩まされます。

画像の容量が大きければ大きいほど画像の読み込みに時間がかかって、
A -> B -> C
と滑らかに切り替えたいのに、
A -> (画像の読み込み) -> B -> (画像の読み込み) -> C
といった感じに遅延が発生してしまいます。

この点を解決する手段として、以下のようなやり方が考えられます。

メジャーなブラウザは画像などの静的ファイルをキャッシュしてくれるので、一度読み込んだ画像を次に表示する時は滑らかになります。

この機能を利用して、ページをロードした時点で画像をまとめて読み込んでおくと、いざ画像を表示しようとする時に遅延が発生せずスムーズに切り替えを行うことができるようになります。

ようするに、Aの画像を表示する前に、ユーザーには見せない形でB,Cの画像も読み込んでおくという方法です。


ただ、これを実装するにはどうすればいいの?というのが疑問だったので、とりあえずは自分なりに実装してリリースしてみましたが、stackoverflowを眺めていたらまさしくこれに関する回答があったので感動しました。

Preloading images with jQuery
http://stackoverflow.com/questions/476679/preloading-images-with-jquery

function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
// Alternatively you could use:
// (new Image()).src = this;
});
}

// Usage:

preload([
'img/imageName.jpg',
'img/anotherOne.jpg',
'img/blahblahblah.jpg'
]);

ちなみにjQuery Gallery Pluginでは以下のように記述しています。
var preLoad = function (url) {
jQuery('<img />')
.hide()
.attr('src', url)
.appendTo(document.body)
.load(function () { jQuery(this).remove(); })
.error(function () { jQuery(this).remove(); });
}

大きな違いはdocument.bodyにappendしているかしていないか、です。

bodyにappendしないと画像を読み込むことはできないと思い込んでいたのですが、そうではないらしく
firebugで確認したところ
jQuery('<img />').attr('src', url);

これだけで画像の読み込みが始まりました。

無駄なappendを省いたので要素を削除する処理も必要ありません。

使いどころは限られているかもしれませんが使えるテクニックだと思います。

ブラウザによって挙動が変わったりしたら怖いのですが。。。

2009年8月20日木曜日

[jQuery]animateで気づいたことメモ

jQueryの特徴的な関数 animate
特にギャラリー系のプラグインを作る時お世話になっています。(こんなの とか こんなの)

animateってなんなの?という方はこちらをお試しください。

Hello World!



<div id="animateDemo" style="border:1px solid #ccc;width: 30%;height: 60px;">
Hello World!
</div>

<input type="button" value="animate" id="demoButton" />

<script type="text/javascript">
$('#demoButton').click(function (event) {
$('#animateDemo')
.append('<span id="demoStatus">拡大中...</span>')
.animate(
{width: '80%', height: '150px', borderWidth: '10px'},
1500,
function () {
$('#demoStatus').text('縮小中...');
})
.animate({width: '30%', height: '60px', borderWidth: '1px'}, {
duration: 1500,
complete: function () {
$('#demoStatus').remove();
}
});
});
</script>

非常に有用な関数ではあるのですが、使っている時に気づいたことがいくつかあるのでメモしておきます。


1. animateの引数の違い

ドキュメントを見てもらうと分かるのですが、animateには引数のとりかたが2種類あります。

a. animate( params, [duration], [easing], [callback] )
b. animate( params, options )

はじめはそれぞれ別モノなのかな?と思っていましたが、引数のとりかたが違うだけで同じことをやっているようです。

a. は引数が固定で、 [duration], [easing], [callback]と3つの引数をとることができます。

b.の形式だとこのように書けます。a.の形式では指定できないオプションも指定することが可能です。
$('#foo').animate({width: '50%'}, {
duration: 1500,
easing: 'linear',
complete: function () {...},
step: function () {...},
queue: false
});

complete:
アニメーションが完了した時のコールバック関数

step:
アニメーションのステップごとに呼ばれるコールバック関数

queue:
複数のアニメーションを実行する場合に、即座に実行するか順番に実行するか
trueなら順番に falseならそれぞれ即座に実行される。
(デフォルトはtrue)



2. easingとは?

easingという耳慣れない単語のせいもあって、最初はなんだかよく分からず完全に無視していましたが、これはけっこう面白い。

これは要するに、アニメーションの実行のされ方らしいです。
「最初はゆっくりで徐々に早く」とか「弾けるように」などなど。

ただ、デフォルトでは "linear" と"swing" しか指定することができないのでほとんど意味がないと思われます。

様々なeasingをまとめた jQuery Easing Plugin があるので、気になる方はそちらをどうぞ。



3. 色のアニメーションができない

意外というかなんというか、jQuery単体では色のアニメーションを行うことができません。
「最初は背景が黒で徐々に白く」というのが無理です。

ただ、この点もプラグインが用意されています (Color Animations)。
作者はjQuery本体の作者でもあります。(John Resig氏)

詳しいことは分かりませんが、あえて色のアニメーションをjQuery本体には組み込んでいないのかもしれません。

$('#foo').animate({
color: '#ffffff',
backgroundColor: '#000000'
}, 1500);

2009年8月18日火曜日

使えるjQueryのtipsとトリック20選

よく知られているものから、あまり知られていない(?)ものまで。
知っておくと便利なものばかりです。

20 Top jQuery tips & tricks for jQuery programmers
http://viralpatel.net/blogs/2009/08/20-top-jquery-tips-tricks-for-jquery-programmers.html

  1. 複雑なセレクタのパフォーマンスを最適化する
  2. コンテキストを指定してパフォーマンスを上げる
  3. Liveイベントハンドラ
  4. indexをチェックする
  5. jQuery.dataメソッド
  6. 要素を消すのにfadeout/slideupを活用する
  7. 要素が存在するかどうかを調べる
  8. 動的に要素を生成してDOMに追加する
  9. 改行とチェイニング
  10. カスタムセレクタを作る
  11. オブジェクトをコピーする
  12. 要素が隠れているかどうかをテストする
  13. $(document).ready のもうひとつのやり方
  14. .(ピリオド)を含むIDを指定する
  15. 直下の子要素の数を調べる
  16. 要素をハイライトさせる
  17. 要素をスクリーンの中央に配置する
  18. closestを使って親DIVを取得する
  19. 右クリックのコンテキストメニューを使わせない
  20. カーソルの位置を取得する


ちなみに、コメントで 7.要素が存在するかどうかを調べるにツッコミがいれられています。
if ($("#someDiv").length) {  
//hooray!!! it exists...
}

それは動くけど、セレクトする前に要素が存在するかどうか調べる必要ない。
jQueryは(他のライブラリと違って)ページ上に存在しない要素を選んでもエラーを投げないんだから、不必要なチェックは余計なことだ。



関連記事:

jQueryのパフォーマンスにおいて厳守すべき11の掟

2009年8月17日月曜日

Google Gadgetsの新APIでGoogla Analyticsを利用する

Google Gadgetsの新APIでGoogle AnalyticsのAPIがないのでググってみたら、こんなページを見つけました。

Gadget Tracking - Google Analytics
http://code.google.com/intl/ja/apis/analytics/docs/tracking/gadgetTracking.html 

あくまでもlabsの機能として組み込まれているようです。

<Require feature="com.google.gadgets.analytics"/>
と宣言してから
<script type="text/javascript">
var ga = new _IG_GA('UA-000000-00');
ga.reportPageview('/foo/bar');
</script>

ちなみにレガシーAPIにはなかったreportEventという関数が追加されています。
名前の通りイベント発生を把捉できるようです。
function resetCounter(){
prefs.set("counter", 0);
ga.reportEvent("Counter Gadget", "Reset", "Button", 0);
}

あくまでもlabsの機能なので、APIに正式に組み込まれる時には記述の仕方が変わるかもしれません。
new _IG_GAというのがいかにもレガシー臭いですし。

ちなみにレガシーAPIではこう書いてました。
<Require feature="analytics"/>
と宣言してから
<script type="text/javascript">
_IG_Analytics('UA-000000-00', '/foo/bar');
</script>

現在でもこの記述は認められているようですが、将来的にはなくなるかもしれませんね。

2009年8月16日日曜日

DjangoのLazy translationのメモ

Djangoは多言語化用のモジュールが充実しているので、わりと気軽に多言語サイトを構築できます。

これまで何も考えずに、とりあえず ugettext() を使用してきましたが、formでそれを使った場合に上手い具合に言語の切り替えができなくてハマりました。

from django.utils.translation import ugettext as _

class BookForm(forms.Form):
status = forms.ChoiceField(widget=forms.RadioSelect, choices=(
(1, _(u'already read')),
(2, _(u'want to read')),
(3, _(u'reading now')),
))

※ Django 1.0で確認しています。

上記のように記述して、ブラウザの言語設定を変更しても上手く反映されません。

マニュアルをざっと読んだ所、どうやら ugettext_lazy() というのが使えそう。
from django.utils.translation import ugettext_lazy as _

ugettext を ugettext_lazyに変えただけで期待どおりの動きをするようになりました。


マニュアル
にはModelの使用例のみが書いてありますが、formでもそのように書く必要があるようです。

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):
name = models.CharField(_('name'), help_text=_('This is the help text'))
class Meta:
verbose_name = _('my thing')
verbose_name_plural = _('mythings')



細かいメカニズムなどは時間がある時に調べてみようと思います。

[jQuery] 要素の表示/非表示をアニメーション付きで簡単に切り替えるプラグイン

jQueryにはデフォルトでshow/hideメソッドやtoggleメソッドが用意されているので、要素の表示/非表示の切り替えが非常に簡単に行えます。

特にtoggleメソッドはまさにそのために用意されているメソッドなのですが、effectの指定ができなのが不満でした。
(内部でshow/hideを利用している)

また、要素の表示/非表示と同時にラベル(表示する/非表示にする、など)も同時に切り替えたい場合が多く、その部分を別途書かなければならないのが煩わしかったりします。

その点を踏まえて、こちらのプラグインを作りました。
アコーディオンメニューやFAQのページなどで利用されることを想定していますが、他にも利用シーンは色々あると思います。

Google Code: jquery-togglable
http://code.google.com/p/jquery-togglable/

» デモ

Google Codeのページに必要なファイルがzip形式で圧縮されて置いてありますので、ダウンロードしてお使い下さい。


HTML:

<p>
<!-- rel属性に "toggleall" と指定すると、すべての要素の表示/非表示を切り替えます -->
<a href="#" rel="toggleall" class="togglable">toggle all</a>

<!-- rel属性に "showall" と指定すると、すべての要素を表示します -->
<a href="#" rel="showall" class="togglable">show all</a>

<!-- 上記の値("showall","toggleall")はオプションで独自に指定することができます。. -->
</p>

<div>
<p>
<a href="#id_of_block1" class="togglable">show</a> block #1.
</p>
<div id="id_of_block1" style="display:none;">
block #1.
</div>

<!-- rel属性を使って要素別の独自ラベルを指定することが可能です。-->
<p>
<a href="#id_of_block2" rel="hide block #2" class="togglable">show block #2</a>.
</p>
<div id="id_of_block2" style="display:none;">
block #2.
</div>

</div>


Javascript:
$(document).ready(function () {
$('a.togglable').togglable();
});



オプション:

オプションを指定することでラベルなどをカスタマイズすることができます。
$('a.togglable').togglable({
showAllLabel: 'すべて表示する',
hideAllLabel: 'すべて隠す',
showLabel: '表示する',
hideLabel: '隠す'
});

easing
string / null / easingを指定します。別途jQuery Easing Pluginが必要です。

effect
string / 'sliding' / アニメーションのエフェクト。'basic', 'sliding', 'fading' が指定できます。

hideAll
string / 'hideall' / 要素をすべて非表示にするアンカータグのrel属性に指定する値。

hideAllLabel
string / 'hide all' / 要素をすべて非表示にするアンカータグのテクスト(表示される部分)

hideLabel
string / 'hide' / 非表示にするアンカータグのテクスト(表示される部分)

showAll
string / 'showall' / 要素をすべて表示するアンカータグのrel属性に指定する値。

showAllLabel
string / 'show all' / 要素をすべて表示するアンカータグのテクスト(表示される部分)

showLabel
string / 'show' / 要素を表示するアンカータグのテクスト(表示される部分)

speed
string/integer / 'normal' / 表示/非表示の切り替えのスピード

toggleAll
string 'toggleall' / すべての要素の表示/非表示を切り替えるアンカータグのrel属性に指定する値

2009年8月15日土曜日

[jQuery] 要素をアニメーションでスライドさせる方法


以前jQuery Gallery Pluginを作った時に、要素をアニメーションでスライドさせるのに手こずった覚えがあります。

Sliding door effect with JQuery
http://tutsvalley.com/wp/tutorials/sliding-door-effect-with-jquery/

» デモ

こちらはHTML,CSS,Javascript(jQuery)ともソースの全文が載っているチュートリアルです。

アニメーションで要素をスライドさせるためのポイントが非常にシンプルにまとめられています。

一番のキモはCSSかもしれません。
コンテナと画像のpositionをそれぞれ下記のように記述するのは、慣れていないと気づきにくいのではないでしょか。

.box_container{  
position: relative;
}
.box_image{
position: absolute;
}


Javascriptの記述は本当に少なくてすみます。jQuery様々ですね。
// 横スライド
$(document).ready(function() {
$('.box_container').hover(function(){
var width = $(this).outerWidth();
$(this).find('.box_image').animate({left: width}, {queue:false, duration:300});
}, function(){
$(this).find('.box_image').animate({left: '0px'}, {queue:false, duration:300});
});
});


※ セレクタの書き方がちょい引っかかります » 参考

2009年8月14日金曜日

[jQuery] 3D風タグクラウドを作るチュートリアル


ものすごくかっこいいです。

How to Create a 3D Tag Cloud in jQuery
http://www.devirtuoso.com/2009/08/how-to-create-a-3d-tag-cloud-in-jquery/

デモ


チュートリアルは英語ですが、HTML, CSS, Javascriptともコードが全文載っているので迷うことはないと思います。
意外と記述量が少ないので驚きました。
(Javascriptはコメントを含めて69行!)

ただ、記述量は少ないですが、自分一人では絶対ひねり出せないようなコードが随所に盛り込まれててしびれます。
(数学が得意な人にとってはどうってことないのかもしれませんが)

要素を円周にちらす

for (var i = element.length - 1; i >= 0; i--)
{
element[i].elemAngle = i * Math.PI * 2 / element.length;
}


タグのサイズと位置を割り出す
x = 120 + Math.sin(angle) * 30;
y = 45 + Math.cos(angle) * 40;
size = Math.round(40 - Math.sin(angle) * 40);


ただ、カーソルをはずした時にタグが回りっぱなしになってしまう所は修正したほうがいいかもしれません。

2009年8月13日木曜日

[Ruby on Rails] ControllerとModelで空のパラメータの値が違う件

ひさしぶりにrailsをいじってて、今さらながら気がついたのでメモしておきます。

フォームから送信されたfoo[name]というリクエストパラメーターが空文字だった場合。

foo_controller.rb

class FooController < ApplicationController
def update
logger.debug(params[:foo][:name] == "") # => true

foo = Foo.find(params[:id])
if foo.update_attributes(params[:foo])
end
end
end

Foo.rb
class Foo < ActiveRecord::Base
def validate
logger.debug(self.name == "") # => false
logger.debug(self.name.nil?) # => true
end
end

モデルでは空文字のパラメーターがnilとして保持されています。
データベースにもNULLとして格納されます。(NOT NULLじゃない場合)

empty?blank? を多用してたので気づきませんでした。。。

[jQuery] はてなブックマーク数/ユーザー/コメントをコンパクトに表示するプラグイン

はてなブックマーク件数取得API用のプラグインを作ったばっかりなのにあれですが、
はてなブックマークエントリー情報取得APIを利用すればブックマーク件数だけでなく、ブックマークしたユーザーやコメントもJSONPで取得できるですよね。
すっかり忘れていました。

戯れにjQueryのプラグインを作ってみました。


デモ:

読み込んでいます。しばらくお待ちください...


Google Code: jquery-hatenabookmark-entry
http://code.google.com/p/jquery-hatenabookmark-entry/

» ダウンロード
» ダウンロード (圧縮版)


準備:

上のダウンロードリンクからお好きな方を選んでダウンロードしてください。
もともと超軽量なので、どちらでもほとんど同じです。

ダウンロードしたファイルをアップロードします。
(レンタルサーバーを借りている方はFTP等でサーバー上へ、ファイルをアップロードできるブログサービスで利用する場合はそのファイルアップロード機能を利用して)

アップロードしたファイルをインクルードするようHTML内に下のように記述すれば準備完了です。
<script type="text/javascript" src="jquery.hatenabookmarkentry.js"></script>

※ ファイルのパス/ファイル名は自分の環境に合わせてください。
※ プラグインのJavascriptをインクルードする前にjQuery(1.3.x系推奨)をインクルードする必要があります。

jQueryを準備していない方はGoogle AJAX Libraries APIを利用したほうが早いかもしれません。
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>



使い方:

HTML:
エントリ情報を表示する要素を用意します。
<div id="container"></div>


Javascript:
<script type="text/javascript">
$(document).ready(function () {
$('#container').hatenaEntry('http://www.mudaimemo.com');
});
</script>

これだけで指定されたURLのはてなブックマークエントリー情報を表示することが可能です。


オプション:

プラグインの第1引数はURL、第2引数にオプションを指定することができます。
$('#container').hatenaEntry('http://www.mudaimemo.com', {
comment: false,
limit: 10
});

callback
function / null / 独自のコールバック関数を指定することができます。

icon
boolean / true / ユーザーのアイコンを表示

username
boolean / true / ユーザー名を表示

tags
boolean / true / タグを表示

comment
boolean / true / コメントを表示

timestamp
boolean / true / ブックマークされた日を表示

headerBgColor
string / #2C6EBD / ヘッダーの背景色

headerColor
string / #ffffff / ヘッダーの文字色

userColor
string / #0000DD / ユーザー名の文字色

tagColor
string / #6666cc / タグの文字色

timeColor
string / #666666 / ブックマーク日の文字色

limit
integer / 7 / 表示件数

headerLabel
string / "ブックマークしているユーザー" / ヘッダーのラベル

useJsonlite
boolean / false / jsonliteエンドポイント(/entry/jsonlite/)を利用するか

onLoad
function/ null / ブックマークがロードされた時のコールバック関数

2009年8月11日火曜日

[jQuery] はてなブックマーク件数取得APIをもっと手軽に使うためのプラグイン

はてなブックマーク件数取得API がJSONPに対応しました。

皆さんご存知の通り、これまでも画像形式でブックマーク数を取得することは可能でしたが、
JSONPに対応したことでカスタマイズが楽しめるようになりました。

単純にブックマーク数を返すだけのシンプルなAPIなので、小難しい所は一切ないのですが、jQueryのプラグイン化してもっと手軽に扱えるようにしてみました。

Google Code: jquery-hatenabookmark-count
http://code.google.com/p/jquery-hatenabookmark-count/

» ダウンロード
» ダウンロード (圧縮版)

デモ:
はてなブックマーク数 » 読み込んでいます...


準備:

上のダウンロードリンクからお好きな方を選んでダウンロードしてください。
もともと超軽量なので、どちらでもほとんど同じです。

ダウンロードしたファイルをアップロードします。
(レンタルサーバーを借りている方はFTP等でサーバー上へ、ファイルをアップロードできるブログサービスで利用する場合はそのファイルアップロード機能を利用して)

アップロードしたファイルをインクルードするようHTML内に下のように記述すれば準備完了です。

<script type="text/javascript" src="jquery.hatenabookmarkcount.js"></script>

※ ファイルのパス/ファイル名は自分の環境に合わせてください。
※ プラグインのJavascriptをインクルードする前にjQuery(1.3.x系推奨)をインクルードする必要があります。

jQueryを準備していない方はGoogle AJAX Libraries APIを利用したほうが早いかもしれません。
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>


使い方:


HTML:

aタグhref属性にブックマーク数を取得したいURLを指定します。
<a href="http://blog.mudaimemo.com/" class="hatena"></a>

Javascript:
$(document).ready(function () {
$('a.hatena').hbCount();
});

これだけでブックマーク数を表示することが可能です。

<a href="http://b.hatena.ne.jp/entry/blog.mudaimemo.com/" class="hatena">ブックマーク数</a>

※ デフォルトでリンク先がはてなブックマークのエントリーページに置き換わります。



オプション:

callback
コールバック関数を指定することが可能です。
$('a.hatena').hbCount({
callback: function (count, element, url) {
if (count > 5) {
var style = {fontWeight: 'bold', color: '#ff0000'};
} else {
var style = {color: '#666666'};
}
$(element).css(style).text('はてなブックマーク数: ' + count);
}
});

コールバック関数には最大3つの引数がセットされます。

count: ブックマーク数
element: 表示中のアンカー要素
url: replaceUrl(下記参照)が true の場合、はてなブックマークのエントリーページURLが渡ります。falseの場合はnullが入ります。

コールバック関数が省略された場合は以下の関数が呼ばれます。
function (i, e, url) {
if (url)
jQuery(e).text(i).attr('href', url);
else
jQuery(e).text(i);
}


replaceUrl (boolean)
trueの場合、コールバック関数にはてなブックマークのエントリーページのURLを渡します。
(デフォルト true)

[jQuery] ページ内の指定の要素にスクロールしてハイライト

ページ内の特定の要素にしゅるしゅるっとスムーズにスクロールして、その要素をハイライト。
下記のサイトはjQuery.ScrollTojQuery UI Effectsを利用してそれを実現するためのチュートリアルです。

英語ですが丁寧にコードを書いてくれてるのでとても分かりやすいと思います。

jQuery FAQs: Scroll To and Highlight Tutorial
http://www.corydorning.com/blog/jquery-faqs-scroll-and-highlight-tutorial

デモ

2009年8月8日土曜日

[jQuery Gallery Plugin] 画像ギャラリー用のプラグイン作りました


世の中には画像ギャラリー/スライドショーを簡単に設置するためのjQuery用プラグインがたくさんあるので、今更自分でこんなもの作らなくても... と思いながらも、衝動的に作ってしまいました。

LibroSpotで利用させてもらっているプラグイン (GalleryView) はとてもすばらしいのですが、自分でカスタマイズしやすいものを使いたかったので。

デモページ
http://www.mudaimemo.com/p/gallery/

Google Code: jquery-gallery-plugin
http://code.google.com/p/jquery-gallery-plugin/

jQuery Plugins: jQuery Gallery Plugin - easy image gallery
http://plugins.jquery.com/project/jquery-gallery-plugin


準備:

Google Code と jQuery Pluginsのページにファイル一式をzipにまとめて置いてあります。
それをダウンロードするとJavascriptとCSSのファイルがありますので、
サーバー上のしかるべき場所にアップロードしてください。
アップロードしたファイルをインクルードするようHTML内に下のように記述すれば準備完了です。

<link href="jquery.gallery.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="jquery.gallery.js"></script>

※ ファイルのパスは自分の環境に合わせてください。
※ プラグインのJavascriptをインクルードする前にjQuery(1.3.X系推奨)をインクルードする必要があります。



使い方:

Javascript
<script type="text/javascript" >
$(document).ready(function () {
$('#id_of_gallery').gallery({
height: '400px',
width: '500px'
});
});
</script>

指定できるオプションの一覧はこちらをご覧下さい

HTML
<div id="id_of_gallery" class="gallery">
<ul class="galleryBar">
<li><a href="picture1.jpg" title="demo #1."><img src="thumbnail1.jpg" title="image1" /></a></li>
<li><a href="picture2.jpg" title="demo #2."><img src="thumbnail2.jpg" title="image2" /></a></li>
<li><a href="picture3.jpg" title="demo #3."><img src="thumbnail3.jpg" title="image4" /></a></li>
</ul>
</div>

aタグtitle属性がギャラリーのタイトルになります。
imgタグtitle属性がギャラリーの説明文になります。


※ HTMLの構造は上記の構造が前提となっています。 (DIV > UL > LI > A > IMG) これを崩すと正しく動作しないのでご注意ください。

※ こちらで用意しているCSSファイルは上記のclass名(gallery, galleryBar)を前提にしています。class名を変更する場合は、CSSファイルの記述もあわせて変更してください。

2009年8月2日日曜日

5分で理解する!jQueryで簡単AJAX

jQueryを覚えたてでAJAXをやってみようとする時、マニュアル に色々メソッドあってどれを使っていいのか分からない!というのが最初のハードルだったりします。

jQueryでAJAXをする時は、原則 jQuery.ajax のみ使用すればOK!というのが個人的な印象です。

jQuery.getJSON や jQuery.post は結局のところjQuery.ajaxのショートカットメソッドです。
ajaxCompleteやajaxErrorなどのAjax Eventsも、利用できるシーンは以外と限られてるのではないかと思っています。(使いこなせば便利ですが)

とにかく、jQuery.ajax の使い方さえ覚えてしまえばやりたいことのほとんどは達成できるはずです。

jQuery.ajax({key: value});

jQuery.ajaxはAJAXといっても全然難しいことはなく、単純にkey-valueペアのオブジェクトを引数に渡すだけです。

で、その引数ですが、マニュアル にはだーっと並んでいてどれを使っていよいのかよく分かりません。

ここでは思い切って、これだけ知っとけば80%大丈夫!(たぶん) というオプションを紹介します。


url
リクエスト先のURLです。これがなければはじまりません。
基本ですが、AJAXの場合は今開いているページと同じドメインしか指定できません。

data
リクエストURLに付加するクエリストリングです。 '&foo=bar1&foo=bar2'
key-valueペアのオブジェクトを指定することも可能です。
data: {
foo1: 'bar1',
foo2: 'bar2'
}

dataType
サーバーから受け取るデータの種類です。
xml, script, json, jsonp, text
以上5つが指定可能です。 jsonhtml を指定することが多いのではないでしょうか。

success
リクエストが成功した場合のコールバック関数です。
引数の型はdataTypeによって変わります。
success: function (obj) {
console.log(obj);

// dataTypeが'html'の場合はHTMLの文字列になります。
// <p>foo</p>
// dataTypeが'json'の場合はkey-valueペアのオブジェクトになります。
// {foo1: 'bar1', foo2: 'bar2'}
}

当たり前ですが、htmlにしろjsonにしろ、サーバー上にそれを返すスクリプトを置いておく必要がありますのでお忘れなく。

error
リクエストが失敗した場合のコールバック関数です。
error: function () {
alert('error!');
}



基本となるコードは下のようになります。
$.ajax({
url: 'ajax.php',
data: {
foo1: 'bar1',
foo2: 'bar2'
},
dataType: 'json',
success: function (obj) {
console.log(obj);
},
error: function () {
alert('error!');
}
});

リンクをクリックした時にAJAXでリクエストを送信する場合の例はこちら
<a href="#" id="id_of_link">LINK</a>

<script type="text/javascript">
$('#id_of_link').click(function (e) {
e.preventDefault();
$.ajax(...);
});
</script>


jQueryでJSONPをやるのはちょいとばかし毛色が違います。
詳しくは下記の記事をごらんください。

jQueryでJSONP
http://blog.mudaimemo.com/2008/09/jqueryjsonp.html


ファイルのアップロードをAJAXでやりたい場合はこちらの記事をどうぞ

Ajax + jQueryで超簡単にファイルをアップロードするためのメモ
http://blog.mudaimemo.com/2009/05/ajaxfileuploadajaxjquery.html

2009年7月31日金曜日

都道府県のDBマスターテーブルとHTMLセレクト要素の雛型

こういう雛型(都道府県選択するやつ。)って、あらかじめ作っておくと便利なことありますよね。

都道府県の場合はDBにマスターテーブル作って管理することが多いと思うので、DB用の雛型も作ってみました。

MySQL用のCREATE文とINSERT文の雛型


CREATE TABLE `prefectures` (
`id` int(2) NOT NULL,
`name` varchar(15) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `prefectures` VALUES
(1, '北海道'),
(2, '青森県'),
(3, '秋田県'),
(4, '岩手県'),
(5, '山形県'),
(6, '宮城県'),
(7, '福島県'),
(8, '山梨県'),
(9, '長野県'),
(10, '新潟県'),
(11, '富山県'),
(12, '石川県'),
(13, '福井県'),
(14, '茨城県'),
(15, '栃木県'),
(16, '群馬県'),
(17, '埼玉県'),
(18, '千葉県'),
(19, '東京都'),
(20, '神奈川県'),
(21, '愛知県'),
(22, '静岡県'),
(23, '岐阜県'),
(24, '三重県'),
(25, '大阪府'),
(26, '兵庫県'),
(27, '京都府'),
(28, '滋賀県'),
(29, '奈良県'),
(30, '和歌山県'),
(31, '岡山県'),
(32, '広島県'),
(33, '鳥取県'),
(34, '島根県'),
(35, '山口県'),
(36, '徳島県'),
(37, '香川県'),
(38, '愛媛県'),
(39, '高知県'),
(40, '福岡県'),
(41, '佐賀県'),
(42, '長崎県'),
(43, '熊本県'),
(44, '大分県'),
(45, '宮崎県'),
(46, '鹿児島県'),
(47, '沖縄県');


select要素の雛型
<select name="都道府県">  
<option value="">-- 都道府県を選択 --</option>
<optgroup label="北海道・東北">
<option value="1">北海道</option>
<option value="2">青森県</option>
<option value="3">秋田県</option>
<option value="4">岩手県</option>
<option value="5">山形県</option>
<option value="6">宮城県</option>
<option value="7">福島県</option>
</optgroup>
<optgroup label="甲信越・北陸">
<option value="8">山梨県</option>
<option value="9">長野県</option>
<option value="10">新潟県</option>
<option value="11">富山県</option>
<option value="12">石川県</option>
<option value="13">福井県</option>
</optgroup>
<optgroup label="関東">
<option value="14">茨城県</option>
<option value="15">栃木県</option>
<option value="16">群馬県</option>
<option value="17">埼玉県</option>
<option value="18">千葉県</option>
<option value="19">東京都</option>
<option value="20">神奈川県</option>
</optgroup>
<optgroup label="東海">
<option value="21">愛知県</option>
<option value="22">静岡県</option>
<option value="23">岐阜県</option>
<option value="24">三重県</option>
</optgroup>
<optgroup label="関西">
<option value="25">大阪府</option>
<option value="26">兵庫県</option>
<option value="27">京都府</option>
<option value="28">滋賀県</option>
<option value="29">奈良県</option>
<option value="30">和歌山県</option>
</optgroup>
<optgroup label="中国">
<option value="31">岡山県</option>
<option value="32">広島県</option>
<option value="33">鳥取県</option>
<option value="34">島根県</option>
<option value="35">山口県</option>
</optgroup>
<optgroup label="四国">
<option value="36">徳島県</option>
<option value="37">香川県</option>
<option value="38">愛媛県</option>
<option value="39">高知県</option>
</optgroup>
<optgroup label="九州・沖縄">
<option value="40">福岡県</option>
<option value="41">佐賀県</option>
<option value="42">長崎県</option>
<option value="43">熊本県</option>
<option value="44">大分県</option>
<option value="45">宮崎県</option>
<option value="46">鹿児島県</option>
<option value="47">沖縄県</option>
</optgroup>
</select>

2009年7月19日日曜日

bit.lyでURLを短縮してTwiiterに投稿するPythonコード

ブログとTwitterの棲み分けは色々議論があると思いますが、個人的にはまとまった記事にならないような一言メモなんかはTwitterにポストするようにしています。

はてなブックマークがWeb Hookをリリースしてから色々妄想したところ、ありがちですがはてブとTwitterを連動させたら面白そうだなと思いました。
下手したらうざいリンクスパムになるかもしれませんが。。。


最近はHookHubなるサービスが登場したのでわざわざ自分で作る必要ないかもしれませんが、とりあえず勉強のために自作することに。

TwitterのAPIはURLを短縮してくれないようなので、あわせてbit.lyのAPIも叩きます。

bit.lyのAPIは認証式なので、アカウントを作成してAPI Keyをゲットする必要があるのでご注意を。


両APIのドキュメントはこちら

Twitter API Wiki
bit.ly API Documentation

import urllib, urllib2, logging
import xml.dom.minidom

class Twitter:

def __init__(self, login, password, bitly_login=None, bitly_apikey=None):
self.uri = 'http://twitter.com'
self.end_point = ''
self.login = login
self.password = password
self.bitly_login = bitly_login
self.bitly_apikey = bitly_apikey

def bitly_account(self, bitly_login=None, bitly_apikey=None):
self.bitly_login = bitly_login
self.bitly_apikey = bitly_apikey

def post(self, body='', url='', limit=20):
self.end_point = '/statuses/update.xml'

# bit.ly
if len(url) > limit and self.bitly_login and self.bitly_apikey:
bit = Bitly(self.bitly_login, self.bitly_apikey)
try: url = bit.shorten(url).get()
except BitlyError: pass

message = '%s %s' % (body, url)
options = {'status': message.encode('utf_8')}
return self.send_request(options, auth=True)

def destroy(self, status_id):
self.end_point = '/statuses/destroy/%s.xml' % status_id
return self.send_request({}, auth=True)


def send_request(self, options, auth=False):
if auth: self.auth()

try:
request = urllib2.Request(self.uri + self.end_point, urllib.urlencode(options))
response = urllib2.urlopen(request)

if response.code != 200:
e = 'Twitter response: code > %d, message > %s' % (response.code, response.msg)
logging.error(e)
raise TwitterRequestError, e

return TwitterResponse(response.read())
finally:
response.close()

def auth(self):
#Basic Auth
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password('Twitter API', self.uri, self.login, self.password)

opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)

class TwitterResponse():

def __init__(self, content):
self.content = content
self._node = xml.dom.minidom.parseString(content)

def get(self, name='id'):
return self._get_data(name)

def _get_data(self, nodename, node = None):
if node is None : node = self._node
elm = node.getElementsByTagName(nodename)
return elm[0].firstChild.data.rstrip().lstrip() if elm else ''

class TwitterError(Exception):
"""Used to indicate that an error occurred when trying to access Twitter via its API."""

class TwitterRequestError(TwitterError):
"""Used to indicate that an error occurred when trying to access Twitter via its API."""

class TwitterResponseError(TwitterError):
"""Used to indicate that an error occurred when trying to access Twitter via its API."""



class Bitly:

def __init__(self, login, api_key):
self.uri = 'http://api.bit.ly'
self.end_point = ''
self.version = '2.0.1'
self.login = login
self.api_key = api_key

def shorten(self, url):
self.end_point = '/shorten'
options = {'longUrl': url, 'format': 'xml'}
return self.send_request(options)

def send_request(self, options={}):
options['login'] = self.login
options['apiKey'] = self.api_key
options['version'] = self.version

if not options.has_key('history'):
# history=1というパラメータがないとbit.lyのHistoryで見ることができない
options['history'] = '1'

apiurl = self.uri + self.end_point + '?' + urllib.urlencode(options)

response = urllib2.urlopen(apiurl)

try:
if (response.code != 200):
e = 'bit.ly response: code >> %d, message > %s' % (response.code, response.msg)
logging.error(e)
raise BitlyRequestError, e

return BitlyResponse(response.read())
finally:
response.close()

class BitlyResponse():

def __init__(self, content):
self.content = content
self._node = xml.dom.minidom.parseString(content)
self.status = self._get_data('statusCode')

def get(self):
if self.has_error(): raise BitlyResponseError, self.get_error()
return self._get_data('shortUrl')

def has_error(self):
return self.status == 'ERROR'

def get_error(self):
return self._get_data('errorMessage')

def _get_data(self, nodename, node = None):
if node is None : node = self._node
elm = node.getElementsByTagName(nodename)
return elm[0].firstChild.data.rstrip().lstrip() if elm else ''

class BitlyError(Exception):
"""Used to indicate that an error occurred when trying to access bit.ly via its API."""

class BitlyRequestError(BitlyError):
"""Used to indicate that an error occurred when trying to access bit.ly via its API."""

class BitlyResponseError(BitlyError):
"""Used to indicate that an error occurred when trying to access bit.ly via its API."""



使い方はこんな感じです。


twit = Twitter('Your Twitter Login', 'Your Twitter Password')
twit.bitly_account('Your bit.ly Login', 'Your bit.ly API Key')
twit_res = twit.post(body='コメント', url='http://www.example.com')
# body と url にはてブから投げられたコメントとURLを指定すれば、はてブとTwitterを連動できます