Flex Builder 3が首筋に噛み付いた

Tags: ,

年の瀬なんで泣ける小話でも。

******

Flex Builder 3では、Flex Builder 3で作った各プロジェクトをFlex Builder 3から削除する際に二つオプションが選べる。

  • Flex Builderからプロジェクトの参照だけを削除し、ファイル自体はマシン内に残す(デフォルト)
  • Flex Bulderからプロジェクトの参照を削除し、さらにファイル自体もマシンから削除する(ゴミ箱に移動させるわけではなく、マシンから抹消する)

使用者が指定しない限り、前者の削除方法が選ばれる。しかし、例えばプロジェクト名を中途半端に間違えて作ってしまい、「あ、やべ、ミスった。消そ」とか、同じ名前のプロジェクトを作り直したい場合なんかは後者を選ぶ方が楽な場合がある。僕自身も面倒が少ないからという理由で後者の削除方法を使うことが少なからずあるのだけど、この後者がやばい。後者のファイル削除の範囲はプロジェクトと関係あるかないかに関わらずそのプロジェクトのディレクトリ配下全部だからである。以下実例。

Aさん(僕じゃないよ)の場合

Aさん(僕じゃないよ)は、普段Flex Builder 3のデフォルトのドキュメントディレクトリを使ってプロジェクトを作成していた。Macの場合だと

/Users/USERNAME/Documents/Flex Builder 3/

普通にFlex Builder 3を使っているとプロジェクトは全てこの階層配下に作成されるようになっている。(デフォルトの場所を使用するにチェックが入っており、他の場所へのプロジェクト作成がロックされた状態)。しかしそのときは、どうしてもローカルサイトでテストする必要があり、localhostにプロジェクト(PROJECT_JP)を作成した。

/Users/Username/Sites/PROJECT_JP/src/
/Users/Username/Sites/PROJECT_JP/bin-debug/
/Users/Username/Sites/PROJECT_JP/bin-release/

かくしてPROJECT_JPは完成したが、PROJECT_JPをローカライズしたもの(PROJECT_EN)を作成する必要があった。同様にしてローカルサイトにプロジェクトを作成するが、普段デフォルトのFlex Builder 3ディレクトリしか使っていなかったため、思わぬミスを犯す。一階層上をプロジェクトディレクトリにしてしまったのだ(つまりSites)。PROJECT_ENの内容は以下のようになった(PROJECT_EN内にPROJECT_JPが混在した状態)。

Aさん(僕じゃないよ)が予定していたディレクトリ構造

/Users/Username/Sites/PROJECT_EN/src/
/Users/Username/Sites/PROJECT_EN/bin-debug/
/Users/Username/Sites/PROJECT_EN/bin-release/
/Users/Username/Sites/PROJECT_JP/src/
/Users/Username/Sites/PROJECT_JP/bin-debug/
/Users/Username/Sites/PROJECT_JP/bin-release/

実際に作ったディレクトリ構造

/Users/Username/Sites/src/
/Users/Username/Sites/bin-debug/
/Users/Username/Sites/bin-release/
/Users/Username/Sites/PROJECT_JP/src/
/Users/Username/Sites/PROJECT_JP/bin-debug/
/Users/Username/Sites/PROJECT_JP/bin-release/

Sitesをプロジェクトのトップディレクトリに設定しているにもかかわらず、Flex Builder 3上ではこのプロジェクトディレクトリは”PROJECT_EN”と表示される点がポイント。Flex Builder 3のデフォルトのドキュメントディレクトリ配下のプロジェクトでは、Flex Builder 3上のプロジェクトフォルダ名とマシン上のフォルダ名は必ず一致するが、デフォルトではない場所にプロジェクトを作成した場合必ずしも両者は一致しない。

すぐに作成場所のミスに気づいたAさん(僕じゃないよ)は、PROJECT_ENを削除して作り直そうとした。その際横着をして前述の「プロジェクトの参照を削除し、なおかつファイルをマシンから抹消する」方法をとった。つまり「Flex Builder 3上でPROJECT_ENと表示されているプロジェクトの参照を削除し、さらにそのプロジェクトファイルをマシンから抹消する」方法をとったのである。その結果プロジェクトはたしかにマシンから削除され、以下のような構造になった。Sites配下には何も残っていない。っておい。

