デジタル・ヒューマニティーズにおける横断的分類スキーム

以下はIsis Forcus読書会#11のためのレジュメです。

Isis, Focus読書会#11 "Ordering the Discipline" | Facebook

現論文へのリンクはこちら:
JSTOR: An Error Occurred Setting Your User Cookie



導入
 インディアナ哲学オントロジープロジェクト(InPhO)において、筆者らは哲学的概念や哲学者を分類し関連付けるための手法を開発している。このプロジェクトの当初の目的は、500人以上の筆者と100人以上の編集者を抱えるスタンフォード哲学百科事典(SEP)の編集を補助するという実用的なものであった。ただし、筆者らの意図はより一般的な手法の開発と、より研究志向的な目標の達成にあると強調されている。
 SEPの記事中に記述される諸概念をまとめ上げる上で最も困難な側面は、文脈や歴史上の時期によって、用語の意味に微妙な差が生じることである(同じ「機械論」であっても
デカルト哲学におけるそれと現代哲学におけるそれでは大きく意味が異なる)。あらゆる分類体系は、こうしたニュアンスの違いに敏感である必要がある。
 InPhOプロジェクトでは、「オントロジー」という用語をやや独特な用法で使用している。コンピュータサイエンスにおけるオントロジーは、主にセマンティック・ウェブへの応用を企図されている。これは、WWW上に表現されたエンティティのクラスを形式的に規定し、これに機械推論を適用することを目的とするものである。しかしながら、文脈や歴史を通じて変化する哲学や科学史上の諸概念に対して、フォーマルな定義を与えることは困難である。そこでInPhOプロジェクトでは、セマンティック・ウェブの手法を取り入れつつも、文脈に依存する解釈を人間に頼る方法を採っている。このため筆者らはInPhOにおけるオントロジーを「ダイナミック・オントロジー」と呼んでいる。ダイナミック・オントロジーが提供するのは、意味論的にフォーマルに規定されないものの、自動推論を含む機械処理をサポートする、階層的な分類スキームである。
I. 分類のための理論的根拠
 情報の分類には長所と短所があり、これは図書館司書が長らく直面してきた問題でもあある。司書は図書に対してメタデータを付与することでこれをカタログ化する。例えばDublin Core Metadata Initiative(DCMI)はこうしたメタデータ付与のために策定されたスキームである。図書の分類にはアメリカ議会図書館分類表やデューイ十進法といったスキームが用意されているが、より詳細な分類は今もって専門知識を有した図書館司書の手に委ねられている。InPhOの取り組みは、こうした専門家の仕事を代替するものではなく、むしろ意味論解析の手法によって司書や研究者に益することだと筆者は説明する。
 また、InPhOにおける概念分類の方法を透明化することで、筆者らは次の二点が可能になると述べている。第一は他分野への一般化である。筆者らの手法は哲学分野に限定されたものではないため、科学史分野への応用も可能であると示唆されている。第二は分類スキームの可能性の体系的な探求である。InPhOで利用される手法は再現可能な形式で公開されているため、代替となる分類スキームの作成が容易に可能である。
 複数のスキームの配置は難しい問題であり、コンピューターサイエンスの世界でも活発に研究が行われている。しかしながら、代替スキームをコンピューター上で体系的に変化させて生成することで、この問題は取り組みやすいものとなると述べられている。
 哲学概念を分類する上での困難について、筆者は以下の三点を挙げている。第一には、概念が高度に抽象的であり、”is_a”関係の導出が困難であること。第二に、概念によって"is_a”関係のスキームの適/不適があること。第三は、哲学の対象領域が非常に広範にわたる点である。こうした困難は専門家の力を借りることで解決できるかも知れないが、これはコストの点で許容し難い選択である。
