Hatena::ブログ(Diary)

Tosikの雑記 このページをアンテナに追加 RSSフィード Twitter

2010-09-13

ruby の win32ole のメソッド名が UpperCamelCase で気持ち悪いので、underscore で使えるようにした

お仕事でエクセルのデータを変換する必要があって、でも VBA は勘弁して欲しいと思ってなんとかできないかなと思ってたら、ruby で COM を操作するライブラリがあるじゃないですか!

ところが、この ruby の win32ole はメソッド名が COM のまま。COM のメソッド命名規則的には UpperCamelCase らしいけど、ruby でそれは気持ち悪い。というわけで、ruby の win32ole のメソッドを underscore で使えるようにした

require 'win32ole'
require 'active_support/inflector'

class WIN32OLE
  alias_method :old_method_missing, :method_missing
  def method_missing(name, *args, &block)
    begin
      old_method_missing(name.to_s.camelize(:upper), *args, &block)
    rescue NameError
      old_method_missing(name, *args, &block)
    end
  end
end

# trial
excel = WIN32OLE.new('Excel.Application')
excel.visible = true
workbook = excel.workbooks.add()
worksheet = workbook.worksheets(1)
worksheet.range('A1:D1').value = ['North','South','East','West']
puts worksheet.used_range.rows.extend(Enumerable).map {|row|
  row.columns.extend(Enumerable).map {|column| column.value }.join(",")
}

どうでしょうか。ちなみに、active_support/inflector は camelize しか使ってないので、active_support を使わない場合は適当に置き換えてください。

2010-08-18

ruby で時間待ちテストを高速で終わらせる方法

お湯を入れると3分後に食べられる麺クラス

class Noodle
  def pour_water
    @time_of_poured = Time.now
  end
  def can_eat?
    (@time_of_poured + 3 * 60) > Time.now
  end
end

テストケース(3分たったら食べられるか)

noodle = Noodle.new
noodle.pour_water
assert !noodle.can_eat?
sleep(3*60)
assert noodle.can_eat?

このテストは sleep を使っているので3分待たないと終わらない。

開発中になんどもカップ麺が出来上がるのを待ってる暇などない。

なので、適当に時間を進められるように Time クラスを改造した。

class Time
  @@default_now_method = self.method("now")
  @@n_seconds_early = 0

  def self.now
    @@default_now_method.call + @@n_seconds_early
  end

  def self.set_early(seconds)
    @@n_seconds_early += seconds
  end
end

これを使うと、上のテストはこう書ける。

noodle = Noodle.new
noodle.pour_water
assert !noodle.can_eat?
Time.set_early(3*60)
assert noodle.can_eat?

Time.set_early で直ちに時間を進めることができる。

仕事で「3秒待つ」みたいなテストケースが何個かあって結構頻繁にテストを実行するのでこう作った。

それから、sleep って不正確だしね。他のオーバーヘッドで遅くなっても Time.now は待ってくれない。

ほんとうのところは Time クラスをいじらず、Time のラッパを作ってあげたほうがよかったのかも。

resque on rails

installing

ruby script/plugin install git://github.com/defunkt/resque.git

rake redis:install PREFIX=..........

rake dtach:install PREFIX=..........

running

QUEUE=* rake resque:work # run worker

./vendor/plugins/resque/bin/resque-web # run resque web interface

defining queue class

class Hoge
 @queue = :hoge
 def self.perform(fuga)
   # perform this queue
 end
end

enqueue

Resque.enqueue(Hoge, fuga)

2010-06-01 このエントリーを含むブックマーク このエントリーのブックマークコメント

hudson が落ちる。

hudson 1.3.60

マスターを ubuntu で、スレーブを windows にしたときだけ発生。(マスタースレーブどっちも windows, どっちも linux のような他の組み合わせでは発生しなかった)

プラグインは無効にしてある。

checkout の途中で windows のスレーブが terminated になり、次のようなエラーがマスターで発生する。


Checking out a fresh workspace because C:\hudson\workspace\hello_hudson\Media doesn't exist Checking out http://192.168.(省略)

FATAL: hudson.remoting.RequestAbortedException: java.net.SocketException: Connection reset hudson.remoting.RequestAbortedException: hudson.remoting.RequestAbortedException: java.net.SocketException: Connection reset
at hudson.remoting.Request.call(Request.java:137)
at hudson.remoting.Channel.call(Channel.java:551)
at hudson.FilePath.act(FilePath.java:742)
at hudson.FilePath.act(FilePath.java:735)
at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:653)
at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:601)
at hudson.model.AbstractProject.checkout(AbstractProject.java:1044)
at hudson.model.AbstractBuild$AbstractRunner.checkout(AbstractBuild.java:479)
at hudson.model.AbstractBuild$AbstractRunner.run(AbstractBuild.java:411)
at hudson.model.Run.run(Run.java:1241)
at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46)
at hudson.model.ResourceController.execute(ResourceController.java:88)
at hudson.model.Executor.run(Executor.java:124) Caused by: hudson.remoting.RequestAbortedException: java.net.SocketException: Connection reset
at hudson.remoting.Request.abort(Request.java:257)
at hudson.remoting.Channel.terminate(Channel.java:598)
at hudson.remoting.Channel$ReaderThread.run(Channel.java:880) Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:185)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2265)
at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2558)
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2568)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1314)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
at hudson.remoting.Channel$ReaderThread.run(Channel.java:856) 

2010-04-03

Windows 用コマンドランチャー TeaLauncher 開発経緯

愛用していたコマンドランチャ "bluewind" の開発者のサイトが消えてしばらくたちました。再配布サイトは存在しますが、開発が続行することは期待できません。

bluewind にはいくつか問題がありました。コマンド入力時にクラッシュしたり、IME 関連で不具合がありました。

それでも愛用し続けていたのは、その補完機能が魅力的だったからです。

それは非常にシンプルで、設定しだいでは zsh の "unsetopt auto_menu" をしたときの挙動をまねることができたからです。候補が複数あるときに共通部分まで補完して候補リストを出すものです。

多くのコマンドランチャーはその機能がなく、bash のデフォルト設定のような候補が複数あっても見つかった順に全部補完してしまう挙動のものばかりです。

この動作は僕にはあいません。すばやく間違いなく入力するのに絶対必要な機能だと思うのですが。

ただ、bluewind の IME 関連の不具合いは耐えられなくなりました。入力モードにすると IME 入力モードを英数にする機能を使っていたんですが、おそらく IME に対して間違ったフラグを設定してしまい、こちらも愛用している mayu の機能で日本語入力モードに切り替えることができなくなるという問題でした。

どうせもう開発が進むこともないし、色々問題を抱えていたこともあったので、自分で作ってしまおうと考えるまでに至りました。

TeaLuncher

そこで開発を開始したのが TeaLuncher

簡単な紹介をします。使い方についてはまた今度。

C# で .NET Framework で開発していますが、一部 IME 関係で Windows の API を利用しているので Windows 専用です。

bluewind に比べると設定項目はありませんし、グラフィカルなコマンド登録画面もありません。アイコンや起動オプションなど細かい設定も使えません。

使えるのは、コマンドに結わえ付けた URL, ファイルパス(引数付き), 一部の TeaLuncher の特殊な機能だけです。コマンドで引数を渡すことは可能です。

このように、自分に必要な最低限の機能をつけました。

github でオープンソースで開発しているので、関心がある方は機能追加などご自由にどうぞ。