はてなブログに移行しました

ここに書くのが遅くなってしまいましたが、はてなダイアリーからはてなブログに移行しました。

メインで使用するはてな id も id:vividcode から id:nobuoka に変更しました。 今後ともよろしくお願いします!!

Ruby での Test::Unit や MiniTest::Unit を使った複数のファイルのテスト

Perl で複数のテストを実行する場合は prove コマンドがあるけれど、Ruby の場合はどうするのがいいんだろうなー。 と思って調べてみました。

Rubyベストプラクティス -プロフェッショナルによるコードとテクニック』 によると、Rake::TestTask を使うのが良いようです。 以下のような rakefile を書いて、あとは rake test で実行、と。

# coding: UTF-8

require 'rake/testtask'

task :default => [:test]

Rake::TestTask.new do |test|
  # $LOAD_PATH に追加するパス (デフォルトで 'lib' は入っている)
  test.libs << 'test'
  # テスト対象ファイルの指定
  test.test_files = Dir[ 'test/**/test_*.rb' ]
  test.verbose = true
end

このときのフォルダ構成は以下のようになります。

Project --+- lib -----+- ...
          |           +- ...
          |
          +- test ----+- test_main.rb
          |           +- test_aaa.rb
          |           +- ...
          |
          +- rakefile

Project フォルダにいる状態で、以下のようにコマンドをたたくと、test ディレクトリ内の "test_" ではじまるファイル名のファイルが全て実行されます。

$ rake test

Aspire One 722 に Ubuntu 11.10 をインストール

AcerAspire One 722 に Ubuntu 11.10 をインストールしたときのメモ。 64 ビット版をインストール。 いくつか問題があったが、以下の設定にすることで快適に使えるようになった。

GNOME Shell のインストール

Ubuntu 11.10 標準の Unity は動きがもっさりしているので GNOME Shell をインストール。

$ sudo apt-get install gnome-shell
$ sudo apt-get install gnome-tweak-tool

ATI/AMD プロプラエタリ FGLRX グラフィックドライバ」 を使っていると、GNOME Shell の画面が乱れるため、プロプラエタリのグラフィックドライバはインストールしない。

GNOME Shell Extension としては、とりあえず以下のものをインストール。

  • Windows Alt Tab : Alt + Tab でウィンドウ切り替えできるように (デフォルトではアプリケーション切り替え)
  • Alternative Status Menu : 電源オフとハイバネートの追加

無線 LAN 接続後にフリーズしてしまう問題

どうやら無線 LAN ドライバとイーサネットドライバが競合するようで、無線 LAN への接続後にフリーズしてしまうことがある。 自動的に無線 LAN に接続する場合は、ログイン直後にフリーズしてしまう。 とりあえずの回避策としては 「BIOS でネットワークブートを有効にして、HDD での起動よりもネットワークブートの優先順位を高くする」 というもの。 これで一応回避できている模様。

Gtk のパッケージの不足

(gvim:5194): Gtk-WARNING **: module_path にはテーマ・エンジンがありません: "pixmap",

GUI アプリケーションを起動すると上記のような警告が発生することがある。 Gtk のパッケージが不足していることが原因らしいので、足りないパッケージをインストール。

$ sudo apt-get install gtk2-engines-pixbuf

Alt + F2 のコマンド実効プロンプトがデフォルトで無効になっている

システム設定を開き、キーボード > ショートカット > システム で "コマンド実行プロンプト" のショートカットキーとして Alt + F2 を割り当てる。

Ubuntu の admin グループと sudo 権限の関係

今日の朝書いた記事 「Ubuntu 11.10 で全てのユーザーを一般ユーザー (admin グループに属してない) にしてしまった場合の対処法」 で書いたように、Ubuntu では admin グループに属しているユーザーが管理者ユーザーになります。 また、どのユーザーに sudo 権限を与えるかは /etc/sudoers というファイルで指定されます。

では admin グループ (管理者ユーザー) と sudo 権限 (/etc/sudoers の内容) はどういう関係になっているのでしょうか? /etc/sudoers の中を覗いてみると、以下のような 2 行がありました。

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

つまり、admin グループのメンバーに sudo 権限を付与するように /etc/sudoers が記述されている、というわけです。

Ubuntu 11.10 で全てのユーザーを一般ユーザー (admin グループに属してない) にしてしまった場合の対処法

Ubuntu では、特権を得るために原則として root ユーザーになることはせず、管理者ユーザー (admin グループに所属しているユーザー) が sudo コマンド (グラフィカルプログラムの場合は gksudo など) を使うことで特権を得ます (Ubuntu document - RootSudo)。 そのため、ユーザーが所属するグループを変更するときには注意しなければいけません。 間違って全てのユーザーを admin グループから取り除いてしまう (全てのユーザーが管理者ユーザーではなくなってしまう) と少し復旧に手間がかかってしまいます。

