2012年7月21日土曜日

BEAR.Sundayミートアップ#0でLTしました

BEAR.Sunday meetup#0 (2012年7月19日開催)で
LTしてきました。

タイトルは
「Cena-DTA:リソース指向データ転送プロトコル」



Cena-DTAとは2009年の後半から考え始めて、2010年の春頃から開発を始めた技術です。一応、動くところまで持ってきましたが、開発方針で行き詰まってしまい、この一年ほど開発が止まってました。

BEAR.Sundayのmeetup#0に参加すること決めてから何かひらめく物が無いか考えてました。適当なキーワードを散りばめたツイートを書いたり…

そんなとき、LTしませんか?というツイートが!


即、応募しました。
何となく感じてたことを言葉にするいい機会です。

BEAR.Sundayとは関係ない話なのですが、
「気にしないで」という@koriymの言葉に励まされてLTしてきました。

珍しい内容だと思うので、何かの参考になればと思います。

リソース指向とURI


個人的には、
BEAR.Sundayは、全てをURIで表している、という話が面白かったです。

URIというのは間違った理解かも知れません。
ページも含めて、全てを表現するディレクトリ風階層構造、とでもいうのでしょうか。パッと見、URIのような記述

一方Cena-DTAは、ばっさりURIを切り落としてます。
少なくとも細かなリソースごとにURIを用意することはしてません。

これはアプリケーションのモデルが違うからかもしれません。
何しろ「クライアントデバイス上にしか存在してないデータもリソースとして考える」という無茶ぶりで理屈を構築してみたもので。


ともあれ、いまだ興奮冷めやらぬmeetupでした。

2012年7月17日火曜日

UbuntuでJavaが走らない(Error: could not open `/usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/amd64/jvm.cfg')

Ubuntuで快適に仕事していたが、
突然PhpStormが動かなくなった。

直接端末からPHPStormを起動したらJavaのエラーメッセージが出た。

Error: could not open `/usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/amd64/jvm.cfg'

そこで、端末から
java -version

と打ってみたら同じエラーが出た。
Javaのインストールエラーだ。

適当に修正



ちょっとググったが、ぴったりのがなかったので、
適当にcdしながら追いかけてみた。
cd /usr/lib/jvm/java-6-sun/jre/lib/amd64

何のことはない、上記のファイルはリンクになっていた。
jvm.cfg -> /etc/java-6-sun/jvm.cfg
リンク先を見ると、java-6-sunというディレクトリがない。
代わりに「java-sun」というのがある。

そこで
sudo ln -s /etc/java-sun/jvm.cfg .

としたら治った。

ググるより、自分で解決したほうが早そうな、珍しいパターンでした。

壊れた原因は・・・


思いつくのは、さくらインターネットさんでVPSを借りた。
Ubuntuをインストールするには、VNCクライアントが必要で、それを動かすためにJREをインストールした覚えがある。それで壊れたのか。

些細な原因ですが、いちいち面倒だな。
その点、WindowsやMac/OS Xとかは、きちんとしてそう。
その代わり有償だし色々と不自由だけど。

2012年6月20日水曜日

データベースでテーブル一覧を取得する方法

もう複数のDBについてまとめられてました。

◆PostgreSQLがなかったので追加。

ちなみに、このページから取得しました。
SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public'


2012年6月14日木曜日

PHP:COMでMSワードにアクセスするメモ

仕事がらみでPHPを使ってMS-Wordの中身を抜き出す方法を調べたメモ。

PHP:COMモジュール

PHPの標準で、MS-Wordを直接扱えるCOMモジュールが提供されている。
COMというのはOLE2の基盤技術のことで、アプリケーションから別のアプリケーションを呼び出して使うためのプロトコル(?)らしい。余り詳しくはないので、間違っているかも。

ともあれ、COMモジュールを使うには、
・OSがWindowsで、
・MS-Wordがインストールされている、
のが条件。
PHP:COMモジュール自体もウィンドウズ版でのみ提供されている。

自分の環境は、
Windows7(64bit)、MSOffice2003、XAMPP、という条件で動いた。

php.ini設定

php.iniの設定で、COMを使えるように変更する必要がある。
ここの実行時設定にあるディレクティブを、
デフォルトのままコメントを削除したら動いた。

dcomcnfgの設定

スターとメニューの「プログラムとファイルの検索」に
dcomcnfg
と入力して、dcomcnfg.exeを実行。
すると、こんなウィンドウが開きました。




後は…書くのが面倒なので、こちらの素晴らしいページを参考に作業を進める。

つまり、

1)コンポーネントサービス > コンピューター > マイ コンピューター
のプロパティを表示
2)プロパティタブの「COMセキュリティ」を選択
3)起動とアクティブ化のアクセス許可の既定値の編集
4)IUSR_を追加する
追加ボタン > 詳細設定ボタン > 検索ボタン > IUSRを選択してOK連打

