Ruby on HTA

少し触っただけだけども、HTA + ActiveScriptRubyにぐっときた。

VisualuRubyよりも、もっともっとサクサク簡単なGUIを作りたいときに便利っぽい。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp" lang="ja-JP">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>サンプル</title>
		<script for="window" event="onload" language="RubyScript">
			@window.resizeTo(400, 100)
			
			def btnOk_onclick
				@window.document.getElementById("lblOutput").innerHTML = "Hello World!!!"
			end
		</script>
	</head>
	<body>
		<input id="btnOk" type="submit" value="OK" onclick="btnOk_onclick" />
		<span id="lblOutput">...</span>
	</body>
</html>



ちょっとめんどくさい

イベントハンドラを定義したり(onclick="...")するのが面倒なんで、うまいことできないか考え中。

んで、とりあえずidが付いている要素にイベントハンドラを定義するような仕組みを作ってみた。

ついでにHTAにスタイルを設定してもっとネイティブのアプリっぽく。


hta-support.rb

class HTASupport
  # イベントハンドラ一覧
  EVENTHANDLERS = [
    "onblur",
    "onfocus",
    "onchange",
    "onselect",
    "onselectstart",
    "onsubmit",
    "onreset",
    "onabort",
    "onerror",
    "onload",
    "onunload",
    "onclick",
    "ondblclick",
    "onkeyup",
    "onkeydown",
    "onkeypress",
    "onmouseout",
    "onmouseover",
    "onmouseup",
    "onmousedown",
    "onmousemove",
    "ondragdrop"
    ]

  def initialize(window)
    @window = window
    set_event_handler
  end

  # idを持つ要素すべてにイベントハンドラを設定します
  def set_event_handler
    body = _d.getElementsByTagName("body").item(0)
    set_event_handler_recursive(body)
  end

  # idを持つ要素すべてにイベントハンドラを設定します
  def set_event_handler_recursive(elem)
    # Element以外だったら終了
    return if elem.nodeType != 1

    id = elem.getAttribute("id")
    if id != ""
      EVENTHANDLERS.each do |name|
        handler_name = "#{id}_#{name}"
        elem.attachEvent(name, Proc.new {
          if methods.include?(handler_name)
            __send__(handler_name)
          end
        })
      end
    end

    # 子要素も処理する
    elem.childNodes.each do |i|
      set_event_handler_recursive(i)
    end
  end

  # windowへのショートカット
  def _w
    @window
  end

  # window.documentへのショートカット
  def _d
    _w.document
  end

  # window.document.getElementByIdへのショートカット
  def _e(id)
    _d.getElementById(id)
  end
end

sample.rb - このファイルに処理を実装する

require "hta-support"

class Sample < HTASupport
  def btnOk_onclick
    _e("lblOutput").innerHTML = "HelloWorld!!"
  end
end

sample.hta - HTA本体

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp" lang="ja-JP">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>サンプル</title>
		<style>
			body {
				background-color: ButtonFace;
			}
		</style>
		<script for="window" event="onload" language="RubyScript">
			require "sample"
			Sample.new(@window)
			@window.resizeTo(400, 100)
		</script>
		<hta:application
			applicationname="サンプル"
			version="1.0"
			singleinstance="no"
			showintaskbar="yes"
			navigable="no"
			windowstate="normal"
			border="dialog"
			innerborder="no"
			borderstyle="normal"
			contextmenu="yes"
			selection="yes"
			scroll="no"
			scrollflat="no"
			caption="yes"
			icon="explorer.exe"
			sysmenu="yes"
			maximizebutton="no"
			minimizebutton="yes"
			/>
	</head>
	<body>
		<input id="btnOk" type="submit" value="OK" />
		<span id="lblOutput">...</span>
	</body>
</html>



はまりどころ

openが何かの名前と衝突してるっぽくてうまく使えなかった。

そのときはKernel.openとすれば期待通りに動作する。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp" lang="ja-JP">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>サンプル</title>
		<script for="window" event="onload" language="RubyScript">
			@window.resizeTo(400, 100)
			
			def btnOk_onclick
				open("a.txt", "w") do |f|
					f.puts "aaa"
				end
			end
		</script>
	</head>
	<body>
		<input id="btnOk" type="submit" value="OK" onclick="btnOk_onclick" />
		<span id="lblOutput">...</span>
	</body>
</html>


ううーん

仕事ツール作りに使えるかな?

DBからselectした行はtableに出せば良さそう。


GUIエディタがほしいな。

hta:applicationタグを作ってくれたり、画面サイズを考慮しつつWYSIWYGでHTML編集したりとか。

ORって遅いのね

ひさしぶりに、とあるシステムのパフォーマンスをチューニングしてみた。
Ludiaで全文検索インデックスを使ってみたり、ORM任せにしないで自前でSQLを書いたりで、だいぶさくさく動くようになったっぽい。


