メモ: NetBeansの空白、改行のフォント色設定

タブや改行を可視化する際デフォルトだと黒で無駄に目立つのでフォント色を変えたのだけど、割りと面倒だったのでメモ

  1. 表示>表示不可能な文字を表示 で可視化
  2. ツール>オプション でオプションを開く
  3. フォントと色>構文 のタブを開いて 言語:すべての言語 を選択
  4. カテゴリ:デフォルトの前景をタブ、改行用として目立たない色に適当に設定(カスタムで[153,204,255]にした)
  5. デフォルト以外のカテゴリで全景が継承で黒になってるものを全部継承ではなく直に黒に設定

※空白だけならカテゴリ指定で直接色を変えられるけど、改行文字はデフォルトのやつが使われるっぽいので面倒なことになっている
もしかすると、言語によってはこれでは色が変になるかもしれないけど、今使っている範囲(Java,HTML,Javascript,CSS,PHPあたり)では問題なさげ

2013/03/01追記
HTML,XMLなどで色がおかしなことになってた。そして、言語個別の設定で頑張ってもHTML,XMLでは空白、改行文字だけ色は変えるのは無理っぽいので、できるやつだけ個別の言語で設定することにした。

メモ: IEnumerable

関数型言語でよくあるmapとかfoldっぽいのがIEnumerableにあるけど、対応が分からなかったのでメモ

Haskell ruby(1.8) ruby(1.9) .NET
map collect,map 同左 Select
concatMap - flat_map,collect_concat SelectMany
foldl,foldr inject inject,reduce Aggregate
filter find_all,select 同左 Where
- reject 同左 -
takeWhile - take_while TakeWhile
dropWhile - drop_while SkipWhile
- uniq 同左 Distinct

2/26追記: ruby1.9についても調べた

メモ: ActiveRecord

ActiveRecordのloggerはモデルを定義する前に設定しないと有効にならない。

NG

ActiveRecord::Base.configurations = YAML.load_file(config_file)
ActiveRecord::Base.establish_connection

class User < ActiveRecord::Base
end

# 中略

ActiveRecord::Base.logger = Logger.new(STDOUT)

# 以下、なんかActiveRecord使う処理

OK

ActiveRecord::Base.configurations = YAML.load_file(config_file)
ActiveRecord::Base.establish_connection
ActiveRecord::Base.logger = Logger.new(STDOUT)

class User < ActiveRecord::Base
end

# 後略

人材獲得作戦・4 試験問題

人材獲得作戦・4 試験問題ほか: 人生を書き換える者すらいた。を解いてみた。
所要時間は問題を読み始めてから解いてみようと思い立つまでに5分、eclipseを立ち上げて書き終えるまでに20分で計25分ほど。試したのは問題文中のサンプル入出力のみだけど、さすがに単純なBFSで間違ってるってことはないでしょう。
コードの方は短時間で書くことを優先したので大分雑な感じになってます。

import java.awt.Point;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;


public class Maze {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		List<char[]> list = new ArrayList<char[]>();
		while (sc.hasNext()) {
			list.add(sc.nextLine().toCharArray());
		}
		char[][] maze = list.toArray(new char[list.size()][]);
		int sx = 0, sy = 0;
findStart:
		for (int y = 0; y < maze.length; y++) {
			for (int x = 0; x < maze[0].length; x++) {
				if (maze[y][x] == 'S') {
					sx = x;
					sy = y;
					break findStart;
				}
			}
		}
		
		Queue<Point> queue = new ArrayDeque<Point>();
		queue.add(new Point(sx, sy));
		
		Point[][] route = new Point[maze.length][maze[0].length];
		int[] dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
bfs:
		while (!queue.isEmpty()) {
			Point p = queue.poll();
			for (int i = 0; i < dx.length; i++) {
				int nx = p.x + dx[i];
				int ny = p.y + dy[i];
				if (maze[ny][nx] == ' ') {
					maze[ny][nx] = '_';
					queue.add(new Point(nx, ny));
					route[ny][nx] = p;
				}
				else if (maze[ny][nx] == 'G') {
					while (p != null) {
						maze[p.y][p.x] = '$';
						p = route[p.y][p.x];
					}
					break bfs;
				}
			}
		}
		
