JavaScriptでRubyのArray#replaceのようなことをしたい

どういうことかというと、新しい Array を生成するのではなく同一オブジェクトのまま Array を破壊的に変更したいということ。

Rubyの場合

a = [1, 2, 3]
b = a.map {|e| e * 2}
a.replace(b)

# => [2, 4, 6]

と Array#replace を利用することで既存の Array を新しい Array で置き換えてしまうことができる。オブジェクトとしては同じものを指したまま内容を書き換えてしまうことができるわけだ。

JavaScriptの場合

古い知識のままだと結構面倒くさいんだけど、

スプレッド構文

  • JavaScriptMDN</a>

を使うと簡単にできる。

a = [1, 2, 3]
b = a.map(e => e * 2)
a.splice(0, b.length, ...a)

# => [2, 4, 6]

なるほどな。

PHPのサイトをcapistranoで自動deployしてみた

最近バックエンドのバックエンドの整備を進めています。今回は PHP でできたサイトを Capistrano で deploy できるようにしました。

構成

今回のサイトは Rails 風のディレクトリで言うと

...
  sub/
    app/
    public/
    setup_script*
DOC_ROOT/foo -> sub/publib
...

こんな感じになっていて、DOCUMENT_ROOT のツリーの外にある public/ への symlink を作成して、そこから app/ などのコードを読む、ちょっと変わった形の PHP 製の Web サイトです。

とても残念なことにオレフレームワークでできています。

準備

ruby と bundler gem は事前にインストールしておいてください。

上の sub/ に当たる手元のツリー上で

source :rubygems

gem 'capistrano'
  • 上の内容の Gemfile を作って
  • bundle install [–path vendor]
  • bundle exec capify
  • Capfile, config/deploy.rb の編集
  • bundle exec cap deploy:setup

releases, shared というディレクトリがない限り、ここまでは従来サイトを壊さずに、かつ何もcommitせずに行えます1

自分の場合は Capistrano そのものは他の Web サイトへの deploy や定型タスクの管理などに使っていたのでここでそれほど苦労はありませんでした。

できれば最初は Capistrano と相性のいいフレームワーク(Railsなど)で練習しておいた方がいいと思います。

setup 用のスクリプトは実際にサーバ上に展開されたあとに実行されるので、直しては commit して deploy、をくり返すことになります。ここで commit log がとても汚くなります。うぅ…。

今回の影響

上のツリーの中の

sub/

以下に直接 upload していたものが cap deploy:setup のおかげで

sub/
  releases/
  shared/

となり、sub/releases/ 以下への deploy になります。

従来は sub/ 以下で手作業で setup 用のスクリプトを叩いていたので、スクリプト内で自身からの相対パスでいろいろな作業をしていたんだけど、Capistrano から実行するには相対パスを絶対パスに直して実行する必要があります。

あとは releases/ が挟まっている場合とそうでない場合で DOC_ROOT がこのスクリプトから見て ../../ から ../../../../ にずれてしまうので、その対応をすれば ok となります。実際には実行するスクリプトが current/ 以下にあるので current が挟まっていると絶対パスを算出したときに 2階層ずれる、というパッと見分かりにくいコードになってしまいますが。

※ 開発環境などでは releases/ が挟まっていないので場合分けして従来通り動くようにしておかないとギャッとなります。

もともと考慮していたもの

たぶんこの準備ができているといないとで大きく作業時間が変わってきます。

  1. 全部バージョン管理する
  2. できるだけ設定は php.ini から分離させているので、一つのサイトだけを独立して扱いやすくなってる
  3. .htaccess などはスクリプトから自動生成
  4. このスクリプトは自身の置き場所からもろもろのパスを自動解決

このため必要なことのほとんどは setup 用のスクリプトを絶対パスで動くようにすることでした。

1 が地味にハードル高いかもしれません。実は古いサイトは無駄にファイルが多すぎたり開発者と更新者で触るファイルが混ざっていたり、そもそもバージョン管理を作業者全員に教えるのが大変とか様々な理由でバージョン管理していない場合があります。

今回のサイトは「全部」バージョン管理されています。ただし全員が中央のリポジトリにcommitできる形ではない変則的な運用になりますが2

バージョン管理は必須と考えた方がいいと思います。安心して使えるファイル群がどれなのかが一意に決まるし、「いつの時点」も revision や commit hash で容易に特定できるからです。もちろん組織に馴染まない可能性はありますが。

DOCUMENT_ROOTからのsymlinkで公開する方法は使える