/Users/Username/Sites/

PROJECT_ENは正しく削除されたが、PROJECT_EN配下に存在していたPROJECTも跡形もなく削除されたわけだ。幸いPROJECT_JPのバックアップは前日にとってあったが、一日分の作業が跡形も無く抹消されたわけである。さらにローカルサイトという特別な場所に作成したのが災いした。ローカルサイトには今回とは無関係なフォルダが多数あったのである。例えば

/Users/Username/Sites/phpMyAdmin/

など。これらも同様に跡形も無く消去された。

教訓

今後は以下を死んでも遵守する、とAさん(僕じゃないよ)は言っている。

  1. Flex Builder 3のプロジェクトは可能な限りデフォルトのドキュメントディレクトリを使う
  2. 不要なプロジェクトは参照だけを削除する。実際のファイル削除は面倒でも手動で行う
  3. バックアップは頻繁に行う。そのためにコミット回数が増えても気にしない

ちなみにマシンルートに作ったFlexプロジェクトの完全削除とかどうなるのだろう。マシン破壊?誰か試してみて。トラウマになりそうでできんわ。

[Books] AIRの良書とFlexとRailsのクソ本

Tags: , , ,

どちらも同じ出版社の本だけど対照的。

  • Adobe Air in Action
    Adobe Air in Action

    AIRの良書。Flash, Flexに慣れ親しんだ人がAIRについてのみ知りたい場合などに最適。逆にFlashの知識が全くない状態でAIRをやってみようという場合には解読不能かも。Window, File system, Drag-and drop, SQLiteなど、AIR特有の機能に内容を絞っていて、しかもかなり原理的なところから説明しているので好感度が高い(FileStreamの進行状況を視覚化してあったり)。難点を挙げるとすると、これは出版社MANNINGの問題なんだけど、ここの本のレイアウト、文字スタイルが無駄に凝ってたり見出しごとにフォントかえてたりして見づらいんだよね。目がチカチカするっていうか。O’Reillyはそのへんさすがだと思う。

    » レーダーチャート評点

  • Flexible Rails: Flex 3 on Rails 2
    Flexible Rails: Flex 3 on Rails 2

    Flex + Rails。2008年に購入した本の中でぶっちぎり独走状態のクソ本。扱っている内容はFlex, Railsとも実践的で高度なのだが(Flex 3, Rails 2.0, RubyAMF, Cairngormなどを一緒に扱っている本はたぶん世の中にこれしかない)、著者の文章力がお粗末。自分の挙げた質問に脱線しまくったあげく見当違いな答えが書いてあったりして愕然とさせられる。要所要所でかいま見られる「この本への著者の愛」も読んでて非常に気持ち悪い。「TVゲームが超絶うまい小学生に書かかせたゲーム攻略本の文章」っていうとイメージ湧くかな。この本のせいで出版社のMANNINGのイメージがよろしくなくなった。

    » レーダーチャート評点

[Flex] Tube3D

Tags: ,

ローカルから画像をロードしたらそれっぽく陰影を付けて立体的に見せてくれるアプリケーション。気に入ったタイミングでスナップショットボタンを押せばそのときの状態の画像がローカルマシンに保存されます。タイミング難しいけど。

» Tube3D (要Flash Player 10)

[Flash] パワースペクトル

Tags: ,

[Flash] パワースペクトル
» [Flash] パワースペクトル (SWF) (要Flash Player 10、音注意)
» ソースコード

Flash Player 10から音を生成できるようになったのでそのテスト。単周期のサイン波を生成してそのパワースペクトルをSoundMixer.computeSpectrum()で表示。ダイナミックサウンドについては情報がまちまちなので完全には理解できていない。が、Saqoosha.net :: SoundMixer.computeSpectrum の FFT モードの周波数帯に書いてあるように0-11kHzの範囲でスペクトルが表示されているので結果はおかしくない、と思う。スペクトルに幅がでちゃってるのは生成されたサウンドに問題があるのかフーリエ変換の精度に問題あるのか不明。

FileReferenceオブジェクトと変数のスコープの関係

Tags: ,