		maze[sy][sx] = 'S';
		for (int y = 0; y < maze.length; y++) {
			for (int x = 0; x < maze[0].length; x++) {
				if (maze[y][x] == '_') {
					maze[y][x] = ' ';
				}
			}
		}
		
		for (int y = 0; y < maze.length; y++) {
			System.out.println(maze[y]);
		}
	}

}

eclipse3.5

リリースされたようなので早速落としてみた。
ぱっとみで分かる変更点はパースペクティブ切り替えのバーがツールバーと完全に分かれてレイアウトが2段組になったことかな。デスクトップでやってるときはいいけど、元に戻せないとノートPCで作業するときに狭くなって微妙。どうなんだろう?
追記:↑に書いたのはwin32-x86_64でのことなんだけど、win32-x86の方をノートに入れてみたら、もとのレイアウトのままだった

追記の追記:普段使ってるもろもろのプラグインを突っ込んだらノートの方も2段になった。どれが原因かはよく分からないけど、標準では以前のままっぽい。
それと以前は新規プラグインのインストールとアップデートがひとまとめになってたけど、それが別々に分かれたみたい。これについてはかなり外観が変わっていて一瞬とまどったもののすぐに慣れた。
ってなわけで、気がついた新機能/強化点をいくつか挙げてみる。

  • Call Hierarchyの強化

Expand With Constructorsというオプションができた。これにチェックを入れておくと通常の呼び出し元以外に、そのメソッドの属するクラスのコンストラクタの呼び出しも展開されるようになる(コンストラクタが展開されるのは設定したインターフェース/クラスおよび匿名内部クラスのみ。デフォルトで入っているのはRunnableなど)。これによってRunnableのrun()などが呼び出し元になっていても、そこで階層がとぎれずにさらに、そのコンストラクタの呼び出し部(=匿名内部クラスの宣言部など)からさかのぼることができる。この機能はかなりうれしい。

  • コンテンツアシストの強化

匿名内部クラスをnewしているところで自動補完を使うと勝手にabstractなメソッドを実装してくれるようになった。これも地味に助かる。

  • その他JDT周り

Sourceメニューの中のGenerate系にtoStringが増えた。他にも型名のマッチングの気の利きっぷりも強化されていたり、ナビゲーション系では今まであったOpen Declarationに加えてOpen Implementationなんてのもできていたり。

  • アップデート周りの強化

Installation Historyなるものができて、アップデート等の履歴が見れて復元もできる様子。

これら以外にも色々と新機能があるっぽい。
参考: http://update.eclipse.org/downloads/drops/S-3.5M7-200904302300/eclipse-news-M7.html

eclipseプラグインの依存関係

JFaceなどeclipseプラグインを使ったアプリを作ろうとすると必要なjarの依存関係を探すのがかなり面倒だ。
PDEを使えば、勝手に解決してくれるが、プラグインを作るわけでもないのにそこまでするのも面倒だということで、eclipseプラグインの依存関係にあるjarを探してくるコードを書いてみた。なんとなくバージョンチェックも付けてみたが意味はない。

public class PluginJarDependencies {

	public static void main(String[] args) throws IOException {
		File target = new File("org.eclipse.jface.text_3.4.2.r342_v20081119-0800.jar");
		RequirementSearch search = new RequirementSearch(Arrays.asList(new Requirement(target)));
		File pluginDir = new File("C:/eclipse/plugins");
		search.execute(pluginDir);
		for (File found : search.founds) {
			System.out.println(found);
		}
		for (Requirement r : search.notFounds) {
			StringBuilder sb = new StringBuilder();
			sb.append("Not found: " + r.name);
			if (r.max == r.min) {
				sb.append(" " + r.max);
			}
			else {
				sb.append(r.minInclude ? "[" : "(");
				sb.append(r.min);
				sb.append(",");
				sb.append(r.max);
				sb.append(r.maxInclude ? "]" : ")");
			}
			System.out.println(sb);
		}
	}
	