II. 分類のための諸アプローチ
 合理的なコストで形式的・機械可読なオントロジーを構築・運用するには、自動化とクラウドソーシングという2つのアプローチがある。両者それぞれに長所・欠点があり、InPhOプロジェクトでは、アルゴリズムに基づく自動化と、フォークソノミーに基づくクラウドソーシングの両者を併用するアプローチが採られている。
 SEPの自動統計解析から得られた用語の関連性に関する仮説は、専門家によるフィードバックを受け、データベース上に登録される。このデータベースは、機械推論によって哲学概念の関係性を表現する分類のシードを生成するために利用される。テキストから分類を生成するこのパイプライン上には、修正可能なポイントがいくつも用意されており、分析対象となるテキストを別ソースに変更することや、使用される統計的手法を調整することが可能となっている。
 InPhOの目的は哲学を階層的に表現することであるが、より非構造的(非分類的)な表現の価値も筆者らは認めており、最近ではベクトル空間モデルの構築に取り組んでいる。このモデルでは個々の用語は多次元空間上のベクトルとして表現され、種々の数学的解析の対象となる。例えば用語間の意味論的類似性は、2つのベクトルがなす角の余弦として与えられる。ベクトル空間モデルにもいくつかの派生種があり、それぞれに長所と短所がある。筆者らの目標のひとつは、モデル毎の有用性を直観的に評価することから、パラメーターやソースとなるテキストの変更に対して、モデルから得られる結果がどれだけ頑健か理解することに議論のポイントを移すことである。このために、筆者らはパラメーターやソーステキストを変化させ結果を分析するためのツールを開発している(これらのツールのソースコードはgithub上で公開されている)。

IV. 意味論モデリングのさらなる応用
 意味論空間モデルは、歴史上の人物が異なるソースにおいて異なる仕方で表現されていることを明らかにすることができる。ベクトル空間モデルを利用すれば、相互のリソースの類似点と相違点を画像化し、各々のリソースが発散する度合いを統計的に計測することも可能である。筆者はカントを例に取り、SEPとIEP(インターネット哲学辞典)の両者においてカントと関連付けられる用語のネットワークを比較している。こうした意味論モデルから得られる表現は非階層的であるが、筆者の関心は、統計的手法が代替分類スキームの評価に利用できるか否かにあるという。また、画像表現による比較には限界があるため、与えられた用語に対し関連性の高い用語のリストを比較する手法が紹介されている。
V. 結論
 異なる分類スキームが互いにいかに理解するためには、複数のモデル、ソース、表現方法、比較方法を体系的に検討することが必要である。筆者らはオープンソースでソフトウェアを公開し、オープンアクセスな素材を選択したが、これは筆者らの実験結果を再現・拡張可能にし、他の研究者の研究に役立てることを意図したものである。

IndexedDBに画像ファイルを保存する

大量かつ大容量の画像ファイルを扱うWebアプリを現在開発しておりまして、ロード時間縮減のために画像ファイルをローカルに保存する仕組みを作ろうと思ったのです。キャッシュではなく persistent な形で。

で、HTML5のFile System APIを使ってこの処理を実装しようと目論んだのですが、実装状況を確認したところまさかのFireFoxが未対応。

Can I use Filesystem & FileWriter API

モダンブラウザの代表格たるFireFoxがFile System APIを実装していないのは合点が行きません。といってもChromeしか対応していないAPIを使うわけにもいかず代替案を探していたところ、Mozilla Hacks で IndexedDB を画像ファイルのストレージとして利用する方法が紹介されていました:

Storing images and files in IndexedDB ✩ Mozilla Hacks – the Web developer blog

IndexedDBを利用したことがないのでI/Oのパフォーマンスがどの程度のものなのか気掛かりですが、とりあえずこの方法で実装してみようと思います。

The History of Science as Oxymoron: From Scientific Exceptionalism to Episcience

以下は、前回から参加させて頂いている「Isis, Focus読書会#9 科学史の未来」(https://www.facebook.com/events/488774157858750/)のレジュメです。
(なお、本ブログは自分がエンジニアだった時期にメモ帳代わりに作成したもので、レジュメを掲載する場所として適当ではありませんがご寛恕乞いたく存じます…)

Ken Alder, "The History of Science as Oxymoron: From Scientific Exceptionalism to Episcience," Isis, 104(1), 2013, pp. 88-101.
http://www.jstor.org/stable/10.1086/669889

筆者の Ken Adler は米ノースウェスタン大学歴史学部の教授。18世紀フランスと20世紀アメリカにおける科学史・科学技術史に関する著作がある。

本稿では「科学史」という研究領域の自己理解・自己定義の問題が論じられている。

