ひよっこ。

I want to…

Posts Tagged ‘ActionScript3’

GeohashのAS3版

Posted by hikaruworld : 2010 2月 10

を適当に作ってみました。

Geohashとは何かに関しては、Wikipedia(英語)のGeohashが参考になるかと思います。
簡単にいうと緯度経度情報の矩形情報を特定の文字列を使って表現することができる仕様です。

アルゴリズムの日本語の解説としては

の記事がわかりやすいと思います。

自分の文系脳みそでも理解できました。ありがとうございます。

一応簡単にテストは済ませてありますが、勢いで作ったのであんまり自身なし。
浮動小数演算そのままやっているので丸め誤差が出ると思います。
launchpad.netのここからダウンロードできます。

bit演算とかした方が良いのかもしれませんが、恥ずかしながら普通にやってしまいました。
勉強し直してから修正します。

以下の機能が実装してあります。

  • エンコード機能(緯度/経度情報をgeohashに変換する)
  • デコード情報(geohash情報を緯度/経度に変換する)

以下はTODO

  • キャッシュの実装
  • 矩形の上下左右9方向への移動
  • 拡大/縮小機能
  • 隣り合うgeohashの取得方法
  • googleのジオコーディング連携

使いかたはGeoSampleを見ても分かりますが、以下の通りです。

// インスタンス化
var geo:Geohash = new Geohash();

// 富山城址公園の緯度経度をgeohashにエンコード
var hash:String = geo.encode(36.693286, 137.210877);
trace(hash);

// 富山城址公園のgeohashを緯度経度にデコード
var latlng:Object = geo.decode("xn98drccvhm2");
// Objecetの"lat"と、"lng"でそれぞれの情報を取得可能
trace(latlng[Geohash.LAT_KEY], latlng[Geohash.LNG_KEY]);

バグがあれば指摘していただけると助かります。

以上です。

広告

Posted in program | タグ: , , , | Leave a Comment »

FlexPMDのRC4が出ていた

Posted by hikaruworld : 2009 9月 25

以前の投稿で、Hudson上にFlexPMDの環境構築を行いました。
その際に、以下のようなバグがあって正常にGUIで参照できませんでした。

本来はこれで問題なく参照できるはずですが、sourceが表示されず対応行がビジュアルに表示されませんでした。
Violationの設定がおかしかったのかなとも思ったのですが、filenameが絶対パスで示されている関係なのかなぁと思ったりして検索してみたら、こんなのを見つけました。
http://forums.adobe.com/message/2242523#2242523
http://bugs.adobe.com/jira/browse/FLEXPMD-70

いつ修正されるかなーと思いstarをつけて経過を見ていたんですが、
今回リリースされたRC4で修正されたと聞いて早速試してみました(修正一覧はこちら)。
すると無事修正されてソースコード上で参照できるようになっていました。
中の人ありがとーございます。

#TODO 今手元に反映版がないので後で反映版を貼付けること

Posted in program | タグ: , , | Leave a Comment »

FlexAutomationAPIに関して

Posted by hikaruworld : 2009 9月 17

FlexAutomationAPIの説明がぐだぐだになったので、悔しいのでblogで補足していきます。

FlexAutomationAPIとは

FlexAutomationAPIとは、Flexフレームワークで提供されているAPIで
Flexコンポーネントに対するユーザ操作をオートメーションする事が可能になります(と、解釈しました)。

ただし、このAPIはFlexBuilderProfessionalが必須に成ります。
※standard版でも実行可能ですが、一回あたりのアクション数が30回に限定されています。
(リリースドキュメントに書いてあったんですが、探すに苦労しました…)

これは、FlexAutomationAPIを利用するのに必要なライブラリ

  • automation.swc — Flexコンポーネントの委譲クラス群
  • automation_dmv.swc — FlexチャーティングとAdavancedDataGrid用の委譲クラス群
  • automation_agent.swc — agentクラス

が通常のFlexSDKに含まれていないためです。

AutomationAPIで実現可能なこと

FlexAutomationAPIを用いると以下の事が実現可能だとヘルプには書いてあります。

  1. メトリック(Omniture) — Adobeが買収しましたが、要するに詳細なアクセス解析を提供します。
  2. 自動テスト(FlexMonkey & MerquryQTP) — 周知の通りユーザ操作をエミュレートしてGUIテストの自動化を行います。
  3. コブラウジング — 特にサンプルがあるわけではありませんが、リモートでのユーザ操作の同期などを可能とします。ここ辺り(PDF)が参考になるかと思います。

AutomationAPIのフロー