これは知らないとはまる。Filereferenceオブジェクトへの参照をローカル変数の受け渡しで扱っている場合注意が必要。ローカル変数のみを使用する場合ロードが中断される可能性がある。Flash Player 10 (Astro)のAPIはまだ日本語になっていないようだったので以下を引用するが同じことがFilereference.load()にもあてはまる。

FileReference オブジェクトがスコープ外に移動した場合、そのオブジェクトに対して完了していないアップロードまたはダウンロードは、スコープから離れた時点でキャンセルされます。アップロードまたはダウンロードの続行を期待できる限りは、FileReference オブジェクトがスコープ内にあることを確認してください。

Adobe® Flex™ 3 リファレンスガイド

以下にFileRefarence.load()が正しく完了する場合と完了しない場合の二種類の例を挙げる。どちらも”Load”ボタンを押すとローカルから画像を選択できるようになり、画像を選択するとステージにその画像が表示されるという構造になっている。両者の違いはFilereferenceオブジェクトを扱う変数がローカル変数のみかそうではないかだけである。

FileReference.load()が成功する場合

FileReferenceオブジェクト変数をクラスプロパティで定義しているため(_fr)クラスファイル内でFilereferenceオブジェクトのスコープがはずれることはない。そのためボタンクリックでローカルから選択された画像はFileReference.load()で正しくロードされキャンバス(_canvas)に表示される。

<!– FileReference.load()が正しく完了する例 –>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Button label="Load" click="onClick(event)"/>
    <mx:Canvas id="_canvas"/>

    <mx:Script>
        <![CDATA[
            import flash.net.FileReference;

            //クラスプロパティとして定義
            private var _fr:FileReference;

            private function setListeners(target:FileReference):void{
                var fr:FileReference = target as FileReference;
                fr.addEventListener(Event.SELECT,onSelect);
                fr.addEventListener(Event.COMPLETE,onComplete);
            }

            private function onClick(e:Event):void{
                _fr = new FileReference();
                setListeners(_fr);
                _fr.browse();
            }

            //関数を抜けてもFileReferenceオブジェクトへの参照”_fr”はスコープ内
            //そのため関数を抜けてもFileReference.load()は続行される
            private function onSelect(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                fr.load();
            }

            private function onComplete(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                var loader:Loader = new Loader();
                loader.loadBytes(fr.data);
                loader.contentLoaderInfo.addEventListener(Event.INIT,onInit);
            }

            private function onInit(e:Event):void{
                _canvas.rawChildren.addChild(e.target.content);
            }
        ]]>
    </mx:Script>
</mx:Application>

FileReference.load()が失敗する場合

一方、以下の場合FileReferenceオブジェクト変数はローカル変数でしか定義されておらず、Filereferenceオブジェクトのスコープが完全にはずれる箇所がある(onSelect()を抜けた直後)。その時点でFileReference.load()はキャンセルされるためロード完了によるEvent.COMPLETEが発動しない(_canvasに画像が表示されまでに至らない)。

<!– FileReference.load()が途中でキャンセルされる例 –>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Button label="Load" click="onClick(event)"/>
    <mx:Canvas id="_canvas"/>

    <mx:Script>
        <![CDATA[
            import flash.net.FileReference;

            private function setListeners(target:FileReference):void{
                var fr:FileReference = target as FileReference;
                fr.addEventListener(Event.SELECT,onSelect);
                fr.addEventListener(Event.COMPLETE,onComplete);
            }

            private function onClick(e:Event):void{
                //ローカル変数として定義
                var fr:FileReference = new FileReference();
                setListeners(fr);
                fr.browse();
            }

            //関数を抜けるとFileReferenceオブジェクトへの参照がスコープ外になる
            //そのため関数を抜けるとFileReference.load()は完了前にキャンセルされる
            private function onSelect(e:Event):void{
                trace(e);
                var fr:FileReference = e.target as FileReference;
                fr.load();
            }

            private function onComplete(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                var loader:Loader = new Loader();
                loader.loadBytes(fr.data);
                loader.contentLoaderInfo.addEventListener(Event.INIT,onInit);
            }

            private function onInit(e:Event):void{
                _canvas.rawChildren.addChild(e.target.content);
            }
        ]]>
    </mx:Script>
</mx:Application>

Next Page →