SCALAの記事一覧

Scala Process exec

特徴などの紹介

DOSのコマンドでディレクトリの情報を表示するコマンドといえば、

メリット

JavaScript?のPrototype.jsにインスパイアされて、名前をつけました。

設計方針

文字列型推論

極力文字列から文字列から文字列にデータが展開されるような設計です。たとえば、ファイルを読み込むのにFileというクラスをインポートするのではなく、コマンドが指定された時点で文字列をファイル名だと認識して処理すれば良いという発想です。

また、文字列がメールアドレス風であれば、メールなので同じメソッドでも処理を変更するなどが可能となるでしょう。

使用例

ダウンロード

fileprototype.jar

最新版は下記からダウンロードしてください。機能アップのため必要なJARファイルが増えたのでまとめてZIPファイルにしました。

scala prototype.zip

インストール

prototype.jarをクラスパスに追加してください。 コンパイル時や実行時にクラスパスを自動追加するバッチファイルを別途用意してありますので、 そちらを使うと便利です。

scalaを使う場合

scalaa.bat (リターン)
scala> import prototype.Prototype._
scala> "dir".exe

ProcessMain?.scala

package test
object ProcessMain {
   def main(args: Array[String]): Unit = {
       //Prototype.scalaを用意した後、次の一行で呼び出す。
       import Prototype._
       println("--例1 直接こんな感じでシェルを呼び出せます。--")
       "dir ".exe //ディレクトリの情報が表示される
       
       println("--例2 値を文字列変数で取得可能です。--")
       println("dir /w".exeresult)

       println("--使い方3--")
       "dir /w".exe_eachLine{line =>
         	println(line)
       }
       
       "使い方4".p
       "文字列の表示はprintlnと同じ意味のpを用意しました。違いは値を返します。".p
       
       "2回表示して実行する例".p
       "echo aaaa".p.p.exe
       
       "実行ごとにプロセスが生成されるので、ディレクトリの移動は意味がありません".p
       "echo zzzz".exe
       "cd c:\\".exe
       "dir".exe
       
       println(currentdir)
       
   }
}

Prototype.scala

package test
import java.io._
import scala.util.DynamicVariable
import java.lang.Process
import java.util.ArrayList 

//--------------------------------
//   Object記述部分
//--------------------------------

object Prototype {
 	var currentdir :String= ""
      
   implicit def wrapBufferedReader(src: BufferedReader) = {
	    new WrapBufferedReader(src)
   }
   
   implicit def wrapString(src: String) = {
	    new WrapText(src)
   }

   implicit def wrapList_String(src: List[String]) = {
	    new WrapList_String(src)
   }
   
   implicit def wrapList_Object(src: List[Object]) = {
	    new WrapList_Object(src)
   }
   
   implicit def wrapArray_String(src: Array[String]) = {
	    new WrapArray_String(src)
   }
   
   def init_currentdir ={

		if (currentdir == ""){
		    currentdir = "cd".exeresult.chomp
		    //("カレントディレクトリを" + currentdir + "にしました").p
		} 
   }
   init_currentdir
}

//--------------------------------
//   class記述部分
//--------------------------------

//BufferedReaderにeachLineメソッドを拡張する
class WrapBufferedReader(src: BufferedReader) {
   def eachLine(f: String => Unit) {
	  var line:String = null
     while({line = src.readLine ; line != null}){
       f(line)
     }
   }
}

//Stringを拡張するメソッド
class WrapText(string : => String){
   //行末の改行を削除します。
   def chomp() :String = {
       gsub("\n$","")
   }

   //実行して結果を出力する
   def exe(current :String)  :String= {
       var result = exeresult(current)
       println(result)
       result
   }
   
   
   //実行して結果を出力する
   def exe() :String = {
   	var result = exeresult
       println(result)
       result
   }
       
   //プロセスを実行し結果の文字列を返す。
   def exeresult(current :String) :String = {
       import Prototype._
       var process:ProcessScala =  new ProcessScala
       process.current = current
       var result :String = ""
       if (string.length > 3 && string.substring(0,3)=="cd ") {
       	result = process.exeresult(string + " & cd")
       	currentdir = result
       } else {
       	result = process.exeresult(string)
       }
       result
   }    

   //プロセスを実行し結果の文字列を返す。
   def exeresult() :String = {
       exeresult("")
   }
   

   
   implicit def wrapArray_String(array: Array[String]) = {
	    new WrapArray_String(array)
   }  
   
   //実行して結果を出力する
   def exe_eachLine(current :String)(f: String => Unit) {
     val lines = exeresult(current).split("\n")
     lines.each{line=>
       f(line)
     }
   }
   
