Ruby: Win32OLEでの Excelマクロの操作
ExcelのインストールされているWindows環境ではExcelを Win32OLE という仕組みで 利用することが可能です。この仕組みを使うとExcelのVBAで出来ることはRubyからも 同様に出来るようになります。このページを読む前にOLEでの操作のページ「 Excel操作(OLE) 」を読んで下さい。
このページではExcel内のマクロを修正したり、置き換えたりする方法を紹介します。
このページの元と成るコードは Ruby 1.8.7 で利用した物です。
Ruby: Excelのコンポーネントを操作するための設定
まず、ExcelのマクロはVBProjectモジュール内のVBComponentsの中にあります。
このVBProjectモジュールを外部から操作するにはExcel2003以後のバージョンでは
セキュリティ設定が必要と成ります。
具体的には各バージョンのExcelのセキュリティ設定ダイアログで下記の項目にチェックを入れて
アクセスを許可してください。
「Visual Basic プロジェクトへのアクセスを信頼する」
上記の設定が無い場合、VBProjectを操作しようとするとエラーに成ります。
Ruby: Excelの中のマクロを表示する。
ExcelのマクロはVBProjectモジュール内のVBComponentsの中にありますので VBComponentsを順に調べると見つけられます。
下記のコードと同じ場所にbook1.xlsを作り適当にマクロの記録でマクロを作って置いて下さい。 その後このコードを実行するとbook1.xls内に記録されたマクロが表示されます。
#! ruby -Ks # -*- mode:ruby; coding:shift_jis -*- $KCODE='s' require 'excel' openExcelWorkbook('book1.xls') do |book| book.VBProject.VBComponents.each do |compo| compo_name = compo.Name print "\n---------- book1.xls has component : #{compo_name} -------\n" n = compo.CodeModule.CountOfLines if n > 0 print compo.CodeModule.Lines(1,n) end end end
VBProjectのVBComponentsをeachで順に見て、CodeModuleのライン数(CountOfLines)が ゼロでないものについてマクロのコードの1行目から最後の行まで(Lines(1,n))を 表示させています。
Ruby: Excelの中のマクロを修正する。
マクロのコードを修正したい場合にはモジュールの名前で対象を絞り、 各行毎に見て修正していけばOKです。
下記の例はモジュール名がModuleで始まるものの中の 「マクロの記録」と言う文字列を「マクロの修正」に書き換えます。
#! ruby -Ks # -*- mode:ruby; coding:shift_jis -*- $KCODE='s' require 'excel' openExcelWorkbook('book1.xls') do |book| book.VBProject.VBComponents.each do |compo| if compo.Name =~ /^Module/ n = compo.CodeModule.CountOfLines if n > 0 compo.CodeModule.Lines(1,n).each_with_index do |line,i| line.chomp! if line =~ /マクロ記録/ line.sub!(/マクロ記録/,'マクロの修正') compo.CodeModule.ReplaceLine(i+1,line) end end end end end book.save end
注意点はReplaceLineに渡す文字列に改行文字を入れない事です。 改行がある文字列を渡すと行の追加のような動作になり、 想定外の変更になってしまいます。
この例では line.chomp! で改行を削除してから処理しています。
また行数が1始まりですからeach_with_indexを使うときには+1して下さい。
変更後は book.save で保存することを忘れないで下さい。
操作するモジュールが固定の場合、下記の様に book.VBProject.VBComponents('Module1').CodeModule と 直接指定して操作することが出来ます。
#! ruby -Ks # -*- mode:ruby; coding:shift_jis -*- $KCODE='s' require 'excel' openExcelWorkbook('book1.xls') do |book| code = book.VBProject.VBComponents('Module1').CodeModule n = code.CountOfLines if n > 0 code.Lines(1,n).each_with_index do |line,i| line.chomp! if line =~ /マクロの記録/ line.sub!(/マクロの記録/,'マクロの修正') code.ReplaceLine(i+1,line) end end end book.save end
行ごとのチェックが必要ない場合には一旦文字列として全体のコードを 取出して、修正し、丸ごと書き換える方法も使えます。
#! ruby -Ks # -*- mode:ruby; coding:shift_jis -*- $KCODE='s' require 'excel' openExcelWorkbook('book1.xls') do |book| code = book.VBProject.VBComponents('Module1').CodeModule n = code.CountOfLines if n > 0 macro = code.Lines(1,n) # 内容取出し macro.gsub!(/マクロ/,'Macro') # 修正 code.DeleteLines(1,n) # 全行消去 code.AddFromString(macro) # 修正内容に置換え end book.save end
Ruby: Excel、マクロ操作関数
利用しそうな関数を列記しておきます。修正したら book.save をお忘れなく。
(注意) 行番号は 1 始まりです。
-
CodeModule.Name
モジュール名
-
CodeModule.CountOfLines
マクロの行数
-
CodeModule.Lines(開始行,行数)
開始行から行数分のマクロの内容
-
CodeModule.ReplaceLine(行番号, 文字列)
行番号の行の内容を文字列に置き換える。改行を含ませないこと。
-
CodeModule.InsertLines(行番号,文字列)
指定した行番号の前に挿入されますので、行番号は挿入した行の番号と成ります。 改行を含ませないこと。
-
CodeModule.DeleteLines(開始行,削除行数)
指定した行を削除します。1行目から最終行まで全行削除することで add系の関数で全体を置き換えることが出来ます。
code = book.VBProject.VBComponents('Module1').CodeModule code.DeleteLines(1,code.CountOfLines) #全行削除
-
CodeModule.AddFromFile(ファイル名)
ファイルの内容を先頭に追加します。ファイル名はフルパスで指定して下さい。
code = book.VBProject.VBComponents('Module1').CodeModule code.DeleteLines(1,code.CountOfLines) #全行削除 code.AddFromFile('c:\\code.txt') #ファイルの内容を追加
-
CodeModule.AddFromString(文字列)
文字列を先頭に追加します。文字列は複数行を指定可能です。
openExcelWorkbook('book1.xls') do |book| book.VBProject.VBComponents('Module1').CodeModule.AddFromString("'追加コード\n'2行目") book.save end
Ruby: Excelマクロのバージョン管理
下記の様なスクリプトでExcelのマクロをファイルに取出しておいて、gitやsubversions等で管理することで マクロのバージョン管理が出来ます。
取出す時のファイル名の拡張子や取出し先 等はお好みで変更してください。
終了ボタンは作っていませんので、 ウインドウ右上の「X」の閉じるボタンで終了してください。
#! ruby -Ks # -*- mode:ruby; coding:shift_jis -*- $KCODE='s' require 'excel' require 'tk' STDOUT.sync = true def save_macros file if file =~ /\.xls/i b_name = File.basename(file,".*") dir = File.dirname(file) openExcelWorkbook(file) do |book| book.VBProject.VBComponents.each do |compo| compo_name = compo.Name n = compo.CodeModule.CountOfLines if n > 0 path = dir + '/' + b_name + '_' + compo_name + '.txt' print "Output : #{path}\n" File.open(path,'w').write(compo.CodeModule.Lines(1,n)) end end end end end Tk.root.title('Save Excel macro') b1 = TkButton.new('text' => 'Excelファイル選択ボタン').pack('fill'=> 'x') b1.command { file = Tk.getOpenFile({'title' => 'Excelファイル選択','filetypes'=>[['excel','.xls']],}) if file != '' save_macros file end } Tk.mainloop
南岳気象データ ← : Excelマクロの操作 : → ブロックを使う
お勧めのRuby開発環境
Trail4You 仮想マシンバザール : Ruby統合開発環境仮想マシン上にruby統合開発環境をインストールしてあります。 rvm, git もインストール済みで各種rubyを切替ながら試せます。