	static class RequirementSearch {
		List<Requirement> requires;
		Set<File> founds = new TreeSet<File>();
		List<Requirement> notFounds;
		RequirementSearch(List<Requirement> requires) {
			this.requires = new ArrayList<Requirement>(requires);
			notFounds = new ArrayList<Requirement>(requires);
		}
		void execute(File pluginDir) {
			int oldSize;
			do {
				oldSize = requires.size();
				for (File child : pluginDir.listFiles()) {
					checkFile(child);
				}
			}
			while (oldSize != requires.size());
		}
		void checkFile(File file) {
			if (!file.getName().endsWith(".jar")) {
				return;
			}
			String name = file.getName().split("_")[0];
			boolean require = false;
			for (Requirement req : notFounds) {
				if (req.name.equals(name)) {
					Version fileVer = new Version(file.getName().split("_", 2)[1]);
					int minCmp = fileVer.compareTo(req.min);
					int maxCmp = fileVer.compareTo(req.max);
					if ((req.minInclude ? minCmp >= 0 : minCmp > 0)
							&& (req.maxInclude ? maxCmp <= 0 : maxCmp < 0)) {
						requires.remove(req);
						notFounds.remove(req);
						founds.add(file);
						require = true;
						break;
					}
				}
			}
			if (require) {
				try {
					JarFile jar = new JarFile(file);
					Manifest manifest = jar.getManifest();
					jar.close();
					Attributes attributes = manifest.getMainAttributes();
					String requiresStr = attributes.getValue("Require-Bundle");
					if (requiresStr != null) {
						addRequires(requiresStr);
					}
				}
				catch (IOException e) {}
			}
		}
		static final Pattern COMMA_PATTERN = Pattern.compile("(([^\",]+|\"[^\"]+\")+),?");
		void addRequires(String requiresStr) {
			Matcher matcher = COMMA_PATTERN.matcher(requiresStr);
			while (matcher.find()) {
				String[] match = matcher.group(1).split(";");
				Requirement req = new Requirement(match[0], match[1]);
				if (!requires.contains(req)) {
					requires.add(req);
					notFounds.add(req);
				}
			}
		}
		
	}
	
	static class Requirement {
		String name;
		Version min;
		boolean minInclude;
		Version max;;
		boolean maxInclude;
		public Requirement(File file) {
			String[] split = file.getName().split("_", 2);
			name = split[0];
			minInclude = maxInclude = true;
			min = max = new Version(split[1]);
		}
		Requirement(String name, String version) {
			this.name = name;
			String[] vers = version.substring("bundle-version=".length() + 1, version.length() - 1).split(",");
			if (vers.length == 2) {
				if (vers[0].startsWith("[")) {
					minInclude = true;
				}
				min = new Version(vers[0].substring(1));
				if (vers[1].endsWith("]")) {
					maxInclude = true;
				}
				max = new Version(vers[1].substring(0, vers[1].length() - 1));
			}
			else if (vers.length == 1) {
				minInclude = true;
				maxInclude = true;
				min = max = new Version(version);
			}
			else {
				throw new RuntimeException("bundle-version parse failed");
			}
		}
	}
	
	static class Version implements Comparable<Version> {
		int major;
		int minor1;
		int minor2;
		String revision;
		Version(String version) {
			String[] vers = version.split("\\.");
			major = Integer.parseInt(vers[0]);
			minor1 = Integer.parseInt(vers[1]);
			minor2 = Integer.parseInt(vers[2]);
			if (vers.length > 3) {
				revision = vers[3];
			}
		}
		public int compareTo(Version o) {
			int cmp = major - o.major;
			if (cmp != 0) {
				return cmp;
			}
			cmp = minor1 - o.minor1;
			if (cmp != 0) {
				return cmp;
			}
			return minor2 - o.minor2;
		}
		@Override
		public String toString() {
			return major + "." + minor1 + "." + minor2
					+ (revision != null ? "." + revision : "");
		}
	}
	
}