といった感じで動きました。

Bookmarkとの連携

ワードをテンプレートの用に使うことが出来ます。
そのときに利用するのが「ブックマーク」という機能。

HTMLのフォーム要素のような存在です。
ブックマークにも名前があるので、名前を使って要素を指定し、要素の値を読み込んだり書き込むことがPHPから出来ます。

便利そうですよね。

サンプルコード

こんなので動きます。


$word = new COM( "Word.Application", NULL, CP_UTF8 ) or die( 'no word!?' );
$word->Visible = 0;
$word->Documents->Open( 'word.doc' );
// show all bookmarks
$num_bookmarks = $word->ActiveDocument->Bookmarks->Count;
for( $i = 1; $i <= $num_bookmarks; $i ++ ) {
    try {
        $mark = $word->ActiveDocument->Bookmarks($i)->Name;
        $wdMark = $word->ActiveDocument->Bookmarks( $mark );
        $range = $wdMark->Range;
        $range->Text = "#{$i}:$mark";
    }
    catch( Exception $e ) {}
}
$word->Documents[1]->SaveAs( 'word_new.doc' );

結構、問題が・・・

実際に動かすと分かりますが、
すべてのブックマークを読み込めませんでした。

また日本語を書き込むと後ろにゴミのようなものが・・・!

そこそこ動きますが、仕事に必要な精度は出せませんでした。

2012年6月13日水曜日

JavaScriptでBookmarklet


何となく、JavaScriptを使ったBookmarkletを作って見た。
ブックマークにJavaScriptを書き込んで、ページ上で走らせることができる。
参考:Bookmarklet - ブックマークレットを作成する際のポイント

使ったことはあったけど、自分で作ったことがなかったので
ちょっとやってみた。

基本形:

javascript:( function() { var v; /* do it */ })()



  1. 上の無名関数内に実行するスクリプトを書いて、
  2. 改行をとって(つまり一行にして)、
  3. ブックマークのURLの部分に貼り付けると
  4. Bookmarkletになる。


無名関数を使うのは、varで宣言された変数がローカルになるので。
上の基本形を元に作る方が安全と思う。

作ったブックマークボタンを押すと、表示されてるページでスクリプトが実行されます。

いくつか作ってみたので、解説でも。

inputタグの名前を抜き出す。


  1. 全input要素を抜き出して:document.getElementsByTagName("input")
  2. 要素をループして:for(i=0;i<theForms.length;i++)
  3. list変数に書き込んで:list = list + ','+theForms[i].name;
  4. alertとして書き出す:alert( list );

javascript:(function() { /* do something */ var theForms = document.getElementsByTagName("input");var list = '';for(i=0;i<theForms.length;i++) list = list + ','+theForms[i].name;alert( list );})()


inputタグの自動入力

今度はinputタグの名前を抜きだし、値として使ってみる。

javascript:(function() { /* do something */ var theForms=document.getElementsByTagName("input");var list='';for(i=0;i<theForms.length;i++) theForms[i].value=theForms[i].name;})()
開発していて、大量の入力フォームがある時に便利かなと思って作って見た。