今回のサイトの公開はもともと symlink の生成で行われるので、この link が切り替わらない限り従来の方法で deploy したサイトは壊れないということが大きな安心に繋がりました3

実は symlink 生成での公開になったのは当時としては苦し紛れだったんですが、今回はこれがとても役に立ちました。

実はDOCUMENT_ROOT 以下に直接ファイル置かない方がいろいろ便利かもしれません。

独自セットアップスクリプトはいつ動かす

deploy:restart hook に定義しました。今回はサーバの再起動は必要ないものなので、再起動させずにセットアップ用のスクリプトを動かすだけです。

まとめ

CI のときも思ったけど、ちゃんと自動化しておいてよかった。

  1. Capfile やconfig/deploy.rb は手元のものが使われるため。 

  2. このため wtnabe は普段自分用に git-svn を使いつつ「共有」用に hg も使うというアホなことをしています。 

  3. このスクリプト作成時や公開当初に Capistrano の current -> releases/XXXXXX の link 方式を意識していたわけではありませんでした。 

電話しながら端末の画面を見る

以前から思ってたんだけど、

Evernoteとか便利だからこれ「見ながら」電話するよね

ってことを実際にやった。

これまでは iPod touch + ガラケーだったので iPod touch 上のメモや資料を見るのはまったく苦労がなかった。しかし Android に一本化したらそうもいかない。耳のそばに端末を持っていくと画面が消える。なんか聞くと iPhone もそうらしい。で、顔から端末を離しても一瞬画面が現れるまでタメがある。うむ。ちょっと使いにくい。

というか端末を耳に付けたり離したりしながら話すのってこれハタから見たらすごく変だよな、きっと。

ということで以前 Skype を使った勉強会に参加するために買ったヘッドセットをペアリングしてバッグインバッグに放り込んでおくことにした。充電のことは考えてないし、まぁ普段は普通に持って電話するけどね。

※ Simplenote クライアントである Flick Note は電話番号がリンクにならずに電話掛ける手間が省けなかった。こういう細かいところでやはり Evernote には一日の長があるのぉ。

Sinatra on CGI はとりあえず諦めた

Sinatra

最近あちこちで聞くので試してみた。

  • WEBRick では動く
  • CGI ではダメっぽい

CGI で動かしてる人はいるんだけどやっぱ quick hack が必要らしい。

うーん、惜しいなぁ。

実は妙に DSL DSL してる昨今の Ruby 界隈はあんまり好きじゃなくて、Sinatra も DSL って説明を読む限りではあんまり好きになれそうにないなぁという印象だった。まぁでも中身はどうせ全部 library として追い出して書くんだし、そんなに気にしなくていいかもなぁという気になるくらいには期待していただけに素直に CGI で動かないのは痛い。いちいちアプリケーションサーバとか立てたくないんですよ。主目的は内部利用のものをサクッと作ることなので。

[追記 2009-09-02]高橋会長が CGI でうまいこと動かす感じの書き方を見つけたらしい。

SinatraをCGIでもThin等のアプリサーバでも使えるようにする書き方 - 思っているよりもずっとずっと人生は短い。

__PHP_Incomplete_Class を防ぐ富豪アプローチ

調べると session start が auto になってて必要なファイルが読み込めてませんとかいう間抜けな事例が多いこの問題は、別に session とは無関係にオブジェクトのシリアライズを使う場面でよく出くわす。

原因はいたってシンプルで、unserialize() しようとしているオブジェクトの必要としているファイルがすべて揃っていないとこういう現象が起きる。

そもそも unserialize() してできあがったオブジェクトというのはクラス名そのものは保持しているけれどもクラス定義も、もちろんメソッドも保持していないオブジェクトで、自身が保持しているクラス名の定義を、現在読み込んである PHP スクリプトから探し出して当てはめようとする。

当然この段階で include されていないクラス定義を利用することはできず、結果、__PHP_Incomplete_Class という特殊なクラスの宙ぶらりんなオブジェクトができあがる。くり返す。これは変数しか持っていない。メソッドと変数をパッケージにしたものがオブジェクトなのだから、メソッドがないオブジェクトなんて何の役にも立たない。

解決方法も簡単である。unserialize() の時点で必要なファイルがすべて読み込まれていればよい。

でもさ。読み込んだ先のクラスを定義しているファイルで読み込んでいるファイルも、ぜーんぶ準備してから unserialize() なきゃいけないってことになったらそのクラスは生のファイルの情報については何も隠蔽してくれないへっぽこクラスだと思わないかい?