「科学史」という分野名称は、アカデミア外部の人間や他分野の人間にとっては混乱のタネである。筆者によれば、これは「科学史」という用語が一種の撞着語法であること、つまり「科学」と「歴史」という互いに矛盾する用語が併記されていることに起因している。一般に「科学」は現代的な価値に基づき、過去の諸発見に対して最新の説明を与える企てとして考えられているが、それに対して「歴史」は現代的な関心にとらわれず独自の用語・方法で過去の事物を要約するものだと理解されているからである。

なぜ我々の自己描写はこれほど頻繁に人々を混乱させるのか?そもそも我々(科学史研究者)は一体何者なのか?

まず筆者は科学史研究者の置かれた外的状況の分析から開始する。1960年代のT.クーンの予想とは裏腹に、科学史は自律的な研究部門を持つことに関しては完全に失敗した。科学史家は歴史学部を始めとする大学の様々な部局で見出すことができる。これは1920〜1930年代にかけてほとんどすべての大学に専門部局が設置された美術史とは対照的である。しかし、様々な部門に研究者が分散することによって、科学史は知的な柔軟性を享受することができたと筆者は肯定的に評価している。また、とりわけ重要な点として、制度的な多様性によって科学史の研究が自己目的化せず、様々な歴史的目的を実現する「方法」(means)として作り変えられたことが強調されている。

制度的な安定性を得る代わりに、科学史の研究者達は「科学研究の内容とその文脈を接続するツール群」を作り上げてきた。これらは異なる部門に属する科学史研究者を互いに結び付けるだけでなく、より一般的な歴史学の問題の解決にも寄与するものだとされる。こうして筆者は歴史学一般と科学史の連続性を強調し、科学史を歴史学における例外として扱う「科学的例外主義」に反対を表明している。アメリカ近代史やホロコーストの歴史と同様に、科学の歴史もまた科学の枠内に留まらず同時代の知識形成の慣習と並行して研究されるべきだと筆者は主張する。

科学史の自己理解・自己定義に関する問題を整理した上で、科学史家の研究対象をより的確に表現する用語として、筆者は発生学の一分野である「エピジェネティクス」(epigenetics)をもじった「エピサイエンス」(episcience)という新語の導入を提案する。

遺伝子としてのDNA発見以降、発生学の分野ではDNA→RNA→タンパク質の順で情報が転写されるプロセス(セントラルドグマ)をベースとして研究が進められてきた。しかし、DNAメチル化やヒストン修飾など、ゲノム以外の細胞内環境が個体(とその子孫)の形質発現に大きな役割を果たすことが明らかになり、特に2000年代以降ゲノムと細胞内環境の複雑な相互作用を解明するための研究が活発に行われるようになった。「エピジェネティクス」は、こうした研究を従来の発生遺伝学の研究から区別するための用語として使用されている(用語自体は1942年にイギリスの生物学者C. H. Waddingtonによって初めて導入された)。

科学とエピサイエンスの関係は、発生学とエピジェネティクスの関係と同型であると筆者は説明する。つまり、エピジェネティクスが個体形質の発現に作用する細胞内環境を研究するのと同様に、エピサイエンスは特定の科学的知識や習慣が生成・伝播する「環境」(environment, milieu, Umgebung)を構成するものだとする。

エピサイエンスの名称の下で行われる具体的な研究については、現行の慣習から大きく逸脱するものではなく、それ故にエピサイエンスという用語自体も長い寿命は持ち得ないと筆者は説明する。エピジェネティクスという用語は伝統的研究に対する差異を強調するために利用され、研究分野としての自覚を促し多大な財政投資を呼び込むことに成功した。しかしいったん分子生物学者がエピジェネティクス的思考を自らの研究に取り込んでしまえば、エピジェネティクスが「遺伝」という概念に包括され、独立した用語としては風化することは予想がつく。それと同様に、筆者は用語としての「エピサイエンス」も「科学」という「遺伝」以上に弾性的かつ多義的な用語に早急に吸収されるべきであるとする。

RubyのMatrixクラスで遊ぶ

ここのところ画像処理について勉強する機会があって、線形代数の偉大さを身をもって感じている。
そりゃ位相・集合論とか抽象代数とは比べ物にならないほど応用範囲が広いことは分かっていたけれども、
行列の固有値を求める方法が顔認識システムで活躍しているなんて思ってもみなかった。