想定どおりに動くんだけれど、数字のみにしたい、セレクト・チェックボックスなどに対応して内など、細かな問題が多くて使いづらい。

一行なので修正も動作確認も面倒だし、
Bookmarkletは使いどころが難しい、という感想。

2012年5月16日水曜日

DIを擬人化して理解してみる

Dependency Injection(DI)とか依存性の注入などと言われてもピンとこない。
仕方がないので、実験的に作っているAmidaMVCというPHPフレームワークでDIコンテナを自作してみました。

まぁDIとはこういうものかな?
というのを擬人化して説明を試みた結果です。

◆ DI以前のオブジェクトとは

あるオブジェクトが動作するため、別のオブジェクトに依存している状況を「依存性がある」と言います。依存性があること自体は問題はありませんが、
依存性が固定されている
のが問題と考えられます。

これを擬人化すると
「俺は、こいつと永遠に一緒だぜ」
となるのではないでしょうか?

コードで書くと

class foo {
  protected $love = NULL;
  function __construct() {
    $this->love = new \My\Love();
  }
}

というところでしょう。

一途というのはいいものだけれど、融通がきかない。
これを何とかするのがDIです。

◆ DI(依存性を注入する)

ようは
「誰とでもOK、注入してして」。
という軽さを売りにするのがDI。

コードにすると、

class foo {
  protected $love = NULL;
  function injectLove( $love ) {
    $this->love = $love;
  }
}

こういうのを汎用性が高いと言うのでしょう。
テストしやすい、というのがDIを正当化するのによく言われます。

ただ実際には使いづらい面があります。

◆ IoC(Inversion of Control)

何しろオブジェクトを作るには何かを注入してやらなければいけない。
独り立ちではなく、逆に誰かに依存してしまいます。

これを擬人化すると、
「一人だと何も出来ないんです。誰か注入してください」
と言う「ひ弱な僕」というのがピッタリな表現でしょう。

このように、使う方から使われる側へとオブジェクトの実装を変更することを
制御の反転(Inversion of Control)
と呼びます(多分)。

◆ Container(コンテナ)

こんなひ弱なオブジェクトたちにはママが必要です。
「あ~、坊やにはこれを注入してあげるからね」
これをコンテナと呼びます。
いろんな作り方があるけど、例えばこんな感じ?

class DiMom {
  function loveFoo() {
    $foo = new foo();
    $foo->injectLove( new \I\Love\You() );
    return $foo;
  }
}
オブジェクトの生成を一手に担い、適切なオブジェクトを注入して依存性を解決してあげる。そんなBig Motherのようなクラスをコンテナと呼ぶのでしょう。

実際には、コードでゴリゴリ書くのではなく設定できるようにすると思いますが。


◆ Service Locator(SL)

以上、色々書きましたが、未だにSLとコンテナの違いがよく分かってません。似ているようで違う、というか、多分自分の書いたコンテナはSLの事な気がしています。いや、何が違うのだろう?

思うに、オブジェクトがコンテナに依存している状態をSLと呼ぶのではないでしょうか?

自分が開発しているフレームワークはChain of Responsibilityを使っていて、必要に応じてモジュール(オブジェクトのことです)を呼び出します。
正確に言うと、ある処理を行うのに必要なモジュールを判断するモジュールがあって、そのモジュールがチェーンに必要なモジュールを追加します。
フレームワークは順番にオブジェクトを生成・実行するだけですが、生成部分にコンテナを使いますが、これだと多分SLという区分になる気がします。

また理解できたと思ったら書いてみます。


◆ 参考文献

色々読んだけど、今ブックマークしてあるもののみリスト。


2012年5月7日月曜日

Dependency Injection とリソース指向について

GW最後の夜、ストレッチをしながらDependency Injection(DI)について考えてみた。DIについて調べ始めてまだ3ヶ月の新人なので、未だによく分からないことだらけだが。

DIってリソース指向と似ているのでは?