そこでこういうのはどうだろう。

  1. すべての基本になるクラスを用意する
  2. そいつに以下のコードを用意する
function __sleep() {
  $this->_included = get_included_files();
  return array_keys( get_object_vars( $this ) );
}

function __wakeup() {
  if ( is_array( $this->_included ) ) {
    foreach ( $this->_included as $file ) {
      require_once( $file );
    }
  }
}

これでとりあえずクラスを定義しているファイルを読み込み忘れて incomplete なんちゃらになっちゃうミスは防げる。何段階にも読み込んでいて何が何やら訳が分からなくなっててもクラス定義を再現できる。

あーめんどくせ。

注意1 不必要なファイルの読み込みとクラスの再定義

問答無用で利用していたファイルを読み込み直すと、オブジェクトの呼び出し方によっては不必要なファイルを読み込むことがある。単に不要なだけなら問題ないが、このとき、クラス名がかぶっていると問題が起きる。PHP は同名のクラスを再定義することができないが、これは warning などではなく Fatal Error なのでそこでスクリプトがストップしてしまう。

PHP には名前空間がないし、これを避ける方法を考えるのは、とりあえず今は面倒くさい。ちゅーことで名前がかぶってるクラスを作るときには

if ( !class_exists( 'KLASS' ) ) {
  class KLASS {
  }
}

と定義する。work around バンザイ。どちくしょう。

注意2 ファイル名のリストによる serialized object の容量増大

オブジェクトの配列など、大量のオブジェクトを上の方法で serialize すると容量のふくれ方が半端でない。その場合はそれぞれのメソッドを上書きして

function __sleep() {
  return array_keys( get_object_vars( $this ) );
}

function __wakeup() {
  // 絶対に必要なファイルを自力 include
}

にしておくとよい。あるいはファイル名のリストを serialize して zlib で圧縮するという方法があるかもしれないが、serialize したオブジェクトの容量のふくれ方や必要なファイルの特定しやすさなどを加味して決めればよい。

ajax は組み込み向けかも

いやふと思いついたんだけど。

クライアントサイドの処理に期待して HTML に整形しないでデータ投げ返せるし、転送量も減らせそうだから負荷が減るんじゃないか的な話があるじゃないですか。あれに期待して HDD レコーダなんかの組み込みの Web インターフェイスは ajax にしていったらいいかも。

と思ったのは RD の Web インターフェイスの反応にいつもちょっとイライラするからなんだけど。まだ実際に番組登録とかの処理に入ってないんだからもっとサクサク返してきてよーと思うわけ。あとすでになんかブラウザの機能で戻るなとかそういう制限が加わってるので ajax になってもその辺は今と同じだし。

ただもっと十分に枯れないと危険かな。一度リリースしたらなかなかデバッグできないもんな。アップデートの強制適用とかできるんなら話は別だろうけど。

プログラミング言語を学んで、さて何を書く?

rubyco の日記のコメントに注目。難しい質問だな、これ。

まずこの人は言語そのものが初めてということなので、その言語のサンプルを片っ端から打ちこんで1動かすというだけでもよいような気がする。言語そのものが初めての場合、その言語では何を実現するのがどれくらい大変か、あるいはどれくらい簡単かなんて辺りがさっぱり分からないだろうから、「作りたいものを作れば?」と言っても背伸びしすぎてとんでもないものを作り始めて挫折しちゃうかもしれない。

あるいは言語そのものが初めてということは当然アルゴリズムも学んだことがないだろう2ということで、基礎的なアルゴリズムを学べる本(別にサイトでもなんでもいいけど)に手を出すというのもありだろう。個人的には簡単なゲームを題材にしたものがあればアルゴリズムの学習にいいと思っているので、そういうのが見つかればベスト。

ある程度慣れているんならその人のやり方(例えば rubyco さんはいきなりリファレンスを参照する方法を調べている)でやればいいんだけど、初めての場合はその初めての言語を学ぶ環境にもよるし、漠然としたままだと考えにくいなぁ。

  1. 打ち込む。これ大事。野球で言うと素振りみたいなもの。 

  2. 先にアルゴルズムからやる人なんていないよね? 

RDService で ok

その後のネット de ダビング

vrx(with 有線)×1
RDService(with 有線)
RDService(with 無線)

ということで

RDService + ffmpegX で無問題ということになりました。しかし 30分のムービーを Xvid(640*480, 1500kbps, High Quality, 2pass)にエンコードするのに3時間半orz 遅いぞ PPC G4 1GHz. おまけに Deinterlace とか Filter 掛け忘れたorz

しかしこんなこと普段やっとれんな。

※ 追記。フィルタ加えたら5時間半になったorz

  1. なんと転送始まりもせず 

おー

unison 楽やなぁ。あっちで編集してこっちで編集して、っていう環境の場合はめちゃめちゃ楽ですやん。これが synchronize ですか。いやー欲しかったわ、こんなの。そう言えば。

MPEG2 はエライ

「MPEG-2至上主義」の間違 (ITmeaid)

いや、エライんだよ。Microsoft と同じさ。

わざわざ違うフォーマットを選ぶにはそれなりのリスクを背負わなきゃいけない。リスクを背負う覚悟がないものは MPEG2 を選ぶべきだ。

だから私は AAC でも WMA でも Ogg でもなく mp3 を選ぶのよ。

そうきたか

はてな、グループウェアサービスを開始

  • グループを作れる。
  • キーワードをグループ内だけで利用できるという違いはあるが、要は日記である。
  • グループは公開にも非公開にもできる。

非公開にできるからって企業ユースか? グループウェアか? まーでも SSL でやってくれるならとりあえずサーバ管理しなくていいって意味ではいいかもしんない。はてなの日記の記法が分からないのでなんとも言えないけど、

  • 簡単に書けること
  • ディスクスペースは十分にあること(画像の活用は重要なので)
  • バックアップなんかの体制はどうなってんの?
  • 回線が十分に速いこと(別料金で高速回線てのはアリかも)

なんかがカギかな。

でもなー。個人的にはやっぱそのデータを自由に扱えるかどうかってすごく気になるんだよな。例えば WebDAV とか SSH で元データを取り出せるってんなら安心なんだけど。ブラウザのインターフェイス経由でしか取り出せませんてことだったら、大量になったデータをいっぺんに扱いたいって要求にはちょっと応えようがないわけで。まぁその辺を気にする人は自分でサーバ立てて頑張んなさいってことなんだろうけどさ。

(Web 2.0 時代は Web ベースでも API でって形みたいだ。)

マインドマップって昔ちょっとやったな

MindMapBBS

Zope プロダクト。面白いんだけど、これはクライアントサイドのパワーをえらく食うような。強烈 table レイアウトですよ。Flash とか Java を入れた方がいいんちゃいますか。

unison の profile 基本編

こんなもんか?

auto   = true
prefer = newer
ignore = Name .project
ignore = Name .trustudio.dbg.php
ignore = Regex .*CVS
ignore = Name *~
times  = true

..project と .trustudio.dbg.php は使っている人には分かるが eclipse の WebStudio(TruStudio)の作るプロジェクトファイルである。CVS 関連ファイルを自動で除外するような便利なオプションはないので、正規表現で .*CVS をまとめて除外している。emacsen 使いなので当然 *~ も除外。

この設定の場合、不要になったディレクトリの削除は自動的に反映されない。逆に prefer newer の影響で、消したはずのディレクトリを newer として書き戻そうとしてしまう。

ただ、unison の場合は rsync のようにいきなりは実行せず、こういう更新が反映されますよ、いいですか、で一度ユーザーに伺いを立てる(設定により回避可能)ので、それを見て、あ、このディレクトリはもう要らないんだった、と思ったら手で消してもう一度実行する、という方法を採ればいいかな? ちょっと微妙だけど、反映の方向が一意に決まらない場合はしょうがないだろう。

何はともあれこれでまた内職しやすくなったってことだ。

nifty さんよぉ

@nifty のセカンドメールを使っているのですが(取得したときは「追加アカウント」って言ってたんだけどな。こっちの方が好きだな。)、これの Web メールのインターフェイスががらりと変わりました。変わったのはセカンドメールだけじゃなくて Web メール全体的に変わったらしいのですが、セカンドメール用のフィルタリングの設定を、セカンドメールのパスワードで行うことができません。おいおいおい。わざわざ @nifty ID のパスワードを聞いてきやがります。おいおいおい。

前より使いにくくなっとるやんけ。

なんだか画面が華やかになったのはいいんだけど、新着の受信をポップアップで知らせてくれたり、なぜかプレビューがなくなったり、好みでない方向に変化しております。あーあ。まぁ @nifty に質実剛健なんて似合わないんだろうけどさ。もうちょっと考えようぜ。

About

例によって個人のなんちゃらです