VBScriptでInterface風

日頃、雑用?を担当しているせいか、くだらないことを聞きにやって来る人が何人かいる。よくあるのが、あるフォルダ下(サブフォルダも含めて)の全てのファイルに対して何かしたい、というもの。そのぐらい自分でなんとかしてよ…。
自分のマシンであればcygwin上でコマンド組み合わせたりperlで数行書いたり好き勝手にするんだけど、大抵そういう人のマシンには使えるものが入っていなく、標準のVBScriptで頑張るしかない。
いつもは使い捨てていたが、この機会?に使いまわせるように書き直しておく。

'
' tracer.vbs
'
Option Explicit
'
Class Tracer
  '
  Private objFso
  '
  Private Sub Class_Initialize()
    Set objFso = CreateObject("Scripting.FileSystemObject")
  End Sub
  '
  Private Sub Class_Terminate()
    Set objFso = Nothing
  End Sub
  '
  Public Function Run(handler, path)
    Dim objFile, objFolder
    ' file
    If objFso.FileExists(path) Then
      Run = handler.HandleFile(path)
    ' folder
    ElseIf objFso.FolderExists(path) Then
      For Each objFile In objFso.GetFolder(path).Files
        If Not handler.HandleFile(objFile.Path) Then
          Run = False
          Exit Function
        End If
      Next
      For Each objFolder In objFso.GetFolder(path).SubFolders
        If Not Run(handler, objFolder.Path) Then
          Run = False
          Exit Function
        End If
      Next
      If Not handler.HandleFolder(path) Then
        Run = False
        Exit Function
      End If
      Run = True
    ' ?
    Else
      Run = False
    End If
  End Function
End Class
'
Sub Main(handler)
  Dim objTracer, objArgs, objArg
  Set objTracer = New Tracer
  Set objArgs = WScript.Arguments
  If objArgs.Count > 0 Then
    For Each objArg In objArgs
      objTracer.Run handler, objArg
    Next
  Else
    objTracer.Run handler, "."
  End If
End Sub

以下のEchoHandlerはパスを表示するだけの単純な例で、XxxHandlerクラスはその都度適当なクラス名で実装する。HandleFile()にはファイルに対する処理、HandleFolder()にはフォルダに対する処理を実装すればよい。

'
Class EchoHandler
  Function HandleFile(path)
    WScript.Echo path
    HandleFile = True
  End Function
  Function HandleFolder(path)
    WScript.Echo path
    HandleFolder = True
  End Function
End Class
'
Main New EchoHandler
c:\> cscript tracer.vbs c:\temp\

VBScriptのクラスは継承やJavaでいうInterfaceなどもない。全然使えないという意見もあるが、動的型付けなためInterfaceの定義を記述する必要がないだけで、Interface風な使い方は可能である。

特定フォルダを削除したいときはこう。

'
Class CvsDelHandler
  Private objFso
  Private Sub Class_Initialize()
    Set objFso = CreateObject("Scripting.FileSystemObject")
  End Sub
  Private Sub Class_Terminate()
    Set objFso = Nothing
  End Sub
  Function HandleFile(path)
    HandleFile = True
  End Function
  Function HandleFolder(path)
    If Right(path, 4) = "\CVS" Then
      objFso.DeleteFolder path
    End If
    HandleFolder = True
  End Function
End Class
'
Main New CvsDelHandler

多少のエラーも気にしない自分は以下のコマンドで :-)

c:\> for /r %i in (CVS) do rmdir "%i"