Hatena::ブログ(Diary)

Windchase

2007.5.26

LimeChat 2.17 リリース

細かい bug fix のための更新です。

ダウンロードは、http://limechat.net/ からどうぞ。

  • 設定ファイルを設定変更時にすぐ保存するようにした。
  • UnrealIRCd の mode を誤って解釈しないように mode のパース方法を変更した。
  • mode +a 受信時にメンバリストをクリアしないようにした。
  • mode +R 受信時に Reop ダイアログにマスクを追加していなかったバグをfixした。
  • mode 送信時に +R のペナルティ計算が抜けていたバグをfixした。
  • ヘルプのマクロの箇所で、Inviteアクションの説明が間違っていたのを直した。

2007.5.25

JavaScript で幅に合わせて文字列を切りつめる

デスクトップアプリを開発してると、ListView のカラム幅が足りなくなったときに「My Docume...」のように自動的に末尾を「...」で埋めて切りつめてくれる機能がある。ウェブでも同じことをやりたかったので、作ってみた。

まず、文字列の幅を測定するには、

<span id="ruler" style="visibility:hidden;position:absolute;">
</span>

みたいな隠しエレメントを用意しておいて、

String.prototype.getExtent = function(ruler) {
  var e = $(ruler);
  var c;
  while (c = e.lastChild) e.removeChild(c);
  var text = e.appendChild(document.createTextNode(this));
  var width = e.offsetWidth;
  e.removeChild(text);
  return width;
}

文字列をテキストノードにして流し込んでやるといい。

'JavaScript is fun'.getExtent('ruler'); // => 148

次に、この関数を利用して、指定した幅に収まるように文字列を切りつめる方法を考えてみる。

一番簡単なのは、与えられた幅より小さくなるまで文字列をどんどん切りつめていくという方法。

イメージはこんな感じ。

maxWidth = 120
JavaScript is fun  // => 146
JavaScript is fu   // => 135
JavaScript is f    // => 124
JavaScript is      // => 110 ok

この処理をコードにすると、

String.prototype.truncateTailInWidth = function(maxWidth, ruler) {
  if (this.length == 0) return '';
  if (this.getExtent(ruler) <= maxWidth) return this;
  for (var i=this.length-1; i>=1; --i) {
    var s = this.slice(0, i);
    if (s.getExtent(ruler) <= maxWidth) return s;
  }
  return ''
}

こんな感じになる。

やりたいことは「...」をつけて切りつめることなので、このコードを少し変えて、

String.prototype.truncateTailInWidth = function(maxWidth, ruler) {
  if (this.length == 0) return '';
  if (this.getExtent(ruler) <= maxWidth) return this;
  for (var i=this.length-1; i>=1; --i) {
    var s = this.slice(0, i) + '...';
    if (s.getExtent(ruler) <= maxWidth) return s;
  }
  return '';
}

これで完成。

使ってみると、

'JavaScript is fun'.truncateTailInWidth(120, 'ruler'); // => JavaScript i...
'日本語も平気'.truncateTailInWidth(60, 'ruler');       // => 日本...

ちゃんと動作してることがわかる。

動作サンプル: http://limechat.net/sample/truncate/

実際に使うときには、ruler として使う span 要素に、切り詰めた文字列を使う場所と同じスタイルを指定してください。

完成したソースは以下の通り。

String.prototype.getExtent = function(ruler) {
  var e = $(ruler);
  var c;
  while (c = e.lastChild) e.removeChild(c);
  var text = e.appendChild(document.createTextNode(this));
  var width = e.offsetWidth;
  e.removeChild(text);
  return width;
}

String.prototype.truncateTailInWidth = function(maxWidth, ruler) {
  if (this.length == 0) return '';
  if (this.getExtent(ruler) <= maxWidth) return this;
  for (var i=this.length-1; i>=1; --i) {
    var s = this.slice(0, i) + '...';
    if (s.getExtent(ruler) <= maxWidth) return s;
  }
  return '';
}

2007.5.24

RubyCocoa で NSObject.alloc.init が NSObject を返さない問題

RubyCocoa で WebView を使うと NSObject.alloc.init が NSObject を返さないことがあったのでレポートしておいた。→ rubycocoa-devel:890

こんなコード

class AppController < OSX::NSObject
  include OSX

  def webView_decidePolicyForNavigationAction_request_frame_decisionListener(
          sender, action, request, frame, listener)
    listener.use
  end

  def awakeFromNib
    3000.times do |i|
      obj = NSObject.alloc.init
      if obj.class.name != 'OSX::NSObject'
        puts "Not NSObject at: #{i}"
        p obj
        return
      end
      view = WebView.alloc.initWithFrame(NSZeroRect)
      view.setPolicyDelegate(self)
      view.mainFrame.loadHTMLString_baseURL('<html></html>', nil)
    end
    puts 'No problem'
  end
end

を実行すると、

Not NSObject at: 104
#<OSX::WebPolicyDecisionListener:0x159ed6 class='NSObject' id=0x500e20>

となり、NSObject.alloc.init が NSObject 以外のオブジェクトを返していることがわかる。

