JavaScriptって、の続き

具体的には、ゲームなんかで

function playTutorial() {
  message('歩きます。');        // メッセージwindowが開き、クリックすると次に進む
  walk();                       // プレイヤーが歩く。アニメーションが終わると次に進む
  message('歩きました。');
}

こう書きたい。function を chain させるのは記述が面倒で嫌。HTML5 でマルチスレッドが使えるという Web Workers も、yield とかできないのでこういう用途には使えないっぽい。JavaAppletを使ってJavaScriptをsleepさせる裏技があるようなのでそれを使って、とかWeb Workers でビジーウェイトさせて、とか考えたけど相当いまいち。そうなるとメタ言語みたいな方向ですかね、というわけですぐ使えそうなのが Concurrent.Thread である。

var  message = Concurrent.Thread.compile(function(msg) {
  document.body.innerHTML = msg;
  var thread = Concurrent.Thread.self();
  document.onclick = function() {
    document.onclick = null;
    thread.notify();
  };
  try {
    Concurrent.Thread.stop();
  } catch(e) {}
});

var walk = Concurrent.Thread.compile(function() {
  document.body.innerHTML = 'walking';
  for (var i = 0; i < 5; i++) {
    Concurrent.Thread.sleep(1000);
    document.body.innerHTML += '.';
  }
});

Concurrent.Thread.create(playTutorial);

牧さんすごいねー。

重大な問題が

Concurrent.Thread は Array.prototype などを拡張しているので、多くのJavaScriptフレームワークと競合する。こまったねー。

javascript ってなに

JavaScript - Wikipedia
これをみてIEを切るのならJavaScript1.7で書いていいのかなと思ったんだけど、実際のところはFirefoxでしか動かない。ここらへんは各ブラウザが従うべき標準ではなくてmozillaが言ってるだけなのかな。ECMA 3rd を継ぐ標準として ECMAScript Harmony っていうのをみんなで考えようよ、という段階のようだ。数年はどうにもならなそうに見える。yieldをつかいたかったんだけどにゃー

split でデリミタも結果に含めたい

sep で指定されたパターンに括弧が含まれている場合には、各括弧のパターンにマッチした文字列も配列に含まれます。括弧が複数ある場合は、マッチしたものだけが配列に含まれます。

プログラミング言語 Ruby リファレンスマニュアル

へえ、知らなかった。そもそもperlでできるようだ。

authlogic + OpenID でちょっとはまる

GitHub - binarylogic/authlogic_openid: Extension of the Authlogic library to add OpenID support. の通りにやるとエラーになります。困ります。すぐに修正されそうですが、とりあえず対処。

Rack::OpenID 関連

http://github.com/binarylogic/authlogic_openid/issues#issue/15
とのことなので、http://github.com/mreinsch/authlogic_openid を使います。gem の作り方がよくわからなかったのでソースを直接置いてごまかします。

$ sudo gem uninstall authlogic-oid
$ git clone http://github.com/mreinsch/authlogic_openid.git vendor/plugins/mreinsch-authlogic_openid

Rack::OpenID を入れます。

# config/environment.rb
Rails::Initializer.run do |config|
  # ...
  config.gem "rack-openid", :lib => 'rack/openid'
end
$ sudo rake gems:install

relative_url_root

Rails 2.2 以降では ActionController::Request#relative_url_root がないよっていうエラーが出ます。適当な場所で作ってください。

class ActionController::Request
  def relative_url_root
    return ActionController::Base.relative_url_root || ''
  end
end

require_fields など

あとそのままだと OpenID::SReg の require_fields, optional_fields に空の Array を渡してエラーになるので、使わない場合は acts_as_authentic の config で false に設定しましょう。[] や nil だと駄目です。

class User < ActiveRecord::Base
  acts_as_authentic do |c|
    c.openid_mreinsch = false
    c.openid_optional_fields = false
  end
end

モデルに name, first_name などのカラムがあると困る

mreinsch さんが OpenID の情報から name などを自動で設定するような修正を入れているのですが、require_fields などを適切に設定していない場合エラーが出ます。問題であれば AuthlogicOpenid::ActsAsAuthentic#map_openid_registration の中身をコメントアウトするなどしましょう。

authlogic_openid のこなれてなさ具合から OpenID の普及度を感じますね。以上です。

追記

んー、使ってみるといろいろとよくない。binarylogic-authlogic_openid を使って http://github.com/mreinsch/authlogic_openid/commit/9b802c347f5addebcbce945af3b5f80b3ee7b214 これだけマージした方が素直に動いて良いと思う。新しく作るなら authlogic でない認証を使うとか。

追記2

OpenID 2.0 では claimed_id の fragment (#以降の部分) を捨ててはいけないらしいのだけど、上ので使っている OpenID.normalize_url は fragment を捨てているので、fragment 付きの claimed_id が帰ってくる Yahoo の認証で問題が出たりする。ちゃんとやると修正箇所が多そうなので、とりあえずは fragment 捨て統一で事をうやむやにする方針で。

はてなみたいに /user_name/ ってやる routes

map.with_options(
  :path_prefix => '/:user_name',
  :requirements => {
    :user_name => /[a-z][0-9a-z_\-]{2,30}[0-9a-z]/i
  },
  :name_prefix => 'user_',
  :namespace => 'user/'
) do |user|
  user.root :controller => 'index'
end

こんな感じで。

Q4M for Ruby マルチスレッド

RubyのスレッドがMySQLで詰まるのはそういうものらしくて、最近話題らしいNeverBlockの関連プロダクトmysqlplusがあると解決するらしい。

require 'mysqlplus'
ActiveRecord::Base.connection.raw_connection.async_query("select queue_wait('#{table_name}')")

こうするとちゃんとスレッドが切り替わってる気がする。あとCtrl+Cでちゃんと終了してくれるようになった。

Q4M

Q4Mで書き直してみたけど、簡潔に書けてなかなか良い。drubyだとテストの書き方がいまいちわからないのだよね。それと、下の記事のようにTupleSpaceを隠匿するのはよくない気がすると思った。

しくはっく

waitしてる間にrubyのスレッドが切り替わらない。スレッドよくわからない