ASR便利!
artonさんの
WIN32OLEの高速化手法 - L'eclat des jours(2011-02-07)
Rubyizeのインプロセス/インスレッド化 - L'eclat des jours(2011-02-09)
記事を読んで、スクリプトを文字列で渡しても実行可能とあったのでやってみた。
<実行環境>
Windows 7 64bit
ASR (Ruby-1.9.2-p136 Microsoft Installter Package(2010-12-25))
Excel 2002
スクリプトは[script.rb]ファイルを文字列として読み込む。
[RubyModule.bas]モジュールをExcelにインポートして、execRubyをマクロ実行する。
[RubyModule.bas]
Attribute VB_Name = "RubyModule" Sub execRuby() Dim ruby As Object Dim script As Object Set ruby = CreateObject("rubyize.object.1.9") Set script = ruby.erubyize(loadScript()) MsgBox script.exec(ActiveWorkbook) End Sub Function loadScript() As String Dim fileSystem As New Scripting.FileSystemObject Dim textStream As Scripting.textStream Dim filepath As String Dim code As String On Error GoTo Err 'FileSystemObject生成 Set fileSystem = New Scripting.FileSystemObject 'ファイルパスを取得 filepath = fileSystem.GetAbsolutePathName(ActiveWorkbook.Path & "\script.rb") 'ファイルを開く Set textStream = fileSystem.OpenTextFile(filepath, ForReading, False, TristateUseDefault) 'ファイルの内容を読み出し code = textStream.ReadAll 'クローズ textStream.Close Set textStream = Nothing Set fileSystem = Nothing loadScript = code Exit Function Err: 'エラー Set textStream = Nothing Set fileSystem = Nothing MsgBox (Err.Description) End Function
スクリプトは実行する.xlsファイルの名前と同じ名前のメソッドが実行するようにした。
[sample.xls]なら[script.rb]のsampleメソッドが呼び出される。
[ex01.xls]なら[script.rb]のex01メソッドが呼び出される。
[XXX.xls]とメソッドXXXがある[script.rb]は同じフォルダに置いておく。
[script.rb]
# coding: CP932 args = { sample: nil, ex01: [1..65536, 'A'..'IV'], } Script = Class.new do define_method :sample do |book, *params| start = Time.now sheet = book.worksheets(1) 1.upto(10000) do |row| cells = sheet.Range(sheet.Cells(row, 1), sheet.Cells(row, 26)) values = cells.Value 26.times do |col| if row.even? values[0][col] = 3 else values[0][col] = 'こんにちは' end end cells.Value = values end %{Elapsed time: #{Time.now - start} secs} end define_method :ex01 do |book, *params| start = Time.now rows, cols, * = [*params].flatten cols = alpha_to_num(cols) sheet = book.worksheets(1) sheet.Name = File.basename((book).Name, ".*") rows.each do |row| cells = sheet.Range(sheet.Cells(row, cols.min), sheet.Cells(row, cols.max)) values = cells.Value cols.each do |col| if row.even? values.first[col] = 3 else values.first[col] = 'こんにちは' end end cells.Value = values end %{Elapsed time: #{Time.now - start} secs} end define_method :exec do |book| bookname = File.basename((book).Name, ".*") send(bookname.to_sym, book, args[bookname.to_sym]) end def alpha_to_num(alphas) tables = {}.tap{|h| ('A'..'Z').to_enum.with_index(1){|c, i| h[c]=i} } convertor = ->s{s.upcase.reverse.chars.with_index.inject(0){|r, (c,i)| r+=tables[c]*26**i}} result = case alphas when String then convertor[alphas] when Array then alphas.map(&convertor) when Range then Range.new(*alphas.map(&convertor).minmax) else alphas end rescue exit(1) end end script = Script.new
.xlsxとか他のExcelバージョンでは動作確認していません。
環境がないので…