EXCELファイル内のVBAプロジェクトのソース一式をエクスポートする

EXCEL VBAでプログラムを書いた場合にSubversionなどでソースコードをテキストで管理したいのですが従来はEXCELVBAプロジェクトではモジュールひとつずつ選択してエクスポートする方法しかなくて面倒な思いをしていました。
そこですべてのモジュールのソースコードを一括でエクスポートをする方法がないか調べたところVBAを使用すればできることがわかりました。


VBAを使用してVBAプロジェクトを操作する場合にはEXCELのセキュリティのオプションを変更する必要があります。
EXCELのオプション」の「セキュリティセンター」タブで「セキュリティセンターの設定」を実行して「マクロの設定」タブで「開発者向けのマクロ設定」の「VBAプロジェクトオブジェクトモデルへのアクセスを信頼する」にチェックを入れます。


具体的にな方法としては下記の内容をSourceExporter.basとして保存して、VBAプロジェクトの「ファイル」メニューの「ファイルのインポート」でこのSourceExporter.basをインポートしてからマクロあるいはイミディエイトウィンドウからExportSource()関数を実行すればカレントフォルダの下にsrcフォルダが作成されてその下にすべてのモジュールのソースファイルが一括でエクスポートされます。
○SourceExporter.bas

Attribute VB_Name = "SourceExporter"
Option Explicit

'標準モジュール
Const vbext_ct_StdModule As Integer = 1
'クラス モジュール
Const vbext_ct_ClassModule As Integer = 2
'Microsoft Forms
Const vbext_ct_MSForm As Integer = 3
'ActiveX デザイナー
Const vbext_ct_ActiveXDesigner As Integer = 11
'ドキュメント モジュール
Const vbext_ct_Document As Integer = 100

Sub ExportSource()
    Dim export_path As String
    export_path = "src"

    Dim vb_component As Object
    For Each vb_component In ThisWorkbook.VBProject.VBComponents
        Debug.Print vb_component.Name
        Dim extention As String
        Select Case vb_component.Type
            Case vbext_ct_StdModule
                '標準モジュール
		extention = ".bas"
            Case vbext_ct_ClassModule
		'クラス モジュール
                extention = ".cls"
            Case vbext_ct_MSForm
		'Microsoft Forms
                extention = ".frm"
            Case vbext_ct_ActiveXDesigner
		'ActiveX デザイナー
                extention = ".cls"
            Case vbext_ct_Document
		'ドキュメント モジュール
                extention = ".cls"
        End Select
        
        vb_component.Export ThisWorkbook.Path & "\\" & export_path & "\\" & vb_component.Name & extention
    Next
End Sub


ただ、この方法だといちいちEXCELにSourceExporter.basをインポートしてから実行しなければならなくて面倒です。
そこで外部からVBAを実行するようにすればこの必要がありません。
わたしはActiveScriptRubyを使用しているのでそのスクリプトexcel_vba_source_export.rbを以下に引用しておきます。
このスクリプトexcel_vba_source_export.rbの第一引数でソースをエクスポートしたいVBAプロジェクトが含まれるEXCELファイルを指定して第二引数で出力先のパスを指定します。
たとえばExcelTool.xlsというEXCELファイルのVBAプロジェクトのソース一式をカレントの下のsrcフォルダの下にエクスポートする場合には以下のように実行します。

>> ruby excel_vba_source_export.rb ExcelTool.xls src

この場合にも上記のEXCELのセキュリティのオプションの変更が必要です。
excel_vba_source_export.rb

# -*- coding: cp932 -*-
require 'win32ole'
require 'fileutils'

if ARGV.length < 1
  puts '引数が不足しています'
  p ARGV
  exit
else
  excel_file = File.expand_path(ARGV[0])
  unless test(?e, excel_file)
    puts 'EXCELファイルが存在しません'
    exit
  end
  if ARGV.length == 1
    export_path = '.'
  else
    export_path = ARGV[1]
  end
  export_path = File.expand_path(export_path)
  FileUtils.mkdir_p(export_path) unless FileTest.exist?(export_path)
end

# EXCEL VBA オブジェクト
excel = WIN32OLE.new('Excel.Application')
book = excel.Workbooks.Open(excel_file)
# 標準モジュール
Const_vbext_ct_StdModule = 1
# クラス モジュール
Const_vbext_ct_ClassModule = 2
# Microsoft Forms
Const_vbext_ct_MSForm = 3
# ActiveX デザイナー
Const_vbext_ct_ActiveXDesigner = 11
# ドキュメント モジュール
Const_vbext_ct_Document = 100

book.VBProject.VBComponents.each do |vb_component|
p vb_component.Name
  case vb_component.Type
    when Const_vbext_ct_StdModule
    # 標準モジュール
    extention = '.bas'
    when Const_vbext_ct_ClassModule
    # クラス モジュール
    extention = '.cls'
    when Const_vbext_ct_MSForm
    # Microsoft Forms
    extention = '.frm'
    when Const_vbext_ct_ActiveXDesigner
    # ActiveX デザイナー
    extention = '.cls'
    when Const_vbext_ct_Document
    # ドキュメント モジュール
    extention = '.cls'
  end

  vb_component.Export export_path + '\\' + vb_component.Name + extention
end

excel.Quit

これで今までEXCEL VBAでプログラムを書く際の大きな障害が解消されました。