どうやら Objective-C object id → ruby object の変換テーブルのキャッシュが悪さをしていたらしく、すぐに fix してくれた。→ rubycocoa-devel:893

hisaさん、Laurent、ありがとう。

2007.5.20

RailsConf2007: Dave Thomas closing keynote

IMG_3803.JPG

最後は Dave Thomas のキーノート。これがすごかった。

カーゴカルト を引き合いに出して、Orthodoxy (形式が整ってることを信じること) ではなく、Orthopraxy (正しいことを実行すること) を大切にしようということを言っていた。

取り上げられたのは、

  • ウェブブラウザ (半二重で IBM 3270 と変わらない)
  • Object-Oriented Programming (いま実際に使われてるのは Class-Oriented だよね)
  • RDB

というところ。

参加者からは、

  • REST
  • Social Networking
  • TDD

という声も上がっていた。

このうち、どれがカーゴカルトに当たるのか考えてみようよと。

さすが Dave Thomas。考えさせられるスピーチだった。

RailsConf2007: Scaling Twitter

3日目よかったのは、Twitter の中の人 Britt Selvitelle と Alex Payne による Scaling Twitter。

4月の話 からアップデートもあり、より突っ込んだ話が聞けた。

まずは、ハードウェア構成について。

  • Mongrel across 19 cores
  • Message processing/delivery across 16 cores
  • Jabber across 2 cores
  • MySQL on one big 8 core box
  • 16GB+ for memcache across a bunch of machines
  • 32 cores total

意外にマシン数は多くない。

負荷の状況について。

  • 200 - 300 connections per second
  • Spiking at 800 connections per second
  • We've done 11,000 connections per second
  • MySQL has spiked to 2,400 quieries per second

負荷対策はとにかく memcached で、acts_as_cached を使ってるらしい。

あと、ruby で書いた分散キューシステムで書き込みをしていて、キューは memcached に載せてるのだとか。このあたり、memcached が落ちたらデータがなくなるとか考えないところがおもしろい。

http://www.slideshare.net/al3x/scaling-twitter-railsconf-2007

http://bostonsteamer.livejournal.com/875052.html

2007.5.19

RejectConf

2日目の夜、id:ogijun さんから RejectConf が開催されると聞いたので行ってみる。

会場の Free Geek は大学のサークル棟みたいなところで、古いコンピュータがところ狭しと積み上げられているステキな場所だった。

IMG_3748.JPG

広い部屋いっぱいのパイプイスは満席。JRuby の Charles Nutter とか Mongrel の Zed Shaw もいる。

IMG_3764.JPG

発表者は与えられた2分で、自分が作った物をプレゼンする。プレゼンが始まったら、まだ話してる人に「静かに!」と注意する大声が飛ぶほどみんな真剣だった。すごいものを作った人には大きな拍手。

やっぱり創る人の話には力があると思う。見てるだけでも楽しくて、正直うらやましかった。

動画が上がってるので、見てみると雰囲気がわかるかも。

http://video.google.com/videoplay?docid=-603944638448214790

http://video.google.com/videoplay?docid=-2381939140760426511

RailsConf2007: Memcaching Rails

2日目よかったのは、Chris Wanstrath のセッション。Sexy Migrations といい、acts_as_cached といい、この人はセンスがいいと思う。

memcached の概要からはじまり、acts_as_cached の具体的な使い方の説明へ。モデルにフィールドを追加したときとか、古くなった cache を expire させる機能が便利っぽい。

http://www.slideshare.net/err/kickin-ass-with-cachefu/

2007.5.18

RailsConf2007: David Heinemeier Hansson keynote

IMG_3731.JPG

初日は、やはり DHH のキーノートが一番よかった。

開口一番、TextMate いいよ!という話からはじまり、いよいよ本題の Rails 2.0 へ。

一番大きな変更点は、やはり ActiveResource の respond_to で REST にネイティブ対応したよ、というところ。続いて、その他 9つの変更点が挙げられた。

  • Breakpoints are Back
  • HTTP Performance Improvements
  • Query Cache
  • Action Mimetype Renderer
  • Config Initializer
  • Sexy Migrations
  • HTTP Authentication
  • The MIT Assumption
  • Spring Cleaning

個人的に、注目は HTTP Performance Improvements。

具体的には、

  • 複数の Javascript や css をそれぞれ1ファイルにまとめて、1回の HTTP リクエストで読めるようにする
  • img タグのホスト名をランダムに振って、ブラウザの1ホスト2接続制限をくぐり抜ける

という感じ。

YAPC::Asia 2007 で Ben Trott も言ってたけど、1つ目の Javascript と css を1ファイルにまとめるのは実際にかなり効果がある。

Lingr では、5つあった script タグを1つにまとめた結果、4.45秒が 3.76秒になった (転送時間をFirebugで確認)。さらに、4つの css を1つにまとめると 3.12秒にまで短縮できた。

これを標準でできるのはすばらしい。

概要が O'Reilly Radar に載ってるので、詳しくはそちらを参照してください。

http://radar.oreilly.com/archives/2007/05/dhhs_rails_keyn.html