2008年12月14日日曜日

jquery + jquery-sizzle.js のセレクタの違い(2)

jquery + jquery-sizzle.js のセレクタの違い(2)

昨日の続き

jglycy を動かすための改造

jglycy が動かない原因は sizzle の セレクタの場合 HTMLElement が持っているプロパティとして存在する属性以外は取得できなくなっているから
で、その問題の行は jquery-sizzle.js の 561行目

561行目 var result = elem[ match[1] ], value = result + "", type = match[2], check = match[4];

match[1] には $('[xxx]'); とした際の xxx が入る。 elem.className や elem.id などは存在するが
elem.jg などと言うものは存在しない。
(xxx が class の場合は preFilter で className に変更されている)

elem.getAttribute(name) としてならば jg は取得できるので以下のように変更することで利用できるようになる。

var result = elem.getAttribute(match[1]), value = result + "", type = match[2], check = match[4];


ただし、この場合 preFilter の ATTR で class -> className と変更されているので [class] が使えなくなる。
275行目を削除する必要がある。
(elem.getAttribute() の場合は class , elem のプロパティは className と名前が違う。)

275行目 "class": "className"

削除するのも嫌だし、速度も多少遅くなりそうな気もするので、以下のように Sizzle.selectors を拡張し、
[@xxx] とした場合は、jg など定義されていない属性値も取れるようににした。
(速度は計っていないので近いうちに・・・遅くならないならこんなことする必要もない)


