3D mode!

Entries tagged with "Ruby"

Rubyでシンプルなページャ

あるページにアクセスして,ある処理をして,そしたら次のページに遷移して,また同じ処理をして… ってのはよくある処理です.ボクも過去に何度かそういった処理をするスクリプトを書いた覚えがあります.特に,Nokogiri 登場以後は,がしがしと XPath を扱えるようになったのでスクレイピングがとても楽しくて,その手のスクリプトを書く機会が増えました.

そこで,シンプルなページャを作ってみました.対象となる Web ページの URL と,そのページ中に「次ページへのリンク」の XPath を与えます.each に与えるブロックが,各ページへの処理になります.

サンプルでは,http://june29.jp/ にアクセスして,各エントリのタイトルとリンクを表示させています.2008年11月より古いエントリが現れたら,ページングを止めています.

コンソール出力はこんな感じです.

------------------------

http://june29.jp/

------------------------
「ウェブで一発当てる方法」を読んだ

http://june29.jp/2009/01/05/kayac-book/

ユーザ向けレコメンデーションを考える

http://june29.jp/2009/01/04/thinking-about-recommendation-for-user/

新しくなったはてなブックマークが面白い

http://june29.jp/2009/01/03/new-hatena-bookmark/

年賀状的なもの

http://june29.jp/2009/01/02/something-like-a-new-year-greeting-card/

パッケージング能力

http://june29.jp/2009/01/02/ability-topackage/

------------------------

http://june29.jp/page/2/

------------------------
2008年を振り返る!

http://june29.jp/2008/12/31/looking-back-at-the-year-2008/

Fairy Tale に行ってきた!

http://june29.jp/2008/12/28/fairy-tale/

高専カンファレンスのこれから

http://june29.jp/2008/12/21/kosenconf-in-future/

数ヶ月ぶりにテレビを楽しんだ

http://june29.jp/2008/12/21/tv-shows-are-interesting/

マイネット・ジャパンさんとの交流勉強会

http://june29.jp/2008/12/21/workshop-in-mynet/

(途中略...)

------------------------

http://june29.jp/page/6/

------------------------
LimeChatにTwitterのアイコンを表示させてみる

http://june29.jp/2008/11/03/show-twitter-user-icon-on-limechat/

どこで終わるか分からない処理を each で書くのはどうなんだろう,とか考えたりもしつつ,二転三転して今の形になっています.非常に短いプログラムですが,考えることがたくさんあって勉強になりました.引き続き,自分で使ってみながら作り込んでいこうと思っています.

指定のWebページに含まれる単語の出現回数をカウントする

HTML を Nokogiri に渡してテキストノードの内容だけを切り出して文字列にする.あとは文字列の中から単語っぽいものを見つけて計上する.文の解析はしていないから日本語とかは無理だ.

Example

ranking = count_word("http://infolab.stanford.edu/~backrub/google.html")

ranking.each do |word|
  puts "#{word[0]}\t#{word[1]}"
end

とすると

the		601
of		397
a		303
to		284
and		230
is		189
in		173
search	141
web		128
that		107
for		103
we		103
this		96
are		96
it		82
be		72
google	70
on		65
by		55
which	54
with		51
as		49
text		49
page		48
engine	48
results	47
pages	46
engines	46
have		46
from		45
can		44

(以下略...)

な感じです.

CouchDBに触れてみた

聞くところによると,CouchDB の魅力ってのは,ドキュメント指向であったり,Map/Reduce であったり,その辺りにあるらしいのですが,ボクはまだよく分かっていません.このエントリでは,後述の目的を果たすために,CouchDB をサーバにインストールして動かしてみて,永続化ハッシュとして利用するために,値の格納と取得をやってみた,ってところまで扱います.その先の話はエントリを改めてまた今度.

目的

よく,cron なんかで定期実行させるスクリプトの中で,前回実行時の情報をファイルに保持させたりしている.これだとスクリプトを実行させるマシンが変わったときにそのファイルも忘れずに移動させなきゃいけないし,複数マシンで実行させるスクリプトともなると,協調が大変.そこで,情報を保持する箇所をひとつにし,かつ,どのマシンからでも情報を読み書きできる仕組みを用意し,ファイルに保持させないようにする.

CouchDB のインストール

Debian 機にインストールした.参考にしたのは以下のエントリ.ありがとうございました.

インストールしたサーバに設定したポート(デフォルトは5984)


http://my.server.jp:5984/

でアクセスすると

{"couchdb":"Welcome","version":"0.8.0-incubating"}

が返ってくる.ここがすでに JSON だ.楽しい.

ご丁寧にブラウザから中身を操作できる管理画面がついてくる.ここからデータベースを作成したり,レコードの値を書き換えたりできる.


http://my.server.jp:5984/_utils/

Screenshot of CouchDB Futon

couchdb.rb

今回使いたい get と put だけを実装した.公式のサンプルでは JSON 文字列を受け渡ししているんだけど,Ruby のハッシュをそのまま与えるようにしてみた.

photoshare2twitter.rb

ボクが iPhone で撮った写真をアップしている Big Canvas PhotoShare から,新着があれば Twitter に流すっていうサンプル.

