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バージョンでは動作確認していません。
環境がないので…