AutomationAPIはAutomationManagerの実行によって対象Flexコンポーネントを委譲する形で組み込まれます。
(正確にはAutomationManagerによってSystemManagerに対してADDEDイベントが登録され、
SystemManagerにADDされるタイミングで委譲クラスがインスタンス化され、
Automationの静的プロパティdelegateClassMapに追加されます。)

# AutomationManager自体はAPIドキュメントが存在せず、インターフェイスの
# IAutomationManager,IAutomationManager2のみしか参照できません
# このようにFlexAutomationAPI関連はAPIドキュメント上に表示されない@privateなものが多いようです。
# AutomationManagerは参照できませんがAutomationはソースが参照できますので直接のぞいてみるとよいでしょう。

この辺りはヘルプを参照して頂くと理解が進むと思います(以下の図を参照。Adobeのヘルプより)。

AutomationAPIのイベント伝播

AutomationAPIのイベント伝播

AutomationAPIの初期化処理

では、SystemManagerから始まる内部の初期化の流れを追ってみます。
以下の図は、SystemManagerから始まる処理の流れを図にしたものです。

AutomationAPI関連図

AutomationAPI関連図

  1. SystemManager内のdocFrameHandler()でMixinに指定されているクラスのinit()メソッドが呼び出されます
    (詳細は前記事Mixinを参照して下さい)。
  2. AutomationManager及び委譲クラス群はMixinに指定されているため、
    SystemManagerのmixin呼び出しを受けて、AutomationManagerと委譲クラス群の処理が実行されます。
  3. 2.のMixinにより各設定が行われた後、画面上に各コンポーネントの描画が行われます。
  4. Automation.delegateClassMapにマッピングされたオブジェクトは、
    ADDEDのタイミングで処理の委譲が行われることになるため、委譲先のイベントとしてRECORDがdispatchされます。
  5. エージェントはこの委譲クラス群(正確にはAutomationManagerより発生される)イベントをListenすることでそのイベント及びイベントのトリガとなったコンポーネントの情報を取得することが可能になります。

ここで注目したいのは2番目の処理になります。AutomationManager及び委譲クラス群の処理に関して、もう少し掘り下げてみます。

AutomationManagerの場合

init()メソッドでは、rootに対してADDEDイベントをListenするイベントハンドラ(childHandler())が定義されます。
これは、SystemManagerをrootする表示オブジェクトにコンポーネントが追加(Event.ADDED)されたときにdispatchされます。
childHandler()は、引数に渡されたコンポーネントから対応するAutomationクラスに定義された委譲クラスのインスタンス化を行い、
Automation.delegateClassMapにそのインスタンスを登録します。

委譲クラス群の場合

init()メソッドでは、Automation.registerDelegateClassを利用してAutomation.delegateClassMapに自身を登録します。
# ここでは自身を登録しているのみで、インスタンス化を行っているわけではありません。
# 委譲クラスのインスタンス化はAutomationManagerのchildHandlerによって行われます。

また、委譲クラスの持つイベント(つまり実体クラスと同様のイベント群)に対しイベントリスナが登録されます。
このイベントリスナは内部でAutomationManager.recordAutomatableEvent()を呼び出します。
# AutomationManager.recordAutomatableEvent()が実行されると、
# AutomationManagerクラスによってRecordEventがDispatchされます。

Automationクラスの場合

実クラスと委譲クラスのMapを保持するAutomationクラスは静的クラスとして設計されており、
初期のアクセス時に内部プロパティdelegateMapを初期化しその値を保持します。

    /**
     *  Registers the component class and delegate class association with Automation.
     * 
     *  @param compClass The component class. 
     * 
     *  @param delegateClass The delegate class associated with the component.
     */
    public static function registerDelegateClass(compClass:Class, delegateClass:Class):void
    {
        if (!delegateClassMap)
            delegateClassMap = {};

        var className:String = getQualifiedClassName(compClass);
        delegateClassMap[className] = delegateClass;
    }

これらの仕組みを組み込んだ上で、AutomationRecordEvent.RECORDをListenするように
エージェントクラスの実装を行う事になります。

この4.から5.の流れは、Flexのヘルプを参照していただくとわかりやすいと思います(Flexのヘルプから)。

エージェントへの操作フロー

エージェントへの操作フロー

次へ続く…

Posted in program | タグ: , , , , | Leave a Comment »

Flex@北陸in石川に行ってきた。

Posted by hikaruworld : 2009 9月 14

Flex@北陸in石川に行ってきました。