線形代数は学部の頃に独学で勉強したきりで、大半の知識は忘却の彼方にある。
復習のため線形代数の教科書を開いたはいいが、紙とペンで一から復習するのはしんどいので、手始めにRubyのMatrixクラスで勘所をつかむことにした。

require "matrix"

r1 = [1,-1,-1]
r2 = [-1,1,-1]
r3 = [-1,-1,1]

m1 = Matrix.rows([r1,r2,r3])    # => Matrix[[1, -1, -1], [-1, 1, -1], [-1, -1, 1]]
m1.det                          # => -4
m1.inverse                      # => Matrix[[(0/1), (-1/2), (-1/2)], [(-1/2), (0/1), (-1/2)], [(-1/2), (-1/2), (0/1)]]
m1 * m1.inverse                 # => Matrix[[(1/1), (0/1), (0/1)], [(0/1), (1/1), (0/1)], [(0/1), (0/1), (1/1)]]
m1.rank                         # => 3
m1.trace                        # => 3
m1.transpose                    # => Matrix[[1, -1, -1], [-1, 1, -1], [-1, -1, 1]]
m1.square?                      # => true
m1.singular?                    # => false
m1.regular?                     # => true

e = Matrix.unit(3)              # => Matrix[[1, 0, 0], [0, 1, 0], [0, 0, 1]]

m2 = Matrix.columns([[3,4,5]])  # => Matrix[[3], [4], [5]]
m1 * m2                         # => Matrix[[-6], [-4], [-2]]

Rubyの式の評価結果をコメントに吐き出してくれるxmp filterを今回初めて使ってみたのだけど、irbで式の結果を確認するより遥かに使い勝手がいい。
ソースを貼り付けるのもとっても楽だ。

さて固有値固有ベクトルを求めるメソッドをMatrixクラスに追加したいなあ、と思うんだけど、どうやって定義したらいいだろう。

追記:
Matrixクラスを拡張して固有値とか固有ベクトルを求めるメソッドを追加したものが Githubに置いてあった。
clbustos/extendmatrix · GitHub
こんど試してみよう。

「Facebookアカウントでログイン」機能をつくる(Rails3, Devise, OmniAuth, Mongoid)

はじめに

巷のWebアプリでよく見かける「Facebookアカウントでログイン」「Twitterアカウントでログイン」のボタン。ユーザー認証の必要があるWebサービスでも、メールアドレスやパスワード設定の手間が省けてとっても便利だ。これはOAuthと言って、FacebookTwitterといった外部サービス(認証プロバイダ)が提供するAPIを利用することで実現されている。

今回はRails3で上記の「Facebookアカウントでログイン」機能を実現する手順についてまとめてみた。

※なお、「マイグレーションが無くて楽」という理由でRailsのORMにはActiveRecordではなくMongoidを利用している。

環境

使用するライブラリ

  • Mongoid: Ruby用MongoDBのORM。MongoDBのORMとしては他にMongoMapperというものもあるが、こちらの方がドキュメントが充実していて人気の模様。
  • Devise: 言わずと知れたRails3デファクトの認証用ライブラリ。
  • OmniAuth: RubyでOAuth認証を実現するためのライブラリ。Deviseと連携可能。

MongoDBのインストール

homebrewが入っていればMongoDBのインストールは簡単。

$ brew install mongodb

で一発。インストールが済んだら、とりあえず

$ mongod &

でバックグラウンド起動しておく。
本当はサービスとしてOS起動時に立ち上がるよう設定したいけど今はこれで 十分。

Devise, Mongoidインストール済みRailsアプリの作成

世の中には徳のある御仁がいて、yes/noの質問に答えるだけでDeviseとMongoidの設定済みRailsアプリを生成してくれるテンプレートがgithubで公開されている。今回はこれを利用させて頂く。
RailsApps/rails3-mongoid-devise · GitHub
テンプレートからRailsアプリを生成するには-mオプションでテンプレートファイルを指定する:

$ rails new my_auth_test_app -m https://github.com/RailsApps/rails3-application-templates/raw/master/rails3-mongoid-devise-template.rb -T -O

