jQuery.extendとjQuery.fn.extendの使いわけ
jqueryのextendメソッドですが、$.extendと$.fn.extendとなんか2種類あります。
今まではとりあえずみんなが使っている$.fn.extendばかり使っていました。
どちらも引数がひとつのオブジェクトの場合はjqueryを拡張するものだと思っていたんですが、全然違うものなんですね。
具体例として以下の記事に書いてある一文がわかりやすかったです。
$.extendは静的メソッドの追加、$.fn.extendはインスタンス・メソッドの追加。
http://www.atmarkit.co.jp/fdotnet/jqueryref/05core/core_11.html
少し疑問だったのは$.fn.extendは、jqueryのprototypeにプロパティを追加するという意味でした。
prototypeへの追加なのになぜnewせずに使えるのか?と今まで全く考えたこともなかったのですが、よくよく考えればjqueryは常にprototypeをフル活用しているのですね。
$("p")という関数が返すのはオブジェクト。
jqueryの中でreturn new jQuery.fn.init( selector, context, rootjQuery )としているんですね。
$.extendは、$.test = "test"、
$.fn.extendは、$.prototype.test = "test"
ということだと思います。
$.prototypeに直接追加しても問題ないのは、
function a(){function b(){}; b.prototype = a.prototype; return new b()}
みたいな感じでprototypeを代入しているんでしょうか。
$("p").testとして使いたい場合には$.fn.extendを使うってことですね。たぶん。
格好良いformを作りたいなぁ(jqueryとcss)
格好良いcheckbox作り。
まずは適当なcheckboxを用意。
p要素はボタンの代役をする要素です。
div要素はあると便利なので。
双方ともp,divである必要はありません。
<div> <input type="checkbox" id="chk1" /> <label for="chk1" class="notselected">犬</label> <p class='notselected'>クリック</p> </div>
ボタンとなるp要素がクリックされた時、
checkeboxのchecked属性を切り替えます。
check済みならばchecked属性をはずし、
未checkならchecked属性をつけます。
方法はいろいろあると思いますが、今回はclass属性を使いました。
selectedとnotselectedという2つのclassをclickイベントで入れ替えます。
(jquery使わせてもらいます。)
$("div p.selected").live("click",function(){
$(this).removeClass("selected").addClass("notselected");
$(this).parent().find("input:checkbox").removeAttr("checked");
})
$("div p.notselected").live("click",function(){
$(this).removeClass("notselected").addClass("selected");
$(this).parent().find("input:checkbox").attr("checked","checked");
})addClassとremoveClassでclass属性を入れ替えます。
removeAttr("checked")でchecked属性を削除できます。
読み込み後に生成される要素に関数をバインドするためにliveメソッドを使います。
あとはcssでselectedやnotselectedのスタイルを指定すれば良いでしょう。
animateメソッドを使っても良いかもかも。
最後にcheckboxとlabelをjqueryで消しちゃいましょう。
こうすればjavascriptがOFFでも、スタイルシートがOFFでも元のcheckboxが表示されることになるはずです。たぶん。
$("div input:checkbox , div label").css("display","none");p要素もjavascriptが無効の場合は表示されないように、javascriptで生成したほうが良いような気がしました。勘ですが。
$("div").each(function(){
if($(this).find("input:checkbox").attr("checked")){
$(this).append("<p class='selected'>クリック</p>");
}else if($(this).find("input:checkbox").attr("checked")==false){
$(this).append("<p class='notselected'>クリック</p>");
}
});最終的にこんな感じになりました。
毎度ながら欠陥がある恐れは十分あります。
<head>
<script type="text/javascript">
<!--
$("document").ready(function(){
$("div input:checkbox , div label").css("display","none");
$("div").each(function(){
if($(this).find("input:checkbox").attr("checked")){
$(this).append("<p class='selected'>クリック</p>");
}else if(!$(this).find("input:checkbox").attr("checked")){
$(this).append("<p class='notselected'>クリック</p>");
}
});
$("div p.selected").live("click",function(){
$(this).removeClass("selected").addClass("notselected");
$(this).parent().find("input:checkbox").removeAttr("checked");
});
$("div p.notselected").live("click",function(){
$(this).parent().find("input:checkbox").attr("checked","checked");
$(this).removeClass("notselected").addClass("selected");
});
})
-->
</script>
<style type="text/css">
<!--
.selected {
background: #ffcccc;
color: #ffffff;
}
.notselected {
color: #ffcccc;
background: #ffffff;
}
-->
</style>
</head>
<body>
<!--HTML-->
<div>
<input type="checkbox" id="chk1" />
<label for="chk1" class="notselected">犬</label>
</div>
<div>
<input type="checkbox" id="chk2" checked />
<label for="chk2" class="notselected">猫</label>
</div>
</body>
lxmlのetree.parseでStringIOが
lxml を使用して Python での XML 構文解析をハイパフォーマンスにする
を読んでターゲットパサーのとこを試してたんですが、etree.parseに渡すStringIOで失敗しまくったので書いときます。
とりあえずStringIOを初期化します。
s = StringIO('test')
s.tell() # 0 を返します
s.read() # test を返します
これはStringIOのインスタンスを作成すると同時に"test"という文字列を書き込んでます。
s.read()した時に"test"を返すということはファイルの現在位置は先頭になっているということなんですね。
s.tell()というファイルの現在位置を教えてくれるメソッドがあるので確認すると0が返ってきます。
このインスタンスにwriteメソッドで文字列を書き足すと初期化した時に書き込んだ"test"に上書きされてしまうんですな。
ちなみwriteした場合はファイルの現在位置は書き込んだ直後の位置を返すようです。
s = StringIO("test")
s.write('write')
s.tell() #5 を返します
s.getvalue() #write を返します
で、etree.parseに渡すStringIOインスタンスはxml文書の先頭(普通は0)を指した状態で渡さなければならないようで、
s.seek(0)
とすればいいようです。
普通に
StringIO('テスト ')
とインスタンスを作成すれば済む話なんですが一応。
macportsでvirtualenvとapacheとmod_wsgi
virtualenvで仮想環境を作ることが出来たので、これをmod_wsgi経由でapacheから利用できるようにしたいと思います。
過去にmacportsでwsgi_modを入れていたのでこれを使おうと思ったのですが、
確認したところインストールされているのはmod_wsgi@3.3_0+python26となっていてpython2.6を使用する設定になっている模様。
仮想環境はpython2.5にしたので1度deactivateにして再度インストールすることに。
sudo port install mod_wsgi -python25
しかしpython2.5を指定しても結局インストールされるのはmod_wsgi@3.3_0+python26。
うーん、ヴァージョンを下げなければpython2.5では入らないんですかね・・・。
悩んだあげく、よくわからず仮想環境をpython2.6に変更しました。
さて気を取り直してmod_wsgiを有効にするためapacheのhttpd.confを書き換えます。
macportで入れたapache2ならopt/local/apache2/conf/の中にあります。
54行目あたりのLoadModuleが羅列してある最後に
LoadModule wsgi_module modules/mod_wsgi.so
があることを確認します。なければ追加します。
続いてWSGIPythonHomeを設定します。
virtualenvwrapperで作成した仮想環境のパスを指定すればいいようです。
WSGIPythonHome ~/Test/Test1/
仮想環境はヴァーチャルホストで運用するのがいいかと思います。
virtualhostを設定して、Directoryディレクティブに以下の設定を書けば動かせるはずです。
<Directory "~/Test/Test1"> Options Indexes FollowSymLinks ExecCGI SetHandler wsgi-script AddHandler wsgi-script .wsgi AddHandler wsgi-script .py </Directory>
これくらい書いとけば取りあえず動くと思います。
Djangoでテストしてみる
せっかくなのこの環境でDjangoを動かしてみたいと思います。まずはworkon Test1としてpipでdjnagoをインストール。
設定については以下のドキュメントで詳しく説明してくれています。
Apache と mod_wsgi 環境で Django を使う方法
自分の仮想環境の設定では以下のような感じ。
httpd.conf
WSGIScriptAlias / ~/Test/Test1/django/django.wsgi
djnago.wsgi
sys.path.append('~/Test/Test1')
macportsでvirtualenv環境
virtualenvというサンドボックス環境を作ってくれるものが面白そうだったので手をつけてみました。
毎度のことながらmacportsを使った方法です。
まずはmacportsでpipを入れる。とりあえずGAEで使用しているpython2.5のやつを。
sudo port install py25-pip
コマンド名はpip-2.5になっていると思います。
sudo pip-2.5 install virtualenv
上記のようにコマンドを打ちvirtualenvをインストールしました。
pipでインストールしたものは/opt/local/lib/python2.5/site-packages に入ってます。
macportsから直接virtualenvをインストールすることも出来るみたいです。
あとはvirtualenv.pyを実行すれば勝手に環境を作ってくれます。
オプションにpythonのパスと環境を作成するディレクトリ名を指定します。
python /opt/local/lib/python2.5/site-packages/virtualenv.py --python=/opt/local/bin/python2.5 ~/example
このコマンドではHOMEにexampleという名前のディレクトリが作られ、
pythonの仮想環境が出来上がっています。
そしてこの環境に元のpythonに影響しないパッケージをいれてみました。
まず仮想環境のbin/activateをsourceで実行します。
source ~/example/bin/activate
するとシェルの表示が自分の環境では以下のようなものになりました。
(example)pc_name:~user_name$:
ここでwhich pipとすると~/example/bin/pipと表示されます。
仮想空間にpipがインスールされ、パスも通っているようです。
このpipを使いpip install django などとすると仮想環境へパッケージをインストールをしてくれます。
ありがたい。
virtualenvwrapperをついでにインストール。
さらに、これらの仮想環境を管理するvirtualenvwrapperという便利なものがあるそうなので、ついでに入れてみました。
macportsで入れた方のpip-2.5でvirtualenvwrapperをインストール。
sudo pip-2.5 install virtualenvwrapper
環境変数WORKON_HOMEを定義。このWORKON_HOME内で仮想環境が管理されます。
今回はTestというディレクトリを作り、それをWORKON_HOMEに指定してみました。
export WORKON_HOME=$HOME/Test
そしてsourceコマンドでvirtualenvwrapper.shを実行します。
自分の環境では以下の場所に入ってました。
source /opt/local/Library/Frameworks/Python.framework/Versions/2.5/bin/virtualenvwrapper.sh
WORKON_HOMEで指定した$HOME/Test以下に、モロモロがインストールされました。
postactivate , preactivate , get_env_details , hook.log , initialize ...etc
そして mkvirtualenv --help などとコマンドしてhelpが表示されれば、
virtualenvwrapperが動いていることになるんですが、ここで失敗。
ERROR: Found virtualenv in path as "no virtualenv in /usr/local/bin …
virtualenvへパスを通さなければいけないようです。
export PATH=/opt/local/Library/Frameworks/Python.framework/Versions/2.5/bin:$PATH
とパスを通したらmkvirtualenvを実行できました。
virtualenvwrapperでの作業の流れ。
Test1という名前のvirtualenv環境を作成。
mkvirtualenv Test1
Test1の環境を利用。
workon Test1
作業終了。
deactivate
Test1を削除。
rmvirtualenv Test1
mkvirtualenvで使いがちなオプション。
本家にインストールしたパッケージを使用しない。
--no-site-package
setuptoolsではなくdistributeを使う。
--distribute
pythonのヴァージョンの指定。
--python=/opt/local/bin/python2.5
最後にvirtualenv環境をmod_wsgiを使ってapacheと連携させたいと思います。
長くなったので次の記事に分けて書くことにします。
macportsからtomcat5をインストール
tomcat5をいれました。
google app engine でjava版を試してみたくなりjavaサーブレットを始めてみようと思い立ちまして。
自分の32bitMacにはjava6を入れられないのでtomcat5を選択。
インストールはmacportsで行ったので簡単でした。
sudo port install tomcat5
無事インストールが完了したら、
sudo launchctl load -w /Library/LaunchDaemons/org.macports.tomcat5.plist
とコマンドを打って、localhost:8080にブラウザからアクセス。
apache tomcat5のページが表示できれば成功です。
ちなみに止める時は、
sudo launchctl unload -w /Library/LaunchDaemons/org.macports.tomcat5.plist
/opt/local/share/java/tomcat5/conf にあるserver.xmlが設定ファイル的なもので、
ポート番号の変更などいろいろ設定できるようです。
あとは/opt/local/share/java/tomcat5/common/lib/
あたりに重要なものが入ってますんでクラスパスを通しておくと便利かも知れません。
tomcatは単体でもサーバーとして動作するのですが、
apacheとtomcatの連携というのを近いうちにやってみたいです。