と思った気がした。
生成するオブジェクトをリソースとして捉えると、
  1. リソース(オブジェクト)の生成
  2. リソースの操作(依存性の注入)
という手順が成立する。

リソースの操作っていうのは、要するに設定の代入と依存性の注入になる。

そこで、さらに手順を細分化してみると

  1. 生成するオブジェクトを特定する
    new、Singleton、staticなど生成方法を含めて一意に特定する
  2. 設定の注入
    オブジェクトにconfigを代入する
  3. 依存性の注入
    任意のオブジェクトを注入可能とする

という手順になるのかな。

◆ オブジェクトを特定するDIN表記

まずはオブジェクトを特定する記述について考えてみる。
こんな感じかな。
['DIN' => [ $className, $type, $idName] ]
ここで
$classNameは生成するクラス名。
$typeはnew、get、static、のどれか。意味は明白だよね。
$idNameは前に生成したオブジェクトを指定するID名。省略可。英数字ならOKとか。

ちなみにDINはDependency Injection Notationの略(笑
で、DIN表記と呼んでみよう。

◆ 設定の注入

さっき作ったオブジェクトに対して、設定を注入する。

['DIN' => [ $className, $type, $idName],
'config' => [ 'A' => 'a', 'B' => 'b', ] ]

と表現できるでしょう。

◆ 依存性の注入

他のオブジェクトをDIN使って表しておいて、依存性を注入。


['DIN' => [ $className, $type, $idName],
'config' => [ 'A' => 'a', 'B' => 'b', ]
'inject' => [
    'name1' => [ 'class1', 'get', 'test' ],
    'name2' => [ 'class2', 'new' ],
  ]
]
これで、DIN表記を導入したメリットが見えるのでは。

必ずしもnewしたオブジェクトを代入する必要はなくて、get(singleton)で作ったオブジェクトを使うことができる。あるいは、複数のオブジェクトで共通したオブジェクトに依存する、という場合もあろう。


◆ PHPでの実装を想像してみる

DIN表記は、こうだよね。
$di->din( 'className', 'new' );
$di->din( 'className', 'get' );
あるいは
$di->din( [ 'className', 'get', 'test' ] );
$di->din( [ 'className', 'static' ] );
設定を注入してみよう。
( Di::start() )->din( 'className', 'new' )->config( $config );
とか格好良くない?

で、依存性を注入。
( Di::start() )->din( 'className', 'get', 'test' )
->config( $config )
->inject( 'loader', [ 'myLoader', 'new', '1' ] )
->inject( 'loader2', [ 'yourLoader', 'get' ] );
さらに
( Di::continue() )->din( 'className', 'get', 'main' )
->config( $config )
->inject( 'loader', [ 'myLoader', 'new', '1' ] )
->inject( 'loader2', [ 'myLoader', 'new', '1' ] );
と別のオブジェクトも続けて生成できたら、便利かなぁ?

あ、まだオブジェクトを入手してない。
( Di::continue() )->forge()
->obtain( $obj1, [ 'className', 'get', 'test' ] )
->obtain( $obj2, [ 'className', 'get', 'main'' ] )
->saveAs( 'myTest' );
設定を保存できたりして。
で、いつでも呼び出せる。
( Di::start() )->forge( 'myTest' )
->...


う~ん。
全部を実装すると大変そうだ。

特に最後の設定の保存あたり。多分このAPIでは使えない気がする。
たとえば、注入されるオブジェクトを保存した設定で生成したい、という場合に対応できない。また生成されるオブジェクトの性質が一定になってしまう。常にnewとか。ちょっと使い勝手が悪そうだ。

それとデフォルトの依存性を誰が管理するか、決めないと。
コンテナ側でデフォルトは持たない、設定の保存などはコンテナの責任、として
どういうAPIで実装すると分かりやすいのか?


まぁGWの夜の夢ということですが、
実際に実装しないとDIとは何かすら分からない状態なので、
もう少し調べてみてから実装してみよう。