コマンドを実行するとウィザードがアプリで使用するテンプレートエンジンやテスティングフレームワークなどの項目を尋ねてくるので、以下のように返答した:

      wizard  You are using Rails version 3.2.6.
      wizard  Checking configuration. Please confirm your preferences.
      insert    config/application.rb
      recipe  Running HAML recipe...
        haml  Would you like to use Haml instead of ERB? (y/n) y
y
     gemfile    haml (>= 3.1.6)
     gemfile    haml-rails (>= 0.3.4)
      recipe  Running RSpec recipe...
       rspec  Would you like to use RSpec instead of TestUnit? (y/n) y
y
    question  Which library would you like to use for test fixtures with RSpec?
          1)  None
          2)  factory_girl
          3)  machinist
       rspec  Enter your selection: 2
2
     gemfile    rspec-rails (>= 2.11.0)
     gemfile    database_cleaner (>= 0.8.0)
     gemfile    mongoid-rspec (1.4.6)
     gemfile    factory_girl_rails (>= 3.5.0)
     gemfile    email_spec (>= 1.2.1)
      create    features/support/email_spec.rb
      recipe  Running Cucumber recipe...
    cucumber  Would you like to use Cucumber for your BDD? (y/n) y
y
     gemfile    cucumber-rails (>= 1.3.0)
     gemfile    capybara (>= 1.1.2)
     gemfile    database_cleaner (>= 0.8.0)
     gemfile    launchy (>= 2.1.0)
      recipe  Running guard recipe...
    question  Would you like to use Guard to automate your workflow?
          1)  No
          2)  Guard default configuration
          3)  Guard with LiveReload
       guard  Enter your selection: 1
1
       guard  Guard recipe skipped.
      recipe  Running Mongoid recipe...
     mongoid  Would you like to use Mongoid to connect to a MongoDB database? (y/n) y
y
     mongoid  REMINDER: When creating a Rails app using Mongoid...
     mongoid  you should add the '-O' flag to 'rails new'
     gemfile    mongoid (>= 3.0.1)
      recipe  Running ActionMailer recipe...
    question  How will you send email?
          1)  SMTP account
          2)  Gmail account
          3)  SendGrid account
          4)  Mandrill by MailChimp account
  action_mailer  Enter your selection: 1
1
      recipe  Running Devise recipe...
    question  Would you like to use Devise for authentication?
          1)  No
          2)  Devise with default modules
          3)  Devise with Confirmable module
          4)  Devise with Confirmable and Invitable modules
      devise  Enter your selection: 2
2
      devise  Would you like to manage authorization with CanCan & Rolify? (y/n) n
n
     gemfile    devise (>= 2.1.2)
      recipe  Running AddUser recipe...
      recipe  Running HomePage recipe...
      recipe  Running HomePageUsers recipe...
      recipe  Running SeedDatabase recipe...
      recipe  Running UsersPage recipe...
      recipe  Running html5 recipe...
    question  Which front-end framework would you like for HTML5 and CSS?
          1)  None
          2)  Zurb Foundation
          3)  Twitter Bootstrap (less)
          4)  Twitter Bootstrap (sass)
          5)  Skeleton
          6)  Just normalize CSS for consistent styling
       html5  Enter your selection: 1
1
      recipe  Running SimpleForm recipe...
    question  Which form gem would you like?
          1)  None
          2)  simple form
          3)  simple form (bootstrap)
  simple_form  Enter your selection: 1