ここでは、間違って全てのユーザーを admin グループから除いてしまった場合の復旧方法について述べます。

Ubuntu でユーザーをグループに追加するときにしてはいけないこと

間違って全てのユーザーを admin グループから除く、なんてことは GUI のみの操作をしていれば (多分) できないと思うのですが、コマンド操作をしているとついやってしまう失敗ではないでしょうか。

上記の記事に書いているように、usermod コマンドを使用してユーザーの所属グループを変更するときに、元々所属しているグループを記述し忘れてしまうという失敗はやりがちです。 この失敗を元々 admin グループに属しているユーザーに対してしてしまうと (そしてそのユーザーが唯一の管理者ユーザーだと) 管理者ユーザーが居ないという状況になってしまいます。 理由はわかりませんが、ログアウトするまでは sudo 権限は残っているようなので (グループ情報が読み込まれるのがログイン時だから? sudo 権限が付与されるのがログイン時だから?) admin グループから除いてしまってもログアウトするまでに気づけば直せるのですが、一度ログアウトしてしまうと誰も sudo 権限を持っておらず復旧が困難になります。

sudo 権限がないと、グループを変更しようとしても以下のようになって変更できないのです。

~$ sudo usermod -g usergroup -G usergroup,admin username
username is not in the sudoers file

Ubuntu 11.10 だと recovery menu のシングルユーザーモードから復旧できない?

上に挙げた 2 つの記事では、復旧方法として recovery menu のシングルユーザーモードでログインして usermod コマンドを使うという方法を書いています。 (/etc/group ファイルを変更してもよいでしょう。)

また、Ubuntu 11.10 のドキュメントの 「I forgot my password!」 にはパスワードを忘れた際の対処法として、同様のシングルユーザーモードでのログインによる復旧方法が書かれています。

しかしながら、私の環境で試してみたところ recovery menu のシングルユーザーモードでログインしても、usermod コマンドがうまくいきませんでした。 (以下のように /etc/passwd がロックできなかったと言われた。)

~# usermod -g usergroup -G usergroup,admin username
usermod: cannot lock /etc/passwd; try again later

また /etc/group ファイルの編集もできませんでした (Read-only だと言われる)。 chmod コマンドを使っても以下のようにエラーが発生。

