2008年 01月 11日

svn log と Trac につけたはてなスターをつかって ChangeLog を自動生成するアイデア

svn2cl がアレなのはノイズが多いからだよなぁと思って (でも ChangeLog と svn log をどっちも書くのはめんどう)

 ~/coderepos/lang/perl/Config-Pit/trunk
$ changelog-with-hatenastar.rb
ChangeLog of http://svn.coderepos.org/share/lang/perl/Config-Pit/trunk

2008-01-09  SATOH Hiroh <cho45@lowreal.net>

        * [interface] @4310:

            Implement pipe function for output stdout (but tty)
            Always notice profile switching for ppit ui.


        * [interface] @4309:
                 like ruby pit

        * [bug] @4282:

            Add local not to violate global env.

あんま☆つけてなくておもしろくないというか、タグの changeset は trunk の log に残らないので release のログは工夫しないとだせないことに気付いた…… あとマルチユーザを考慮してないのでまずい (4390 は SATOH さん(笑)のコミットではない)

この方法の利点は、はてなスターによってあとからつけられるので、「このチェンジセットをもうすこし詳しくして ChangeLog に書きたい」みたいなのを簡単にできるところと、他の人のチェンジセットにも情報増やせるところ。ただ、はてなスターの quote は quote なのでブックマークレットとかつかって書かないといけないのはめんどい。

ちゃんと使うには

  • svn log に書く内容からタグを抽出 (簡単)
  • はてスタ簡単につけるブックマークレット (UI がめんどい)
  • 出力の形式をまともに (めんどい)

とかやらないといけない。ChangeLog を手書きするのと、svn log から抽出しつつ、はてスタで補足するのとではどっちが楽かってなんか微妙だ。


ここまで書いてきづいたけれど、ChangeLog を先に書いて、svn di ChangeLog した内容を svn ci 時のデフォルトにすれば、すくなくとも ChangeLog と svn log をどっちも書くのはめんどう は解決できるからそのほうがいい気がした。あれー

tags もみるようにして、出力を改善した。

開発してるときはコミットログにタグいれるのよくわすれるからあとからどうにでもなるのはいいかもなぁ、とおもってちょっと使ってみる (あたらしい gem で)

自由なスタークオート

location.href = "javascript:"+encodeURIComponent(uneval(function () {
	var orig = Hatena.Star.AddButton.prototype.addStar;
	Hatena.Star.AddButton.prototype.addStar = function (e) {
		if (e.shiftKey) {
			var q = prompt("Star quote:");
			var t = new Ten.Element("div", {style:{display:"none"}}, q);
			document.body.appendChild(t);
			var r = window.getSelection().selectAllChildren(t);
			orig.call(this, e);
			document.body.removeChild(t);
		} else {
			orig.call(this, e);
		}
	};
}))+"()";

OpenStruct で String キーの Hash と Symbol キーの Hash のめんどいのをどうにかする

p OpenStruct.new(:foo => "bar").foo
p OpenStruct.new("foo" => "bar").foo

どっちでもいけて便利ですね @config = OpenStruct.new(config) とかやっとけば自然とどっちにも対応できますね

userscripts.org でコマンドラインからスクリプトの追加/アップデート

$ sudo gem install userscripts_org
$ userjs create foobar.user.js
$ userjs update foobar.user.js

とかできるやつです。

ついでに linkuserjs.rb を統合してあります

$ userjs install foobar.user.js
# Fx で foobar.user.js をひらくだけ

$ userjs install -l foobar.user.js
# Fx で foobar.user.js をひらき、インストールされたあとに
# インストール済みのファイルを指定したファイルへの symlink にする

なんか説明しにくいのですが、ようは symlink にすると svn ci がすぐできるようになります。Mac のコードしか書いてないので他の OS だとうごかない (チェックさえしてないのでつけよう)

一応 Windows (cygwin) と Linux (firefox にパスが通っていること前提) のコードをいれました。テストしてないのでうごくかわからないのですが

2008年 01月 10日

Changes の基準

外部から見える変更 (書くことないときはリファクタリングしてどうなったかだけ) かな

設定を管理する pit の Perl もづーる Config::Pit

http://subtech.g.hatena.ne.jp/cho45/20080102/1199257680 の Perl 版です。最低限うごくようになったところでコミットして #CodeRepos の方々にお世話になりながらリファクタリングをしました (ありがとうございます)。(Path::Class++) コマンドラインツールは Yappo さんが書いてくれました (Yappo++)。

テストとか一通り書いて 0.01 をリリースしました。が既にあれげなところの修正が入ったので 0.02 をリリースしました。

一通り本家 ShipIt の感じもつかめてよかった。MANIFEST の確認を怠っていたら .svn をふくんでリリースしてしまってめっさあせる……


プロトタイプだけ書いて放置していたら PHP 版が先に! はやい!

2008年 01月 08日

Rake タスクの引数のほげほげ

http://d.hatena.ne.jp/rubikitch/20080107/rakeargs をみてて、使えるようになったノカーとか思いつつ、このままだとちょっと使えないなぁと思ったので、Rakefile で対応できる範囲でつかいやすくしてみた

def args(hash)
	name = hash.keys.first
	args = hash[name]
	task name, *args
end

desc "foo task"
args :foo => [:bar, :baz]
task :foo do |t,a|
	p t.arg_names
	p a.bar
	p a.baz
end

desc "bar task"
task :bar do |t|
	puts "this is bar."
end

# ARGV は Rakefile が実行される時には既に rake 自体への引数は全てとりのぞかれている
Rake.application.top_level_tasks.replace(ARGV.map {|a|
	name, vals = *a.split(/@/, 2)
	vals ? "#{name}[#{vals}]" : a
})

これで

$ rake 'foo[aaa,bbb]'
(in /Users/cho45/tmp)
[:bar, :baz]
"aaa"
"bbb"

$ rake foo@aaa,bbb
(in /Users/cho45/tmp)
[:bar, :baz]
"aaa"
"bbb"

になって、どっちでもいけるようになる。


あと引数の宣言の DSL がめちゃくちゃわかりにくいと思うのでオレオレメソッドを定義してみた (あの DSL で、後ろに書いてあるのが引数だと想像できる人はどれほどいるんだろう……)。先に args の宣言がくるのはちょっとキモいけど、task メソッドうわがきせずやるとこんなもんなのかなぁ。


でもそんなに引数めちゃくちゃとりたいケースってないのかもしれない……

いまさらだけど別に ARGV みなくても top_level_tasks.map! でいいのだった。(最初は ARGV をもっといじくるコードを書いてたなごり)

文字列の繰り返し

ref. http://d.hatena.ne.jp/higeorange/20080107/1199710820

String.prototype.repeat = function (n, sep) {
	if (n < 1) return "";
	return Array(n).join(this + (sep || "")) + this;
};

print("hoge".repeat(-1, '+')); //=> ""
print("hoge".repeat(0, '+'));  //=> ""
print("hoge".repeat(1, '+'));  //=> "hoge"
print("hoge".repeat(3, '+'));  //=> "hoge+hoge+hoge"
print("fuga".repeat(4, '-'));  //=> "fuga-fuga-fuga-fuga"
print("foo".repeat(4));        //=> "foofoofoofoo"

Perl の YAML と Ruby の YAML の相互運用

Ruby は標準添付の yaml で、Perl は YAML::Syck にします。でもって、Syck のオプションを

$YAML::Syck::ImplicitTyping = 1;
$YAML::Syck::SingleQuote    = 1;

にするとたぶん互換になるみたいです。ImplicitTyping は POD にも「こうすると互換になるよ」って書いてあるやつです。SingleQuote は 8 進数みたいな文字列 (/0[0-7]+/) をよみかきするときに必要になります。

use strict;
use warnings;
use Data::Dumper;
sub p { print Dumper shift }

use YAML::Syck;
p YAML::Syck::Load(YAML::Syck::Dump({foo=>"0100"}));
p YAML::Syck::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '--- 
foo: 0100
';

$YAML::Syck::ImplicitTyping = 1;
$YAML::Syck::SingleQuote = 1;
p YAML::Syck::Load(YAML::Syck::Dump({foo=>"0100"}));
p YAML::Syck::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '--- 
"foo": \'0100\'
';

$YAML::Syck::ImplicitTyping = 1;
$YAML::Syck::SingleQuote = 0;
p YAML::Syck::Load(YAML::Syck::Dump({foo=>"0100"}));
p YAML::Syck::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => 64
        };
$VAR1 = '--- 
foo: 0100
';

use YAML;

p YAML::Load(YAML::Dump({foo=>"0100"}));
p YAML::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '---
foo: 0100
';

use YAML::XS;

p YAML::XS::Load(YAML::XS::Dump({foo=>"0100"}));
p YAML::XS::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '---
foo: 0100
';

Ruby の YAML.load の挙動は YAML::Syck の $YAML::Syck::ImplicitTyping = 1; のときの挙動と一緒です。すなわちクオートしない /0[0-7]+/ は8進数の数値になります。YAML.dump は数値っぽい文字列を自動でクオートします。

require "yaml"

p YAML.load(<<EOS) #=> {"foo"=>64}
---
foo: 0100
EOS

p YAML.load(<<EOS) #=> {"foo"=>"0100"}
---
foo: "0100"
EOS

puts YAML.dump({"foo" => "0100"})
# --- 
# foo: "0100"
#
puts YAML.dump({"foo" => "aaa"})
# --- 
# foo: aaaa

ポイントは結局のところ

  • Dump 時に8進数っぽい文字列がクオートされるか
  • Ruby の yaml は特にオプションとかがない (なので、クオートされないものはつかえない)

みたいですね。あと、Perl しか使わない場合でも、$YAML::Syck::ImplicitTyping = 1 で使うときは必ず $YAML::Syck::SingleQuote = 1; も指定しないとデータがこわれてしまうみたいです。

Perl については調べきれてないかもしれないです (Syck 以外でもクオートできるのかな……)。もしかするともっといい方法があったりするのかもしれない……

2008年 01月 07日

shipit.rb

よびわけにこまったので shipit.rb とよぼう……

  • svk その他への対応
    • Commit/Tag とかの実際の処理を分離する
    • Rake::ShipitTask::VC::{SVN,SVK,Git} とかかなぁ
  • ステップ間で共有される state
    • instance_variable_set でハッシュセットすればいいかなぁ

をやんないとだけど、ここにこんなふうに書いてる時点でやる気ないよなぁ (今ちょっと svk をつかっていないので、svk 使うようになったらすぐに実装する感)

というかさっきまで全くオリジナルの ShipIt のコードを読んでなかった (Shipit::Step::Twitter だけ先に読んで処理を想像してた) ことに気付いてあわてて読んだ (全部じゃないけど)……アイデアだけでふくらませて考えてた。やばい…… CPAN はオンラインで簡単にソースよめていいなぁ。rubyforge も直接見れるリンクがほしい。

ちなみに shipit.rb で initialize と prepare にわけたのは、initialize っていう名前が Ruby 的に特別な名前なので、あんまり準備をするっていうイメージがないからです。instance_variable_set するなら initialize とわけたのは正解かなぁ (new すると initialize が走ってしまうので instance_variable_set するタイミングがない)

http://coderepos.org/share/changeset/4139

state には対応した。instance_variable_set はちょっと黒い気がしたので (みえないうちにセットされてしまうので)、いまのうちに initialize の仕様を変えることにした。