1
  simple_form  Form help recipe skipped.
      recipe  Running Cleanup recipe...
      recipe  Running Extras recipe...
      extras  Would you like to use 'rails-footnotes' (it's SLOW!)? (y/n) n
n
      extras  Would you like to set a robots.txt file to ban spiders? (y/n) y
y
      extras  Would you like to add 'will_paginate' for pagination? (y/n) n
n
      extras  Add 'therubyracer' JavaScript runtime (for Linux users without node.js)? (y/n) n
n
      extras  Banning spiders by modifying 'public/robots.txt'
      recipe  Running Git recipe...
      wizard  Running 'bundle install'. This will take a while.

これでDeviceとMongoidのインストール済みアプリが出来上がった。おまけにfactory_girlもrspecもhamlも導入済み。超ラク。ところでCanCanとRollifyってよく知らないけど何だろう。

mongoidの設定

MongoDBへの接続設定ファイルをジェネレーターで作成する:

rails g mongoid:config

これでconfig/mongoid.yml というデフォルト状態の設定ファイルができあがる。コメントを抜かした中身はこんな感じ:

# config/mongoid.yml
development:
  sessions:
    default:
      database: my_auth_test_app_development
      hosts:
        - localhost:27017
      options:
        consistency: :strong
  options:
test:
  sessions:
    default:
      database: my_auth_test_app_test
      hosts:
        - localhost:27017
      options:
        consistency: :strong

サンプルアプリだし特に変更する必要も無いので今回はデフォルトのままにしておく。
mongodbの便利な所は、事前に上記データベースのcreateを実行しておく必要がないところ。初回のデータinsert時にデータベースが自動で作成される。

OmniAuthとDeviseの連携

DBの設定も完了してRailsアプリの土台は出来上がった。ここからOmniAuthとDeviseを連携させてFacebook経由でユーザー認証を行う仕組みを作っていく。連携と言ってもDeviseはver 1.2からOmniAuthによる認証をサポートしていて、OmniAuthの設定はすべてDevise側から行うことができる。

Facebook側の設定

Facebookを認証プロバイダーとして利用するためには、まずFacebook開発者サイトでアプリの登録を行っておく必要がある。
新しくアプリを作成するとアプリIDとシークレットキーが与えられるので、これをメモっとく(あとで必要)。
またアプリのサイトURLの設定も必要。今回はローカルのみで動かすので "http://localhost:3000/"とだけ設定しておいた。

OmniAuthのインストール

Gemfileに以下を追記して bundle install。

gem "omniauth"
gem "omniauth-facebook"

Userモデルの作成

そもそもの認証の対象となるUserモデルのひな形を作成しておく。その前にdeviseの初期化も実行しておかないといけない。

$ rails g devise:install
$ rails g devise User

ジェネレータで作成されたuser.rbを編集し、UserがOmniAuthの対象であることをDeviseに教えてやる。また認証情報を保持するため、Userモデルのひな形にはproviderとuidというフィールドを加えておく:

  devise :omniauthable
  field :provider, :type => String # facebook等の認証プロバイダ
  field :uid,      :type => String # 認証プロバイダ内のユーザーID

ここでrake routesを実行すると、ユーザーのomniauth用名前付きパスが作成されていることが分かる:

 user_omniauth_authorize        /users/auth/:provider(.:format)        devise/omniauth_callbacks#passthru {:provider=>/facebook/}
  user_omniauth_callback        /users/auth/:action/callback(.:format) devise/omniauth_callbacks#(?-mix:facebook)

サーバーを立ち上げhttp://localhost:3000/users/auth/facebookにアクセスすると、Facebookの認証用ページにリダイレクトされる:
f:id:yhashy:20120721160833p:plain
このページでユーザーが「アプリへ移動」を選択すると、認証情報が/users/auth/facebook/callbackにコールバックされる、という寸法。あとはFBからのコールバックを受け取る処理を加えてあげればよい。

Facebookからのコールバックを処理する

config/routes.rbを編集し、omniauthのコールバック用コントローラーを下記の通り変更する:

devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

コールバックの処理は次のように実装する:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
    if @user.persisted?
      flash[:notice] = "Athentication successful!"
      sign_in(:user, @user)
      redirect_to root_path
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
end

Facebookから送られる認証情報はrequest.env["omniauth.auth"]に渡されるため、これを使ってユーザーの検索/作成をしている。

Userモデルでは find_for_facebook_oauthを次のように実装する:

  def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth.provider, :uid => auth.uid).first
    unless user
      user = User.create(name: auth.extra.raw_info.name,
                         provider: auth.provider,
                         uid: auth.uid,
                         email: auth.info.email,
                         password: Devise.friendly_token[0,20]
                         )
    end
    user
  end

ちなみにomniauthを使用する場合ユーザーがパスワードを入力する必要がないので、passwordフィールドにはDevise#friendly_tokenで生成したランダム文字列を渡している。

Viewを整える

整えるっていうか動作確認のためにリンク作るだけだけど...
Homeコントローラーを作成して、rootパスをhome#indexアクションに割り当て、index.html.hamlに次のように記述してやる。

%h1 Home#index
%p Find me in app/views/home/index.html.haml
- if !user_signed_in?
  = link_to "Facebookアカウントでログイン", user_omniauth_authorize_path(:facebook)
