ちょっとカスタマイズ

emacsに慣れてしまった私は、窓使いの憂鬱、xkeymacs等を使っていました。
カスタマイズやVISTA, 7対応等の問題から、今はkeyhacを使用しています。

クリップボード拡張機能が付いた(migemoが使える)ので使ってみたのですが以前使用していたeClipと比べて以下の不満がありました。
1. 取り込む文字サイズの制限が出来ない
2. 他のWindowへの貼り付け方法がC-V固定

1.は仕事柄巨大なファイル等をコピペするのですが、基本的に1回きりで使いまわす事がないデータまで取り込まれてしまいます。
2.はemacsxyzzyなどのエディタを使っているとページが半スクロールして使いにくいです。

本家にお願いすることも考えたのですが、暫くpythonから離れていたのでリハビリがてらコードをいじってみました。
とりあえずconfig.pyで以下の設定で使えるようになりました。

      # クリップボード履歴の最大数 (デフォルト:1000)
      keymap.clipboard_history.maxnum = 10000
+     keymap.clipboard_history.maxlength = 1024 * 100
+ 
+     keymap.pastemode = 1 # 0:キーボード送信(C-V), 1:キーボード送信(Shift-Insert), その他:メッセージ送信(WM_PASTE)

※実装はかなり手抜きです。。。pastemodeとかsendMessageとか。。。

diff -cN keyhac_org/_config.py keyhac_dst/_config.py
*** keyhac_org/_config.py	2011-08-17 23:31:28.000000000 +0900
--- keyhac_dst/_config.py	2012-04-23 13:33:30.453601900 +0900
***************
*** 203,208 ****
--- 203,211 ----
  
      # クリップボード履歴の最大数 (デフォルト:1000)
      keymap.clipboard_history.maxnum = 10000
+     keymap.clipboard_history.maxlength = 1024 * 100
+ 
+     keymap.pastemode = 1
  
  
      # クリップボード履歴リスト表示のカスタマイズ
共通の下位ディレクトリー: keyhac_org/dictとkeyhac_dst/dict
共通の下位ディレクトリー: keyhac_org/docとkeyhac_dst/doc
共通の下位ディレクトリー: keyhac_org/extensionとkeyhac_dst/extension
diff -cN keyhac_org/keyhac_clipboard.py keyhac_dst/keyhac_clipboard.py
*** keyhac_org/keyhac_clipboard.py	2012-04-08 02:44:06.000000000 +0900
--- keyhac_dst/keyhac_clipboard.py	2012-04-17 11:19:47.000000000 +0900
***************
*** 46,51 ****
--- 46,52 ----
          
          self.items = []
          self.maxnum = maxnum
+         self.maxlength = 1024
          
          self.debug = debug
  
***************
*** 87,93 ****
      
      # クリップボード履歴にテキストを登録する ( OSのクリップボードに反映させない )
      def _push( self, text ):
! 
          for i in xrange(len(self.items)):
              if self.items[i]==text:
                  del self.items[i]
--- 88,95 ----
      
      # クリップボード履歴にテキストを登録する ( OSのクリップボードに反映させない )
      def _push( self, text ):
!         if text == None or  len(text) > self.maxlength:
!             return
          for i in xrange(len(self.items)):
              if self.items[i]==text:
                  del self.items[i]
diff -cN keyhac_org/keyhac_keymap.py keyhac_dst/keyhac_keymap.py
*** keyhac_org/keyhac_keymap.py	2012-04-08 02:44:06.000000000 +0900
--- keyhac_dst/keyhac_keymap.py	2012-04-17 10:59:43.000000000 +0900
***************
*** 662,667 ****
--- 662,668 ----
          self.virtual_modifier = 0               # 仮想のモディファイアキー状態 ( beginInput 〜 endInput で使用 )
          self.record_status = None               # キーボードマクロの状態
          self.record_seq = None                  # キーボードマクロのシーケンス
+         self.pastemode = 0                      # 0:キーボード送信(C-V), 1:キーボード送信(Shift-Insert), その他:メッセージ送信(WM_PASTE)
  
          self.clipboard_list_window = None
  
***************
*** 2010,2016 ****
          def jobPasteFinished(job_item):
              self.clipboard_history.setClipboardText(job_item.text)
              if job_item.paste:
!                 self.command_InputKey("C-V")()
  
          if callable(items[select][1]):
              command = items[select][1]
--- 2011,2023 ----
          def jobPasteFinished(job_item):
              self.clipboard_history.setClipboardText(job_item.text)
              if job_item.paste:
!                 if self.pastemode == 0:
!                     self.command_InputKey("C-V")()
!                 elif self.pastemode == 1:
!                     self.command_InputKey("S-Insert")()
!                 else:
!                     # WM_PASTE
!                     job_item.wnd.sendMessage( 0x0302, 0, 0 )
  
          if callable(items[select][1]):
              command = items[select][1]
共通の下位ディレクトリー: keyhac_org/licenseとkeyhac_dst/license
共通の下位ディレクトリー: keyhac_org/themeとkeyhac_dst/theme
共通の下位ディレクトリー: keyhac_org/toolとkeyhac_dst/tool

ProGuardを使ってみた

仕事でProGuardを使用することになったので調査

Eclipseプラグインで使用するのでobfuscate4eを使用することに
http://code.google.com/p/obfuscate4e/

GettingStartedに従って試しにプラグインプロジェクトをエクスポートしてみる
全く難読化されていない。。。

おかしいと思ってantのbuild.xmlを出してデバッグしてみると途中でエラーを吐いている。
Can't process class [com/oracle/net/Sdp$1.class] (Unsupported version number [51.0] for class format)

ちょっとググってみたら「ProGuard version 4.6 does not support Java 7 yet」だって。

仕方ないのでJRE6をインストールして、JRE7はアンインストール。
Eclipseを再起動して再度実行。

今度は無事難読化出来た。

ProGuardは以下のサイトを参考に色々設定はいじりました。
http://d.hatena.ne.jp/hyoromo/20101120/1290216449

GroovyでXMLに書きこむ

GroovyでXMLの保存とちょっとした要素の書き換えをしてみた。
Nodeの編集が上手く行かなくて悩み中。。。
既存のNodeの子要素はそのままに、属性をちょっといじって差し替えたいだけなんだけどなぁ。

def carRecordTxt = """
<records>
  <car name='HSV Maloo' make='Holden' year='2006'>
    <country>Australia</country>
    <record type='speed'>Production Pickup Truck with speed of 271kph</record>
  </car>
  <car name='P50' make='Peel' year='1962'>
    <country>Isle of Man</country>
    <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg in weight</record>
  </car>
</records>
"""

def carRecords = new XmlSlurper().parseText(carRecordTxt)

// 先頭要素にowner属性を追加
carRecords.car[0].@owner = "hironei"

def ret = XmlUtil.serialize(new StreamingMarkupBuilder().bind { mkp.yield carRecords })
new File("./output.xml").withWriter {  it << ret }

ウォークスルーとインスペクション

  • ウォークスルー
    • 特徴
      • レビュー対象者がチーム・メンバーに声を掛けて自主的に運営
    • 目的
      • 品質に関するチーム・メンバー間の意識の向上やメンバー自身の技術的育成、フィードバック、仕様の共通理解
    • タイミング
      • 要件定義フェーズや設計フェーズ等の上流工程
    • やり方
      • 点検対象物に対して事前点検をし、メンバからのレビューを貰いフィードバックを受ける
      • その場で問題点を解決するために予め事前にチェック対象簡潔に明らかにする必要がある
  • インスペクション
    • 特徴
      1. 成果物の作成者自身による検証が完了してから数日以内に実施する
      2. 点検の記録をしっかりと残し,修正状況のトラッキングも必ず実施して再発防止に役立てる
      3. ウォークスルーが要件定義フェーズや設計フェーズなどの上流工程で頻繁に実施されるのに対して,インスペクションは設計フェーズ〜開発フェーズで実施されることが多い
      4. 準備と運営は専任の「モデレータ(Moderator,推進役または調整役)」が担当する
    • 目的
      • プロジェクトの成果物に入り込む欠陥の早期発見と除去
    • やり方
      1. インスペクション/レビューの実施計画立案
        • 実施のタイミング、対象、実施結果をどう使うかを決定する
      2. 参加メンバ、役割分担の決定
        • インスペクション/レビューの実施にあたって誰が参加するか、インスペクタ、レビューア、記録係、進行役等の役割分担を決定する
      3. 準備、メンバへの参加依頼
        • インスペクション/レビューの対象がそろっているかどうかを確認し、会議の形態で実施する場合には日程調整をする
      4. 実施
        • ンスペクション/レビューの目的を明確にした上で、欠陥指摘に集中します。話題がそれたり、質問だけが繰り返されたりするようであれば、進行役が欠陥指摘に集中できるよう誘導する
      5. フォローアップ
        • 終了した後、指摘された内容が修正されているか、再インスペクション/レビューが必要でないかをチェックする

仮想環境でUbuntu10.04から11.04へアップグレード

仮想環境でUbuntu10.04を使っていたのですが、Unityをちょっと触ってみたくて11.04にアップグレードしてみました。
いつもどおり、すべての更新が終わり再起動すると久々に見るGrubのプロンプトが。。
やられた、ブートに失敗したと思い。早速ググりました。
同様に悩んでいた方のサイトを発見し、以下のコマンドで無事復帰。


grub> linux /vmlinuz root=/dev/sda1
grub> initrd /initrd.img
grub> boot

久しぶりにgrubを触ってみるとTAB保管が効く事に気がついた。
滅多にやらないから直ぐ忘れるので備考録を兼ねてここにメモっておきます。

Groovyでpythonのzip関数のような使い方

Groovyでpythonのzip関数のような使い方をするにはtransposeを使えば良いらしい。

コード

keys = [1, 2, 3]
vals = ["One", "Two", "Three"]
def result = [keys, vals].transpose()
print result.toString()

結果

[[1, One], [2, Two], [3, Three]]

MockitoとQuickJunitの組み合わせ


を見てMockitoを使ってみました。

感想・・・今までの時間返して・・・ってぐらい単体テストを書くのが簡略化されました。

ちょっと前にdjUnitを使ってモックを作って、テスト書いて、リファクタリングして、テストコード直してみたいなことをしていたんですが、
djUnitだと

addReturnValue("HelloWorld", "getMessage", "こんにちわ。");

みたいにクラスとメソッドを文字列でしていするので、どうしてもリファクタリングに弱い面がありました。

これがMockitoだと

SimpleClass m = mock(SimpleClass.class);
when(m.getMessage()).thenReturn("こんにちわ。");

のようにメッソドをコンパイルの通った形で指定する事が出来ます。
そのため、EclipseのようなIDEを使ってリファクタリングでメッソド修正等した場合にテストコードも一緒に修正されます。
※別途検証は必要ですが。

あまり良いサンプルではありませんが、

public interface TcpClient {
	/**
	 * Socketを開く
	 * 
	 * @return true/false
	 */
	boolean open();

	/**
	 * Socketを閉じる
	 */
	void close();

	/**
	 * メッセージ送信
	 * 
	 * @param msg
	 *            メッセージ
	 */
	void sendMessage(String msg);

	/**
	 * メッセージ受信
	 * 
	 * @return 受信メッセージ
	 */
	String receiveMessage();
}
public class SampleClient {
	/**
	 * クライアント
	 */
	private final TcpClient client;

	/**
	 * コンストラクタ
	 * 
	 * @param client
	 *            クライアント
	 */
	public SampleClient(TcpClient client) {
		this.client = client;
	}

