[VBA] 複数のVBAで参照する定数をConfigファイルで一元管理 (改善ver)

やりたいこと

元ネタはコチラ:[VBA] 複数のVBAで参照する定数をConfigファイルで一元管理
コンフィグファイルから定数を取得しようというもの。

改善点は2つ

1.複数のコンフィグファイルを読み込めるようにする。
コンフィグファイルの中で、一生変えなくてもよい値と、たまに変更を加えるかもしれない値がある。
それぞれが混在していると予期せぬ修正が入ってしまう可能性があるためファイルを分けることにした。

2.正規表現を持つフォルダから合致するフォルダを検索できるようにする。
メソッド「GetFilePathList()」はファイルの名前に正規表現が「*」含まれている場合、それに合致するファイルのフルパスを取得することができる。しかし、フォルダ名に正規表現が含まれている場合には対応をしていなかったので、それの改修をした。

ソースコード

Option Explicit

' 参照設定
' Windows Script Host Object Model
'

' コンフィグのKeyとValueを保持するMap
Private params As Dictionary

' コンストラクタ
Private Sub Class_Initialize()
End Sub

' デストラクタ
Private Sub Class_Terminate()
End Sub

'
'【処理】
'   指定フォルダ内の全てのコンフィグファイルを読み込む
'
'【引数】
'   root_path : confファイルの親フォルダのパス
'
'【返り値】
'   なし
'
Public Sub LoadFileList(root_path As String)
    Set params = New Dictionary
    
    ' コンフィグファイルへのパスを設定する
    Dim config_path As String
    config_path = root_path & "\conf"
    Dim fso As FileSystemObject
    Set fso = New FileSystemObject
    Dim f As Scripting.File
    ' 指定フォルダ内の全てのコンフィグファイルを取得する
    For Each f In fso.GetFolder(config_path).files
        If (f.Name Like "*.conf") Then
            Call LoadFile(f.Path)
        End If
    Next
    Set fso = Nothing
End Sub

'
'【処理】
'   コンフィグファイルを読み込む
'
'【引数】
'   file_path : コンフィグファイルの格納されたフォルダへのパス
'
'【返り値】
'   なし
'
Public Sub LoadFile(file_path As String)
    
    Const CHARSET As String = "UTF-8"

    ' ファイル読み込み
    Dim buf As String
    Dim ado As New ADODB.Stream
    With ado
        .CHARSET = CHARSET
        .Type = adTypeText
        .Open
        .LoadFromFile (file_path)
        buf = .ReadText
        .Close
    End With
    Set ado = Nothing
    
    Dim lines() As String
    lines = Split(buf, vbCrLf)
    Dim i
    For i = 0 To UBound(lines)
        Dim line  As String
        line = lines(i)
        line = Trim(line)
        ' コメント行
        If (Left(line, 1) = "#") Then
            ' スキップ
        ' パラメータ追加
        ElseIf (InStr(line, "=") > 1) Then
            Dim kv() As String
            kv = Split(line, "=")
            Call params.Add(kv(0), kv(1))
        End If
    Next
End Sub

' コンフィグ内のKeyに対応するValueを取得する
Public Function ResolveValue(key As String) As String

    ' キーが存在しない場合、処理を中断する
    If (params.Exists(key) = False) Then
        Dim err_message As String
        err_message = "コンフィグ定義エラー" & vbCrLf & "キー:[" & key & "]がコンフィグファイルに定義されていません。"
        Call Err.Raise(1001, "", err_message)
    End If
    
    Dim val As String
    val = params.Item(key)
    
    ' 置換文字列を取得する
    Dim reg As RegExp
    Set reg = New RegExp
    reg.Pattern = ("<.+?>")
    reg.Global = True
    Dim matches As MatchCollection
    Set matches = reg.Execute(val)
    Set reg = Nothing
    
    Dim m As Match
    For Each m In matches
        Dim replace_key As String
        Dim replace_val As String
        ' 置換文字列を取り除く
        replace_key = Mid(m.Value, 2, Len(m.Value) - 2)
        replace_val = ResolveValue(replace_key)
        val = Replace(val, m.Value, replace_val)
    Next
    
    ' 全ての置換文字列が置換された状態でValueを返却する
    ResolveValue = val
End Function
Option Explicit
' コンフィグファイルからキーに対応する値を取得します。
Public Function GetEnv(key As String) As String
    Dim c As ConfigAccessor
    Set c = New ConfigAccessor
    Call c.LoadFileList(ThisWorkbook.Path)
    Dim val As String
    val = c.ResolveValue(key)
    Set c = Nothing
    
    GetEnv = val
End Function

'
' コンフィグファイルからパス/ファイル名を指定し、合致するファイルパスのコレクションを取得する。
' フォルダ/ファイル名には正規表現を指定することも出来る。
' [config]
'     template_file_path=C:\Works\
'     template_file_name=Dog*.xlsx
' [vba]
'     GetSpecificFileName("template_file_path", "template_file_name")
'    ⇒ ["C:\Works\Dog123.xlsx", "C:\Works\Dog456.xlsx", "C:\Works\Dog789.xlsx"]
'
Public Function GetFilePathList(key_file_path As String, key_file_name As String) As Collection
    Dim fso As FileSystemObject
    Set fso = New FileSystemObject
    
    ' コンフィグファイルからフォルダパスとファイル名を取得する。
    Dim file_path As String
    Dim file_name As String
    file_path = GetEnv(key_file_path)
    file_name = GetEnv(key_file_name)
    
    Dim folderNames() As String
    folderNames = Split(file_path, "\")
      
    ' GetFolderの引数が"C:\"のみを設定することができないため
    ' 1,2番目を結合して渡している。
    Dim parentFolder As Folder
    Set parentFolder = fso.GetFolder(folderNames(0) & "\" & folderNames(1))
    Dim currentFolder As Folder
    Dim i As Long
    ' 正規表現に合致するフォルダを取得する
    For i = 2 To UBound(folderNames)
        For Each currentFolder In parentFolder.SubFolders
            Dim hasFounded As Boolean
            hasFounded = False
            If (currentFolder.Name Like folderNames(i)) Then
                Set parentFolder = fso.GetFolder(currentFolder.Path)
                hasFounded = True
                Exit For
            End If
        Next
        ' フォルダが見つからなかった場合、処理を中断する。
        If (hasFounded = False) Then
            Dim err_message As String
            err_message = "指定したフォルダ" & vbCrLf _
                            & "「" & file_path & "」" & vbCrLf _
                            & "が見つかりませんでした。コンフィグの設定を見直してください。"
            Call Err.Raise(1000, "", err_message)
        End If
    Next
    Dim c As Collection
    Set c = New Collection
    Dim match_count As Long
    Dim currentFile As Scripting.File
    ' 正規表現に合致するファイルを取得する
    For Each currentFile In currentFolder.files
        If (currentFile.Name Like file_name) Then
            c.Add (currentFile.Path)
        End If
    Next
    
    Set fso = Nothing
End Function