Sizzle.selectors.match.EXTATTR = /\[@((?:[\w\u0128-\uFFFF_-]|\\.)+)\s*(?:(\S{0,1}=)\s*(['"]*)(.*?)\3|)\]/
Sizzle.selectors.filter.EXTATTR = function(elem, match, i, array){
var result = elem.getAttribute(match[1]), value = result + "", type = match[2], check = match[4];
return result == null ?
false :
type === "=" ?
value === check :
type === "*=" || type === "~=" ?
value.indexOf(check) >= 0 :
!match[4] ?
result :
type === "!=" ?
value != check :
type === "^=" ?
value.indexOf(check) === 0 :
type === "$=" ?
value.substr(value.length - check.length) === check :
type === "|=" ?
value === check || value.substr(0, check.length + 1) === check + "-" :
false;
}


また、この変更をするだけでは jglycy は動かないので jglycy の 27 行目を以下のように変更する。

$[jg].invoke($("*[" + prefix + "]", node));

$[jg].invoke($("*[@" + prefix + "]", node));

これで動作するようになる

ここまでやって 対象を絞るために htmlに準拠しない attribute を追加するよりも、 class="jglycy" と
書くようなのでもいい気がしてきた。

こんな感じ?
<a href="" class="jglycy" jg="xxxx" jg:xxxx="aaa:'bbb'">link</a>

ちょっと長くなるのが嫌ならこんな感じかな、この方がシンプルか
<a href="" class="jglycy" jg="xxxx:{aaa:'bbb'}">link</a>


これで動くための jqlycy の変更はまた今度

2008年12月13日土曜日

jquery + jquery-sizzle.js のセレクタの違い(1)

sizzle については 「高速な CSS セレクタエンジン「Sizzle」「Peppy」を試す 」 を参考にさせてもらいjquery用に作成。


一部のプラグインがどうしても動かないので、セレクタ内部を調査してみた。

jQuery の 標準のセレクタの attribute 部分の正規表現

1441行目 /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/

sizzle の attribute 部分の正規表現

267行目 ATTR: /\[((?:[\w\u0128-\uFFFF_-]|\\.)+)\s*(?:(\S{0,1}=)\s*(['"]*)(.*?)\3|)\]/

見た目からして違っているが、最初に気づく違いは @? の部分

jquery の場合 $('a[@href]') のようにかけるけど
sizzle で同じように書くと例外が発生する。sizzle の場合 $('a[href]')であれば問題ない。

と言うわけで、 対象プラグインの @href を href に変更し動くようになった。
sizzle側の正規表現の「 \[ 」の直後に 「 @? 」 と追加しても動くようになるが、sizzle のバージョンアップ時に問題が出るのでお勧めできない。

と言うか、これは仕様なのかバグなのか・・・。

次回は jglycy が動かないのでその対応を考えようと思う。
そもそも html に存在しない属性は取れなくなってるような気がするけど。


追記

@ を使う書き方どこかでできたよなぁとなやんだけど、たぶんXPathかなという結論に
CSSで @はimportとかそのあたりくらいしか見つからなかった。

2008年11月22日土曜日

jQuery プラグイン : Ajax で読み直してもイベント再登録不要にする

reglib versus JQuery に触発されて
機能としてほしくなったので一部を jQuery で実装してみた。
#Ajax で画面ロードしたときイベント登録しなおしたくない


実装したのは、DOM を再構築してもイベント登録が消えない部分。
DOM 構築までイベントが登録されない点は悪い面と良い面があるのでとりあえず不要かな。

jquery.hijack.js

まだ click イベントでしか動作チェックしてないのでご利用は自己責任でお願いします。
名前を適当につけちゃったので名前も募集してます。

こんな変な実装ダメよとかあったらご指摘いただけるとうれしいです。

===使い方===
・イベント登録
$.hijack.click(selector, function);

click以外のイベントでもOK
selector には イベント対象になる要素を選択するための jQuery のセレクタ を入力
function には イベント発生時の処理を記載する。

例)
$.hijack.click('#click', function(){alert('click!');});

id="click" を持つ要素をクリックすると click! とアラーとを出す。

なお、function は 引数として event オブジェクトをとり、 function 内部での
this は イベント発生したオブジェクトなので、いままで通常のイベント登録で
登録していたものも利用可能(のはず)。


その他メソッド
・イベント登録
$.hijack.bind(event, selector, function);
これでも登録可能、第一引数にイベント名、第二引数以降はセレクタと関数を入れる。

・イベント削除
$.hijack.unbind(event, selector, function);
引数は上と同じ、ただし引数は必須ではない。
引数がない場合、すべてのイベントを削除する。
引数を増やすごとに削除するイベントが制限される。

$.hijack.unbind('click'); ならば click イベントすべて削除
$.hijack.unbind('click', 'a'); ならばアンカータグへの click イベントをすべて削除

と言った感じ

jQuery + IE6 ではまった

Ajax で json を取得して json で持っている HTML 要素と入れ替えようとしたときに
IE6 でだけどうしても重くて仕方なかった。

コードはこんな感じ

function(json){
var html = $(json.html);
$('#main').empty().append(html);
}
#json は HTML のほかにいろいろ入っている

html が小さければ特に問題ないけれども、ある程度以上のHTMLを挿入しようとすると
とたんに重くなってずっと悩んでいた。
#実際 Firefox だと 400ms なところが、IE だと12000ms くらいかかる。

empty が重いのか? append が重いのか?と悩んでいたが、重かったのは $(json.html) の部分。

以下のようにして解決。コードもすっきり。
function(json){
$('#main').html(json.html);
}

それでも大きい HTML だと 1000ms くらいかかるけど、もう仕方ないかなぁ

2008年9月20日土曜日

Smalltalk ベストプラクティスパターンを読んでのメモ2

これの続き



Comparing Method


オブジェクト同士を並び替えたいときは比較用メソッドを定義しよう
メソッド名で le だと分かりにくい気もする。lessThanOrEqual のほうが良いか。。。
<=って書きたい。


class Event {

public function le($anEvent) {
return ($this->timestamp <= $anEvent->timestamp);
}

}



Reversing Method


メッセージの流れをスムーズに。
よくわからないけど


class Point {

public function printOn($asStream) {
$this->x->printOn($asStream);
$asStream->nextPutAll('@');
$this->y->printOn($asStream);
}

}


class Stream {
public function _print($anObject) {
$anObject->printOn($this);
}

}
class Point {
public function printOn($asStream) {
$asStream->print($this->x);
$asStream->nextPutAll('@');
$asStream->print($this->y);
}

}



Method Object

たくさんの引数や一時変数であふれているメソッドを単純化する。


class Obiligation{

public function sendTask($aTask, $aJob) {
//一時変数いっぱい
$notProcessed = null;
$processed = null;
$copied = null;
$executed = null;
// たくさんの処理
}
}



class Obiligation{

public function sendTask($aTask, $aJob) {
//一時変数いっぱい
$notProcessed = null;
$processed = null;
$copied = null;
$executed = null;
$this->prepareTask($aTask, $aJob, $notProcessed, $processed, $copied, $executed);
}

public function prepareTask($aTask, $aJob, $notProcessed, $processed, $copied, $executed){
//ComposedMethodで処理を請け負うと引数が多くなりすぎ、コード量の削減にもならない
}
}



class TaskSender{
private $obiligation;
private $task;
private $job;
private $notProcessed;
private $processed;
private $copied;
private $executed;

public function __construct($anObiligation, $aTask, $aJob) {
$this->obiligation = $anObiligation;
$this->task = $aTask;
$this->job = $aJob;
}
public function compute(){
//ここにたくさんの処理。
}
}

class Obiligation{

public function sendTask($aTask, $aJob) {
$taskSender = new TaskSender($this, $aTask, $aJob);
$taskSender->compute();
}
}



Execute Around Method

続けて実行しなければならないアクションのペアを表現

class Cursor {
public function showWhite($aBlock) {
$old = null;
$old = Cursor::currentCursor();
$this->show();
$aBlock->value();
$old->show();
}
}

class File{
public function openDuring($aBlock) {
$this->open();
$aBlock->value();
$this->close();
}

}


class File{
public function openDuring($aBlock) {
$this->open();
try{
$aBlock->value();
}catch(Exception $e){
//更に例外を投げるならその前に$this->close()をする。
}
$this->close();
}
}



Debug Printing Method

デバッグ用のメッセージを出力する。


class Association{
public function printOn($asStream) {
$asStream->print($this->key);
$asStream->nextPutAll('->');
$asStream->print($this->value);
}
}


Method Comment
メソッドのコメントの書き方

メソッドの先頭にコメントを書き、コードから明白に読み取れない重要な
情報を伝える。

2008年9月15日月曜日

Smalltalk ベストプラクティスパターンを読んでのメモ1



PHPで書いてみる。

3 振る舞い
3.1 メソッド

ComposedMethod


1つのことのみするメソッドに分割しよう。


class Controller{
public function controlActivity() {
$this->controlInitialize();
$this->controlLoop();
$this->controlTerminate();
}
public function controlInitialize(){
//初期化
}
public function controlLoop(){
//ループ処理
}
public function controlTerminate(){
//切断
}
}


Constructor Method

インスタンス生成時にいろいろな引数を渡したいときは適切に作ってくれる
メソッドを用意しよう。


class Point{
public function __construct($x, $y){
// .....
}
public function Polar($r, $theta) {
$x = $r * cos(deg2rad($theta));
$y = $r * sin(deg2rad($theta));
new self($x, $y);
}
}

new Point(1, 1);

Point::Polar(sqrt(2), 45);


Constructor Parameter Method

インスタンス変数を一度に設定するメソッドを定義しよう


class Point {
public function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
}



class Point {
public function __construct($x, $y) {
$this->_setXY($x, $y);
}
private function _setXY($x, $y) {
$this->x = $x;
$this->y = $y;
}
}




Shortcut Constructor Method
ショートカットメソッドを定義しよう

こんな感じ?


class Number {
public function __construct($x) {
$this->x = $x;
}
public function getPoint($y){
return new Point($this->x , $y);
}
}

$number = new Number(1);
$point = $number->getPoint(2);



Conversion

オブジェクトのプロトコルを増やすのではなく、別のオブジェクトに変換しよう

Converter Method

オブジェクトを同一プロトコルのオブジェクトに変換するメソッドを用意しよう
メソッド名はasXXXとする。

こんな感じ?微妙・・・

class Collection {
private $collection = array();
public function __construct(array $array = array()){
$this->collection = $array;
}
public function asSet() {
return array_unique($this->collection);
}
}

class Number {
public function __construct($x){
$this->x = (int)$x;
}
public function asFloat() {
return (float)$this->x;
}
}



Converter Constructor Method

変換もとのオブジェクトを引数として受け取りインスタンスを生成しよう


Query Method
真偽値を返すメソッドを用意しよう。メソッド名はisXXXとする。


class SwitchClass {
public function makeOn() {
$this->status = 'on';
}
public function makeOff() {
$this->status = 'off';
}
public function status() {
return $this->status;
}
}

class WallPlate{
public function __construct(){
$this->switch = new SwitchClass();
$this->lignt = new Light();
}
public function update() {
if($this->switch->status == 'on'){
$this->lignt->makeOn();
}elseif($this->switch->status == 'off'){
$this->lignt->makeOff();
}
}
}




class SwitchClass {
public function makeOn() {
$this->status = 'on';
}
public function makeOff() {
$this->status = 'off';
}
public function status() {
return $this->status;
}
public function isOn() {
$this->status == 'on'' ? true : false;
}
}

class WallPlate{
public function __construct(){
$this->switch = new SwitchClass();
$this->lignt = new Light();
}
public function update() {
if($this->switch->isOn){
$this->lignt->makeOn();
}else{
$this->lignt->makeOff();
}
}
}


続く

2008年9月7日日曜日

is_readable について

is_readable だと include_path を見てくれないようなので、以下の2つをつくって
どちらが早いか試してみた。isReadable は Zend_Loader での実装。



class readable {

public function test() {
$time1_s = microtime(true);
for($i = 0; $i < 2000; $i++ ){
self::isReadable('spyc/spyc.php5');
}
$time1_e = microtime(true);

$time2_s = microtime(true);
for($i = 0; $i < 2000; $i++ ){
self::isReadable2('spyc/spyc.php5');
}
$time2_e = microtime(true);

Zend_Debug::dump($time1_e - $time1_s);
Zend_Debug::dump($time2_e - $time2_s);
}

public static function isReadable($filename){
if (!$fh = @fopen($filename, 'r', true)) {
return false;
}
@fclose($fh);
return true;
}

public static function isReadable2($filename){
$ret = false;
$paths = explode(':',get_include_path());
foreach($paths as $path){
if(is_readable($path. '/' .$filename)){
$ret = true;
break;
}
}
return $ret;
}
}

※ get_include_path は . 以外に2つのディレクトリを返し、spyc/spyc.php5は最後のディレクトリに存在する。

1回目
float(1.2477900981903)

float(0.3044650554657)

2回目
float(1.3001132011414)

float(0.31661415100098)

3回目
float(1.3001132011414)

float(0.31661415100098)

と isReadable2 が圧勝。clearstatcache()を isReadable2 の中に追記しても+0.2秒程度。

2008年9月6日土曜日

週に一度、日曜日に自問すべき20の質問

やらなきゃいけないこととか、やらなくてもいいこととか、やりたいこととか
やったほうがいいこととか、いろいろあって、いろいろごちゃごちゃで最近すごく大変。

自分のキャパの狭さに唖然となりつつ、少しずつでも成長していかないとと。

で、今日ちょっと巡回してたらこんなエントリが

週に一度、日曜日に自問すべき20の質問



  1. 先週何を学んだか?
  2. 先週一番の達成は何か?
  3. 先週思い出に残った瞬間は?その理由は?
  4. ・・・・・・


とほかにもあり、全部で20個ちょっと。多いけど、ずっとこの内容を気にし続けるわけではなくて週一回のみだから続くかも。

といいつつ、多いと三日(3週?)坊主になりそうだったので、なやんでたけど、昔の記事で
以下のエントリがあったので、まずは7つから来週金曜から毎週にメールするように
Googleカレンダに登録てみました。

あなたの人生を変える、たった7つの魔法の質問



慣れてきたらいろいろ変更したり増やしたりしていこう。

2008年9月4日木曜日

独自ドメインに変更

独自ドメイン使えるのかなぁ?と調べたら意外と簡単に使えたので設定

まずはドメインの参照先を ghs.google.com. へ変更。
※なんか最後の「 . 」がポイント?

そのドメインのページを開いたときに Server Not Found になれば自分の環境ではOK
※ISPなどにより伝播の速度が違うので、場合によっては2,3日見たほうがいい

Blogger の設定 の「公開中」→ 「カスタムドメイン」 → 「アドバンス設定に切り替え」として、ドメインを入れて終了

GoogleAnalytics の設定変更とかできるのかなぁ・・・

2008年8月25日月曜日

JavaScript の new 演算子についてのメモ

先日会社の勉強会で教わったのだけど、忘れそうなのでメモ。
勘違いして覚えてるかも・・・


function dummyObject(x,y){
this.x = x;
this.y = y;
}

var newObject = new dummyObject(2,5);


new で 空のオブジェクト作成

参照先として、自分自身のプロトタイプ (dummyObject.prototype) を設定

作成した空のオブジェクトを this として、引数はそのままで、関数の中身を実行。

左辺の変数に作成した空の(既に空じゃないけど)のオブジェクトへの参照を渡す。

この際の this.x , this.y は外部からは以下で参照できる。

newObject.x // 2
newObject.y // 5

以下のようにした場合はどうなるか?

var newObject = dummyObject(2,5)

newObject.x //undefined
newObject.y //undefined

this には window オブジェクトが入るため、参照できない。
参照する場合は、以下のような感じ。

window.x // 2
window.y // 5

=-=-=-=-=-=-=-=-=-=-=-=-=-=

ここからはブラウジングしてて以下の内容を見つけたので、参考(ほとんどそのままだけど・・・)にさせてもらいました。

【jQuery】Simple Class  Instantiation


以下のように定義すればいろいろ回避?
new した際は必ず this instanceof arguments.callee が true になるのか気になる。


function dummyObject(x,y){
if(this instanceof arguments.callee){
this.x = x;
this.y = y;
} else {
return new arguments.callee(x,y);
}
}




可変長引数の場合どうしたらいいんだろ・・・

function dummyObject(){
if(this instanceof arguments.callee){
this.init.apply(this,arguments);
} else {
return new arguments.callee(ここの引数が分からない);
}
}


return new arguments.callee(arguments); とすると applyの際に [arguments] が渡るし・・・

と思ってもう一回よく読んだら答えが書いてあった・・・
第一引数が callee プロパティを持っていたら内部で new したこと確定か。。。
今日一日悩んでて気づかなかった。orz

function dummyObject(args){
if(this instanceof arguments.callee){
this.init.apply( this, args.callee ? args : arguments );
} else {
return new arguments.callee(arguments);
}
}

2008年8月23日土曜日

Adobe Flex 3リファレンスガイド の関連項目のリンク先についてメモ

たとえばこのページの関連項目のリンク先は以下だけれども、開いてみると404 になる。

http://livedocs.adobe.com/flex/3_jp/about_dataproviders_1.html

で、最初はどうでもよかったんだけど、どうしたら見れるんだ!?と悩んだ結果以下のようにすると見れることが分かった


http://livedocs.adobe.com/flex/3_jp/html/help.html?content=about_dataproviders_1.html


以下のURLだと上のURLにリダイレクトされるので、こちらでもOK
http://livedocs.adobe.com/flex/3_jp/html/about_dataproviders_1.html


adobe に修正のお願いをしようと思ったけど、メールアドレスが見つからないので挫折した。
さすがに ドメインの登録アドレスに送るのなぁ・・・

2008年8月5日火曜日

Eclipse で mxml の コード補完

EclipseでFlex (でぃべろっぱーず・さいど) を参考にさせてもらってFLEX3でswfの作成はできたけれども自動補完に慣れてしまっている所為か思うようにmxmlを書けず1月ほど悩んだ末にやっと、自動補完をできたのでメモ

自動補完をするには、WTP?WST?が必要。もしかしたらほかのxmlエディタでもできるかも

まず、最初に以下のサイトから flex3.xsd をダウンロード
http://code.google.com/p/xsd4mxml/



ダウンロードしたファイルを適当なところに保存して、
Preferences → Web and XML → XML Catalog で追加



General → Content Types 内の XML を選択肢、*.mxmlを追加

以上で、終了。
General → Editors → File Associations にも *.mxml を追加したけど
必要なのかは不明


これで、mxmlファイルを開くと 色はついてるし、ctrl + Spaceで補完候補はでるし
やりやすくなった。


とはいえ、HTMLと違ってよく分からないので絞り込めず候補が多すぎてすぐには使えない・・・

まずはリファレンスをしっかり読むか・・・

2008年5月9日金曜日

jQueryとjGlycy

jQueryプラグイン呼び出し用ライブラリjGlycyを使ってみた。


使ってみて、どうしても重い気がするので、速度の違いを比較してみた。
比較はFirebugのプロファイラを使用


対象は以下。2chの板一覧をtreeviewでツリー構造にし、更に各板のリンクにはクリックで
イベントが発生するようにしている。(urlは#数字と適当)

jglycyを使って呼び出し。


ヘッドのスクリプトタグにwindow.onloadを記述し呼び出す。id/classを利用


bodyの閉じタグの後にスクリプトタグ埋め込み、即実行。


/**
* jquery.myOnClick
*
**/
(function($){
$.fn.extend({
myOnClick: function(options){
var opt = $.extend({
msg: 'yes'
}, options ||
{});
$(this).click(function(event){
id = event.target.hash.split('#')
console.log(id);
});
}
});
})(jQuery);


・結果(って5回しかやってないけど)
jglycy
Profile (3375ms, 89201 calls)
Profile (6796.875ms, 135056 calls)
Profile (3421.875ms, 89551 calls)
Profile (3390.625ms, 89401 calls)
Profile (3312.5ms, 88801 calls)

onload
Profile (4859.375ms, 105592 calls)
Profile (2609.375ms, 60308 calls)
Profile (2078.125ms, 59637 calls)
Profile (4812.5ms, 105730 calls)
Profile (2718.75ms, 60011 calls)

footer
Profile (5046.875ms, 105396 calls)
Profile (5312.5ms, 105451 calls)
Profile (2781.25ms, 59340 calls)
Profile (2578.125ms, 59131 calls)
Profile (2390.625ms, 59752 calls)

onload と footer は大して違わない、ちょっとonloadのほうが早い?誤差の範囲だとおもうけど、onloadの分遅くなると思ってたので意外。
jglycy は確実に遅いと思われる。2割前後遅くなってる感じ

回数少なすぎ&軽すぎるようにも思うので、もう少し時間のかかる処理を回数こなしてみたい。プロファイルの詳細の読み方がよく分からないので調べつつ、、、

invokeElement avg:3171msとかなってるので、各要素にイベントを登録するのに時間かかってるのが敗因か・・・

というわけで、やっぱり重いのでjglycyはやめる方向かなぁ。
使い勝手は悪くないので、どうしたら軽くできるか考えるのも面白いかも



あ、opt.msg使ってない・・・


---ちょっと追記
よく考えたらアンカーに登録しなくてもいいんだと思いついて変更。
親要素にイベント登録してみた。



Profile (2859.375ms, 59243 calls)
Profile (2375ms, 59185 calls)
Profile (2984.375ms, 59335 calls)
Profile (2218.75ms, 59288 calls)
Profile (2546.875ms, 59382 calls)

大して変わらない・・・jGlycyの各要素に1回1回登録以外は大して違いはないのか・・・

2008年4月21日月曜日

passengerで初めてのRoR(3)

Subversionへの登録

ここにあるのを上からやって終わり。
http://wiki.rubyonrails.com/rails/pages/HowtoUseRailsWithSubversion


次はモデルの作成。ボタン一発!位の気持ちでやったんだけどscaffoldでうまく生成できない

% script/generate scaffold boards id:integer name:string url:string

最初のエラー
undefined local variable or method `new_boards_path' for #

なぜか分からず、コンソールからDBにとりあえずデータを入れてみる。

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.to_sym

またエラー・・・ここで気になったのが、生成されるindex.html.erbの10行目から19行目のfor文

<% for boards in @boards %>

<%=h boards.id %>
<%=h boards.name %>
<%=h boards.url %>
<%= link_to 'Show', boards %>
<%= link_to 'Edit', edit_boards_path(boards) %>
<%= link_to 'Destroy', boards, :confirm => 'Are you sure?', :method => :delete %>

<% end %>

for で生成している boards とlink_toで使ってるboardsがかぶってる。。。エラーもlink_toの最初に出る行だし、、、なんて悩みつつ


で、いろいろ探してこちらのサイトでドンピシャな答えをいただきました。
http://www.smallmake.com/smalltalk/computer/2007/12/rails_the_error_evaluating_nil.html

答えは複数形・・・orz

こう変えて、解決しました。
% script/generate scaffold board id:integer name:string url:string
% rake db:migrate


本当はもっと紆余曲折あったけど、(scaffold の前にgenerate migrateしたり、それを消したりとか)コマンド履歴を見るとそのころは単数形で書いているので、どこでどうまちがったんだか・・・

Rubyの構文がまったくわかっていのが今日の敗因。そのせいであからさまに変数名がかぶってるのに、そういうものなのか?と思って放置してしまったり。

とりあえず、今日、「たのしいRuby」買いました。

2008年4月20日日曜日

passengerで初めてのRoR(2)

原因が分かった。たいした問題ではなかった・・・。

cp /usr/local/src/passenger-1.0.1/bin/passenger-spawn-server /usr/local/lib/ruby/passenger/

上記のように実行ファイルのみをコピーしていたけど、ライブラリ関連も必要な感。

以下のように移動する。
mv /usr/local/src/passenger-1.0.1 /usr/local/lib/ruby/passenger

あわせて、httpd.confも修正。一行目変更なしでもいいけど、一応。

LoadModule passenger_module /usr/local/lib/ruby/passenger/ext/apache2/mod_passenger.so
RailsSpawnServer /usr/local/lib/ruby/passenger/bin/passenger-spawn-server

動いた!

./script/generate controller index
touch ./app/view/index/index.tpl.erb

./config/routes.rbの下のほうに[# map.root :controller => "welcome"]という行があるので、
コメントアウトをはずして、welcopmeをindexに変更。

最後に、[./public/index.html]を削除すると、トップページがindex_contorllerのindexアクションに
変更される。

rm ./public/index.html

次はバージョン管理へ登録

passengerで初めてのRoR(1)

RoRを使ってみたいと思いmod_passengerを入れてみる

とりあえず、gemなんてコマンドはないので、ソースをDLしてコンパイルすることに

http://www.modrails.com/install.html

tar xzvf passenger-1.0.1.tar.gz

./passenger-1.0.1/bin/passenger-install-apache2-module

Checking for required software...

* GNU C++ compiler... found at /usr/bin/g++
* Ruby development headers... found
* OpenSSL support for Ruby... found
* RubyGems... not found
* Rake... not found
* Apache 2... found at /usr/local/sbin/httpd
* Apache 2 development headers... found at /usr/local/sbin/apxs
* Apache Portable Runtime (APR) development headers... found
* fastthread... not found

なんかエラーが出てとまった。gemは必要らしい。

仕方ないので、以下からDL、インストール
http://docs.rubygems.org/

tar xzvf rubygems-1.1.1.tgz
ruby setup.rb

インストール完了。コマンド名はgem18らしい

ついでにnot foundなRakeとfastthreadをインストール。gem大活躍

gem18 install rake --remote
gem18 install fastthread --remote
gem18 install rails

もう一度インストーラーを起動して、Enter何度か押してインストール完了(たぶん)

./passenger-1.0.1/bin/passenger-install-apache2-module

インストール完了メッセージメモ
--------------------------------------------
The Apache 2 module was successfully installed.

Please edit your Apache configuration file, and add these lines:

LoadModule passenger_module /usr/local/src/passenger-1.0.1/ext/apache2/mod_passenger.so
RailsSpawnServer /usr/local/src/passenger-1.0.1/bin/passenger-spawn-server
RailsRuby /usr/local/bin/ruby18

After you restart Apache, you are ready to deploy any number of Ruby on Rails
applications on Apache, without any further Ruby on Rails-specific
configuration!

Press ENTER to continue.


--------------------------------------------
Deploying a Ruby on Rails application: an example

Suppose you have a Ruby on Rails application in /somewhere. Add a virtual host
to your Apache configuration file, and set its DocumentRoot to
/somewhere/public, like this:


ServerName www.yourhost.com
DocumentRoot /somewhere/public


And that's it! You may also want to check the Users Guide for security and
optimization tips and other useful information:

/usr/local/src/passenger-1.0.1/doc/Users guide.html

Enjoy Passenger, a product of Phusion (www.phusion.nl) :-)
http://www.modrails.com/

srcディレクトリを参照するのも微妙なので、コピー

cp /usr/local/src/passenger-1.0.1/ext/apache2/mod_passenger.so /usr/local/libexec/apache22/
cp /usr/local/src/passenger-1.0.1/bin/passenger-spawn-server /usr/local/lib/ruby/passenger/


httpd.confファイルに以下を追記
LoadModule passenger_module /usr/local/libexec/apache22/mod_passenger.so
RailsSpawnServer /usr/local/lib/ruby/passenger/passenger-spawn-server
RailsRuby /usr/local/bin/ruby18


ServerName xxxx.reirou.jp
DocumentRoot "/path/to/project/public"
RailsEnv "development"
RailsBaseURI /

Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all



これで再起動

サーバーバージョンのところにPhusion_Passenger/1.0.1 って記載が出てきたので、とりあえずの
インストールは完了。のはず

と思って xxx.reirou.jp を開くもエラーが出るのでちょっと悩む。

Passenger error #2
Passenger thinks that the Rails application's "public" directory is "/path/to/project/public", but it doesn't seem to be valid.

結局railsのプロジェクト?を作ってないかららしい、
/path/to で以下のコマンドを入力して一応画面は表示された。

#rails プロジェクト名

と画面は出たけど、[About your application’s environment] をくりっくするとInternalServerError・・・

とりあえず、それはおいておいて、sqlite3を入れておくgem18 install sqlite3-ruby

WEBrick「./script/server」を使って試すと動作するので、問題はPassengerにある模様・・・

眠いのでまた明日。

2008年4月1日火曜日

Zend_Config自体をキャッシュする。

YAMLのキャッシュ はクラスを使い分けないといけないのが面倒だったので、ローダー的なものを作った。
ついでに、Zend_Config_Xml,Zend_Config_Iniもキャッシュできるように。

Rf_Config_Yamlもいじったのでその内容は以下
Zend_Configで YAML を使う


Configローダー的な何かはこちら

今回は、配列をキャッシュするのではなく、クラスそのものをキャッシュするように変更。


ロード時間のテストはしてないのでどのくらい違うのかは不明。

ToDo:ファイルの文法エラーなどの場合の動作は?
ToDo:可能であれば、タイムスタンプの確認でキャッシュファイルを消すように変更。

2008年3月29日土曜日

XHTMLでのGAタグ

XHTMLでgaタグがエラーをはいていたのでちょっと調べてみた。
理由はXHTMLではdocument.writeを使えないかららしい。

ちょうどjQueryを試していたので、DOM操作をするようにjQuery形式で書き換えてみた。


<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
var gaScript = unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E");
$('body:first').append(gaScript);
</script>

2008年3月11日火曜日

YAMLのキャッシュ@Zend_Cache

YAML というか Spyc は重いらしい、、、ということで、キャッシュして高速化を考えてみた。
せっかくなので、Zend_Config対応&Zend_Cacheを使ってみる。

参考:
cl.pocari.org:PHP 用 YAML パーサ spyc の結果をキャッシュする方法
http://cl.pocari.org/2006-03-17-2.html


キャッシュ関連を調べてるときに、簡単なYAML生成用スクリプトがあったので使わせてもらいました。
インデントをスペース二つにしたのと、$i <= 1000 にして。
(100000にしたらファイルが大きすぎるってSpycに怒られた^^; 1000でも1Mあるし問題なしということで。)

symfonyで開発日記:yaml形式のデータをfor文で大量生成
http://blog.symfony.jp/2007/09/25/making_yaml_by_phpcode/


とりあえず結果から。単位は秒。
Rf_Config_Yaml(wiki参照)利用の出力:float(8.76855)
Rf_Config_Yaml_Cache(wiki参照)利用の出力@キャッシュ前:float(9.34218)
Rf_Config_Yaml_Cache(wiki参照)利用の出力@キャッシュ後:float(0.099786)

か、簡単・・・

約100倍の高速化。Zend_Config にセットしてるので、実際はもう少し差が小さいかもしれない。
ただ、メガ単位のYAMLなんか使う気がないし、もっと小さいファイルだと誤差になりそうな気がする。。。

追記:
1k弱のファイルでやってみた。まあ、ちょっとだけ
キャッシュ非対応:float(0.019046)
キャッシュ前:float(0.038066)
キャッシュ後:float(0.016638)





Yamlロード用のZend_Config対応スクリプトは以下
http://www.reirou.jp/php/dokuwiki/doku.php?id=zend_framework:zend_config:yaml


アクション

class IndexController extends Zend_Controller_Action {
public function indexAction() {
$spyc_start = $this->getMicrotime();
$conf = new Rf_Config_Yaml('/path/to/config/sample.yml',null);
$spyc_end = $this->getMicrotime();
$spyc_f = (float)$spyc_end[0] - (float)$spyc_start[0];
$spyc_i = (float)$spyc_end[1] - (float)$spyc_start[1];
Zend_Debug::dump($spyc_i+$spyc_f);

$spyc_start = $this->getMicrotime();
$conf = new Rf_Config_Yaml_Cache('/path/to/config/sample.yml',null);
$spyc_end = $this->getMicrotime();
$spyc_f = (float)$spyc_end[0] - (float)$spyc_start[0];
$spyc_i = (float)$spyc_end[1] - (float)$spyc_start[1];
Zend_Debug::dump($spyc_i+$spyc_f);
}

private function getMicrotime(){
$mt = split(' ',microtime());
return $mt;
}
}

2008年2月24日日曜日

いつの間に!?

一部のファイルがコミットできない を直すために httpd.confをいじってみた。

いや、正確にはいじろうと思った・・・
けど、いじらなくてもコミットできるようになってた。

先週すこし変更したのが原因だと思うけどなぞだ・・・

2008年2月20日水曜日

公開リポジトリと非公開リポジトリ

akioさんに教えていただいた Alias が悪さしてるかもしれない件のテストをしようと思いApacheをいじってみた。

別件でいろいろはまってしまって、結局そこまでたどり着けなかった。
別件のほうは解決したので、メモとして残しておく。

今回サーバー内の svn 用のauthzファイルを書き換えた。
全リポジトリ読み込み可、書き込みは権限者のみだったのだけれども、あるリポジトリの匿名読み込みをとめたかった。

[/]
* = r
@user = rw


[repo1:/]
* = r
@user = rw

[repo2:/]
@user = rw
* =

[repo3:/]
@user = rw
* = r


最初に authz をこのように書き換えたところ、repo2 へのアクセスが 403 になってしまった。もちろん repo1 と repo3には read アクセス可能。

ここで、そもそも認証画面が出てこないことが問題だと気づけばすぐに分かったのだけれども・・・


最終的には、以下のように書いて解決。


<Location /svn>
DAV svn
SVNParentPath /path/to/svn/
AuthzSVNAccessFile /path/to/authz
AuthType Digest
AuthName svn
AuthUserFile "/path/to/passwd"

#<LimitExcept GET PROPFIND OPTIONS REPORT>
# require valid-user
#</LimitExcept>

</Location>
<LocationMatch "/svn/repo2">
require valid-user
</LocationMatch>


/svn 以下には認証をかけない
ただし、/svn/以下のディレクトリで、repo1 / repo2 以外のディレクトリは必ず認証をする。
正規表現にしたのは基本設定として認証が必要としたかったから。

↑正規表現間違ってた・・・

よく考えれば当たり前で、1時間も悩んだ原因がこれかと思うと泣けてくる・・・


しっかりした構成をするのであれば、公開と非公開はサーバーを分けたほうがいいだろうし、せめてディレクトリくらい分けようかなぁとおもったけど、めんどくさいのでやめた。


あ、最初から分けてれば悩むことなかったのか・・・orz

apache の設定と svn の設定とどちらもしないといけないのは面倒なので、どちらかだけで何とかなる方法ないかなぁ・・・

2008年2月18日月曜日

フォクすけぬいぐるみほしい!

http://foxkeh.jp/campaign/fx2/

相手の姿も映しつつ記念撮影はさすがに大変なので、Bでのみ応募してみた。
フォクすけ かわいいよ フォクすけ。


これだけではなんなので、お気に入り拡張紹介
以前軽く書いてるけどもう少し絞ってみる

1.All-in-One Gestures

これがないと生活に支障をきたします。マウスジェスチャー用拡張。
ついつい IE とかデスクトップでもジェスチャーしちゃって(^^;

2.IETab

Firefoxのタブ内にIEでレンダリングしてくれる優れもの。
URL毎に自動で使う/使わないを設定できるので、IE でないと開けないページとか登録しておくと便利。手放せません。

3.MR Tech's Local Install

いろいろできる拡張。拡張の遅延インストール(何秒か待たないとインストールできないやつ)を無効にしたりできる。というかそれ以外使ってないかも・・・もっといろいろできると思う

4.PDF Download

PDF へのリンクをクリックしたとき、勝手にブラウザ上で開いたりして重くて大変だけど、これを入れておけば、どうするか聞いてくれる。それだけだけど、すごくありがたい。

5.Tab Mix Plus

使ってる機能は、タブバーの多段表示 と タブ幅の指定(固定化)、新しいタブに読み込む動作の指定。
多段表示は 標準だと多くなったとき右にスクロールになるのを段表示してくれる。かなり楽。
タブ幅の指定は範囲を選べるけど、100~100で固定してる。タブの数でサイズが変わるのはすきじゃないから。
ほかにもマウスジェスチャとかいろいろあるけど、使ってない。

以上5つ。実際に入れてる拡張は10個強あるけど、ほかのはなくても最低これだけは!ってものを選んでみました。

番外編。最近で一番入れちゃいけないと思った拡張は AutoPager

いままでGreasemonkeyでGoogleなどの検索結果をページ遷移なしで出してたんだけど、単独の拡張があるならそのほうがいいのかな?と入れてみた。大失敗。
新しいページを読み込むたびにFirefoxが数秒固まる。XPath解析時にとまってるように思うけれども調べるのも面倒なので、すでに無効化済み。

2008年1月27日日曜日

PHPTAL 1.1.10 リリース

PHPTAL 1.1.10 released

* SPLインターフェイスの ArrayAccess と Countable のサポート
* added support for Countable and ArrayAccess SPL interfaces
tal:repeatでのイテレーターサポート強化、TAL_PATH式でのイテレーターのサポート(配列と同じように利用可能になったっぽい)

* スーパーグローバル変数のサポート
* added support for superglobals in php: TALES expressions,
php:_SERVER['PHP_SELF']のような記述法でテンプレート内でスーパーグローバル変数を利用できる。

* 標準のテンポラリファイルのディレクトリの取得に sys_get_temp_dir() を使うように変更。標準以外で使うためには、今まで通りPHPTAL.phpを読み込む前に定数に設定。
* changed default temp directory to use sys_get_temp_dir() . If this causes trouble, you can override it using define('PHPTAL_PHP_CODE_DESTINATION','/tmp/');

* PHPコードでのエラーが原因となるテンプレートの無効化を防ぐためにコード作成時とマクロ実行時のセーフティチェックを追加。
* added additional safety-checks to code generation and macro execution to prevent invalid templates from triggering PHP errors,

* XMLパーサーのバグ修正
* fixed small bugs in XML parser,

* 一部のエラーメッセージの内容の正確性の向上とエラーファイル・エラー行の報告の追加
* fixed few error messages to be more precise and report proper file/line,

* すべての例外を例外をPHP標準の例外からPHPTAL専用の例外処理に変更
* changed all exceptions thrown by PHPTAL to inherit PHPTAL_Exception.

2008年1月20日日曜日

PHPTALに属性追加

PHPTALのトリガーを使う際に、HTMLの属性もパラメータとして使いたいなぁと思い
phptal:attributeという属性を作ってみた。
実はそんなことしなくても取得できたりして・・・と悩みつつ。

使い方
以下のように属性として phptal:attribute="" を追加するとトリガー(テンプレート内でも)
のローカル変数($attr)の中に連想配列としてhtml属性を設定できる。

<input type="text" name="testName" value="testValue" class="testClass"
phptal:attribute="" phptal:id="TestTrigger" />




<?php
require_once 'PHPTAL/Trigger.php';

class TestTrigger implements PHPTAL_Trigger
{
public function start($phptalid, $tpl)
{
var_dump( $tpl->getContext()->attr);
}

/**
* Invoked after tag execution
* @var PHPTAL $tpl
*/
public function end($phptalid, $tpl)
{
}
}


出力

array
'type' => string 'text' (length=4)
'name' => string 'testName' (length=8)
'value' => string 'testValue' (length=9)
'class' => string 'testClass' (length=9)



コード
PHPTAL/Php/Attribute/PHPTAL/Attribute.php に保存



<?php
require_once 'PHPTAL/Php/Attribute.php';

class PHPTAL_Php_Attribute_PHPTAL_ATTRIBUTE extends PHPTAL_Php_Attribute
{

var $_pushContext = false;

public function start()
{
if(!array_key_exists('tal:define',$this->tag->talAttributes)){
$this->_pushContext = true;
}
$defineVar = 'attr';
$this->tag->generator->doSetVar('$ctx->'.$defineVar, 'array()');

foreach($this->tag->attributes as $key => $item){
if(!$key) continue;
$this->_defineVar = $defineVar.'[\''.$key.'\']';

if ($this->_pushContext && !$this->_pushedContext){
$this->tag->generator->pushContext();
$this->_pushedContext = true;
}
$this->doDefineVarWith("'$item'");
}
}


public function end()
{
if ($this->_pushedContext){
$this->tag->generator->popContext();
}
}

private function doDefineVarWith($code)
{
$this->tag->generator->doSetVar('$ctx->'.$this->_defineVar, $code);
}
}



PHPTAL上で使えるように以下のファイルを編集
PHPTAL/Namespace/PHPTAL.php



<?php

require_once 'PHPTAL/Dom/Defs.php';
require_once 'PHPTAL/Namespace.php';

require_once 'PHPTAL/Php/Attribute/PHPTAL/Tales.php';
require_once 'PHPTAL/Php/Attribute/PHPTAL/Debug.php';
require_once 'PHPTAL/Php/Attribute/PHPTAL/Id.php';
require_once 'PHPTAL/Php/Attribute/PHPTAL/Cache.php';
require_once 'PHPTAL/Php/Attribute/PHPTAL/Attribute.php'; <--追加

/**
* @package phptal.namespace
*/
class PHPTAL_Namespace_PHPTAL extends PHPTAL_BuiltinNamespace
{
public function __construct()
{
parent::__construct('phptal', 'http://xml.zope.org/namespaces/phptal');
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('tales', -1));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('debug', -2));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround
'attribute', 6));<--追加

$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('id', 7));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('cache', -3));
}
}

PHPTAL_Dom_Defs::getInstance()->registerNamespace(new PHPTAL_Namespace_PHPTAL());


2008年1月16日水曜日

Wiki作成

ある程度整理できた!
blogで書くのが難しいことに気づいたのでWikiにしてみた。

http://www.reirou.jp/php/dokuwiki/doku.php?id=start

切り分けは難しいけど、どうにかなるかなー