- else
  = "#{current_user.name}としてログインしています."
  = link_to "ログアウト", destroy_user_session_path, :method => :delete

動作確認

FBの開発者サイトでテスト用のダミーユーザーを作成した。その名もミスBharambeman。彼女の疑似アカウントでFBにログインし、http://localhost:3000/にアクセスすると
f:id:yhashy:20120722213736p:plain
Facebookアカウントでログイン」のリンクを踏み、FBの認証用ページに移動する:
f:id:yhashy:20120722213801p:plain
ここで「アプリへ移動」を選択してやれば、
f:id:yhashy:20120722213914p:plain
Facebookのユーザー情報からユーザーが作成されたことが分かる。

課題

  • Twitter, OpenIDFacebook以外の認証プロバイダにも対応する(これは簡単だけど)。
  • 上記と関連して、1ユーザーに対して複数の認証情報を紐づけられるようにする(Userモデルと認証情報を切り離す)。
  • Viewをもうちょっとカッコ良くする(プロフィール写真表示するとか)
  • もっと簡潔に記事を書く。

Emacsにmigemoをインストール

空き時間にmigemoをインストールしようとしたら色々ハマったので、インストール手順をメモしておきます。

migemoって何?

Migemo はローマ字のまま日本語をインクリメンタル検索するため のツールです。かな漢字変換をすることなく日本語のインクリメン タル検索を快適に行うことができます。

http://0xcc.net/migemo/

Emacsに限った話ではないけれど、日本語の文章をインクリメンタル検索する場合、

  1. 日本語IMEを有効化(Macなら「かな」キーを押す)
  2. 検索ワードをローマ字で入力
  3. 漢字/カタカナ等に変換

という手順を踏まねばならず、地味にストレスが溜まる。Migemoはこの手順を省略し、ローマ字を入力するだけで変換後の漢字/カナを予測し検索をかけてくれる優れモノ。

環境

  • Mac OSX Lion
  • Cocoa Emacs 23.3.1
  • Ruby 1.9.2, 1.8.7 (Rubyのバージョンはrvmで管理)

インストールの準備

APELのインストール

APELはA Portable Emacs Libraryの略称で、バージョンの異なるEmacs間で移植性を簡単にするためのライブラリであるらしい(あんまりよく分かってない)。
APELは以前elscreenを導入した際に既にインストールしていたので今回は何もしなかった。その時参考にさせて頂いたエントリはこちら:Emacs For Mac OS X に ElScreen と APEL をインストールする方法 / マスタカの ChangeLog メモ

必要なファイルのダウンロード

migemo本体の他、RomkanとBsearchというRubyライブラリが必要なので落としてくる:

$ mkdir work
$ cd work
$ wget http://0xcc.net/ruby-romkan/ruby-romkan-0.4.tar.gz
$ wget http://0xcc.net/ruby-bsearch/ruby-bsearch-1.5.tar.gz
$ wget http://0xcc.net/migemo/migemo-0.40.tar.gz
$ tar xzvf ruby-romkan-0.4.tar.gz 
$ tar xzvf ruby-bsearch-1.5.tar.gz 
$ tar xzvf migemo-0.40.tar.gz 

romkanとbsearchのrubyスクリプトはどこに置いたらいいのか少し悩んだ。結局ホームディレクトリ下にsite-rubyというディレクトリを作ってここに置くことに。

$ cd
$ mkdir site-ruby
$ cp work/ruby-romkan-0.4/romkan.rb site-ruby/.
$ cp work/ruby-bsearch-1.5/bsearch.rb site-ruby/.

Rubyがこのディレクトリを認識するように、別途ロードパスを通してやる必要がある。

migemoのコンパイル & インストール

Rubyのバージョンはrvmで管理しており、デフォルトは1.9.2に設定してあるのだけれど、configureスクリプトを実行したところこれが原因でコケた:

