やったことだけ書く備忘録

MacでHaxeの開発環境→HelloWorldまでやってみた



先日の大なごやJSに参加して、最近流行りのJavaScriptプリプロセッサの中でも一番おもしろそうだった && 実際に案件に投入(しかも大規模)されているということで Haxeに興味を持ったので、さっそくどんなもんかと使い始めてみました。まずは環境構築からHello Worldまでということで。

なお、発表してくださった@terurouさんは日本語でチュートリアルを書いてくださっています。これはありがたい!




Haxe/JavaScriptチュートリアル




上記を参考に進めます。環境はMac OSX 10.7.4です。



Haxeのインストール


公式サイトからMac用のユニバーサルインストーラをダウンロードしてdmgファイルからインストール。簡単に入りますね。以下のようにターミナルでコマンドが発行できれば成功みたいです。






オプションなどはおいおい調べていきますが、まずはやってみます。



ターミナルからコンパイル


多分ちゃんとした開発はIDEにしますが、せっかくコマンドがあるのでまずは試しにコンパイルしてみます。書いてみたコードはこんな感じで、helloworld.hxとします。




package
;

import js.Lib;

class 
HelloWorld {

        static function 
main() {
                
js.Lib.alert('Hello World');
        }
}
 


このhxファイルをターミナルからコンパイルしてみます。




$ haxe -main HelloWorld -js helloworld.js -cp $HOME --js-modern


すると、以下のようなJSファイルができました!(長いです)




