-
-
Save dsisnero/df89a4e94163b158f44bd4711119664b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: windows-31j -*- | |
# Excelを扱うときの支援用 | |
# 2012/10/17 吉田 | |
require 'win32ole' | |
class XlsHelper | |
# 最初にExcelをインスタンス化したときに定数をインポートする | |
def self.const_init(xls) | |
unless self.const_defined?(:XlUp) # Excel定数の代表 | |
WIN32OLE.const_load(xls, self) | |
end | |
end | |
# Excelインスタンスを取得する。 | |
# ブロックを与えると、ブロックを抜けたところでExcelの終了を試みる。 | |
def self.get_app() | |
xls = WIN32OLE.new('Excel.Application') | |
const_init(xls) | |
if block_given? | |
begin | |
yield(xls) | |
rescue => e | |
xls.Visible = true # 非常時に操作できるように | |
# Excelから来る例外メッセージにはエンコーディング情報がない | |
STDERR.puts e.message.force_encoding(ole_encoding) | |
e.backtrace.each do |t| | |
STDERR.puts t | |
end | |
ensure | |
xls.Workbooks.each do |bk| | |
bk.Saved = true | |
bk.Close | |
end | |
xls.Quit | |
end | |
xls = nil | |
else | |
xls | |
end | |
end | |
# 指定ブックにブロックの処理を適用し、終わればブックを閉じようとする。 | |
def self.work_with_book(bk, &block) | |
unless block | |
raise ArgumentError("this method needs a block.") | |
end | |
begin | |
block.call(bk) | |
ensure | |
begin | |
bk.Saved = true # ブロック内で保存されていないなら、おそらくこの方が安全 | |
bk.Close | |
rescue | |
# NOP | |
end | |
bk = nil | |
end | |
end | |
# 指定のExcelインスタンスでブックを開く。 | |
# ブロックを与えると、ブロックを抜けたところでブックを閉じようとする。 | |
def self.open_book_with(app, bk_file, &block) | |
bk = app.Workbooks.Open(bk_fullpath(bk_file)) | |
if block.nil? | |
bk | |
else | |
work_with_book(bk) do |bk| | |
block.call(bk) | |
end | |
nil | |
end | |
end | |
# 指定のブックを開き、与えられたブロック内で処理する。 | |
# Excelの起動/終了、ブックのクローズは自動的に行う。 | |
# 単一のブックを処理する際の簡易メソッド。 | |
def self.open_book(bk_file, &block) | |
unless block | |
raise ArgumentError("this method needs a block.") | |
end | |
get_app do |app| | |
open_book_with(app, bk_file) do |bk| | |
block.call(bk) | |
end | |
end | |
end | |
# ブック名もしくは序数に相当するブックを返す。 | |
# 該当するブックが開いていなければnil。 | |
def self.get_book(app, bk_idx) | |
get_item(app.Workbooks, bk_idx) | |
end | |
# ブック名もしくは序数に相当するブックがあるか否かを返す。 | |
def self.has_book?(app, bk_idx) | |
has_item?(app.Workbooks, bk_idx) | |
end | |
# シート名もしくは序数に相当するシートを返す。 | |
# 該当するシートがなければnil。 | |
def self.get_sheet(bk, sht_idx) | |
get_item(bk.Worksheets, sht_idx) | |
end | |
# シート名もしくは序数に相当するシートがあるか否かを返す。 | |
def self.has_sheet?(bk, sht_idx) | |
has_item?(bk.Worksheets, sht_idx) | |
end | |
# コレクションの中にidxに相当する要素があればそれを返す。 | |
# なければnil。 | |
def self.get_item(collection, idx) | |
if has_item?(collection, idx) | |
collection[idx] | |
else | |
nil | |
end | |
end | |
# コレクションの中にidxに相当する要素があるか否かを返す。 | |
def self.has_item?(collection, idx) | |
result = false | |
case idx | |
when Numeric | |
result = (0 < idx and idx <= collection.Count) | |
when String, Symbol | |
n = ole_encode(idx.to_s) | |
collection.each do |e| | |
if e.Name == n | |
result = true | |
break | |
end | |
end | |
end | |
result | |
end | |
# 指定されたブックのパスを絶対パスにして返す。 | |
# 以前は常にWindows-31Jエンコーディングで返していたが、 | |
# 現在はそのときのWIN32OLE.codepageに応じたエンコーディングで返す。 | |
def self.bk_fullpath(bk_file) | |
File.expand_path(ole_encode(bk_file)).gsub('/', '\\') | |
end | |
## 指定された文字列に対するWindows-31Jエンコーディングの文字列を返す。 | |
#def self.local_encode(s) | |
# if s.encoding == Encoding::Windows_31J | |
# s.dup | |
# else | |
# s.encode(Encoding::Windows_31J) | |
# end | |
#end | |
# 指定された文字列に対するWIN32OLEコードページに応じたエンコーディングの文字列を返す。 | |
def self.ole_encode(s) | |
enc = ole_encoding | |
if s.encoding == enc | |
s.dup | |
else | |
s.encode(enc) | |
end | |
end | |
# 現在のWIN32OLEコードページに対応するRubyエンコーディングを返す。 | |
def self.ole_encoding | |
case WIN32OLE.codepage | |
when WIN32OLE::CP_ACP, WIN32OLE::CP_OEMCP | |
Encoding.default_external | |
when WIN32OLE::CP_SYMBOL | |
Encoding.ASCII_8BIT | |
when WIN32OLE::CP_UTF8 | |
Encoding::UTF_8 | |
when WIN32OLE::LOCALE_SYSTEM_DEFAULT, WIN32OLE::LOCALE_USER_DEFAULT | |
Encoding.default_external | |
else | |
Encoding.default_external | |
end | |
end | |
# 列番号から文字表記に変換する。 | |
def self.colnum2letter(num) | |
if num == 0 | |
'' | |
else | |
q = num / 26 | |
r = num % 26 | |
if r == 0 | |
q -= 1 | |
r += 26 | |
end | |
colnum2letter(q) + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[r - 1] | |
end | |
end | |
# 文字表記から列番号に変換する。 | |
def self.colletter2num(l_col) | |
n = 0 | |
l_col.each_char do |c| | |
p = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.index(c.upcase) | |
if p.nil? | |
break | |
end | |
n = n * 26 + (p + 1) | |
end | |
n | |
end | |
# セル番号で指定された矩形領域のRangeオブジェクトを返す。 | |
def self.get_rectrange(sht, r1, c1, r2, c2) | |
sht.Range("%s%d:%s%d" % [colnum2letter(c1), r1, colnum2letter(c2), r2]) | |
end | |
# VB色表現を得る。 | |
def self.vbcolor(r, g, b) | |
(b & 0xFF) << 16 | (g & 0xFF) << 8 | (r & 0xFF) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment