LDRizeをFirefox13で使えるようにする 解説編

調べたこと、あったことの時系列に合わせて、大雑把に解説。

死亡

過去の問題ほどややこしくなさそうだと目星がついたので、のんびり調べているうちにこんな記事を見つける。

※2012/06/07 追記

下記手順は Firefox12&Greasemonkey(0.9.20)まで有効だったが、Firefox13 ではさらに「ldrize.user.js」を修正する必要があることが判明。

詳細(というか対処療法)は別エントリに掲載予定。

Fascinating: Firefox10 で LDRize を使うには?

ldrize.user.jsの修正だけでよいのなら、すぐに記事もアップされるだろう……と待ってみても、一向に更新されないので自分でどうにかすることを決意する。2〜3日の遅れとあなどるなかれ、拙速が尊ばれる部類の記事もあるのだ。特にこれはそう。そうに違いない。
(ところでblogspotにトラックバックってできないのね。Googleのサービスは時々こういうところで片手落ちなのが解せない)

調査

週末になってちょっと時間ができたのでLDRizeをいじる。安直にconsole.log使ってプリントデバッグ。今から考えるとエラーを吐かない種類の問題点だったので、こうするしかない。

途中までは順調だったが、 LDRize Class の中の initSiteinfo から先にたどれなくなる。

  initSiteinfo: function(){
	  var filter2 = function(arr, fn){
		  var res=[], tmp;
		  arr.forEach(function(arg){if(tmp=fn(arg)) res.push(tmp)});
		  return res;
	  }
	  try{
		  this.siteinfo_available = filter2(this.siteinfo_all, function(arg){
			  var s=new Siteinfo(arg);
			  return s.isAvailable() && s;
		  });
		  return this.siteinfo_current = this.siteinfo_available[0];
	  }catch(e){
		  this.disable = true;
		  return false;
	  }
  },

filter2 に渡される無名関数の中で、 var s=new Siteinfo(arg) が複数回実行されるところまでは確認できるのに、その続きで死んでいる。
arr.forEach だといつ死んでいるのか明確でないので、同じ動作をするfor文に書き換えて( for(var i = 0; i < arr.length; ++i) )、ループの何回目で死んでいるのか確認。 arr.length も出力してみて、明らかにループ途中で止まっているのを確認。具体的には590ちょっとのSITEINFOがあるところ、174回目( i = 173 )でエラーも吐かずに落ちている。

174回目にあたるSITEINFOを確認すると、

アイテム詳細: google sites


name google sites
domain //b[@class="powered-by"]/a[contains(@href, "sites.google.com")]
disable
paragraph id("sites-canvas")/descendant::*[self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6]
link
view
stripe
height
exampleUrl http://wiki.slash-reader.com/

アイテム: google sites - データベース: LDRize - wedata

明らかにdomainがあやしい。

犯人

順当に今度は isAvailable の中身の確認に入る。場所としては Siteinfo Class 内の isAvailable 。

  isAvailable: function(){
	  try{
		  if((this.domain == true || this.domain == 'microformats') &&
			 $X(this.paragraph).length){
			  return true;
		  }
		  if( this.domain.length && location.href.match(this.domain) && (this.disable || $X(this.paragraph).length)){
			  if(this.disable) throw 0;
			  return true;
		  }
		  if($X(this.domain).length && (this.disable || $X(this.paragraph).length)){
			  if(this.disable) throw 0;
			  return true;
		  }
	  }catch(e){
//		  log(['errer', info]);
		  if(e==0) throw 0;
	  }
	  return false;
  }

ふたつ目のif文が機能していないことが分かる。やっぱりdomainがあやしい。
&& で区切られている真偽値の判定を、ひとつひとつがif文になるよう入れ子状に書き換えて、console.logを挟む。
ということで、実用編で述べている問題の箇所をあぶり出せた。

こういうことだ。

まとめ

javascriptの動作として考えると、LDRizeが動かなくなった要因は、

ということなので、短くまとめると、

  • Firefoxの仕様が少し変わった
  • 特に正規表現RegExp)まわりで変わった
  • matchに文字列渡すと、内部では正規表現オブジェクトへと暗黙の変換をしているはず
  • 暗黙の変換がエラーを吐かない
  • つまり不正な文字列を渡すとエラーを吐かずに死ぬのでデバッグが超大変
  • 明示的に変換して渡してやるといい
  • 明示的な変換の段階でエラーが出る

以上。

感想

正規表現オブジェクトの動作は、これがバグじゃなかったら何なんだという感じなので、おそらくFirefox13.01あたりになったら直っているんじゃないだろうかと思う。もちろんそれまでLDRizeなしで過ごす気はないのでさっさと対策を施してしまうほうがずっといい。