SCALAの記事一覧

[編集]

RubyでScalaスクリプトをコンパイル補助するツールを作成する。

目的

HelloWorld程度ならば、コンパイルツールをつくることは必要ないのでしないのですが、
使えるプログラムというものは、はたくさんのjarをインクルードしたものになりがちです。

以下の問題点を解決

となれば、自分で簡潔に動作する最速のツールをつくってしまおうとおもったわけです。

目次

[編集]

仕様

ツール1 タイムスタンプスナップ機能

フォルダ内の.scalaファイルのタイプスタンプのスナップを取得する。

ツール2 更新ファイル抽出機能

既存のタイムスタンプと現在のファイルのタイムスタンプを比較し更新されたファイルを取得しコンパイル可能なバッチファイルを生成する

scalacc.batの例

BASEが2回出てきているが、どちらも自動的にJarファイルを読み込みたいフォルダである。下記の例のように追加したいフォルダの数だけ繰り返し記述するとよいでしょう。

@echo off
setlocal ENABLEDELAYEDEXPANSION
set CP=.
set BASE=C:\scala\lib
for %%f in (%BASE%\*) do set CP=!CP!;%%f
set BASE=C:\scala\lib\user
for %%f in (%BASE%\*) do set CP=!CP!;%%f
SET SCALA_DOC_HOME="C:\scala\doc"
ECHO %CP%
scalac -classpath %CP% %1

ツール1 タイムスタンプスナップ機能

rubyのディレクトリ関連の処理

ディレクトリ中のファイル一覧を取得する

ワイルドカードにマッチしたファイル全てに処理を行う

ファイルのタイムスタンプを取得する

snap_timestamp.rb

path=ARGV[0].gsub("\\","/")
ext="scala"
outfile="timestamp.txt"

buffer = ""
# **は再帰的検索。\0は複数パターンの区切り。.*は隠しファイル取得
Dir.glob("#{path}/**/*\0#{path}/**/.*" + ext).each{|name|
   puts name
   buffer = buffer + name + "\n"
   
	s = File.stat(name)
	timestamp = File.mtime(fname).strftime("%Y/%m/%d %H:%M:%S") # 最終更新時刻
	puts timestamp
	buffer = buffer + timestamp + "\n"
	
} 

# タイムスタンプスナップを上書き更新します。
file = File.open(path + "/" + outfile, "w");
# 書き込む
file.write(buffer);
file.close

snap_timestamp_diff.rb

更新したファイルを出力する

#第一引数はフォルダ名
path=ARGV[0].gsub("\\","/")
ext=/.*\.scala$/
outfile="timestamp.txt"

current={}

# **は再帰的検索。\0は複数パターンの区切り。.*は隠しファイル取得
Dir.glob("#{path}/**/*\0#{path}/**/.*" ).each{|name|
	if ext =~ name
		s = File.stat(name)
		current.store(name,File.mtime(name).strftime("%Y/%m/%d %H:%M:%S"))
	end
}

# タイムスタンプ保存用ファイル読み込み
before={}
file = open(path+"/"+outfile)
buffer = file.read().split("\n");
file.close

#2行を1つの配列にまとめた配列を作成
newItem=""
newItem = nil
buffer.each{|line|
	if newItem == nil
		newItem=line
	else
		if ext =~ newItem
			before.store(newItem,line)
		end
		newItem = nil
	end
} 


#タイムスタンプの比較 更新・新規追加したファイルを出力
current.each{|filepath, timestamp|
	if timestamp != before.fetch(filepath)
		puts filepath
	end
}

備考

RubyをWindowsのDOSで動作させるとRubyからバッチファイルを動作させる際に使用する
システムのShellが使用している

Scala でコマンドの実行結果を文字列として取得

別途prototype.jarをつくって、簡単に取得できるようにつくっておきました。

簡潔でしょ?

下記の例は簡潔にかけているんだけど、実際にはInputStream?を閉じないとそのうち不具合がでるので、しっかりとcloseする処理が必要です。

その点上のprototype.jarを使えば、その点が考慮されているばかりか、文字列、配列の基本クラスの拡張までやってくれるので、

開発効率がアップしますよん。

「java -version」を実行する例

	Runtime r = Runtime.getRuntime();
	Process p = r.exec("java -version");

複数の引数の指定方法

	Runtime r = Runtime.getRuntime();
	Process p = r.exec(new String[] {
		"C:\\Program Files\\Java\\j2re1.4.2_13\\bin\\java",
		"-version" });

「echo zzz」を実行する例

	Runtime r = Runtime.getRuntime();
	Process p = r.exec("cmd /c echo zzz");