知らなかったことがあったのでメモ。ORって遅いのね。
同じ結果を返すようにUNIONで組んだSQLと比べると、36倍程度の差があった。


以下で使用しているテーブルの行数はだいたい
products ... 9万件
product_specs ... 50万件

-- 2.16秒/70件
SELECT DISTINCT
  a.* 
FROM
  products a 
  inner join product_specs b 
    on b.product_id = a.id 
WHERE
  a.title @@ 'テスト' 
  OR b.value @@ 'テスト' 
ORDER BY
  date desc
-- 0.06秒/70件
SELECT
  a.* 
FROM
  products a 
WHERE
  a.title @@ 'テスト'

UNION 

SELECT
  a.* 
FROM
  products a 
  inner join product_specs b 
    on b.product_id = a.id 
WHERE
  b.value @@ 'テスト'

ORDER BY
  date desc


ちなみにORもUNIONも使わずに、片方の条件で検索をかけると0.03秒。ORは本当に遅すぎ。
こんなに違うと、さすがに体感にもだいぶ差が出た。

VAIO type P ファーストインプレッション

実は1月末に注文していたtype P。
予定では2月下旬に発送予定でしたが、2月17日には発送の連絡があり、2月18日に届きました。

type Pについては既に他のブログやニュースサイト語られてはいますが、備忘録的な意味で残しておきたいと思います。

外観

typep

店で見るよりも少しだけ大きい印象を受けました。
それでもだいぶ小さいんだけどもね。

この外観こそがおれがtype Pを買った動機。

デスクトップ

typep

上の画面はセットアップ直後のデスクトップ。

メーカー製PCは久しぶりに買ったけど、前に買ったLavieよりシンプルな気がする。
それでも変なガジェットとかはあるけどさ。


タスクトレイも、ひどいことにはなってない。左から順に

だったはず。たしか。

起動

電源OFFからの起動は遅いけど普通の遅さ。おーそーいーってほどじゃない。
会社で使ってるCore2DuoVistaよりは遅い程度。


スリープからの復帰は2〜3秒。
これを常用するとおもう。


休止状態からの復帰は体感でだけど起動と同じ〜起動よりも時間がかかる印象。
絶対とは言わないけど、使わないとおもう。


インスタントモードの起動は10秒くらい。
早い。けどもたぶん使わない。詳細は次で。

インスタントモード

ローカルにあるファイルしか再生できないっぽい。
ほかのPCでファイル共有してあるファイルは再生できない。(とおもう)


type Pには音楽や動画を置かないで、別のPCにある動画や音楽を再生する、っていう用途には使えないっぽい。
おれはそういった使い方がしたかったので、おそらく現状のインスタントモードは使わない。


ウェブはFirefoxで見れるけど、フォントがフリーフォント。たぶん。汚い。
そしてブラウジングが遅くてイライラする。


これらの点、アップデートで改善されるかなあ。

ネットワーク接続

クライアントマネージャVをインストールして、AOSS無線LANを設定。難なく接続できた。
http://buffalo.jp/download/driver/lan/clmg5.html

インターネット

標準のIE7だと遅すぎてイライラした。
要カスタマイズ。

メディア再生

VAIO Media Plusはインスタントモードと同じで、ほかのPCでファイル共有してあるファイルは再生できない。(きがする)
要カスタマイズ。

そのた

初回セットアップ完了後には常駐しなくても、起動すると常駐設定になるソフトが結構あったきがする。
VAIO モバイル TV」とか「VAIO Media Plus」とか。

そういうところはマイナスかな。面倒くささ的な意味で。

結局どうなの

性能が出ないのはわかりきったことだったので、「やっぱりかー」とか「お、意外といいかも」といった印象でした。
快適に使うためにはカスタマイズが必須だと思います。

mosopc.com 2009/1/12にサービス停止します。

2009/1/12、mosopc.comのドメインが有効期限切れを迎えます。


ドメインを更新しようかなとも思ったのですが、
利用者がほぼいない(10人/月程度)状況で、自分でもほとんど使わないため
更新は行わず、そのままサービスを停止することにしました。


利用してくださっていた方々にはご迷惑をおかけいたしますが、ご了承ください。

標準のレイアウトフレームが不満なので、簡単なレイアウトフレームを作ってみる

背景

おれは仕事用のツールをrubyで作ることが多いんだけれども、近頃はプロジェクトメンバに使ってもらうツールを作る機会も増えてきた。
自分で使うならまだしも、使ってもらうとなるとCUIでは不親切。GUIを作りたい気持ちが出てくるもんだ。

そこで、前々から存在は知っていたけれども使ったことがなかった、VisualuRubyに手を出した。

イベントを拾うのはらくちん

イベントを拾うのはホントにらくちん。
[xxx_clicked]等のメソッドを定義するだけでイベントを拾える。VBちっくで超らくちん。

あとはコントロールの配置!