(function () { "use strict";
var 
HelloWorld = function() { }
HelloWorld.__name__ true;
HelloWorld.main = function() {
    
js.Lib.alert("Hello World");
}
var 
HxOverrides = function() { }
HxOverrides.__name__ true;
HxOverrides.dateStr = function(date) {
    var 
date.getMonth() + 1;
    var 
date.getDate();
    var 
date.getHours();
    var 
mi date.getMinutes();
    var 
date.getSeconds();
    return 
date.getFullYear() + "-" + (10?"0" m:"" m) + "-" + (10?"0" d:"" d) + " " + (10?"0" h:"" h) + ":" + (mi 10?"0" mi:"" mi) + ":" + (10?"0" s:"" s);
}
HxOverrides.strDate = function(s) {
    switch(
s.length) {
    case 
8:
        var 
s.split(":");
        var 
= new Date();
        
d.setTime(0);
        
d.setUTCHours(k[0]);
        
d.setUTCMinutes(k[1]);
        
d.setUTCSeconds(k[2]);
        return 
d;
    case 
10:
        var 
s.split("-");
        return new 
Date(k[0],k[1] - 1,k[2],0,0,0);
    case 
19:
        var 
s.split(" ");
        var 
k[0].split("-");
        var 
k[1].split(":");
        return new 
Date(y[0],y[1] - 1,y[2],t[0],t[1],t[2]);
    default:
        throw 
"Invalid date format : " s;
    }
}
HxOverrides.cca = function(s,index) {
    var 
s.charCodeAt(index);
    if(
!= x) return undefined;
    return 
x;
}
HxOverrides.substr = function(s,pos,len) {
    if(
pos != null && pos != && len != null && len 0) return "";
    if(
len == nulllen s.length;
    if(
pos 0) {
        
pos s.length pos;
        if(
pos 0pos 0;
    } else if(
len 0len s.length len pos;
    return 
s.substr(pos,len);
}
HxOverrides.remove = function(a,obj) {
    var 
0;
    var 
a.length;
    while(
l) {
        if(
a[i] == obj) {
            
a.splice(i,1);
            return 
true;
        }
        
i++;
    }
    return 
false;
}
HxOverrides.iter = function(a) {
    return { 
cur 0arr ahasNext : function() {
        return 
this.cur this.arr.length;
    }, 
next : function() {
        return 
this.arr[this.cur++];
    }};
}
var 
IntIter = function(min,max) {
    
this.min min;
    
this.max max;
};
IntIter.__name__ true;
IntIter.prototype = {
    
next: function() {
        return 
this.min++;
    }
    ,
hasNext: function() {
        return 
this.min this.max;
    }
    ,
__class__IntIter
}
var 
Std = function() { }
Std.__name__ true;
Std["is"] = function(v,t) {
    return 
js.Boot.__instanceof(v,t);
}
Std.string = function(s) {
    return 
js.Boot.__string_rec(s,"");
}
Std["int"] = function(x) {
    return 
0;
}
Std.parseInt = function(x) {
    var 
parseInt(x,10);
    if(
== && (HxOverrides.cca(x,1) == 120 || HxOverrides.cca(x,1) == 88)) parseInt(x);
    if(
isNaN(v)) return null;
    return 
v;
}
Std.parseFloat = function(x) {
    return 
parseFloat(x);
}
Std.random = function(x) {
    return 
Math.floor(Math.random() * x);
}
var 
js = {}
js.Boot = function() { }
js.Boot.__name__ true;
js.Boot.__unhtml = function(s) {
    return 
s.split("&").join("&").split("<").join("<").split(">").join(">");
}
js.Boot.__trace = function(v,i) {
    var 
msg != null?i.fileName ":" i.lineNumber ": ":"";
    
msg += js.Boot.__string_rec(v,"");
    var 
d;
    if(
typeof(document) != "undefined" && (document.getElementById("haxe:trace")) != nulld.innerHTML += js.Boot.__unhtml(msg) + "<br />"; else if(typeof(console) != "undefined" && console.log != nullconsole.log(msg);
}
js.Boot.__clear_trace = function() {
    var 
document.getElementById("haxe:trace");
    if(
!= nulld.innerHTML "";
}
js.Boot.isClass = function(o) {
    return 
o.__name__;
}
js.Boot.isEnum = function(e) {
    return 
e.__ename__;
}
js.Boot.getClass = function(o) {
    return 
o.__class__;
}
js.Boot.__string_rec = function(o,s) {
    if(
== null) return "null";
    if(
s.length >= 5) return "<...>";
    var 
typeof(o);
    if(
== "function" && (o.__name__ || o.__ename__)) "object";
    switch(
t) {
    case 
"object":
        if(
instanceof Array) {
            if(
o.__enum__) {
                if(
o.length == 2) return o[0];
                var 
str o[0] + "(";
                
+= "\t";
                var 
_g1 2_g o.length;
                while(
_g1 _g) {
                    var 
_g1++;
                    if(
!= 2str += "," js.Boot.__string_rec(o[i],s); else str += js.Boot.__string_rec(o[i],s);
                }
                return 
str ")";
            }
            var 
o.length;
            var 
i;
            var 
str "[";
            
+= "\t";
            var 
_g 0;
            while(
_g l) {
                var 
i1 _g++;
                
str += (i1 0?",":"") + js.Boot.__string_rec(o[i1],s);
            }
            
str += "]";
            return 
str;
        }
        var 
tostr;
        try {
            
tostr o.toString;
        } catch( 
) {
            return 
"???";
        }
        if(
tostr != null && tostr != Object.toString) {
            var 
s2 o.toString();
            if(
s2 != "[object Object]") return s2;
        }
        var 
null;
        var 
str "{\n";
        
+= "\t";
        var 
hasp o.hasOwnProperty != null;
        for( var 
k in o ) { ;
        if(
hasp && !o.hasOwnProperty(k)) {
            continue;
        }
        if(
== "prototype" || == "__class__" || == "__super__" || == "__interfaces__" || == "__properties__") {
            continue;
        }
        if(
str.length != 2str += ", \n";
        
str += " : " js.Boot.__string_rec(o[k],s);
        }
        
s.substring(1);
        
str += "\n" "}";
        return 
str;
    case 
"function":
        return 
"<function>";
    case 
"string":
        return 
o;
    default:
        return 
String(o);
    }
}
js.Boot.__interfLoop = function(cc,cl) {
    if(
cc == null) return false;
    if(
cc == cl) return true;
    var 
intf cc.__interfaces__;
    if(
intf != null) {
        var 
_g1 0_g intf.length;
        while(
_g1 _g) {
            var 
_g1++;
            var 
i1 intf[i];
            if(
i1 == cl || js.Boot.__interfLoop(i1,cl)) return true;
        }
    }
    return 
js.Boot.__interfLoop(cc.__super__,cl);
}
js.Boot.__instanceof = function(o,cl) {
    try {
        if(
instanceof cl) {
            if(
cl == Array) return o.__enum__ == null;
            return 
true;
        }
        if(
js.Boot.__interfLoop(o.__class__,cl)) return true;
    } catch( 
) {
        if(
cl == null) return false;
    }
    switch(
cl) {
    case 
Int:
        return 
Math.ceil(o%2147483648.0) === o;
    case 
Float:
        return 
typeof(o) == "number";
    case 
Bool:
        return 
=== true || === false;
    case 
String:
        return 
typeof(o) == "string";
    case 
Dynamic:
        return 
true;
    default:
        if(
== null) return false;
        if(
cl == Class && o.__name__ != null) return true; else null;
        if(
cl == Enum && o.__ename__ != null) return true; else null;
        return 
o.__enum__ == cl;
    }
}
js.Boot.__cast = function(o,t) {
    if(
js.Boot.__instanceof(o,t)) return o; else throw "Cannot cast " Std.string(o) + " to " Std.string(t);
}
js.Lib = function() { }
js.Lib.__name__ true;
js.Lib.debug = function() {
    
debugger;
}
js.Lib.alert = function(v) {
    
alert(js.Boot.__string_rec(v,""));
}
js.Lib["eval"] = function(code) {
    return eval(
code);
}
js.Lib.setErrorHandler = function(f) {
    
js.Lib.onerror f;
}
if(Array.
prototype.indexOfHxOverrides.remove = function(a,o) {
    var 
a.indexOf(o);
    if(
== -1) return false;
    
a.splice(i,1);
    return 
true;
}; else 
null;
Math.__name__ = ["Math"];
Math.NaN Number.NaN;
Math.NEGATIVE_INFINITY Number.NEGATIVE_INFINITY;
Math.POSITIVE_INFINITY Number.POSITIVE_INFINITY;
Math.isFinite = function(i) {
    return 
isFinite(i);
};
Math.isNaN = function(i) {
    return 
isNaN(i);
};
String.prototype.__class__ String;
String.__name__ true;
Array.
prototype.__class__ = Array;
Array.
__name__ true;
Date.prototype.__class__ Date;
Date.__name__ = ["Date"];
var 
Int = { __name__ : ["Int"]};
var 
Dynamic = { __name__ : ["Dynamic"]};
var 
Float Number;
Float.__name__ = ["Float"];
var 
Bool Boolean;
Bool.__ename__ = ["Bool"];
var Class = { 
__name__ : ["Class"]};
var 
Enum = { };
var 
Void = { __ename__ : ["Void"]};
if(
typeof document != "undefined"js.Lib.document document;
if(
typeof window != "undefined") {
    
js.Lib.window window;
    
js.Lib.window.onerror = function(msg,url,line) {
        var 
js.Lib.onerror;
        if(
== null) return false;
        return 
f(msg,[url ":" line]);
    };
}
HelloWorld.main();
})();
 



ふむふむ、なにやら型周りの判定コードなんかが見られますが、読めないレベルではないですね。なお、標準でStdモジュールはimportされる、とのことです。

おそらく実際はここからminifyして使うでしょうし。ここまで大体15分くらいでできました。



IDEを使いたい!


チュートリアルによると、「FlashDevelop」というIDEが一番良い、とされてますが、残念ながらMacでは動かず。で、ちょろちょろと探した結果、MonoDevelopというIDEにはHaxeバインディングが用意されているらしいので、それを入れてみました。下記のサイト参照です。



Haxe IDE for OSX: Monodevelop 3.0 | [mck]



まずはMonodevelopのダウンロードから。

MonoDevelopダウンロードページ

ダウンロードページからOSを選択してDLしますが、先に「Mono + GTK#」というパッケージを入れないと、IDEがlaunchできないよって怒られますので、先にインストールしましょう。起動したら大体日本語されてました。すごい。

続いて、HaxeバインディングもAdd-inリポジトリからダウンロードして、インストールします。mpackというメッセージパック?ファイルがDLされる模様。これもMacのパッケージを選択。

Haxe Language Binding

あとは「Monodevelop」→「アドインマネージャ」と進んで、左下の「Install from file...」で、DLしたバインディングファイルを指定すればインストール完了でした。簡単ですね。






こっちでもHelloWorld


MonoDevelopからHelloWorldを出してみます。

MonoDevelopでは、プロジェクトのもう一階層上というか、「ソリューション」というものがあるみたいで、まずはそれを作らないといけないようです。「ファイル」→「新規」→「ソリューション」で作ります。


 で、ファイルツリーが見えない&展開できないので、「ビュー」→「デフォルト」で左の「ソリューション」をアクティブにするとツリーが見えました。なんだこれ。



ビルド設定とサンプルコード


IDEでは、hxmlファイルをもとにビルドするようなので、このファイルを見てみます。HelloWorld.hxmlです。




-cp Source
-main Helloworld
-js Export/Helloworld.js


要はターミナルでコンパイルするときのオプションが書かれてるだけのようです。--js-modernを追加しとくといいみたいですね。




  • Source : Haxeのソースコード設置先

  • Export : コンパイル後のJSファイルとHTMLが設置される



というファイル構成のようです。なお、コンパイルされたJSファイルはデフォルトではMonoDevelopでは見えないので、プロジェクトを右クリック→「オプションを表示」→「全てのファイルを表示」にチェックを入れとくといいと思います。

デフォルトで作られる雛形はこんな感じでした。Source/Helloworld.hx




package
;

/**
 * ...
 * @author sugimoto
 */
class Helloworld {
    
    public function new () {
        
        
        
    }
    
    static function 
main () {
        
        new 
Helloworld ();
        
    }

}
 


newするタイプの雛形ですね。ではダイアログを出すように書いてみます。




package
;

import js.Lib;
/**
 * ...
 * @author sugimoto
 */
class Helloworld {
    
    public function new () {
        
js.Lib.alert('Hello World');
        
        
    }
    
    static function 
main () {
        
        new 
Helloworld ();
        
    }

}
 


あとはビルドするだけです。ちなみに、js.Libはimportしなくても動きました。自動なのかな?



ビルドして表示してみる


ソリューションツリーのプロジェクトの部分を右クリックしてビルドします。もしくは、ツールバーのブロックみたいなアイコンでもビルド開始できますね。成功したら、ステータスバーに「ビルド成功」と出て、Export内にHelloworld.jsが出来上がっているはずです。



あとは、同じくプロジェクトを右クリックし、「Start Debugging Item」を選択すると、Chromeが立ち上がって(多分デフォルトブラウザが起動します)、ダイアログが出ます。



これでひとまず導入まではいけました!



感想など


公式ドキュメントもまだちゃんと読んでないですが、コード補完はそこそこ出てるんじゃないでしょうか?IDEは好みもあるので何ともですが、ファイルツリー以外はまぁ使える感じです。もっと深く勉強すると色々足りない所が出てきそうですが…。パッケージ使ったり、それほど規模の大きいスクリプトでなければターミナルからお手軽にコンパイルできるので、そういう使い方でいいんじゃないかなー。

とりあえず導入まで出来たので、何かサンプルを作りながら勉強していこうかなーと思っています。
※ちなみにSublime Text2のHaxeパッケージもやってみたのですがしっくりこなかったので割愛(;´Д`)

« 前の記事 次の記事 »

0件のコメント

コメントを投稿する

 画像に表示されている文字を入力してください。