2007年 10月 15日

末尾再帰とか継続とか

解説ページをかなり前に一回、結構前に一回読んだんだけど、その二回とも「うーん、よくわからない……」でおわった。ループへの変換とかそういうのが、いまいちよくわかってなかった。

でも読んでから、ときどきそれを思い出して、反芻しているうちに理解できてくる。あぁそうかって思える。わけのわからないものだったけど、「こういうもの」っていうのがだんだん実感できてきて、継続なんかは末尾再帰のループ化にも繋ったりしておもしろい。継続は継続なんだなって思えてくる (ちゃんと理解して使えているかというと、ぜんぜんそんなことはないんんだけど、イメージができてくる)。本とか文書を読んで、そこでちゃんと理解する、っていうのは、頭が良くないとできないんだと思う。

そうなってから更めて Wikipedia とか見てみると納得できる。この確認作業も好きだ。

切ないに近いけれど、もう少し重い感情

っていうのは言葉にすると何になるんだろう……

AKG のケーブル

K271s のケーブルがミニプラグ側で断線ぎりぎり……

商品が見つかりません|サウンドハウス

たけー! 暇なときにミニプラグ側切ってそこらのステレオプラグにはんだ付けしよう。

他人の日記の生データみるやつ

見えない部分への考えかたがわかってしまいますね。

はてな記法は、例えば

aaaaaaa
bbbbbbb

aaaaaaa

bbbbbbb

は同じ (どっちも段落二つ) なので、どっちで書くかは人によったりたり。

Class.new(DelegateClass(Object)).allocate が nil を返すように見える問題 (あるいは inspect の上書きは慎重に)

--- delegate.rb.orig	2007-10-15 03:54:11.000000000 +0900
+++ delegate.rb	2007-10-15 04:01:23.000000000 +0900
@@ -95,7 +95,7 @@
   klass = Class.new
   methods = superclass.public_instance_methods(true)
   methods -= ::Kernel.public_instance_methods(false)
-  methods |= ["to_s","to_a","inspect","==","=~","==="]
+  methods |= ["to_s","to_a","==","=~","==="]
   klass.module_eval {
     def initialize(obj)
       @_dc_obj = obj
@@ -137,6 +137,11 @@
       raise NameError, "invalid identifier %s" % method, caller(3)
     end
   end
+  klass.module_eval do
+    def inspect
+        "#<#{self.class}:#{"%#0x8d"%self.object_id}:DelegateClass->#{@_dc_obj.inspect}>"
+    end
+  end
   return klass
 end

実際にはちゃんとインスタンスが返ってた。でも inspect まで丸投げしてるのでそれがわからなかった。inspect をそのまま委譲するのは正しいとは思えない。inspect が信用できなくなる。

require "delegate"
p Class.new(DelegateClass(Object)).allocate
#=> before: nil
#=>  after: #<#<Class:0x1ef50>:0xe6b48d:DelegateClass->nil>

location_of... がエラーでるのはこれとはまた別の問題……ここまで気付くのに数時間かかった……

そういえば tmpdir が予想と違った

なんとなく Tempfile の親戚だとおもって /tmp/hoge.9999.1 とかかえすとおもったら、たんに /tmp とか返すだけだった。

で、そういうディレクトリが欲しいときって自分で $$ とか書かないといけなくて嫌なんだけど、Tempfile はファイルを作って返すので使えず残念な感じになってしまう。個人的には Pathname に一時的なパスをつくるメソッドがあればいいと思った。

require "tmpdir"
require "pathname"

class Pathname
	@@tempname_number = 0
	def self.tempname(base=$0, dir=Dir.tmpdir)
		@@tempname_number += 1
		name = "#{dir}/#{File.basename(base)}.#{$$}.#{@@tempname_number}"
		path = new(name)
		at_exit do
			path.rmtree if path.exist?
		end
		path
	end
end

# ファイル
Pathname.tempname.open("w") do |f|
	f << "aaaaa"
end

# ディレクトリ
path =  Pathname.tempname
path.mkpath
10.times do |i|
	(path+"test#{i}.rb").open("w") {|f| f << "test" }
end

こんな感じのやつがほしい。特別ファイルをつくったりせず (Pathname なら作るの簡単だし)、ファイルでもディレクトリでもつかえる。

at_exit とファイナライザだと at_exit のほうが簡単な気がするけど、なんか問題あるのかな。デーモンだとたくさんできすぎるからかな。

そういえば、Pathname#mkpath が nil を返すけど、self を返してほしいと思うなぁ。

dir = Pathname.tempname.mkpath

みたいに書けると幸せ

GM

alert(document.getElementById("flvplayer"));
//=> [object XPCNativeWrapper [object HTMLEmbedElement]]
alert(unsafeWindow.document.getElementById("flvplayer"));
//=> [object HTMLEmbedElement]
alert(unsafeWindow.document.getElementById("flvplayer") === document.getElementById("flvplayer"));
//=> false
alert(unsafeWindow.document.getElementById("flvplayer") === document.getElementById("flvplayer").wrappedJSObject);
//=> true

ちょっと前に GetVariable でごにょごにょしてたときハマった……(XPCNativeWrapper 経由だと呼べない)

Ruby 書くとき

クラスを独自に拡張したのをどこに書くかで悩む……

そういうのに依存してしまうとコード単体で日記にはりつけたりがやりにくくなるしなぁ……ファイルの最初に書くぐらいしかないよなぁ

スター

消せないほうがいいなぁ、消せても今回の変更程度がぎりぎりだなぁと思う。まとめて消せるようになったら絶対嫌だなぁ。あくまでミスって一個つけちゃった、に対応できる、がいいと思う……

連打しといてあとでやっぱ消したいってのはなんかなぁ。

2007年 10月 14日

曜日べつゲリ統計

Mo   13 (18.1%)
Tu   14 (19.4%)
We   10 (13.9%)
Th   9  (12.5%)
Fr   11 (15.3%)
Sa   6  (8.3%)
Su   9  (12.5%)

ひさしぶりにとった。土曜日にむかうにつれて減るようだ

パッケージシステム

たとえば use みたいな感じのシステムをつくるとしても、あんまり使うイメージがうかばない。require "use" みたいなのは必要になってしまうし、require とは全然違う挙動をするから、なじむまでこまるし、中で何をやっているのかパっと見わからないから、ちょっとこわいし……(require はなにやってるのかわかりやすい)

というか RubyGems の何がいやか。なにを改善したらいいのか。パッチかけばすむのか。それでできるならそれにこしたことない。

  • パッケージ名 (gem.spec.name) と require で使う名前と、実際使う名前がそれぞれ関係ない。
    • auto_require つかって gem メソッド使えば少しはいい?
    • 1.9.1 で標準添付になったら、もっと gem メソッド活用してもいいかもなぁ
    • 実際使う名前がちがうのはどうしたらいいんだ。
      • でもこれは gem に限ってない。ostruct とか optparse とかも実際使うなまえと違うのでときどき混乱する。さすがによく使うから覚えたけど……
      • Python では import, Perl では use がある
      • require で読みこまれるファイルに新しいクラス/モジュールが定義されているとは限らない
      • autoload ってどういうケースを想定してるんだろう。
      • あるクラス・モジュール・メソッドがどこで定義されたものなのか簡単に知る方法がない
      • ビルトインの拡張とかどうするの
      • クラス定義のよみこみと機能の拡張はわけて考えてもいい?
      • require "test/unit" と use "Test::Unit" は後者だと定義されるだけみたいなの。実装できない
  • パッケージ名に統一感が全くない
    • camelcase だったり、そうじゃなかったり、アンダースコアいれたりいれなかったり
    • foobar-ruby とか ruby-foobar みたいなのおおい。 RubyGems って時点で ruby つかうのに
    • 政治的だから諦めるしかない?
  • rubyforge がダサい。
    • 機能での検索がしにくい。カテゴリわけされてない
    • プロジェクトだけあって中身がないのが割とある
    • 他にカッチョいい source があって、デフォルトで使用できればいい
      • gem とドキュメントだけホストして、カテゴリわけされていればいい
  • gem コマンドがいちいち遅い
  • require "rubygems" に抵抗がある
    • なんか一杯読みこむ
    • ほんとに読みこむだけでこんなに使ってるの?

require "rubygems" で定義される Module(Class) と読みこまれるファイル

["Gem::OperationNotSupportedError", "Gem::Exception", "Gem::LoadError", "Gem"]
["rubygems.rb",
 "rbconfig.rb",
 "rubygems/rubygems_version.rb",
 "thread.rb",
 "rbconfig/datadir.rb",
 "rubygems/source_index.rb",
 "rubygems/user_interaction.rb",
 "rubygems/remote_fetcher.rb",
 "net/http.rb",
 "net/protocol.rb",
 "socket.bundle",
 "timeout.rb",
 "uri.rb",
 "uri/common.rb",
 "uri/generic.rb",
 "uri/ftp.rb",
 "uri/http.rb",
 "uri/https.rb",
 "uri/ldap.rb",
 "uri/mailto.rb",
 "yaml.rb",
 "yaml/syck.rb",
 "syck.bundle",
 "yaml/basenode.rb",
 "yaml/ypath.rb",
 "yaml/baseemitter.rb",
 "yaml/constants.rb",
 "yaml/encoding.rb",
 "yaml/error.rb",
 "yaml/loader.rb",
 "yaml/stream.rb",
 "yaml/rubytypes.rb",
 "date.rb",
 "rational.rb",
 "date/format.rb",
 "yaml/types.rb",
 "zlib.bundle",
 "rubygems/digest/sha2.rb",
 "digest/sha2.bundle",
 "digest.bundle",
 "rubygems/digest/digest_adapter.rb",
 "forwardable.rb",
 "time.rb",
 "parsedate.rb",
 "rubygems/specification.rb",
 "rubygems/version.rb",
 "rubygems/security.rb",
 "rubygems/gem_openssl.rb",
 "openssl.rb",
 "openssl.bundle",
 "openssl/bn.rb",
 "openssl/cipher.rb",
 "openssl/digest.rb",
 "openssl/ssl.rb",
 "openssl/buffering.rb",
 "openssl/x509.rb",
 "rubygems/custom_require.rb"]

けっきょくいい方法がおもいつかなくて require にもどっていくのだなぁ……飽きるまで考えてみよう

依存ライブラリは次のバージョンから?かなり減るらしい。6ファイルぐらいに

Ruby で、メソッドがどこで定義されたか外から知る方法

「あるクラス・モジュール・メソッドがどこで定義されたものなのか簡単に知る方法がない」と書いたけど、ホントにホント?という切っ掛けで、メソッド内側の binding なら caller つかえば簡単にとれるけど、外から名前を指定してはとれないよなぁと思うので考えてみた。

class Object
	def location_of_method(name)
		c = nil
		ret = callcc {|c| false }
		unless ret
			m = self.method(name)
			args = [nil] * m.arity.abs
			set_trace_func Proc.new {|event, file, line, id, binding, klass|
				case event
				when "c-call"
					if id == name
						set_trace_func(nil)
						c.call([:native, nil])
					end
				when "call"
					set_trace_func(nil)
					c.call([file, line])
				end
			}
			m.call(*args)
			set_trace_func(nil) # attr_* 系で定義されたメソッドは call が trace できない?
		end
		ret
	end
end

class Class
	def location_of_instance_method(name)
		self.allocate.location_of_method(name)
	end
end

p Object.location_of_method(:new) #=> [:native, nil]
p Object.location_of_instance_method(:instance_eval) #=> [:native, nil]

require "pathname"
p Pathname.location_of_instance_method(:absolute?)
#=> ["/usr/lib/ruby/1.8/pathname.rb", 404]

require "ostruct"
p OpenStruct.location_of_instance_method(:initialize)
#=> ["/usr/lib/ruby/1.8/ostruct.rb", 46]

class OpenStruct
	def initialize
	end
end
# 直前の
p OpenStruct.location_of_instance_method(:initialize)
#=> ["test.rb", 44]

o = Object.new
def o.singleton_method_foo
end
# 直前の
p o.location_of_method(:singleton_method_foo)
#=> ["test.rb", 51]

require "webrick"
p WEBrick::HTTPServer.location_of_instance_method(:mount)
#=> ["/usr/lib/ruby/1.8/webrick/httpserver.rb", 111]

set_trace_func と callcc (継続) を使ってる。activesupport の Binding#of_caller の実装を少し前にみて「うわきめー」って思って使う機会があったら使ってみたい、とか考えていたら意外にホイホイあった。やってみてわかったことは set_trace_func 内のデバッグがすごくむずかしいということだった。
もっと簡単にやる方法があるかなぁ……

しかしモジュール定義とかはどうやってとるかがわからなすぎる。現在のファイルと require してるファイルを全部見てくしかないよねたぶん……

Delegater 使ってるときにうまくいかないなぁ。そもそも call がよばれてこない。なんでだろう。

require "tempfile"
p Tempfile.location_of_instance_method(:unlink)
__END__
(eval):3:in `__send__': undefined method `unlink' for class `NilClass' (NameError)
        from (eval):3:in `location_of_method'
        from test.rb:32:in `location_of_instance_method'
        from test.rb:85

Tempfile にも unlink が定義されているはずなのに、それが呼ばれない?で、スーパークラスのデリゲートが呼ばれているように見える。どういうことだろう……

なぜか Tempfile.allocate が nil になる

むーどうして allocate が nil になるかわからない。ちゃんと Class.allocate がよばれてるみたいなのに……

もうちょい改良

  • エラーができるだけでないように
  • スレッドセーフ
  • DelegateClass みたいなのに対応
class Object
	def location_of_method(name)
		old_state = Thread.critical
		Thread.critical = true
		name = name.to_sym
		c = nil
		ret = callcc {|c| false }
		unless ret
			m = self.method(name)
			args = [nil] * m.arity.abs
			set_trace_func Proc.new {|event, file, line, id, binding, klass|
				case event
				when "c-call"
					if id == name
						set_trace_func(nil)
						c.call([:native, nil, binding, klass])
					end
				when "call"
					set_trace_func(nil)
					c.call([file, line, binding, klass])
				end
			}
			begin
				m.call(*args)
			rescue Exception
			end
			set_trace_func(nil)
		end
		ret
	rescue ArgumentError
		false
	ensure
		Thread.critical = old_state
	end
end

class Class
	def location_of_instance_method(name)
		ret = nil
		old_state = Thread.critical
		Thread.critical = true
		self.ancestors.each do |c|
			break if c == Object
			[:location_of_method, :method_missing, :allocate].each do |m|
				[c, (class <<c; self; end)].each do |klass|
					begin
						klass.module_eval <<-EOC
							alias __location_temp_#{m} #{m}
							remove_method :#{m}
						EOC
					rescue NameError
					end
				end
			end
		end
		begin
			ret = self.__send__(:allocate).location_of_method(name)
		rescue NotImplementedError, TypeError, NoMethodError => e
			p e
		end
		self.ancestors.each do |c|
			break if c == Object
			[:location_of_method, :method_missing, :allocate].each do |m|
				[c, (class <<c; self; end)].each do |klass|
					begin
						klass.module_eval <<-EOC
							alias #{m}  __location_temp_#{m}
							remove_method :__location_temp_#{m}
						EOC
					rescue NameError
					end
				end
			end
		end
		ret
	ensure
		Thread.critical = old_state
	end
end

class Module
	def location_of_instance_method(name)
		c = Class.new
		# included を実行させない
		self.__send__ :append_features, c
		c.location_of_instance_method(name)
	end
end

#-- Test

def __modules
	ret = []
	ObjectSpace.each_object(Module) do |o|
		ret << o
	end
	ret
end
before = __modules

require "rubygems"
require "active_support"
require "active_record"

module_files = {}
(__modules - before).each do |o|
	next if o.name.nil? || o.name.empty?
	o.instance_methods(false).each do |m|
		r = o.location_of_instance_method(m.to_sym)
		if r
			(module_files[o.to_s] ||= []) << r.first unless r.first == :native
		end
		module_files[o.to_s] &&= module_files[o.to_s].uniq
	end
end

require "pp"
pp module_files

ri ひく Lusty-Explorer 拡張

http://lab.lowreal.net/trac/browser/config/.vim/plugin/lusty-explorer.vim.ext-ri.vim

\li でひらくようにデフォ設定。選択して RET で、そのまま補完候補バッファで ri のドキュメントを表示する。hjkl はプロンプトの入力にとられてしまっているけど C-p C-n で動ける。(ri のコマンドを ri にきめうちしてるので変えないとだめ。二箇所ある)

ほんとはもうちょい違う挙動にしたかったのだけど、めんどいので既存のを拡張する方向にした。Lusty-Explorer は Ruby だし簡単にできてよいよい。

ってかちょっと重すぎるなぁ……gems でライブラリいれてるとやばい

あれ、なんか C-c とか C-g で消えてくれない。なんでだろう

バッファ名がまずかったらしい。[LustyExplorer-ri] だとなぜか t という名前に変わってしまう。[LustyExplorer-Ri] だと大丈夫。よくわかんないな……vim のほうがそういう仕様なのかなぁ……

2007年 10月 13日

もっと効率的にネットをフィルタリングしたい

全く有用じゃないエントリ (ただ叩いているだけとか) を効率的にフィルタリングしたいなぁ……

うまく自動化するのは言語解析しないとむりっぽいから、有用じゃないエントリ書いてるのを見たらチェックつけて、人ベースでサービスを横断して拒否できればいいかなぁ。はてなでそういうの書いてる人ははてな以外であんま見ないから、はてな内だけで id ベースのフィルタリングつくったらよさそうだ。

  • ブックマークコメを非表示にする
  • id ふくむパスを全て場合ページ内容を空に
  • LDR で id ふくむエントリをスキップ (ほってんとりとか)

あと、GM_setValue とかだとマシン間で同期するのがめんどいから、どっかに保存しておきたいなぁ。はてブの非表示ユーザを共有すればいいか。

Erubis

gems 使えるコンテキストでは全部 Erubis 使うようにしよう。Erubis::EscapedEruby つかおう。
デメリットがない

gems

なんで gem spec のファイルを YAML にしちゃったのかなぁ。Ruby で eval できるコードを吐けばもっと高速で YAML への依存が減らせるのに
この場合 YAML 使う理由ってなんだろう。他の言語から読みかきするわけじゃないしというか結局吐く YAML が Ruby 依存になるし……

とおもったら、ローカル spec は Ruby で eval できるコード吐いてた (キャッシュは Marshal)。すいませんすいません。サーバとのやりとりだけ YAML なのかな

おかね

最近は前よりはビジネスについて興味を持てるようになった気がする。どうやって収入を得て、どこから出ていくのかみたいなのがすこし気になるようになった。でもとても気になるという感じではなくて、むずかしい話になるとカットされる。

Ruby に use を実装する。

RubyGems みたいに、あらかじめ spec をキャッシュしておく、みたいなのが許されるなら、こういうのもありなんじゃないかなぁと思った。以下の実装はいろいろだめなところがあるだろうけど…… (プラットホーム依存のところがほげほげとか)

# module 名 -> ファイル名へのハッシュテーブルを作る
# ruby 起動しまくって時間がかかるので前もってキャッシュする
require "pathname"
module_files = {}
$LOAD_PATH.each do |path|
	path = Pathname.new(path)
	next if path.relative?
	Pathname.glob(path + "**/*").each do |t|
		next unless t.file?
		next if t.to_s =~ /tk/
		puts t
		ENV.delete("RUBYOPT")
		ret = nil
		IO.popen("ruby", "r+") do |io|
			io.puts <<-CODE
				# 自分自身はロード済みにしないと、ループして require している場合にまずい
				$LOADED_FEATURES << '#{t.relative_path_from(path)}'
				$depend_lib = []
				def __modules
					ret = []
					ObjectSpace.each_object(Module) do |o|
						ret << o
					end
					ret
				end

				alias _require_orig require
				def require(lib)
					prev = __modules
					ret = _require_orig(lib)
					if ret
						$depend_lib.concat(__modules - prev)
					end
					ret
				end

				def set_trace_func(*)
				end

				prev = __modules
				stdout = STDOUT.dup
				STDOUT.reopen($stderr)
				begin
					_require_orig '#{t}'
				ensure
					STDOUT.reopen(stdout)
					print Marshal.dump((__modules - prev - $depend_lib).map {|i| i.to_s })
					STDOUT.flush
					exit!
				end
			CODE
			io.close_write
			ret = io.read
			ret = Marshal.load(ret)
		end
		ret.each do |m|
			(module_files[m] ||= []) << t.to_s
		end
	end
end

require "pp"
File.open("module.cache", "wb") do |f|
	Marshal.dump(module_files, f)
end

本体

def use(mod)
	mod  = mod.to_s
	mods = Marshal.load(File.read("module.cache"))
	raise LoadError, "#{mod} is not found." unless mods[mod]
	mods = mods[mod].map {|i|
		[i, i.split(File::ALT_SEPARATOR || File::SEPARATOR).size]
	}.sort_by {|i,ii|
		ii
	}
	mods.select {|i,ii| ii == mods.first[1] }.each do |i,ii|
		require i
	end
end

use %(Test::Unit::AutoRunner)
use %(Test::Unit::TestCase)

class UseTEST < Test::Unit::TestCase
	def test_success
		use %(Pathname)
		assert_kind_of Class, Pathname

		use %(Test::Unit::AutoRunner)
		assert_kind_of Class, Test::Unit::AutoRunner

		use %(ERB)
		assert_kind_of Class, ERB

		use %(ERB::Util)
		assert_kind_of Module, ERB::Util

		use %(WEBrick)
		assert_kind_of Module, WEBrick

		use %(Net::HTTP)
		assert_kind_of Module, Net
		assert_kind_of Class, Net::HTTP

		assert_raise(LoadError) do
			use %(NotInTableModule)
		end
	end
end

Test::Unit::AutoRunner.run($0 != "-e" && $0)

テーブルは require しているファイルに定義されているクラスを除いているので、test/unit.rb みたいな require をしている場合、そのファイルにいくら定義があっても「クラスの再定義/上書き」という判断しかできないので、use "Test::Unit" とかしても test/unit.rb は読みこまれない。

あとは webrick なんかを例にとると webrick.rb は他のファイルを require するだけなので、直接はこのファイルはモジュールハッシュ上にあらわれない。use では同じ深さを持っていて、WEBrick を定義している全てのファイルを require してる。

もっとたくさんテスト書いて、実装精密にすればつかえるかなぁ……

どっかのサーバで rubyforge の gems をミラーして解析して、このテーブルをつくっておいて、パッケージ検索できるようにするとか、あるいはそのままパッケージシステムにしてしまうとかがおもしろいかなぁ。既存の gems をそのままもってこれてたのしそう。