相も変わらず、基本的には一行感想で。

  1. 「Flash Catalyst + Flash Builder 4(仮)」 アドビシステムズ 轟さん
    Catalystすげー、って感じですね。デザイナさんとこういうのをやってみたい。でもそれよりもARに惚れた自分がいます。
  2. 「FlexMonkey紹介」 hikaruworld
    うーん、失敗した。FlexAutomationAPI色々面白いと思うんだけど、説明しきれない。
    Mixinに関しては多重継承の概念の一部の手法のみを許しているという考えが正解?
  3. 「Flexで作るおされビンゴアプリ」 katzchangさん
    ん?いつの間にかFlexから、開発プロセスに流れている気が….bibibingo!!。これからずっと使われることになりそうw
  4. 「Silverlight入門」 hr_saoさん
    やはりFlexとSilverlightは似ているなと言うのが感想。C使いなら導入やりやすいと思うんだけど、Macというのが実は一番の壁だったりする。
    プレゼン見てたら使いたくなってきたので触ってみようかなと思いました。
  5. 「 FlashとSilverlightの配信事情」 coelacanthさん
    動画配信の世界は謎が多いなぁといつも思います。シークひとつとってもどんだけ考えられているんだろうと。
    FlashMediaServerとか利用してみたいけど、何となく敷居が高くて…

以下、LT

  1. 「WebGLについて」 @rch850さん
    WebGLとO3DがGoogleが提供しているというのが今後激変しそうな匂いがします。Adobe vs Microsoft vs Googleの三つ巴?
    そうそう、「提供」をやろうと思ってて忘れてた事実に気づかされました。
  2. 「Android + JavaScript」 @checkelaさん
    個人的にはiPhoneにもFlashが乗るんじゃないかなぁーと期待してたりします。ただ、Android+javascript+HTML5ってのはかなり魅力的な世界。
  3. 「ディベロッパーへデザインのススメ」 @shoitoさん
    プレゼンうまっ、ってのがまず第一の感想。自分的には、デザインサイドの視点を忘れないようにしようとおもいつつ
    いつの間にかデベロッパーよりになっているので、初心にかえりたいところ。

<hr
以下は、個人的な反省。
自分のプレゼンは失敗した感じで泣きたくなりました。
反応がないのはつらいなーという感じで、もっとプレゼンの修行をせねばと思います。

素敵な技術をステキに伝えられないとその技術に申し訳ない。。。
とりあえず、プレゼン資料は以下。

あとTweetBubllesを利用してみたんですが、リアルタイムじゃないのが痛いなぁと思いました。
いっそのこと、会場にプロキシサーバか何か立てて、そこ経由でPOSTしてもらってフックした情報をAppで表示とかやってみよかなと思いました。
需要ある?

あ、シマッタ。
富山で本をゲットした方のIDとかを聞き忘れてしまいました。知っている方がいれば教えてくださいー。

以上ー。

TODO… プレゼン資料のUP

Posted in program | タグ: , , , | Leave a Comment »

Flex3におけるMixinに関して

Posted by hikaruworld : 2009 8月 23

FlexAutomationAPIを理解していく上でMixin(Mix-in)という概念を理解しておく必要があるようなので、
どういった物か調べていました。

自分の脳みそを整理するために書いているので、
もし間違っていたら突っ込んでいただけると感謝します。

なお、Mix-inの公式ドキュメントとしては、古いですがMacromedia FlexDocumentation Mix-inの利用が参考になると思います。
上記から抜粋になりますが、オブジェクト指向におけるMix-inの概要は以下のように説明されています。
あとは、Rubyのまつもとさんがこの概念を説明されているのでそちらの方がより参考になるでしょう。
RubyではMix-inがサポートされているんですね、知りませんでしたorz…

Mix-in は、継承を使用せず、動的に既存クラスのメソッドをカスタムクラスに追加するための簡単な手段です。クラスを Mix-in することで、既存クラスのメンバーを、カスタムクラスのプロトタイプオブジェクトに追加できます。ActionScript では多重継承がサポートされていませんが、Mix-in を使用すれば、他の Flex クラスを継承してカスタムクラスを作成する通常の方法では使用できない機能をカスタムクラスに追加できます。

オブジェクト指向言語における Mix-in とは、他のクラスに機能を追加するために使用される最小限のユニットです

わかるようなわからないような表現です。。。

Flexにおいては、仕様の継承はinterfaceを用いて多重継承することが可能ですが、
機能の継承は単体継承のみで言語仕様上多重継承がサポートされていません。
そのかわりと言っては何ですが多重継承の代替手段的にMix-inという概念が組み込まれているようです。
(Mixin自体は多重継承のテクニックの一つらしいですが、それを言語上非公式にサポートしている事になります。)

実際には、この方法を用いて、Flexアプリケーション起動時にMixin対象クラスに対してinit()メソッドを実行し、
内部で任意の実装(機能)を「織り込む」ことが出来るようになります。
(ただし、initメソッドはpublic staticである必要があるため、自身以外のインスタンスを操作する事は出来ません)