$ ./configure --with-emacs=/Applications/Emacs.app/Contents/MacOS/Emacs  --with-lispdir=~/.emacs.d/site-lisp --with-rubydir=~/site-ruby
loading cache ./config.cache
checking for a BSD compatible install... (cached) /usr/bin//install -c
checking whether build environment is sane... yes
checking whether make sets ${MAKE}... (cached) yes
checking for working aclocal... found
checking for working autoconf... found
checking for working automake... found
checking for working autoheader... found
checking for working makeinfo... found
checking for ruby... (cached) /usr/bin//ruby
checking where emacs files are in... $(datadir)/emacs
checking where .elc files should go... ~/.emacs.d/site-lisp
checking where emacs files are in... 
checking where .rb files should go... ~/site-ruby
-n checking Ruby/Bsearch... 
found
-n checking Ruby/Romkan... 
<internal:lib/rubygems/custom_require>:29:in `require': /Users/hashy/site-ruby/romkan.rb:29: invalid multibyte char (US-ASCII) (SyntaxError)
/Users/hashy/site-ruby/romkan.rb:28: invalid multibyte char (US-ASCII)
/Users/hashy/site-ruby/romkan.rb:28: syntax error, unexpected $end, expecting keyword_end

ググったところmigemoはRuby 1.9では動作しないらしい。仕方ないので一旦Rubyのバージョンをデフォルトの1.8.7に切り替えることにする:

$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.2.0]
$ rvm use system --default
Now using system ruby.
Now using system ruby.
$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0]

Rubyを1.8.7に切り替えたらエラーが出なくなった:

$ ./configure --with-emacs=/Applications/Emacs.app/Contents/MacOS/Emacs  --with-lispdir=~/.emacs.d/site-lisp --with-rubydir=~/site-ruby
loading cache ./config.cache
checking for a BSD compatible install... (cached) /usr/bin//install -c
checking whether build environment is sane... yes
checking whether make sets ${MAKE}... (cached) yes
checking for working aclocal... found
checking for working autoconf... found
checking for working automake... found
checking for working autoheader... found
checking for working makeinfo... found
checking for ruby... (cached) /usr/bin//ruby
checking where emacs files are in... $(datadir)/emacs
checking where .elc files should go... ~/.emacs.d/site-lisp
checking where emacs files are in... 
checking where .rb files should go... ~/site-ruby
-n checking Ruby/Bsearch... 
found
-n checking Ruby/Romkan... 
found
creating ./config.status
creating Makefile
creating tests/Makefile
creating migemo.rb

あとはmake, make installでインストールが完了。

make && make install

さてこのままだとrvmでRubyのバージョンを1.9に戻した時にmigemoが動かない。
悩んだ末、/usr/local/bin/以下にインストールされたmigemo, migemo-grep, migemo-client, migemo-serverのshebangを次のように書き換え、rvmのRubyは使わないように修正した:

#! /usr/bin/ruby

emacs側の設定

~/.emacs.d/init.elに次の記述を加えてやると、migemoが動いた。

(setenv "RUBYLIB" "~/site-ruby")
(require 'migemo)
(setq migemo-command "migemo")
(setq migemo-options '("-t" "emacs"))

backward-searchの不具合を直す

めでたくmigemoのインストールが完了したので喜んでいたのも束の間、C-rで後方検索を実行したところ "wrong-type-argument ..." というエラーメッセージがミニバッファに表示されて涙目になった。
ただこれは既知のバグであるらしく、下記ページで対応方法が公開されていた:
[migemo] Fix error with isearch-backward

lisp用ディレクトリにインストールされたmigemo.elを開き、該当する関数定義を書き換えて再度バイトコンパイルすると正常に動作するようになった。ああ大変だった...

疑問

migemoって何て読むの?みげも?みじぇも?

Emacs Lispを基礎から学ぶ (4): バッファオブジェクト/バッファローカル変数

バッファの作成/選択/削除/ファイル読込/出力

やっとバッファの概念が入ってEmacsらしくなってきた。バッファオブジェクトを扱う関数/コマンドはたくさんあるので使いそうなものを列挙:

バッファローカル変数

ちょっとこれだけややこしかったのでメモ。
elispにはバッファ固有の変数(特定のバッファで値を変更しても他のバッファに影響を及ぼさない変数)というものがある。バッファ毎に異なるmajor-modeとかbuffer-file-nameとかがその例。

このバッファローカル変数を扱う際には、

  1. 常にバッファローカル変数にバッファ固有の値を設定する
  2. グローバルな変数を特定のバッファでバッファローカル変数として設定し直す

という2つの方法がある。

論より実例: