/ 最近 .rdf 追記 設定 本棚

脳log[Ruby: 2013-04-14~]



2013年04月14日 (日)

最終更新: 2013-04-15T03:23+0900

[SakuraEditor][Ruby] サクラエディタBBS[7601]

  • Editor定数の参照で落ちる。他の名前なら問題なし。
  • $Editorとすることで Editorオブジェクトが得られる。
  • マクロコマンドは先頭を小文字にしないと呼べない。(TraceOut→traceOutなど)
  • Editorオブジェクトに SCRIPTITEM_GLOBALMEMBERSフラグが付いてると、Rubyマクロのばあい ITypeLibが必要になる。(ITypeInfo->GetContainingTypeLibを実装する必要がある)
  • ITypeInfo->GetFuncDescがマクロコマンドの数(271)×3回、マクロを実行する前に呼ばれる。
  • 3回目に取得された ITypeInfoがリリースされない。
  • Editorオブジェクトもリリースが足りない。
  • 実行の成否にかかわらず一回につき 100KBぐらいメモリ使用量が増える。
  • リソースリークをなくしたければ参照カウントを捨てて、マクロ実行の前後ですべてのオブジェクトの作成・破棄を行うのが確実。
  • 12回目のマクロ呼び出しが必ず失敗する。例外が発生しているもよう。
  • TYPEATTR.cFuncsの数を減らしてマクロコマンドの数をごまかすと 11回を超えて成功するようになったり。リリースモードにしても回数は変化する。
  • 失敗しても繰り返しマクロを実行してるとときどき成功する。
  • マクロ実行に失敗するとき、IActiveScriptParse->ParseScriptText直前の IActiveScript->SetScriptState(SCRIPTSTATE_STARTED)呼び出しから足取りがつかめなくなる。
  • SetScriptStateを飛ばして ParseScriptTextを実行するようにすると例外はなく、正常にエラーメッセージ("実行に失敗しました")が表示される。なんにせよ失敗。
  • スクリプトエンジンをマクロ実行ごとにきれいに片付けられていれば、○回目から失敗みたいなことは起こらないと思うんだけど。なにが継続しているのか、あるいはこちらの何が破壊されていってるのか。

どうせ Rubyマクロはコマンドの先頭を小文字にする必要があって他のマクロと同じように書けないのだし、使われてないからこれまでに書かれたマクロ資産との互換性を図る必要もないし、例外とリークの元になり実行前の負荷も発生させる SCRIPTITEM_GLOBALMEMBERSフラグを落とすのがいいと思う。ScriptEngine名が "RubyScript." で始まるときとかに限って。

SCRIPTITEM_GLOBALMEMBERSフラグを落とすと $Editor.insTextだけのマクロは何十回でも問題なく実行できてるけど、それだけで安心してよいものか。Editorと書いたときのように(数字で始まるマクロコマンドを呼んだときも?)初回で確実に落ちるというだけならいいけど、何回も実行してるうちに運が悪ければ落ちるというのがあれば(たち)が悪い。


2013年02月13日 (水) 見られてる。わかってるのに何度でも振り向いてしまう。PERSIは美猫だにゃー。■パーシーって読んでる(呼んではいない)。■目。赤外線で目をポイントするとこちらへ焦点を合わせるようなギミックはないものか。ありそうなのは赤外線より磁石かな。近づける、動かす、方向を保ったまま遠ざける。グラスアイの追視は運要素が強すぎるよ。■■■もう一体。乳首と爪を同じ色で塗ろうかとものぐさな計画をたてていたが、これが思いがけずエロティックな想像だった。だって、爪を見られるとき乳首を見られてるような気持ちになるってことだ。<おっさん自重。■せっかくの球体関節人形(※英語だとball-jointed dollとかいうんだろうか。雰囲気台無し。ガンプラみたいだ(子供の頃は混在期で2種類のグレーのポリキャップのどちらかが使われていた。新しいものにボールジョイント))なんだから膝が見える丈のスカートがいいね。■■■美猫ってびびょうって読むんだろうか。イメージ喚起能力に乏しいしきれいな音でもないけど、美人や美姫も先入観を取り除けば似たようなものか。何も考えないとびねこって読みたくなる。みびょうの可能性もなくはないかなと思うが予防医学か漢方のイメージが先に立つ。みねことなると誰かの名前みたいだ。■228「「美猫」に振られるルビは「びじん」 これ常識なw ソースは「綿の国星」とかw」228が大正解w■■■前からちらちら物色してるんだけどデジカメが欲しくなるなあ。三脚も必要だ。重視したい機能は GPSとヒトの目を超える分解能と目を見開かされるような解像感。(セクション3へつづく)

最終更新: 2013-02-22T00:42+0900

[Ruby] どうしていいのか困り果てるバグに当たったのでバージョンアップする。

日本語を含むフルパスを File.expand_pathすると、文字列そのものは変化しない(ように見える)のにファイルを見失う。

C:\>irb19
irb(main):001:0> File.directory? "C:/コピー"
=> true
irb(main):002:0> File.directory? File.expand_path "C:/コピー"
=> false
irb(main):003:0> "C:/コピー" == File.expand_path("C:/コピー")
=> true
irb(main):004:0> RUBY_DESCRIPTION
=> "ruby 1.9.3dev (2011-09-23 revision 33323) [i386-mswin32_100]"
irb(main):005:0> $:
=> ["C:/Program Files (x86)/ActiveScriptRuby-1.9/lib/ruby/site_ruby/1.9.1", "C:/Program Fi
les (x86)/ActiveScriptRuby-1.9/lib/ruby/site_ruby/1.9.1/i386-msvcr100", "C:/Program Files
(x86)/ActiveScriptRuby-1.9/lib/ruby/site_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1
.9/lib/ruby/vendor_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9/lib/ruby/vend
or_ruby/1.9.1/i386-msvcr100", "C:/Program Files (x86)/ActiveScriptRuby-1.9/lib/ruby/vendor
_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9/lib/ruby/1.9.1", "C:/Program Files (x
86)/ActiveScriptRuby-1.9/lib/ruby/1.9.1/i386-mswin32_100"]
irb(main):006:0>

ところで Rubyは Unicode文字を含む(Shift_JIS(※)に含まれない文字を含む)パスを扱えるようになっているだろうか。方法はあるけどやり方を間違えていただけだろうか。


2009年に書いた自分のスクリプトをきちんと動くようにしようと引っ張り出してきた。Rubyの対象バージョンを 1.8から 1.9.3にして ruby-mp3infoを GitHubからダウンロードしてきた最新版に差し替えただけで肝心な部分はほとんど終了。それにしても、4年前の自分がきっちりボトムアップでプログラムを構造化していたことに驚いた。最近 PRS-650のために書いたスクリプトとは比べられない。Rubyは、こうあるべきと書き手が考えるソースコードの流れを比較的自由に表現できる言語であるから、言語の制約を気にせず頭の中に理想形を持っておくのが大事。クラス構文があるからクラスを作るんでなく、こう書きたいという欲求を満たす選択肢としてクラスがある。理想の有無が同じ書きたいように書いた結果に雲泥の差が生じる理由。忘れてた。


このバグだ。>Backport #5629: Windows環境で日本語を含むパスに対して、File.expand_path が存在しないパスを返すパターンが存在する。 - Backport93 - Ruby Issue Tracking System。一年前に 1.9.3にバックポートされて解決してる。Ruby-1.9.3-p385にアップデートするにはいいタイミングだったし、都合のいい理由付けになった。


似たような問題がまだ requireに残ってたみたい >Bug #7881: Windows でパスに日本語を含むスクリプトからの require が失敗する - ruby-trunk - Ruby Issue Tracking System

最終更新: 2013-03-03T06:08+0900

[Ruby] moumar/ruby-mp3info at 9e08852356ff46716d00fac3b553904c8ea503d3 · GitHubに加えた変更点。

  • ID3v1がもともと存在しないファイルに ID3v1を付け加えないように。removetag1してさえ ID3v1が書き出されて困惑した。<<同じ対応を ID3v2にもとったらタグなしの mp3ファイルにタグをセットすることができなくなる。v1が v2がと気にするのなら tagでなく tag1と tag2を使い分けるべきなのかも。でも "universal tag"を使いたいのだよね。もともと v1と v2を両方書き出していたけど v1があると v1を優先してしまう困ったソフトがあるために v2だけにしたい、という今の自分がおかれた状況で、タグを操作する部分から tag1に関連する部分を削除してまわるというのはうまい考えではない。使用するソフトが変わってやっぱり v1もあった方がいいとなったらどうする?タグ操作は universal tagで共通化したい。なら、universal tagを制御するフラグが足りてないように思う。
  • tag["tracknum"]を文字列として扱い、ID3v1に書き出すときにだけ to_iするように。文字列で扱った方が(全体で何トラックあるのかという)情報のロスがないので。
--- ruby-mp3info-master\lib\mp3info.rb~	Wed Feb 13 16:34:42 2013
+++ ruby-mp3info-master\lib\mp3info.rb	Wed Feb 13 20:48:38 2013
@@ -272,7 +272,7 @@
             next unless tag_value
             @tag[key] = tag_value.is_a?(Array) ? tag_value.first : tag_value
 
-            if %w{year tracknum}.include?(key)
+            if %w{year}.include?(key)
               @tag[key] = tag_value.to_i
             end
             # this is a special case with id3v2.2, which uses
@@ -381,7 +381,7 @@
       puts "@tag has changed" if $DEBUG
 
       # @tag1 has precedence over @tag
-      if @tag1 == @tag1_orig
+      if @tag1 == @tag1_orig && ! @tag1.empty?
         @tag.each do |k, v|
           @tag1[k] = v
         end
@@ -418,7 +418,7 @@
             ((@tag1_orig["year"] != 0) ? ("%04d" % @tag1_orig["year"].to_i) : "\0\0\0\0"),
             @tag1_orig["comments"]||"",
             0,
-            @tag1_orig["tracknum"]||0,
+            @tag1_orig["tracknum"].to_i,
             @tag1_orig["genre"]||255
             ].pack("Z30Z30Z30Z4Z28CCC")
           file.write(str)

 利用側でのモンキーパッチング

Vistaの Windows Explorerでタグを書き換えると encoding_indexが 0(iso-8859-1)になるんだけど、これを信用して変換すると日本語文字が化けるので Windows-31Jにしてみた。

require "mp3info"
ID3v2::TEXT_ENCODINGS[0] = "Windows-31J"

2011年09月30日 (金)

最終更新: 2011-10-01T04:28+0900

[Ruby] Google Code Jam Japan 練習問題

練習問題。それも Aだけ。Bは撃墜されました。

# small用
def last_output(n, k)
	snappers = [false] * n
	k.times{
		# 電流をたどってひっくり返す。
		0.upto(n-1){|i|
			snappers[i] = ! snappers[i]
			break if snappers[i] # previously OFF (=next snapper's IN was OFF)
		}
	}
	return snappers.all?
end

# large用
def last_output(n, k)
	# k1 = 2**n-1 # k1:最初に n個の snapperがすべて ONになる操作回数.
	# k = p*k1+(p-1) を満たす自然数pが存在するなら電球は ON.
	return (k+1)%(1<<n) == 0
end

caseno = 0
$stdin.readline; # drop # of cases.
$stdin.each_line{|ln|
	n,k = *ln.scan(/\d+/).map(&:to_i)
	break unless k
	caseno += 1
	puts "Case ##{caseno}: #{last_output(n,k)?'ON':'OFF'}"
}

2011年05月19日 (木) Logicoolの製品情報ページ。URLのフラグメント(ハッシュの後ろ)と onclickハンドラで小賢しい見た目の操作をしてるけど「戻る」に対応していない。読み手の感覚として明らかにページ移動をしている(ヘッダ・フッタといったテンプレートを除いてページ全体が書きかわってる)のに、URLが変わっておらず履歴にも残っていないからだ。枝葉にこだわるなら徹底的にやりな。一方ダイソンは……クエリストリングを使い、スクリプトが有効ならページを動的に書き換え、無効化されていても情報を表示できないなんて間抜けはおかさなかった。何が主で何が従かがわかってる。

最終更新: 2011-05-19T13:48+0900

[Ruby] lostと lots of? だとしても informationに lots?

7. In app code, never use force_encoding to convert BINARY data into a particular encoding. By the time you've reached app code, you have lost the information about which encoding is being used. Instead, find where the String came into Ruby, and fix it to set up the encoding based on the information it knows.

アプリケーションコードの場合、バイナリデータを特定のエンコーディングに変換するために force_encoding を決して使わないこと。アプリケーションコードをいじっているのであれば 使用されているエンコーディングに関する情報をたたくさん持っているはずである。 この場合、その文字列がどこからRubyにやってきたかを突き止め、わかっている情報に 基づいてエンコーディングを設定するように修正すること。

いまもって Ruby 1.9のエンコーディングに関するベストプラクティスがわからないので、すごくためになるリスト。7はこう理解した。

(文字列のエンコーディング情報が失われた)末端コードで、(その場で必要とされるエンコーディングに基づいて場当たり的に) force_encodingしないこと。その文字列の来歴をたどって一番根っこ(※ライブラリの修正が必要かも)で正しい情報(※ないのなら慣習に従うか、その不完全なプロトコルを捨てる)に基づいて force_encodingすること。(末端コードで必要に応じて行うのは encodeだったり encode!)


2011年04月11日 (月)

最終更新: 2011-04-16T21:35+0900

[Ruby] 「HsbtDiary(2011-04-11) rubygems の taint と LOAD_PATH と $SAFE について

前にこうならんかな?って書いたのをもう一度。

require 'hoge'

したときに hoge.rbなり hoge.soなりが taintedな $LOAD_PATH要素に基づいて発見されたときは SecurityError。見つからなければ taintedな要素はスルー。という動作を Rubyに期待したい。今は taintedな $LOAD_PATH要素を無造作に File.expand_pathして SecurityErrorが起こるに任せているんではなかったか。


 @2011-04-16 Ruby 1.9.2p136と 1.8.7p330で挙動が違うのが SecurityErrorへの疑問を増す。

1.9.2では(確かめたわけではないけど)汚染されたパスの展開がセキュリティエラーにつながってるから、汚染されたパスが $LOAD_PATHの末尾にあった場合は $SAFE=1の状況下で require 'cgi'が成功する。require '存在しないファイル'はセキュリティエラー。汚染されたパスを基に展開を試行したかどうかが分かれ目。

1.8.7では $SAFE=1の状況下で汚染された文字列を引数にした File.expand_pathは 1.9.2と違い成功するものの、上のような場合でも require 'cgi'に失敗する。これは requireが内部的に File.expand_pathを呼び出し――これは 1.9.2とは違いセキュリティエラーを起こさないけれど 1.9.2同様汚染された文字列を返す――、その汚染された戻り値を使った require_internal(仮名)が 1.9.2とは違い $SAFE=1のときにセキュリティエラーを起こしてるのだと思う。挙動からの推測。

一貫性が欲しかったね。できれば実用的なものが。特定のディレクトリ(汚染された$LOAD_PATH要素)に特定の .rb, .soファイル(requireされたファイル)があるかないか判った(SecurityError or not)ところでどうだというの。


2011年03月12日 (土) combinationメソッドを調べるために Ruby 1.8.7のドキュメントを少し読んだ(常用のリファレンスは20051129だ)。choiceから sampleへの名前変更は良かった。choiceは意思を明らかにする行為だと思うからランダム抽出とは相容れないよ(それとも神の選択か)。「Ruby 1.8.8 以降では Array#sample を使ってください。」 Ruby 1.8.8 は出るんでしょうか?

最終更新: 2011-03-15T00:15+0900

[ProjectEuler][Ruby] Problem 71, 72

 Problem 71

「HCF(n,d)=1」には用語の説明があると思ったんだけどなかった。n/dの nと dは最大公約数が 1の既約分数だとすると意味がとおるので HCF=Highest Common Factorだと決めた(でっちあげ)。

分数とはなんぞやだとか切断だとか小難しく考えてしまったが(実際には考えられるほど知らない)、ワンライナーだった。3/7より少し小さい100万個の分数を小数になおして、一番小さいものを見つける。有理数にして比較しないのは時間がかかるから。公約数をみつけたりする時間だろうか。

require 'rational'
p Rational(*(2..1_000_000).inject([0,1]){|answer,d|
	answer[0]/answer[1].to_f < (d*3-1)/7/d.to_f ? [(d*3-1)/7,d] : answer
})

 @2011-03-14 なにこれ!

Project Euler Problem #71 « KeyZero Conversation

分数を初めてならった小学生が必ず間違える分数の足し算(通分せずに分母どうし分子どうしを加算する)にこんな意味があるとか!

 Problem 72

分単位のお時間がかかります。(訳:一時間はかからないけど……)

何倍も速くなるので「Integer#prime_division」を使う代わりに 100万要素の配列を使ってる。トレードオフで使用メモリは数MBから 100MB超になるが。 小手先のチューンよりアルゴリズムを改良しろってのはもっともだけど、かなしいかな、できることとできないことがあるのです。

LIMIT = 1_000_000
pfs = Array.new(LIMIT+1){ [] }
count = 0
2.upto(LIMIT){|d| # 0) LIMIT以下のすべての分母 d に対して、
	print d,"\r"
	count += d-1 # 1) とりあえず d-1 通りの分子を計上し、
	d.step(LIMIT, d){|_| pfs[_] << d } if pfs[d].empty?
	# 2) 8分の6など通分可能なものを差し引きする。
	(1..(pfs[d].size)).each{|r|
		cms = pfs[d].combination(r).map{|pf| pf.inject(&:*) }
		count -= (-1)**(r%2+1) * cms.map{|cm| (d-1)/cm }.inject(&:+)
	}
}
p count

Ruby 1.9からバックポートされてきた(のだと思われる見覚えのないメソッド) cycle, tap, combination, permutation, productといったメソッドが便利だ。あとは自然数を無限に生成し続ける無限リストのようなものをどれだけ簡単に書けるかだ。なにかショートカットがあるのだろうか。これでは長すぎる。

Enumerable::Enumerator.new(lambda{|&block| n=0; loop{ block.call n+=1 } }, :call).each{|x| p x }

それと、block.callの部分を yieldにできないのもわかりにくい。Procと blockと lambdaの微妙な違いによるものなのだろうか。

Rubyによる他所の Project Eulerの解答をみていてこういう書き方も知ってるけど、カウンタが Floatになっちゃうのが不満。

1.upto(1/0.0){|n| p n }

あれ? Fixnumだ。Floatになるのは stepだった。

1.step(1/0.0){|n| p n } # 1.0, 2.0, 3.0,...

明示的に Fixnumの増分: 1を指定しても n は Float. この違いはなんだろう。


cycleの使い道として zipを想定していたが拒否されてしまった。

irb> [1,2,3,4,5].zip([0])
=> 1, 0], [2, nil], [3, nil], [4, nil], [5, nil
irb> [1,2,3,4,5].zip([0].cycle)
TypeError: can't convert Enumerable::Enumerator into Array
        from (irb):2:in `zip'
        from (irb):2
        from :0
irb> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mswin32]"

2010年07月30日 (金)

最終更新: 2012-11-01T13:41+0900

[SakuraEditor][SHJS][Ruby] Rubyの %リテラルの色分けを修正。

説明が面倒なのと誰も知りたくないだろうから適当に、備忘のためだけに。

  1. まさか %{literal}literal部分で \{\} を使う人間がいるとは思わなかった。(違う種類の括弧を使えばいいじゃない。開閉の釣り合いがとれてれば同じ種類の括弧でもエスケープ不要だし)
  2. だのに Ruby1.9の rake.rbにこんなパターンが……

    %r{[*?\[\{]}
  3. エスケープされた { 2のはの考慮がないから、閉じ括弧が足りないとしてファイル末尾まで正規表現として色分けされてしまう。
  4. ちょちょちょいと .rkw2ファイルにエスケープ文字を追加してサクラエディタに対する修正は完了
  5. SHJSの lang/sh_ruby.js(自作)への対応も同じですむはずが、入力の末尾に達した時点で意図せぬバックトラックが発動し、閉じ括弧が足りなくても色分けが適当な閉じ括弧で終了してしまう現象に遭遇。これは自業自得(20090808p01)なので自分でなんとかせねば。間違いが埋没してしまうのはよろしくない。
  6. こうした

    %r{余分な開き括弧{。間違いはインタープリタを通す前から目立つように}

2のは Rubyインタープリタに対するエスケープ、と同時に正規表現パターンとしてのエスケープですよ。%r[\[] と /\[/ が同じパターンになって、%r[[] がRubyのシンタックスエラー、/[/ がパターンのコンパイルエラーになるんだから。(ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mswin32] / ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-mswin32])


2010年04月21日 (水)

最終更新: 2010-04-22T02:07+0900

[Ruby] 「まつもと ゆきひろのRuby検定 - ITpro EXPO検定---ITpro EXPO 2008:ITpro

やってみた。Time.parseの問題がわからなかったのと、ブロック変数が外のローカル変数を変更してしまうかどうかという問題(Rubyのバージョンは?回答形式が)以外はたぶん問題なし。で、回答を送信すると一分かそれ以上待たされた後、「一度しか回答できません」だって。ええええ。たしかにそう書いてあるのは読んだけど、以前回答したことも忘れてるんですよ。そんなこと言われても。

そういう要求をするのも、それを額面通りに実施してしまうのも、ある意味感心するけど首を傾げてしまう。回答は適当に受け付けて、後でフィルタリングしてから利用すればいいじゃない。とここで「すでに受験した方は,前回の回答結果を参照できます。」とも書かれてるのに気付いた。ログインを要求されたから見られなかったけど、回答を(回答者の要求に応じて参照できるようにしながら)抱え続けるのって誰得? Ruby検定の予想問題からのピックアップに過ぎないんですよ、この問題って。

回答形式が 一つ選べという問題だったのにチェックボックスが使われていた。他は問題形式によってラジオボタンとチェックボックスが適切に使い分けられていたから、出題形式を間違えたかフォームを間違えたか後でフォームだけ変更されたか。はてさて。


2010年04月05日 (月) とうとう Refererスパムも来始めた。コメントスパムの方も、NGワードが設定されていることを察知するのか vigraとか ciallisだとか微妙にキーワードを変えてきている。こういう段階的対応が自動化されてたらこっちはたまったもんじゃないよ。

最終更新: 2013-08-20T01:04+0900

[Ruby] 「少なくとも優秀ではない」ことを否定する(≠優秀である)。

makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) - ITmedia エンタープライズ」経由で「人生を書き換える者すらいた。: 人材獲得作戦・4 試験問題ほか

粘菌でも迷路問題を解けるというのだから負けてはいられない。Rubyで一時間半弱かかった。

#! ruby
# coding: Shift_JIS

# 迷路データ

maze = <<MAZE
**************************
*S* *                    *
* * *  *  *************  *
* *   *    ************  *
*    *                   *
************** ***********
*                        *
** ***********************
*      *              G  *
*  *      *********** *  *
*    *        ******* *  *
*       *                *
**************************
MAZE

# マップ

class Point
	def initialize(x, y)
		@x, @y = x, y
	end
	attr_reader :x, :y

	def ==(other)
		@x == other.x && @y == other.y
	end
	def to_s
		"(#{@x},#{@y})"
	end

	def left
		Point.new(@x-1, @y)
	end
	def right
		Point.new(@x+1, @y)
	end
	def up
		Point.new(@x, @y-1)
	end
	def down
		Point.new(@x, @y+1)
	end
end

class Map
	def initialize(maze)
		lines = maze.strip.split(/\r\n?|\n/)
		@height = lines.length
		@width = lines.first.length
		y = -1
		@map = lines.map{|line| y += 1
			x = -1
			line.split(//).map{|ch| x += 1
				if(ch == 'G')
					@goal = Point.new(x, y)
					nil
				elsif(ch == 'S')
					@start = Point.new(x, y)
					nil
				elsif(ch == '*')
					-1
				else
					nil
				end
			}
		}
	end
	attr_reader :height, :width
	attr_reader :start, :goal

	def []=(point, value)
		@map[point.y][point.x] = value
	end
	def [](point)
		@map[point.y][point.x]
	end
	def up(point)
		return -1 if point.y-1 < 0
		return @map[point.y-1][point.x]
	end
	def down(point)
		return -1 if self.height <= point.y+1
		return @map[point.y+1][point.x]
	end
	def left(point)
		return -1 if point.x-1 < 0
		return @map[point.y][point.x-1]
	end
	def right(point)
		return -1 if self.width <= point.x+1
		return @map[point.y][point.x+1]
	end
end

map = Map.new(maze)
#puts "width×height = #{map.width}×#{map.height}"
#puts "start:#{map.start} / goal:#{map.goal}"

map[map.goal] = 0;
#puts "goal=#{map[map.goal]}"

# 先端

nodes = [map.goal]
while node = nodes.shift
	next if node == map.start
	[node.left, node.right, node.up, node.down].each{|nxt|
		case(map[nxt])
		when -1
			# 壁
		when nil
			# 未踏
			map[nxt] = map[node] + 1
			nodes.push(nxt)
		else
			# 既に到達したルートがある
			if(map[node] + 1 < map[nxt])
				map[nxt] = map[node] + 1
				nodes.push(nxt) unless nodes.include?(nxt)
			end
		end
	}
end

# Map to result

map.height.times{|y|
	map.width.times{|x|
		point = map[Point.new(x,y)]
		print point == -1 ? '***' : ("% 3d"%point)
	}
	puts
} if false

result = maze.strip.split(/\r\n?|\n/)

node = map.start
until node == map.goal
	[node.left, node.right, node.up, node.down].each{|nxt|
		if(map[nxt] == map[node] - 1)
			node = nxt
			result[nxt.y][nxt.x] = '$'
			break
		end
	}
end

puts result.join("\n")

ノードっていうのはひとマスのこと。「先端」っていうコメントが適当すぎる(植物では頂端分裂組織っていうらしい)。方針はゴールからスタートに向けて、一マス移動するごとに一ポイントを加算しながら全方位に触手を伸ばしていき、すでに他の触手が通過した道は、自分が最適な場合にのみ侵入するこの判断は不要。全ての触手が行き場を失うかスタートに到達するかしたら終了。スタートから一ずつ減っていく数字をたどると(一少ない数をもつ隣接マスが二つ以上あっても解答に求められていないので無視する)ゴールへ着き、それが最短経路(だったらいいな)。

最初は粘菌方式をまねようと思ったが、通路をすべて覆った状態からスタートして、スタートとゴールにつながっていない島を切り捨て、袋小路から撤退するのはいい。遠回りと近道を取捨選択するためにどういう評価をすればいいのかを決められなかった。どうすればいいの?粘菌は何を考えてる?例えば


二番目のリンク先のトラックバックを見てる。みんな優秀なのね、C++で一時間もかかってないし。何人かが言及している「BFS」。それって一般的知識? 幅優先探索(Breadth-First Search)か最良優先探索(Best-First Search)の略だということはわかった。


壁のもつポイントを -1 に設定したことで、壁に侵入しないことを保証する when節を省略してもよかったんじゃないだろうか。気付くのが遅れたが。


ゴールにも $ って書き込んでら。(スタートには書きこまんように気をつけたんだが)


粘菌すごい。

培地に、三個以上の餌を置く。粘菌は迷路の実験のように最短距離を結ぶか?

結果は違った。

粘菌は、丸く、複数の経路を持つ管を作った。「最短経路だと一カ所故障したら必ず孤立する場所が出ます。だから粘菌は、一カ所が故障しても全体はつながり、なおかつ距離がなるべく短い経路を作ったのです」

部分部分がどういう反応をするとそういう結果になるんだろ???


 @2013-08-19 こういうことらしいです。わかりません。

粘菌の行動原理は、量子ドット間の近接場光を介したエネルギー移動プロセスに類似している

この判断は不要 @2010-04-11 不要だったらしい。ノードリストが FIFO(=push/shiftを使う=幅優先)なら起こりえないみたい。

例えば 粘菌が電気を好む抵抗(集まると抵抗が下がる)だとしてスタートとゴールに電圧をかけるイメージ?

本日のツッコミ(全2件) ツッコミを入れる

BorsJoigreeBS GE VC KX LJ UZ ZY RW MS IS ML JE AL FWUN BR EJ AV DD XQ..

ds14050解析班はどこだ?


2009年12月06日 (日) [C++]「ヘッダファイルの依存を減らす」<端緒。パフォーマンスの本といえば『Efficient C++』だけかと思っていた(『Boost』にそのように書かれていた)ら、目当ての本の横に『C++パフォーマンス戦略』という本が。これまでのところ大垣書店はすごくよくやっている。Amazonで注文する前にとりあえずのぞいてみて、一度も期待を裏切られていない。

最終更新: 2014-12-18T13:09+0900

[Ruby] メソッドの困った上書き

すぐ上のセクションで出てきた(俺が書いたんだけど)こういうの、

alias :my_overwritten_by_my_ex :my
def my
  ...
end

こういう「エイリアス&上書き」が嫌いで、不完全ながらこういうものを書いたことがある。(今でも使っている。セミコロンを抑制する努力をしていない頃に書いたもののようだ。Rubyのバージョンで nameをシンボルにするか文字列にするか振り分けているが、今ならやらない。先頭要素を取り出してそれがシンボルか文字列かを調べる。そして、代入を ifで囲うのではなく ifの結果を代入する)

 overwrite.rb

class ::Object
	def overwrite(name, &block)
		if('1.9.0'<=RUBY_VERSION); name = name.to_sym; else name = name.to_s; end
		if(self.singleton_methods(false).member?(name))
			$dirty = [name, block];
			class <<self
				name, block = *$dirty;
				old = instance_method(name);
				remove_method(name);
#				define_method(name){|*params|
#					block.call(old.bind(self), *params); # ブロックは渡せない? 1.9ならできる?
#				}
				define_method("__overwrite__#{name}__#{block.object_id}", &block);
				define_method(name){|*params|
					send("__overwrite__#{name}__#{block.object_id}", old.bind(self), *params);
				}
			end
		else
			if(true != self.class.ancestors.each{|klass|
				if(klass.methods(false).member?(name))
					klass.instance_eval{
						old = method(name);
						remove_method(name);
#						define_method(name){|*params|
#							block.call(old, *params); # ブロックは渡せない? 1.9ならできる?
#						}
						define_method("__overwrite__#{name}__#{block.object_id}", &block);
						define_method(name){|*params|
							send("__overwrite__#{name}__#{block.object_id}", old, *params);
						}
					}
					break true;
				end
			})
				# failure
				raise;
			end
		end
	end
	private :overwrite
end

グローバル変数は赤色でよく目立つね。$dirtyっていう変数はスコープの断絶を乗り越えるために使ってるんだろう。汚いやり方だ。

もはや自分でも読み解けないが、こうして使う(んだったかな? define_methodしたときはブロックで returnが使えた気がする)。

overwrite(:my){|old, *params|
  # 新しいmyを以下に……

  # 必要なら古い定義も呼び出せる。
  return old.call(*params)
}

継承による overrideであれば、隠された同名のメソッドを superで呼び出せるけど、メソッドの上書きではそれができなくて古い定義を呼び出せない。かといって「alias :foo_bar :foo」「alias :foo_baz :foo」式の無秩序なやり方は見るに堪えない。overwrite.rbがやってることも機械的に名前を付ける以外は同じではあるけども(まだましでしょ?)。

<追記@2009-12-19>コメント部分がなんでコメントアウトされているのかやっと思い出せた気がする。奇しくも自分でその理由を書いていたりするのだが。>「define_methodしたときはブロックで returnが使えた気がする」つまり、新メソッド定義(overwriteメソッドに与えられたブロック)を define_methodでメソッド化しておかなければ returnが使えないからだ。かといって古いメソッド定義を渡すために一段余計な処理を挟まなければいけないから、新メソッド定義(ブロック)をそのままの名前でメソッドにすることもできない。ブロックが保持する bindingに変数(旧メソッドを指している)を注入する方法があれば、ダミーの長ったらしい名前を持つメソッドをこっそり定義する今のやり方から抜け出せるかも。</追記>

俺が知らないだけで 1.9以降では解決策があるんだろうか。こういう現実の問題に対処してほしいなあ。わりと見かける aliasの使い方で、問題含みだと思うんだけど。


一人見つけた。

super=承継元クラスの同名メソッドを呼び出す=とは別に、 overridden=上書きされたメソッドを呼び出す=というのを作るというのはどうでしょう?

こちらはちょっと違う。

aliasによるメソッドの再定義は危険なのでUnboundMethodかextendを使おう - (rubikitch loves (Emacs Ruby CUI))

再ロード対策は考えていなかった。

extendは知らないではないけど……(これが求めていたものなんだろうか?)。


新しい名前を導入しないように extendでやってみた。エラーは出ないけどリンク先のサブタイトルが取得できていない(my-exによる拡張が機能していない)。instance_evalを module_evalにしてみてもだめ。

 my-ex.rb

extend Module.new{|mod| mod.instance_eval{
   define_method(:my){|*params| a, str, title = *params
      # myプラグインを拡張し、リンク先が自分の日記のとき、
      # 可能ならサブタイトルやコメントを取得して title属性にセットします。
   }
}}

オーソドックスにやってみても同じこと。

module MyEx
   def my( a, str, title = nil )
   end
end
extend MyEx

extendする対象を間違えてるんだろうか。Pluginのインスタンスに特異メソッドを定義してるつもりでいるんだけど。いずれにしろ答えにたどり着けないのでは使えないよ。def...end と書いてメソッドの定義を上書きするよりも安全で洗練された代替が欲しいんだから、def...endと書く以上の複雑さは受け容れられない。


 @2009-12-11 aliasとコロン

なんでも、aliasするときにメソッド名にコロンを付けてはいけないらしい。

http://www.loveruby.net/w/RubyCodingStyle.html

なぜ付けるかといえば、ほとんどすべてが「実行される」Rubyにおいて、クラスやメソッドの定義(class...end, def...end)ですら実行時の条件によってふりわけられる Rubyにおいて、構文であること、特別扱いされることが許せないからだ。「alias はメソッド呼び出しではなくて構文である。だからこそ引数の間にカンマがないのだ。そこはわかっていながらなぜエセメソッドのような使いかたをするのか。」それは構文であることへの抵抗なのです(俺の場合)。

「ちなみにどうしてもコロンが付けたければ alias_method を使えばいいんではないかと思う。」

そいつ( alias_method )は知らなかった。コロンだけでなくメソッド名とメソッド名の間にカンマを置くこともできるんだから、喜んでそちらを使いますとも。alias_methodと aliasは使える場所や対象が完全には一致していないけども、aliasでしかできないことをした経験はないから問題はなし。


「aliasでしかできないことをした経験はないから問題はなし」なんて書いたそばからこんな例が……

特異メソッドをalias_methodを使用して別名をつけようとするとエラーになる。(中略) 特異メソッドに別名をつけて退避したい場合は、alias_method (_chain)メソッドではなくてaliasをinstance_evalのブロック内で使用するとよい。

特異メソッドは別、でした。想像だけど extendでプラグインメソッドの上書きができなかったのも特異メソッドがらみだと思うな。


 @2009-12-12

昨日の文章はおかしいな。class...endや def...endという構文を認めながら aliasだけを白眼視する説明になっていないような。

class MyClass; endと書いた場合、MyClassは Classオブジェクトの入った定数(という言語のビルディングブロック)だと認識している。def my_method; endと書いた場合、my_methodはメソッド(という言語の(略)であり、以後、my_methodや my_method()と書いた場合それはメソッドの呼び出しである、というのが Rubyという言語の約束だと認識している。「alias alias_of_my_method my_method」という構文は他の構文との共通性がなく例外的なルールに感じられ、(同じコンテクストで用いられる)includeや private、attr_accessorが Moduleのプライベートメソッドとしてあるなかで構文である必然性が認められず、メソッド名に関するルールを破ってさえいる。そこが許せない。aliasの(メソッドではないから正確には違うが)引数の「alias_of_my_method」や「my_method」を言語としてどう位置づけるのか、そこををはっきりさせないのならばそれは使えない、という主張が aliasのメソッド名部分にコロンを付ける理由。

undefや defined?にも aliasと同じ疑問がある(ただし、undefは defの対称として容易に受け入れられるし、defined?の場合、必然性だけは認められる)。JavaScriptの typeof演算子や delete演算子にすら同じ違和感を覚えている*。コンパイル型言語のように、コンパイル時に評価されるのだという言い訳ができないインタプリタ型言語の弱みだろうか。こういうものを見ると Perlに感じたように言語が突然平板なものに見えてしまって嫌なのだ。そこには対象となるメモリやオブジェクトが存在せず、ソースコードの字面しかないでしょう。

* きちんと定義はされています >「[[8.7 Reference 型 (Reference Type)|http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/8_Types.html#section-8.7]]」

最終更新: 2009-12-28T23:38+0900

[Ruby] 1引数ラムダの冗長さ

もうひとつ、最初のセクションからネタ拾い。こんなのや、

 strdump = lambda{|s| s.dump.gsub( /%/, '\\\\045' ) }

別の場所から持ってきたこんなの

 jsstr = lambda{|s| s.gsub(/["\\]/){|x| "\\#{x}" } }

を、自分はときどき書くようだ。[1,2,3].map{|x| ... } みたいなのを書くことはもっとある。「|x| x.」の部分が冗長だね、っていう話。

省きたいけど、単純に考えるとブロックの中が x. で始まっていなければいけない。適用範囲が狭いんじゃないか?と疑問がわく。Rubyは「オブジェクト指向スクリプト言語」をうたっているからメソッドチェインを促す意味でサポートを行う名目はあるだろう。

メソッド呼び出しの構文をとりながら自身を引数にしてよそのメソッドを呼べるようにしたり(C#3.0の extension method風)、Hikiがすでにやっているように

class String
  def escapeHTML
    CGI::escapeHTML(self)
  end
end

本当にインスタンスメソッドにしてしまったり。CGI::escapeHTML("str") より "str".escapeHTML にしておいた方が(1引数ラムダでの利用に)便利ですよ、という動機付けを言語として行ってもいいと思う。あとは引数の束縛やらラムダの .callと []以外の呼び出し方、ブロックやラムダを用いて定義したブロックを引数にしてメソッドを呼び出したりできれば何かができそうな気がしなくもない予感がなきにしもあらず。

全然関係あるのかないのか、Haskellのポイントフリースタイル(初めて目にしたのは 12月15日頃)を検索してみた。$ で順々に処理をつなげているものがあれば . を使って、途中の処理で必要な引数を押し出していくようにしながら一つの処理に書き換えるのだろうか。ポイントフリーなのにポイント塗れとはこれ如何に? 「firstNLines = (.lines).((unlines.).take)」のように明示されなくなった引数 Nはわかりにくくない? 2引数の関数はポイントフリースタイルで書けるの?『ふつける』を通し読みしただけで、モナドもわからず、一行たりとも Haskellコードを書いたことのない人間には疑問がいっぱいです。


2009年07月23日 (木)

最終更新: 2010-01-15T21:38+0900

[Ruby][C++] 釣られますた

C/C++ではもちろん0==false はtrueなわけですが・・・ もしかして、boolean型を整数型とキャスト比較しない仕様なんでしょうか?

この辺はC/C++も難しくて 本質的には 2==trueも本当は真なんですが偽になったりもします。

Rubyでビットフラグをチェックするときは 0との比較を忘れてはいけない。

if(flag & mask)
  # (意図に反して)必ず実行される
end
if(0 != flag & mask)
  # 期待通り
end

というのはさておき、2==true に関して、「本質的には」という言葉が胡散臭い。その「本質」を表すコードは「(2!=false) == (true!=false)」であって、2==true は関係ないのでは? ==は真偽値を返す演算子ではあっても、真偽値のみをオペランドにとる演算子ではないから、2==true も 1==true も -1==true までもが暗黙にそのように解釈されて真になったりしたら、むしろ気持ち悪い。それは PHPの世界だ。(偏見)

Cと逆だな

Rubyでは非0が偽だと言いたげですね。


 @2009-11-06 まさしく偏見でした。

Safe Bool (ja.wikibooks.org)という C++のイディオムがあって、つまり裏を返すと、危険な Boolean変換が C++には存在するということだ。やーめーてー。

C++09(予定)では explicitなコンストラクタみたいに、明示的なキャストを必要とする変換を定義できるようになるらしい。


2009年07月21日 (火) ハルヒのエンドレスエイト。いつまで続くんだろう。F1もテニスも野球もサッカーも似たようなことの繰り返しなんだし、野球を 2時間見るより(<見たことないけど)断然面白く見られるけどね。

[Amazon][tDiary][Ruby] 徒労。劣化コピー。amazon.rb差し替え。SecretKey埋め込みなのでパーミッションは rw-------。

先人 > Amazon Product Advertising APIの認証の件 - zorioの日記

Ruby-1.8.7と Ruby-1.8.6では String#force_encoding("ASCII-8BIT")ができず、String#ordもない(ないのはエンコーディングの概念がないからと、String#[]で代替できるからだと思われる)。それらを使い分けるために 2種類のメソッドを用意するくらいなら、unpackで配列経由でいいです。

require 'digest/sha2'
def hmac_sha256(key, message)
	hash = Digest::SHA256
	hash_block_size = 64 # bytes (= hash.new.block_length)
	key = hash.digest( key ) if hash_block_size < (key.bytesize rescue key.size)
	ikey = Array.new( hash_block_size, 0x36 )
	okey = Array.new( hash_block_size, 0x5c )
	key.unpack("C*").each_with_index{|key_byte, i|
		ikey[i] ^= key_byte
		okey[i] ^= key_byte
	}
	inner_hash = hash.new.update( ikey.pack("C*") )
	outer_hash = hash.new.update( okey.pack("C*") )
	digest = outer_hash.update( inner_hash.update( message ).digest ).digest
	return digest
end

短い秘密鍵は 0を補うって書いてあった。その処理が見あたらないのになぜうまくいくのかと考えたら、0を相手に排他的論理和をとったって何も変わらないのねん。


class Digest::Base

update(str)
self << str
文字列を追加する。self を返す。複数回updateを呼ぶことは文字列を連結してupdateを呼ぶことと等しい。すなわち m.update(a); m.update(b) は m.update(a + b) と、 m << a << b は m << a + b とそれぞれ等価である。

Ruby-1.9で文字列の連結は怖いので m.update(a + b)m << a + bDigest::SHA256.digest(ipad + message) は避けたい。


302 Foundはわかる。リバースプロキシは何するもの?


 追記@2009-08-04: 他の部分も

require 'uri'
require 'base64'
def amazon_authenticated_query_string( host, params )
	re_rfc3986_unreserved = /[^A-Za-z0-9\-_.~]/
	query_string = params.to_a.sort_by{|x| x.first }.map{|key, value|
		URI.encode(key, re_rfc3986_unreserved) +'='+ URI.encode(value, re_rfc3986_unreserved)
	}.join("&")
	string_to_sign = <<-"STRING_TO_SIGN".gsub(/^\t\t/, '').chomp
		GET
		#{host.downcase}
		/onca/xml
		#{query_string}
	STRING_TO_SIGN
	amazon_secret_access_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
	signature = Base64.encode64( hmac_sha256( amazon_secret_access_key, string_to_sign ) ).chomp
	return "#{query_string}&Signature=#{URI.encode(signature, re_rfc3986_unreserved)}"
end

2009年06月15日 (月) 新はてブ。やっとヘッダの fixed/scroll状態を覚えるようになってスクロールが快適だけど。ピンの表示が間違ってる。

[Ruby] Dir.globと Dir.entries

globできない。どういうこと?

irb> Dir.glob("\\\\LS-WSGL420\\MediaLibrary\\*")
=> []
irb> Dir.entries("\\\\LS-WSGL420\\MediaLibrary")
=> [".", "..", "anime", "music"]

こういうことだった。

irb> Dir.entries("//LS-WSGL420/MediaLibrary/*")
=> ["//LS-WSGL420/MediaLibrary/anime", "//LS-WSGL420/MediaLibrary/music"]

DropHandlerから渡されたファイルパスは置換しなければいけない、と。