//	Process p = r.exec(new String[]{ "cmd", "/c", "echo", "zzz" });

環境変数の指定

	String[] env = new String[2];
	env[0] = "TEST=サンプル";
	env[1] = "PATH=" + System.getProperty("java.library.path");
	Runtime r = Runtime.getRuntime();
	Process p = r.exec("cmd /c echo %TEST%", env);

参考URL 外部プロセス起動

http://www.ne.jp/asahi/hishidama/home/tech/java/process.html#Runtime

Javaで,子プロセスを使うときの注意点

http://isolinear.info/wiki/index.php/Java/Tips/Java%A4%C7%A1%A4%BB%D2%A5%D7%A5%ED%A5%BB%A5%B9%A4%F2%BB%C8%A4%A6%A4%C8%A4%AD%A4%CE%C3%ED%B0%D5%C5%C0.html

バッチファイルからだと連続して2つめのコンパイル以降が無視される。

バッチファイルからだと、どういうわけかわかりませんが、1つめのコンパイルが終わるとバッチファイルが終了してしまいます。

startコマンドをつかうと、非同期にコンパイルされてしまい、コンパイルが正しくできない場合があります。 そこで、対策として、SCALAでコンパイルごとにプロセスをたて、なおかつ同期をとりながらコンパイルするコードを作成しました。

説明

余談 コマンドラインの実行結果を環境変数に格納する方法での怪しい現象

コマンドラインの実行結果を環境変数に格納する方法に

FOR /F %t IN ('TIME /T') DO SET NOWTIME=%t

というサンプルがある。これをDOS窓から実行すると,DOS窓が閉じてしまうのだ。ところが、DOS窓からさらに

cmd

と打ち込んで、もう一段DOS窓をかませて実行すると、DOS窓は閉じなくなるのだ。不思議だ。 バッチファイル実行は、どうなるんだろうか。。。

と出てきました。OSはWindowsXPです。 なんでやねん。って言いたいです。

色々サイトをみていたときに、%tではなく%%t表記の表現があることを思い出してバッチファイルを下記のように修正してみました。

FOR /F %%t IN ('TIME /T') DO SET NOWTIME=%%t 

画面が閉じる

ただし

cmd

でコマンド画面を1段かませた場合には画面は閉じない

さもないと次に示すバッチファイルを2段構えにしたファイルが必要です。

DOSからエディタを簡単に開くバッチ

DOS画面からファイルを編集したい場合がちょくちょくある。

そこで次のバッチファイルをパスが通ったところに置くと改善する。

cygwinのシェルから呼び出す場合

上記のバッチファイルを呼び出す例 フォルダの位置は参考まで

#! /usr/bin/sh
/cygdrive/c/userbin/edit.bat "$1"

というか、DOSのよりもCYGWINのシェル環境のほうが少なくても10000倍は優れている

DOSはなぜかXPになっても石器時代のままだ。できればcygwin環境を標準でつかいたいものだ、zsh、すくなくともbashである。

しかしながらcygwin上からscalaを実行しようとすると下記の問題点があることが判明したので、泣く泣くDOS環境に戻ってつかっているという経緯があったのだ。

cygwin上からscalaをつかう際の問題点

対策

cygwin上からscalaを呼び出す際には下記のコマンドで開く

cmd /c start scala

つまり、DOS上かつ別プロセスで実行してやれば問題ないのである。

.zshrcの設定

以上のことから、cygwinのシェルの設定を修正するため .zshrcファイルもしくは.bash_profileに下記の設定を追加しておく

alias scala=cmd /c start scala
[編集]

バッチファイルの例

copy "C:\Documents and Settings\Administrator\workspace\prjPrototype\src\prototype\Prototype.scala" .

:CHECK_UPDATE
ruby "c:\scala\bin\snap_timestamp_diff.rb" . >updatelist.txt

FOR /F %%t IN ('cd') DO SET CURRENTDIR=%%t 
REM 
scalac "c:\scala\bin\scalacc.scala"

カレントディレクトリを取得して コマンドに渡しています。

scalacc.scala

目的

付属のscalacでコンパイルを行うと、連続複数ファイルのコンパイルができないため、これを実現可能なバッチファイルを用意する。

仕様

拡張子が.scalaであれば、単体ファイルのコンパイル、そうでなければファイル指定であると 認識する

実行方法

ただ、これだと書き方が助長なので下記のバッチファイルを作成

scalaccc.bat

scalaa "c:\scala\bin\scalacc.scala" %*
トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-12-18 (金) 08:57:01 (2799d)