Flex自身によって提供されている[Mixin]は、AutomationAPIを例にして考えると、
「Flexコンポーネントクラス」に「オートメーション」という機能をMix-inする事で
Flexオートメーションフレームワークを実現していることになると理解しました。

さて、Flexで具体的なMixinの実装方法は以下の様に行います。

  1. 特定のクラスに対してメタタグ[Mixin]を使いMixin対象である事を指定します。
  2. 上記クラスにpublic static function init(st:SystemManager):voidというメソッドを定義します。
  3. コンパイル時に、明示的にコンパイル対象クラスである事を指定して
    (Flexでは、プログラム上利用されないクラスはコンパイル対象にならないためです)コンパイルを行います。

    • ※コンパイル対象に指定する方法は、どこかに宣言を書くか、コンパイル引数として対象クラスを渡す必要があります。

上記の手順を踏むと、SystemManagerのdocFrameHandler()内部で
MIxinされたクラスのinitのメソッドが実行されます。

# docFrameHandler()はFlashのタイムラインで言う2フレーム目に進んだタイミングで実行されます。
# なお、通常Flexの開発者によって定義された起動クラスは2フレーム目に配置されることになります。

SystemManagerの実装は以下のような感じになっていました。

var mixinList:Array = info()["mixins"];
if (mixinList && mixinList.length > 0)
{
    var n:int = mixinList.length;
    for (var i:int = 0; i < n; ++i)
    {
        // trace("initializing mixin " + mixinList&#91;i&#93;);
        var c:Class = Class(getDefinitionByName(mixinList&#91;i&#93;));
        c&#91;"init"&#93;(this);
    }
}
&#91;/sourcecode&#93;
info()と言うメソッドでmixinsというプロパティ群を取得後、
getDefinitionByNameでクラスを取得し自身を引数としてinitメソッドを実行しています。
このinfo()メソッドはSystemManagerクラス上では以下のような空実装になっています。
&#91;sourcecode language='javascript'&#93;
/**
 *  @private
*/
public function info():Object
{
    return {};
}
&#91;/sourcecode&#93;
このinfo()メソッドは、コンパイル時にMXMLの起動クラスから自動生成された
asクラスの指定先のsystemManagerによってoverrideされたものが参照されるそうです。

HelloWorld文字列を表示するような単純なAirアプリでは、
コンパイル時に生成される_Sample_mx_managers_SystemManagerのoverride部分は以下のようになっていました。
※コンパイラオプションに<em>--keep</em>を指定してコンパイルするとソースファイル以下に
  generatedというディレクトリができMXMLから生成されたASファイルを参照できます。

override    public function info():Object
{
    return {
    compiledLocales: [ "ja_JP" ],
    compiledResourceBundleNames: [ "collections", "containers", "controls", "core", "effects", "skins", "styles" ],
    currentDomain: ApplicationDomain.currentDomain,
    layout: "absolute",
    mainClassName: "Sample",
    mixins: [ "_Sample_FlexInit", "_macMinButtonStyle", "_alertButtonStyleStyle", "_ControlBarStyle", "_ScrollBarStyle", "_winMaxButtonStyle", "_activeTabStyleStyle", "_textAreaHScrollBarStyleStyle", "_ToolTipStyle", "_winCloseButtonStyle", "_DragManagerStyle", "_macCloseButtonStyle", "_statusTextStyleStyle", "_advancedDataGridStylesStyle", "_WindowedApplicationStyle", "_gripperSkinStyle", "_comboDropdownStyle", "_winRestoreButtonStyle", "_HTMLStyle", "_textAreaVScrollBarStyleStyle", "_ContainerStyle", "_globalStyle", "_linkButtonStyleStyle", "_windowStatusStyle", "_windowStylesStyle", "_PanelStyle", "_activeButtonStyleStyle", "_WindowStyle", "_errorTipStyle", "_richTextEditorTextAreaStyleStyle", "_todayStyleStyle", "_CursorManagerStyle", "_dateFieldPopupStyle", "_plainStyle", "_dataGridStylesStyle", "_winMinButtonStyle", "_macMaxButtonStyle", "_ApplicationStyle", "_headerDateTextStyle", "_ButtonStyle", "_popUpMenuStyle", "_titleTextStyleStyle", "_AlertStyle", "_swatchPanelTextFieldStyle", "_opaquePanelStyle", "_weekDayStyleStyle", "_headerDragProxyStyleStyle" ]
    }
}

[Mixin]というメタタグを付与すると、このmixinsにクラス名が格納される事になり、
この配列に格納されている場合に、Mixin処理が行われるという事になるようです。

しかし、これらのことから「Flexは非公式ではあるがMixin型の多重継承をサポートしている」と
言ってしまってよいのかどうなのかその辺りがやっぱりよくわかりませんでした。

Posted in program | タグ: , , , | 2 Comments »

FlexUnit4 補足第3回 – ユーザカスタムメタデータパラメータ –

Posted by hikaruworld : 2009 7月 9

fxug@富山 補足第3回です。
なんだかんだで、補足が多いですねorz…。

さて今回は、User Defined Metadata Parameters
つまり、ユーザによって定義されたメタデータに付与されるパラメータの話になります。
ようするに[Test(milestone=”piyo”)] のことですね。

勉強会でも触れましたが、FlexUnit4のメタデータにはユーザが
好き勝手に任意でkey=value形式でパラメータを設定する事が出来ます。

この値(正確にはメタデータ)は、テスト完了後に参照する事が可能なメソッドが提供されており、
利用したい場合はIRunListenerを実装するクラス(RunListenerなど)を用いてイベントを差し込む事で、
結果の一覧を取得する事が可能になります。

まずは、RunListenerの確認をば。
以下のソースを参照ください。

/** テストクラスの開始時 */
public function testRunStarted( description:IDescription ):void {}
/** テストクラスの完了時 */
public function testRunFinished( result:Result ):void {}
/** [Test]の開始時 */
public function testStarted( description:IDescription ):void {}
/** [Test]の完了時 */
public function testFinished( description:IDescription ):void {}
/** テストが失敗した場合 */
public function testFailure( failure:Failure ):void {}
/** テストの前提条件チェックに失敗した場合 */
public function testAssumptionFailure( failure:Failure ):void {}
/** [Ignore]により無視された場合 */
public function testIgnored( description:IDescription ):void {}

様々なタイミングでイベントを差し込むメソッドが準備されています。
そのうち、org.flexunit.runner.IDescriptionを引数に取っているクラスに関しては、
getMetadata(String) というメソッドを用いて設定されたパラメータを取得することが出来ます。

では、実際にどのように取得できるのか確認してみます。

なお、IDescriptionを実装したクラスにorg.flexunit.runner.Descriptionがあり、org.flexunit.runner.Description.getAllMetadata()というメソッドが実装されています。
当初はこのクラスでパラメータの一覧を取ってみようと思い実行してみたのですが、
以下のようなtraceが出力されました。

Method not yet implemented

ソースをのぞいてみると。。。

public function getAllMetadata():XMLList {
	trace("Method not yet implemented");
	return new XMLList();
}

うーん。思いっきりダミー実装が返されていますw。まぁこの辺りはBeta版ということで、笑って許しましょう。
さて、話を戻します。
先ほども書きましたがgetMetadata(String) というメソッドを用いて設定されたメタデータをXML形式で取得可能です。

例えば、このテストの場合。

[Test(expected="RangeError", description="This one makes sure something works",issueID="12345")]
public function exceptionTest():void
{
	var ary:Array = new Array(-1);
}

ListenerはRunListenerを継承して、testFinished(description:IDescription)の実装をoverrideします。
(必要箇所のみ抜粋)

/**
 * {@inheritDoc}
 */
override public function testFinished( description:IDescription ):void {
	trace(description.getMetadata("issueID"));
}

traceした出力結果は以下の通り。

<metadata name="Test">
  <arg key="expected" value="RangeError"/>
  <arg key="description" value="This one makes sure something works"/>
  <arg key="issueID" value="12345"/>
</metadata>

返されるクラスはXMLですので、後は必要に応じてE4Xなり何なりで処理する事が可能です。
ただし、このgetMetadata(String)に渡すことの可能な引数String型は
Beta1では無視されます。実装が以下の通りなので。

public function getMetadata( type:String ):XML {
	return _metadata;
}

本来は渡されたtypeのメタデータなりパラメータなりを取得してくれると思うのですが、
まぁ、これもβ版ということで笑って流しておきましょう。
正式版が出るまでは、自分でIDescriptionを実装しろってことですよね。

以上。

Posted in program | タグ: , , , , | Leave a Comment »

FlexUnit4Beta1 補足第2回 – XMLListener(→JUnitListener)による出力 –

Posted by hikaruworld : 2009 7月 8

お詫びと補足

この記事は当初UP後、間違いに気がついて大きく書き直してあります。
当初JUnit形式での出力はまだ不可能かと思っていましたが、
実際はJUnitListenerを利用して出力する事が可能と思われます。
なお、出来る限り元の内容を残しておこうかと思っていたのですが、修正しすぎて一部の内容を消しまってあります。


以下本文。

fxug@富山の補足 第2回になります。

IRunListenerのクラス階層

FlexUnit4Beta1では実行時のFlexUnitCoreにaddListener()の引数として、
任意のListenerを渡す事で実行結果を取得する事が可能です。
addLitener()出来るのはorg.flexunit.runner.notification.IRunListenerを実装したクラスになります。
ちなみに、FlexUnit4がデフォルトで提供しているクラスは以下の通りです。

  1. org.flexunit.listeners.UIListener
  2. org.flexunit.runner.notification.RunListener
    • org.flexunit.internals.listeners.FluintDisplayListener
    • org.flexunit.internals.TextListener
    • org.flexunit.listeners.JUnitListener
    • org.flexunit.runner.Result#Listener
  3. org.flexunit.runner.notification.async.WaitingListener
  4. org.flexunit.runner.notification.async.XMLListener

このうち1.UIListenerと2.RunListenerを除く3.と4.のクラスは、
org.flexunit.runner.notification.IRunListenerをさらに継承したインターフェイス、
org.flexunit.runner.notification.IAsyncStartupRunListenerを実装しています。

1.UIListener

これまでの記事でも利用しているように、
TestCaseBaseに対して実行結果をGUI上にハンドリングされるような動きをするようです。

2.RunListener

IRunListenerが実装されたテンプレートメソッドのようです。
ASDocには何らかのテストの前後に何らかのイベント処理を設定したい場合には
必要に応じてこのクラスを拡張するようにと書かれています。

なおRunListenerに関しては、
さらにFluintDisplayListener, TextListener, JUnitListener,Result#Listenerの4つのクラスに継承されています。

FluintDisplayListenerはおそらく統合されたFluint向けの機能と名前から勝手に解釈してスルーします(汗
TextListenerは実装からみるにコマンドライン出力に利用されているようです。
JUnitLitenerはJUnit形式で出力してくれるという事でしょうか。このクラスに関しては後で補足することになりました。
Result#Listenerに関しては外部からは参照できない内部クラスですのでこれも勝手にスルーします。

3.WaitingListener

このクラスは実装のないテンプレートクラスになっているようで
コンストラクタで5000ms遅延させた後、WaitingListener.readytureに設定し
AsyncListenerWatcher.LISTENER_READY をdispatchしているのみのようです。

その他の実装(testRunStarted, testRunFinishedなど。。。)は空になっています。
当初はこのクラスがテンプレートクラスとして利用されるのかなと思っていたのですが、
このクラスはoverrideを許可されていないのでそういった利用方法ではないようです。

4.XMLListener

に関しては出力結果をJUnitライクなXML形式で出力されるだろうと妄想しています。
実際はJUnit形式の出力はJUnitListenerで行われます。
XMLLitenerはXML形式で出力を行いますが、このXMLを誰がどう解釈するかはちょっとかりませんでした。
今後FlexUnit4独自のフォーマットに対応した何らかのアプリケーションが同梱されて出来てくるのでしょうか。。。

さて今回の話題は、このXMLListenerの使い方になります(→上記のように後ほどJUnitListenerに遷移します)。

XMLListenerの実行とその結果

とりあえず、FlexUnitCore.addListener()XMLListenerを与えて、実行してみます(必要部分のみ抜粋)。
なおこのテストはAirプロジェクトで行っています。利用しているIDEはFlashDevelop3RTM1か、FlexBuilder3です。

var core:FlexUnitCore = new FlexUnitCore();
core.addListener(new XMLListener());

但しこのまま実行しても、出力結果は以下の通りでエラーになってしまいます。

[ERROR] FlexUnit4 Listener [object XMLListener] failed to start

エラーの意味はわかりますが、理由が全くわからないのでソースを覗いて見ました(コンストラクタ部分を抜粋)。

public function XMLListener( projectName:String = "", contextName:String = "" ) {
    this.projectName = projectName;
    this.contextName = contextName;

    socket = new XMLSocket ();
    socket.addEventListener( Event.CONNECT, handleConnect );
    socket.addEventListener( IOErrorEvent.IO_ERROR, errorHandler);
    socket.addEventListener( SecurityErrorEvent.SECURITY_ERROR,errorHandler);
    socket.addEventListener( Event.CLOSE,errorHandler);
    try
    {
       socket.connect( server, port );
    } catch (e:Error) {
        trace (e.message);
    }
}

ソースコードを見ればわかりますが、XMListenerは内部でXMLSocketを生成して、XML形式のソケットを送っていることがわかります。
てっきり、ファイルか何かに書き出していると思っていたのですがそうではないようです。

おそらくIOErrorEvent.IO_ERROR,SecurityErrorEvent.SECURITY_ERRORのいずれかが発生していると考えられますので、
念のため確認をしておきます。

private function errorHandler(event:Event):void {
    // trace文を追加
    trace(event);
    dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_FAILED ) );
}

以下は実行結果のログになります。

[IOErrorEvent type=”ioError” bubbles=false cancelable=false eventPhase=2 text=”Error #2031: Socket Error. URL: 127.0.0.1″ errorID=2031]

やはり思ったとおり、接続失敗で落ちているようです。
しかし、わざわざXMLSocketで通信しているのは不思議な感じがします。
FlexUnit4の正式版が出るまでにはAir版のクライアントサーバアプリを同梱してそれを起動して使うようにしようと考えているのでしょうか。
ちょっと背景が気になりますね。。。

エラーを回避

さて、今後の予想はともかく上記の状態ではXMLSocketサーバがないことには話になりません。
原因がXMLSocketサーバに接続できていないとのことでしたので、
XMLSocketサーバを簡単に書いてテストしてみます。

ここはJavaで書いています。
Adobeのリファレンスにも(Javaでの)簡単なXMLSocketサーバの書き方の説明があるので参考になるかと思います。
*ソケット接続 – Java XML ソケットサーバーの作成および接続

なお、XMLListenerのソースを見ればわかると思いますが、XMLListener内部で生成されるXMLSocketは8765ポートを利用していますので、
それに併せる形で書く必要があります。

[Inspectable]
public var port : uint = 8765;

[Inspectable]
public var server : String = "127.0.0.1"; //this is local host. same machine

基本的にはソケット接続とほぼ同じですが、検証に利用した手抜きのソースを張っておきます。

import java.io.*;
import java.net.*;

public class SimpleServer {
    private static final int SERVER_PORT = 8765;

    public static void main(String[] args) throws Exception {
        new SimpleServer(SERVER_PORT);
    }
    public SimpleServer(int port) throws Exception {
        System.out.println(">> Starting SimpleServer");
        ServerSocket socket = new ServerSocket(port);
        Socket incoming = socket.accept();
        BufferedReader readerIn = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
        System.out.println("Enter EXIT to exit.\r");

        String str;
        while ((str = readerIn.readLine()) != null) {
            System.out.println("Echo: " + str + "\r");
        }
        incoming.close();
        socket.close();
    }
}

XMLSocketサーバを起動した上で再度テストを実行してみます。
以下はログになります(複数のテストを実行しています、これは使ったテストケースが別のため。)。

[INFO] FlexUnit4 test::HamcrestTest.assertBetweenFalse .
[INFO] FlexUnit4 test::HamcrestTest.assumTahtTestNG .
[INFO] FlexUnit4 test::HamcrestTest.assumTahtTestNG I
[INFO] FlexUnit4 test::HamcrestTest.assertThrow .
[INFO] FlexUnit4 test::HamcrestTest.assertThatAnything .
[INFO] FlexUnit4 test::HamcrestTest.assumeThatTestOK .
assumeThatOK….
[INFO] FlexUnit4 test::HamcrestTest.assertBetweenTrue .
[INFO] FlexUnit4 test::HamcrestTest.assertDescribedAs .
[INFO] FlexUnit4 test::HamcrestTest.assertThatIsA .
[INFO] FlexUnit4 test::HamcrestTest.assertThatAllOf .
[INFO] FlexUnit4 test::HamcrestTest.assertEither .
[INFO] FlexUnit4 test::HamcrestTest.assertThatGreaterThan .
[INFO] FlexUnit4 test::HamcrestTest.assertNot .
[INFO] FlexUnit4 test::HamcrestTest.assertThatAnyOf .
[INFO] FlexUnit4 test::HamcrestTest.assertThatBoth .
[INFO] FlexUnit4 Time: .102
[INFO] FlexUnit4 OK (14 tests)

無事実行されたことが確認できました。

XMLSocketサーバ側はどうなっているでしょうか。
送られた文字列を標準出力する簡単な実装なので、ログを確認してみます。

<startTestRun totalTestCount='14'  projectName='' contextName='' />
    <testCase name='assertBetweenFalse' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assumTahtTestNG' testSuite='test::HamcrestTest'  status='ignore'/>
    <testCase name='assumTahtTestNG' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThrow' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatAnything' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assumeThatTestOK' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertBetweenTrue' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertDescribedAs' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatIsA' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatAllOf' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertEither' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatGreaterThan' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertNot' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatAnyOf' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatBoth' testSuite='test::HamcrestTest'  status='success'/>
<endOfTestRun/>

こちらもXMLSocketが正常に送られていることがわかります。

但し、疑問点が1つ。
FlexUnit4をXMLListenerで出力を行った際はJUnit4と同様の書式で出力されると予想していたのですが、
そうではないようです。

これは、正式版に向けてJUnitと同様の形式でFlexUnitが実装されていくのか、
それともFlexUnit4独自のレポート形式になるのかどちらになるのでしょうか。。。

JUnitListenerによるレポート出力

IRunListenerを実装したRunListenerを継承したJUnitListenerを用いてJUnit形式の出力を行います。
ただし、このクラスを含むライブラリFlexUnit4CIRunner.swcはダウンロードした版には含まれておらず、
直接ソースから取得する必要がありますので注意してください(探しても見つからない訳だ。)。

JUnitListenerもXMLSocketを利用して通信を確立させていますので、同様のSocketServerを起動しておく必要があります。
また、JUnitListenerの接続ポートは現時点では1024が指定されています。
以下が出力結果になります(これも慌てて確認したのでテストクラスが違います)。

<testsuite errors="0" failures="0" name="exception.ExceptionHandlingTest" tests="2" time="0">
  <testcase classname="exception.ExceptionHandlingTest" name="illegalOperationErrorTest" time="0"/>
  <testcase classname="exception.ExceptionHandlingTest" name="exceptionTest" time="0"/>
</testsuite>
<testsuite errors="0" failures="0" name="exception.ExceptionHandlingTest" tests="2" time="0">
  <testcase classname="exception.ExceptionHandlingTest" name="illegalOperationErrorTest" time="0"/>
  <testcase classname="exception.ExceptionHandlingTest" name="exceptionTest" time="0"/>
</testsuite>

このような形でJUnit形式での出力がおこわれます。
(実際に解釈されるかは未確認なので注意。なんかたりない気がする。。。)

ところで勉強会でも少し話しましたが、ようやくFlashBuilder4でFB-18873がfixされたようですので、次のビルド版が楽しみです。

以上。

Posted in program | タグ: , , , , | Leave a Comment »

ActionScript3のsetメソッドの返り値

Posted by hikaruworld : 2008 12月 9

つまり、AS3のsetメソッド(public function set hoge)は返り値を持つらしい。

詳説ActionScript3 の 3.4 getメソッドとsetメソッドの79Pの下部に、以下のような記述がある。

setメソッドは、呼び出されると、それに対応するgetメソッドを常に呼び出し、getメソッドの戻り値を返します。
これによりプログラムでは、新しい値の設定後すぐにその値を使うことができます。

…<中略>…

値を返すsetメソッドの機能は便利に使える一方で、getメソッドに制限を加えています。
特にgetメソッドでは、内部的な変数の値の取得に必要な程度を超える作業は絶対に行うべきではありません。

…<中略>…

setメソッドによるgetメソッドの自動的な呼び出しによって、カウンタの記録の追跡が損なわれることになります。

まさか、voidで実装しているsetに返り値があるとは知らなかった。
試しにサンプルを書いてみる。

package {
	import flash.display.Sprite;
	
	public class Zoo extends Sprite
	{
		public function Zoo()
		{
			var p:Hoge = new Hoge();
			trace((p.piyo = "test").length);
			
		}
	}
}
class Hoge
{
	private var _piyo:String;
	
	public function get piyo():String
	{
		trace("get");
		return _piyo;
	}
	public function set piyo(piyo:String):void
	{
		trace("set");
		_piyo = piyo;
		
	}
}

上記のコードでは、Hogeクラスの_piyoプロパティにsetメソッドを使用して値を設定しているが、
setメソッドによる値の設定を行うと、

p.piyo = “test”

を行った際に返り値を取得できるので、こんな感じでHoge.piyoの返り値を処理できる(traceの結果は4)。

trace((p.piyo = “test”).length);

これって常識なのかな?
今までget/setはgetter/setter的にしか使ってなかったから大丈夫だけど、しらなかったょ。

ただ、このサンプルだと以下のように表示されると思っていたんだが、

set
get
4

実際は、以下のような感じで出力された。

set
4

という事は、必ず、getメソッドととして明示的に呼ばれる訳ではないという事なのかな?

気になる。
とりあえず、flash.sampler.getGetterInvocationCount()で実行されたgetメソッドの回数を測定してみる。
以下のようにソースを修正して実行(修正したコンストラクタのみ抜粋)。

		public function Zoo()
		{
			var p:Hoge = new Hoge();
			trace((p.piyo = "test").length);
			
			var piyoName:QName;
			for each (var name:QName in getMemberNames(p)) {
				if (name.localName == "piyo") {
					piyoName = name;
				}
			}
			if (isGetterSetter(p, piyoName)) {
				trace(getGetterInvocationCount(p, piyoName));
				trace(getSetterInvocationCount(p, piyoName));
			}
			
		}

結果。

set
4
0
1

やっぱり呼ばれていないよ。
うーん。わからん。。。

Posted in program | タグ: | 4 Comments »