	/**
	 * サーバーに送信したメッセージがエコーバックされるかチェックする
	 * 
	 * @param msg
	 *            送信メッセージ
	 * @param times
	 *            リトライ回数
	 * @return true(成功)/false(失敗)
	 */
	public boolean checkEchoServer(String msg, int times) {
		boolean result = false;
		if (client.open()) {
			for (int i = 0; i < times; i++) {
				// メッセージ送信
				client.sendMessage(msg);
				// メッセージ受信
				String recvMsg = client.receiveMessage();
				// データのチェック
				if (msg.equals(recvMsg)) {
					result = true;
					break;
				}
			}
			// クローズ
			client.close();
		}

		return result;
	}
}
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;

import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class SampleClientTest {
	private static final int TIMES = 10;

	private static final String echoMessage = "test";

	private TcpClient client;

	private SampleClient sample;

	@Before
	public void setUp() throws Exception {
		client = mock(TcpClient.class);
		sample = new SampleClient(client);
		assertNotNull(sample);
	}

	@Test
	public void testCheckEchoServer1() {
		// 処理実行
		// 何もしなければfalseが変える
		assertFalse(sample.checkEchoServer("test", 20));

		// Openが1回呼ばれているはず
		verify(client).open();
		// verifyしていない呼び出しは存在しない。
		verifyNoMoreInteractions(client);
	}

	@Test
	public void testCheckEchoServer2() {
		// openのメソッドの戻り値をtrueに
		when(client.open()).thenReturn(true);
		// 送信メッセージと同じ戻り値にする
		when(client.receiveMessage()).thenReturn(echoMessage);
		// trueが返却
		assertTrue(sample.checkEchoServer(echoMessage, 20));

		// Openが1回呼ばれているはず
		verify(client).open();
		// SendMessageが1回呼ばれている
		verify(client).sendMessage(anyString());
		// ReceiveMessageが1回呼ばれている
		verify(client).receiveMessage();
		// ここではclose()をverifyしていないので有効にすると失敗
		// verifyNoMoreInteractions(client);
		// closeが1回呼ばれている
		verify(client).close();
		// ここでは全てのverifyが終わっているのでOK
		verifyNoMoreInteractions(client);
	}

	@Test
	public void testCheckEchoServer3() {
		// openのメソッドの戻り値をtrueに
		when(client.open()).thenReturn(true);
		// 送信メッセージと同じ戻り値にする
		when(client.receiveMessage()).thenAnswer(new Answer<String>() {
			private int i = 0;

			@Override
			public String answer(InvocationOnMock invocation) throws Throwable {
				i++;
				// N回目にメッセージを返す
				if (i == TIMES) {
					return echoMessage;
				}
				return null;
			}
		});
		// trueが返却
		assertTrue(sample.checkEchoServer(echoMessage, 20));

		// Openが1回呼ばれているはず
		verify(client).open();
		// SendMessageがTIMES回呼ばれている
		verify(client, times(TIMES)).sendMessage(anyString());
		// ReceiveMessageがTIMES回呼ばれている
		verify(client, times(TIMES)).receiveMessage();
		// ここではclose()をverifyしていないので有効にすると失敗
		// verifyNoMoreInteractions(client);
		// closeが1回呼ばれている
		verify(client).close();
		// ここでは全てのverifyが終わっているのでOK
		verifyNoMoreInteractions(client);
	}
}

ここでは静的関数であるmockを使ってTcpClientインターフェースのモックを作成し、
whenを使って戻り値を設定し、verifyを使って検証する様にしています。
※使用しているmockitoのバージョンは1.9.0-rc1です。

特にverifyとverifyNoMoreInteractionsによってmockで指定したインターフェースのメソッドの

  • 規定回数呼び出されたか
  • verifyされていないメソッドが無いか

が検証できるのはとても嬉しいです。


また、以前からQuickJunitを使っていたのですが、Mockitoを使うようになってからCtrl+9, Ctrl+0の使用頻度が非常に多くなりました。
結局、verifyをきちんと通すために実コードとテストコードの往復回数がどうしても増えているためですが。。。

まだ、使い始めなのであまり検証は出来ていませんが、機会があれば続きを書きたいと思います。