超単純なGUIならまだしも、単純なGUIでも、コントロールの配置は超めんどくさい、と思う。
単純なツールを作りたいだけなのに、めちゃめちゃめんどくさい。


雪見酒さんが作っているFormDesignerというソフトも便利そうだったけども、
VRTextをはっつけて移動すると挙動不審になるのには困った。


レイアウトフレームやレイアウトマネージャも使ってみたが、微妙。

VRHorizLayoutFrameやVRVertLayoutFrameとか使ってみたけど、
レイアウトフレーム内で全てのコントロールの幅や高さが揃っちゃうし、
意図したカンジになってくれないんだ。

そこで本題

思い立って、コントロールの幅や高さを変えないレイアウトフレームを作ってみた。
また、中に入っているコントロールのサイズにより、レイアウトフレームのサイズを拡張する。
なんとなくHTMLちっくなレイアウトができる。


まだ実戦投入はしてない(そもそもVisualuRubyもまだ実戦投入はしてない)けれども、なかなか便利そうだから公開してみる。
もうちょいらくらくにできそうな気がするので、やる気がある限り突き詰めてみる。

こんな画面を作れる

ソース
#!ruby -Ks
$KCODE="s"

require "yaml"
require "vr/vrcontrol"
require "vr/vrlayout2"

class MyLayoutFrame < VRLayoutFrame
  attr_accessor :padding

  def w
    @_vr_lw
  end

  def h
    @_vr_lh
  end
  
  def initialize
    super
    @padding = 4
  end
end

class MyHorizLayoutFrame < MyLayoutFrame
  def _vr_relayout
    x = 0
    @_vr_layoutclients.each do |i|
      i.move(@_vr_lx + x, @_vr_ly, i.w, i.h)
      x += i.w + @padding
      @_vr_lw = x
      @_vr_lh = [@_vr_lh, i.h].max
    end
  end
end

class MyVertLayoutFrame < MyLayoutFrame
  def _vr_relayout
    y = 0
    @_vr_layoutclients.each do |i|
      i.move(@_vr_lx, @_vr_ly + y, i.w, i.h)
      y += i.h + @padding
      @_vr_lw = [@_vr_lw, i.w].max
      @_vr_lh = y
    end
  end
end

class Form < VRForm
  def construct
    #
    # メモ
    #  位置はレイアウトフレームが決めてくれるから、
    #  addControlではサイズのみを指定すればよい(位置はx=0, y=0でよい)
    #

    addControl(VREdit, "edit", "", 0, 0, 120, 24)
    addControl(VRButton, "button", "検索", 0, 0, 50, 24)
    @lm1 = MyHorizLayoutFrame.new
    @lm1.register(@edit, @button)
    
    addControl(VRText, "text", "", 0, 0, 400, 200)
    @lm2 = MyHorizLayoutFrame.new
    @lm2.register(@text)
    
    addControl(VRButton, "xxxbutton1", "機能1", 0, 0, 100, 24)
    addControl(VRButton, "xxxbutton2", "機能2", 0, 0, 100, 24)
    addControl(VRButton, "xxxbutton3", "機能3", 0, 0, 100, 24)
    @lm3 = MyHorizLayoutFrame.new
    @lm3.register(@xxxbutton1, @xxxbutton2, @xxxbutton3)
    
    @lm = MyVertLayoutFrame.new
    @lm.register(@lm1, @lm2, @lm3)

    self.caption = "レイアウトフレームのテスト"
    self.move(0, 0, 408, 286)
  end
end

VRLocalScreen.start(Form)

P5Q-EにVine-4.2はダメだった。CentOS-5.2は大丈夫。

表題のとおり。


友人からP5Q-Eを安値で譲ってもらったため、この土日を使ってサーバ機のハードウェアを換装した。
それに伴い、OSも再インストールすることにした。


OSには今と同じVinelinuxの4.2を使おうとしていたんだけども、どうにもインストール時にHDDを認識してくれない。
最初にeSATAで接続したHDDにインストールしようとしていたのだけど、それが原因でもなく、SATAに接続してチャレンジしたけどダメだった。


原因はlinuxに詳しくないのでよくわからないんだけども、ICH10RとかMarvellの、SATAコントローラのドライバが無いみたい。


半日格闘した末、あきらめてCentOSの5.2をインストール。
こちらはすんなりeSATAで接続したHDDを認識してくれた。


DB移行して、SVN移行して、APP移植して。
結構な大仕事でしたが、案外すんなり移行できました。


どうなることかと思いましたが、とりあえずよかった。

Gmailでギフト券が悪者扱いされてた

ふと迷惑メールフォルダを見たら、Amazonクレジットカードの今月分のギフト券が迷惑メール扱いになってた。


「送信者情報が変更されている可能性があります」だって。
別アカウントのメールをGmailで受信したからかな。


ともかく気づいてよかった。

同じような設定にしてる人がいたら、迷惑メールフォルダを確認してみたほうがいいかもですよ。