   //実行して結果を出力する
   def exe_eachLine(f: String => Unit) {
     val lines = exeresult.split("\n")
     lines.each{line=>
       f(line)
     }
  }    
   
   
   //文字列を置換します。
   def gsub(pat : String,afterstring :String) :String = {
   	string.replaceAll(pat,afterstring)
   }
   
   //List要素化
   def l() :List[String] = {
       List(string)
   }
   
   //表示println
   def p() :String = {
       println(string)
       string
   }
   
   //ファイルとして返します。
   def toFile :File = {
       new File(string)
   }
   
}

//Array[String]を拡張するクラス
class WrapArray_String(array : Array[String]){
	def each(f: String => Unit){
	   for (item <- array){
	     f(item)
	   }
   }
}

//List[String]を拡張するクラス
class WrapList_String(list : List[String]) {
 	def toArrayList() :ArrayList[String] ={
 	   var result : ArrayList[String] = new ArrayList[String]()
      for(item <- list){
   	   result.add(item)
      }
      result
 	}
}



//List[Object]を拡張するクラス
class WrapList_Object(list : List[Object]) {
 	def toList_String() :List[String] ={
      list.asInstanceOf[List[String]]
 	}
  
   def flat(): List[Object]={
       flatten(list).asInstanceOf[List[Object]]
   }
   
	def flatten(l: List[Any]): List[Any] = l flatMap {
	    case l: List[_] => flatten(l)
	    case e => List(e)
	  }
}






case class ProcessScala(currentdir :String, charset :String) {
	val dynamicvariable= new DynamicVariable[Process](null)
	var current = currentdir
	var stdout :BufferedReader = null;
   var stderr :BufferedReader = null;
	//var stdin :BufferedWriter = null;
    
   import Prototype._
   
	//デフォルトのキャラクタコードを使う
	def this() = this("","")
	
	//自動的にDestroyするProcess
	def exec(cmd:String)(block : => Unit){
      var process :Process = null
      var processbuilder = new ProcessBuilder

      //カレントディレクトリの設定
      def setting_current = {
         //値がcurrentに格納されているのなら、作業ディレクトリをセットします。
 		  if ("" != current){
       	 processbuilder.directory(current.toFile)
         }
      }
      
      //プロセスを開始します。
      def startProcess(processbuilder :ProcessBuilder){
        process = processbuilder.start
	  	 stdout = getBufferdReader(process.getInputStream(),"")
	     stderr = getBufferdReader(process.getErrorStream(),"")
      }
      
      //プロセスを作成します。
      def makeprocessByList(commands:List[String]){
		 setting_current
        processbuilder.command(commands.toArrayList())
        startProcess(processbuilder)
      } 

      //プロセスを作成します。
  	   def makeprocess(command:String) = {
		 setting_current
        processbuilder.command(command)
        startProcess(processbuilder)
      }
      
      
	   try {
	     //プロセスを作成します。コマンドラインの場合はcatchされます。
	     makeprocess(cmd)
        dynamicvariable.withValue(process){block}
	   } catch {
	      //コマンドラインをためしてみる。
	      case e:java.io.IOException =>{
	        try {
		        if (cmd.length < 7 || !(cmd.substring(0,6) == "cmd /c")){
		           //cmd /cを追加してみる
		           var commands = ("cmd".l :: "/c".l :: cmd.l).flat;
                  makeprocessByList(commands.asInstanceOf[List[String]])
				   dynamicvariable.withValue(process){block}
		        }
	        } catch { 
	          case e =>println (cmd + " is exsits?")
	            throw e
           }
         }
	   } finally {
	     //子プロセス呼び出し後は,必ず,ストリームを閉じる
	     	if (process != null) {
		        process.getErrorStream().close();
		        process.getInputStream().close();
		        process.getOutputStream().close();
		        process.destroy();
	        }
           if (stdout != null) {
           	try {stdout.close} catch {case e:IOException => }
           }
           if (stderr != null) {
           	try {stderr.close} catch {case e:IOException => }
           }
	   }
	}

	//実行結果の戻り値を返します。
	def exeresult(command :String) = {
		var result = ""
		exec(command){
	      var line:String = null
	      while({line = stdout.readLine ; line != null}){
	        result = result + line + "\n"
	      }
	   }
      result
	}


   //get dynamic variable's value
   def $_()={
       dynamicvariable.value
   } 
   
   def getBufferdReader(is:InputStream, charset :String):BufferedReader = {
       if (charset == "") {
       	new BufferedReader(new InputStreamReader(is));
       } else {
			try {
				new BufferedReader(new InputStreamReader(is, charset));
			} catch {
				case e: UnsupportedEncodingException => {
					throw new RuntimeException(e);
				}
			}   
       }
   }
}

今後の方針


添付ファイル: filescalacc.bat 334件 [詳細] filescalaa.bat 329件 [詳細] fileprototype.jar 213件 [詳細]
トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-12-10 (木) 23:17:25 (3139d)