~# chmod 0666 /etc/group
chmod: changing permissions of `/etc/group' : Read-only file system

パスワードの変更も同様で、以下のようなエラーが発生してできませんでした。 Ubuntu 11.10 のヘルプドキュメントに書かれている方法なので私が何か間違っているのかもしれませんが。。

~# passwd username
passwd: Authentication token manipulation error
passwd: password unchanged

(追記) コメントで教えていただいたのですが、recovery mode で起動する方法で復旧できるようです。 私はまだ試していませんが、必要でしたらこの記事のコメントを参照して試してください。

解決策

そんなわけで recovery mode を使う方法では上手くいかなかったので、復旧方法として別の方法をとりました。 大まかな方法としては、Live Disk で Linux をオンメモリで動かし、HDD に書かれているファイルの内容を変更する、というものです。 以下に簡単に手順を書いておきます。

  1. Live Disk で Ubuntu 11.10 起動
  2. 以下のようなコマンドで HDD のファイルシステムをマウントする (/dev/sda1 は環境依存なので適当に変更のこと)
    ~$ sudo mkdir /mnt/myhdd
    ~$ sudo mount /dev/sda1 /mnt/myhdd
  3. ファイルの中身を確認しマウントしたデバイスが正しい HDD かどうかチェックする
  4. 以下のコマンドでもともとの /etc/group にあたるファイルを開く (vi じゃなくても使いやすいエディタを使ってください)
    ~$ sudo vi /mnt/myhdd/etc/group
  5. 以下のように admin グループについて書かれた行にユーザーを追加
    admin:x:118:username
  6. 変更を保存して再起動して、HDD 上の Ubuntu 11.10 を起動

これでうまくいくはずです。

Facebook のユーザー認証と REST API (Graph API) の基本 (web アプリの場合)

Twitter の REST API を使うのと同じように FacebookAPI を使いたいけどドキュメントがよくわからない、と前に思って放置してたんですが、読書メーターFacebook 連携がうまくいかない原因を調べようと思って FacebookAPI を使ってみると意外と簡単だったのでメモしておきます。

Web サービスから FacebookAPI を使うことを想定しています。

まずはアプリケーションの登録

Facebook のアプリ管理アプリ https://developers.facebook.com/apps を使って自分のアプリを登録します。 「Create New App」 というボタンをクリックしてアプリの登録を行います。 アプリ登録の際には、開発者の承認のために携帯電話の番号かクレジットカード番号を登録しておく必要があります。

アプリの登録が終わると、アプリ用の App ID と App Secret が発行されます。

ユーザーごとのアクセストークンの取得

Twitter では OAuth 1.0a を用いてユーザー認証を行いますが、Facebook では OAuth 2.0 を用いてユーザー認証を行います。 その流れを簡単に説明します。 詳細は Facebook の開発者向けドキュメントを見てください。

1. ユーザーを Facebook ページに誘導し、自分のアプリを許可して貰う

ユーザーを

https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL
というページに誘導します。 これはアプリからユーザーの情報にアクセスすることを許可するかどうかをユーザーに尋ねるページです。 YOUR_APP_ID は自分のアプリの ID です。 YOUR_URL は、ユーザーがアプリを許可した後に遷移するページの URL です。 この URL のドメインは、アプリ登録時に web site の site url として記入しておかなければいけません。 (セキュリティ機能のため; 後から変更も出来る。)

また、ユーザーの情報にアクセスするだけでなく、ユーザーの wall への書き込みの許可などが必要な場合は、scope パラメータを追加してそれを指定します。 詳しくは公式のドキュメントを見てください。

2. ユーザーが許可すればリダイレクト

ユーザーがアプリを許可すると、YOUR_URL?code=A_CODE_GENERATED_BY_SERVER にリダイレクトされます。 このとき渡される A_CODE_GENERATED_BY_SERVER を使用して Facebook 側にアクセストークンの発行をリクエストします。

3. アクセストークンを取得

2. で取得した A_CODE_GENERATED_BY_SERVER を使って、

https://graph.facebook.com/oauth/access_token?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=A_CODE_GENERATED_BY_SERVER
に GET メソッドでリクエストを発行します。 YOUR_APP_IDYOUR_APP_SECRET は、アプリの登録をすることによって発行してもらえる値です。 YOUR_URL はなぜ必要なのかよくわかりませんが、とりあえず 1. で使用した値と同じ値でよいと思います。

エラーが発生しなければ、レスポンスとして以下のような文字列を得られます。

access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&expires=6694

これでアクセストークンの取得が完了しました。 access_token パラメータの値がアクセストークンです。 これ以降はこのトークンを使うことで、アプリからユーザーの情報にアクセスしたり、(許可をしてもらっているならば) ユーザーの wall に投稿したりできるようになります。 expires は、このアクセストークンがいつまで有効かを表しています。 (特にユーザーに許可を求めなければ、アクセストークンは期限付きになる; 無期限のアクセストークンにするように最初にユーザーに許可を求めることも可能。)

Graph API を使用する

ユーザーの情報などにアクセスするためには Graph API というものを使用します。 詳細は公式のドキュメントを見てください。

この API にリクエストを投げる際に、パラメータとして access_token=XXXXXXX の形式でさきほど取得したアクセストークンを指定すると、そのアクセストークンを使用できます。

ユーザーの情報にアクセスする例

例えば、自分のユーザー ID を取得するための リクエストメソッドと URL は

GET - https://graph.facebook.com/me

ですので、アクセストークンのユーザーの ID を知りたい場合は

https://graph.facebook.com/me?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
という URL に GET メソッドでリクエストを投げればよいことになります。

また、wall に投稿するための API として

POST - https://graph.facebook.com/ID/feed
がありますので、ID が ID の人の wall にメッセージを投げる場合は
https://graph.facebook.com/ID/feed
という URL に
access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&&message=HELLO
というメッセージボディを POST すればよいことになります。

アクセストークンの文字数

結局、読書メーターFacebook 連携がうまくいかないことがあった原因はアクセストークンの文字数を少なく見積もっていたことだったようです [ http://akahoshitakuya.com/archives/4026 ] が、Facebook のアクセストークンの文字数はユーザーによってまちまちのようですので、アクセストークンの文字数の上限がどうなっているのかの仕様を確認せずにアプリ内でのアクセストークンの文字数を制限することはしないようにしましょう。

HTML 要素にクラスを付与したり削除したりするのに便利なユーティリティメソッド (JavaScript)

HTML5 における HTMLElement#classList

HTML5 では、HTML DOM の HTMLElement インターフェイスclassList というプロパティ が追加される予定です。 このプロパティは W3C DOM 4 の DOMTokenList インターフェイス を実装したオブジェクトを参照しており、このリストに値を追加したり、このリストから値を削除すると、要素のクラス属性に反映されます。

つまり、HTMLElement#classList を使うことで、要素にクラスを追加したり削除したりすることが簡単にできます。 詳細は MDN あたりが分かりやすいと思います。

しかしながら、現在のところ HTMLElement#classList が使える環境は多くはありません。 Firefox 7 や Opera 11.51 では使えることを確認しました (Google Chrome でも使えるようです) が、Safari 5 や IE 10 では実装されていません。

続きを読む