Pit で CouchDB のホストとポートを取ってきて,photoshare ってデータベースの latest_processed_photo っていうドキュメントを get する.最後に処理した id より新しい id を持つ写真があれば put でデータを更新する.まさに Java の Map#get,Map#put と変わらない感じで書ける.ただし _rev ってのはリビジョン番号を表していて,これを正しく渡してやらないと

412: Precondition Failed (前提条件で失敗した)

が返ってくる.複数のトランザクションが同じドキュメントにアクセスするとき,整合性を保つために必要なのだろう.REST について勉強したときも感じたけど,HTTP メソッドとかステータスコードとか,すでにあるものをきちんと理解して,正しく使うってのは大事だなぁ.勉強になります.

今回のサンプルは,データベースもドキュメントもすでに存在することを前提としているから,本当は存在しなかったら作成するとか,そういう処理が必要だ.エラーメッセージも JSON に格納されて返ってくる.

まとめ

ひとまず目的は達成できました.最低限の機能でよければ CouchDB のラッパーは簡単に書けてしまう(中身は HTTP のリクエストを呼んでいるだけ) し,とても手軽に使える.

せっかくインストールしたんだから,もうちょっと凝った使い方もしてみたい.次に触ってみたいのは Map/Reduce です.

UbigraphでTwitterのコミュニケーションを可視化してみた

Ubigraph: Free dynamic graph visualization software ってのを見つけて,デモがこれまた面白くて,しかも Rubigraph っていう Ruby で簡単に扱えるライブラリを mootoh さんが作ってくださっていて,テンションが上がったので遊んでみた.

twitter_visualization.swf

スクリーンキャストはこちら (約3分,約10MB)

ボクから見える Twitter のタイムラインを可視化してみた.ちょー単純に @ メッセージでやり取りするユーザ同士をリンクしただけ.けっこう面白かった.スクリーンショットだと文字が潰れて何が何だか分からないけれど,Ubigraph ではズームしたり回転したりして細部まで見ることもできる.ノードが増えると重いけどね!

twitter_visualization.swf

Ubigraph のサイトを見ると,もっと複雑な配置のアルゴリズムとか使えそうなことが書いてあるんだけど,まだ未完成なのかなー,ノードとリンクを作ってネットワークに追加する,ぐらいしか分からなかった.引き続き可視化系のツールは色々と試してみよう.

PassiveRecord,ハッシュをActiveRecordのインタフェースで使う

PassiveRecord を使ってみた.

PassiveRecord は,ハッシュを ActiveRecord っぽく扱えるようにしてくれる.要 ActiveRecord.

# コマンドラインから gem でインストール
$ sudo gem install passiverecord

# 使うときは require
require 'passive_record'

今回動かした環境では ActiveRecord と PassiveRecord を両方 require したら

Gem::Exception: can't activate activerecord (>= 0, = 1.15.3), already activated activerecord-2.0.2.9216]

とエラーが出たので, PassiveRecord だけ require するようにした.

アプリの中で,ほとんど追加・更新がないようなデータ,テーブルを作って管理するよりは,オンメモリで処理したいデータ,など,あるかと思います.

README を見ればすぐに使い方は分かる.クラス定義の中にレコードも書く.ActiveRecord と同じように find で必要なものだけ取り出したり,has_many で他のクラスとのリレーションを記述したりできるので,ハッシュでデータを持つより扱いやすい.

class Continent < PassiveRecord::Base
  has_many :countries # => an ActiveRecord class

  schema :name => String, :size => Integer, :population => Integer

  create :name => "Africa",        :size => 30370000, :population =>  890000000
  create :name => "Antarctica",    :size => 13720000, :population =>       1000
  create :name => "Australia",     :size =>  7600000, :population =>   20000000
  create :name => "Eurasia",       :size => 53990000, :population => 4510000000
  create :name => "North America", :size => 24490000, :population =>  515000000
  create :name => "South America", :size => 17840000, :population =>  371000000
end

Continent.find(1)                                    # => Africa
Continent.find_by_name("Africa")                   # => Yes, also Africa
Continent.find_by_name_and_size(/America/, 17840000) # => South America
Continent.find_all_by_population(1000..20000000)     # => Antarctica and Australia
Continent.find(:all)                                 # => All 6 (though not in any particular order, yet)

README を見ると

* some integrated ActiveRecord associactions, ie: ActiveRecord#belongs_to(:passive_record)
  PassiveRecord#has_many(:active_records) (excluding has_many :through)

「has_many :throught は使えないよ」って書いてあるんだけど,CHANGELOG には

v0.2. has_many :through is in the house.

「v0.2 で has_many :throught 登場!」っぽく書いてある.よく分からないけど,試しにコードを書いてみたら動いたから,多分,実装されていると思うよ!

雑感

ソースコードを書き換えるだけでテーブルのスキーマを書き換えられるので,アプリ開発の序盤,まだモデルの詳細まで決まっていない段階で,とりあえず動くものを作りたいときには,PassiveRecord 良さげ.モックとして使える.必要になればすぐに ActiveRecord に置き換えることができる.

関連

PassiveRecordで不要なクエリ発行を抑える – pLab blog