飽きるまで Io。
case がないので作ってみる。
簡単なとこばっかやりすぎな気が。super とかの使いどころがわからない。正規表現が微妙な時点で実用性がうっすいんですけど……組み込んで初めて力発揮しそうな。すくなくとも CGI 作るのにはアドオンが弱すぎ。
メッセージ書かない (何もしないと意図する) とエラーになって使えないのでコメンツアウト。邪魔なだけ。
飽きるまで Io。
case がないので作ってみる。
簡単なとこばっかやりすぎな気が。super とかの使いどころがわからない。正規表現が微妙な時点で実用性がうっすいんですけど……組み込んで初めて力発揮しそうな。すくなくとも CGI 作るのにはアドオンが弱すぎ。
メッセージ書かない (何もしないと意図する) とエラーになって使えないのでコメンツアウト。邪魔なだけ。
むー。長く書けば書くほど何やってるか分からなくなるなぁ。Lisp に似てる。なんていうか、コメントが必要な言語だ……
簡単そうなので作ってみる。殆ど c-mode のパクりなわけだけど……結局インデントレベル計算するところしか作ってないわけで、そしてそれも括弧しか使わない Io では数えるだけなわけで的な。とはいえアフォだからかなり詰ったんですけども orz
ioServer の Regex て何か変じゃありませんか。nextMatch と firstMatch が全く同じ挙動名気がする。つーかマニュアル書くなら効果的なサンプルと一緒に書いて欲しいなって思う。戻り値も書いてないこと多すぎ。むしろ最初から String replace に正規表現とれるようにしれと。正規表現がデフォで使えないとかキツすぎて死にます。
io-mode readme, iolanguage
リファレンスを見た限りではメソッドの引数を省略したときの値を指定できないっぽい。ようは可変長変数を使うんだと思うんだけど、これまた長い。んなわけで適当にマクロ化するメソッドを定義しとく。もしかしたらこんなことやらないでももっといい方法があるかもしれない。
/*
pos : 引数の位置
name : 代入されるスロットのキー (勝手に初期化)
default : デフォルトの値
*/
Object opt := method(pos, name, default,
if (sender doString("thisMessage argAt(" .. pos .. ")")) then (
sender doString(name .. " := sender doMessage(thisMessage argAt(" .. pos .. "))")
) else (
sender setSlot(name, default)
)
) んで以下のように使う。
List join := method(
opt(0, "sep", "")
ret := ""
self foreach(index, value,
ret = ret .. value
if (index < self count - 1) then (
ret = ret .. sep
)
)
ret
)
l := List clone push("aaa") push("bbb") push("ccc")
l join(", ") print //=> "aaa, bbb, ccc"
l join print //=> "aaabbbccc" Ruby の Array#join っぽいことをしてみる。 String join というメソッドがあるけど何かこのメソッドは位置がおかしいし、セパレータを引数にとれない。っぽい
というのはデフォルト引数が "" きめうちだから。Io に $, がないから (なくていい) ってことです。あーあと再帰的に join してないや。to_s メソッドとかないからその辺もやってないし。ようは List の中身が String 以外だと例外はきますよと。
どうでもいいけど if を書くときに then と else を使うのは構造的違和感がある。でも可読性はこっちのほうがいいし、case がないうえに if の引数として書く場合 elseif が書けないからどっちにしろ書くことにはなるんだけど。if の引数に全部書くほうはワンライナー向けかしら。
何で Directory が ioServer なのかはとりあえず置いておいて、Directory items が File しか返さない。Returns a list object containing File and Directory objects
ですよ。ついでに list object じゃなくて List object だろうとか思ったけど理解できるからとりあえずフットノート。いや英文解釈が間違っているのかもしれないとか思いつつしかし常識的に考えて (まぁたしかに Directory も File ではあるけど) Directory を File として返さないだろうとか、むしろ File としてしか返さなくて File にタイプを識別するメソッドがなかったら使えないよねって思ったから File にそんなメソッドあるのかなって思ったらなかった。そういや File Primitive にはファイルの更新時間を取得するメソッドもない気が。つまるところ今のデフォルトの Io では blosxom クローンは作れないっぽい。
てか Regexp, Directory を IoVM の Primitive に……
素朴な疑問にひっかかった。if とか else もメソッドで、引数にメッセージをとるけど、何でこの引数は評価されずに渡されるんだろう。ちょっと解りにくいから実際にコードを書いてみる。
if (Nil) then ( "not print" print ) else ( "print" print )
この場合もちろん not print は出力されないし、それが願う動作。しかしながら "not print" print も引数だから、メソッドに渡される前に評価されて not print と出力されるんじゃないかと悩んだ。というか正確に言えば if をユーザから定義するときに評価されてしまってハマった。以下にハマったコードを示す
myif := method(test, ifObj := Object clone ifObj test := test ifObj do ( mythen := method(msg, if (test, sender doMessage(thisMessage argAt(0))) self ) myelse := method(msg, if (test isNil, sender doMessage(thisMessage argAt(0))) self ) ) ) myif (Nil) mythen ( "nil" print ) myelse ( "aaa" print )
これは予想に反して nilnilaaa と出力される。引数が渡される前に評価されしまっているからだ。リファレンス見ててもよくわからないので、適当に書き直していたらできた。書き直した結果を書いてみる。
myif := method(test, ifObj := Object clone ifObj test := test ifObj do ( mythen := method( if (test, sender doMessage(thisMessage argAt(0))) self ) myelse := method( if (test isNil, sender doMessage(thisMessage argAt(0))) self ) ) )
何が変わったかっていうと method の仮引数を書かないようにしただけ。仮引数を書くと評価されてしまうらしい。微妙な罠。プログラミングガイドに明記してもいいじゃん! とはいえこれを踏まえてから読み直すと The thisMessage slot that is preset (see next section) in locals can be used to access the unevaluated argument messages.
と書かれていてといっても原文は引用しただけで日本語訳から探した。 (強調はされていない) 頭がよければ thisMessage スロットには未評価なメッセージが入っていて、仮引数を書かなくても呼び出せる。もしかして仮引数を書かなければメッセージは評価されないんじゃないか、なんて推論できる (苦しい) かもしれないけど、俺には無理!
実は既に今年度の授業が全て終了 (3学期は授業がない) して、期末テスト2日分が終わっていたりするわけだけど、期末テストの期間に入ると、既に休みに入った気分になって微妙に困る。あーむしろ英語ライティングで脅されてる (謎) のに何もやらずに試験に臨むとかアホすぎる。そういえば中間でうけそびれたやつって期末でとらないとヤバイんジャマイカ……
いろいろなことがぼーっとしてるせいで遅れてる。遅れてる。願書請求とかやってなかったとか。あぶねー。12月なのに過去問もやってねー。
あー XML 名前空間とか試験にでませんか。でも XML 全般が出るなら XML Schema とか、既に古いけど健在な DTD ももっとちゃんとやっとくべきじゃないか。いや待てよ、XSLT もまだしらない要素とか、知っていても使ったことがない要素があるな。そういえば RDF のクラスのヒエラルキーとか理解できてないな。あーこれ冬休み中にやっとく鹿。って、いやだから受験科目じゃありませんから! 残念。
ちょっと触った感じではいい感じ。ソースがそこそこ綺麗に書ける。大規模になったときはわからないけども。全部オブジェクト、と考えていいのかな。以下 Io (プロトタイプベース) と Ruby (クラスベース) と ECMAScript (プロトタイプベース) のコード片を比べてみる。
foo := Object clone
foo test := method(x,
x
)
write(foo test("test"))
foo = Object.clone
def foo.test(x)
x
end
print(foo.test("test"))
foo = new Object;
foo.test = function (x) {
return x;
};
WScript.Echo(foo.test("test")); ECMAScript は標準出力の方法を定めていないので、ここでは WSH の cscript から実行していることにしてみる。
パッと見た感じ殆ど同じ。Io の場合、スロットに新しく代入するときは := (=setSlot) で = (=updateSlot) は既に存在するスロットを更新する。updateSlot はチェインを辿って見つけたスロットに代入し、該当するスロットがなければ例外になる。と思う。setSlot はレシーバに新しいスロットを作る。ついでに、Io のトップレベルで使われる関数のように見えるものもメソッドで、このメソッドのレシーバは見えない Lobby というもの。全てメッセージ。素敵だ。Ruby も関数のように見えるものは self を省略しただけ。ただ、Io の場合は他の言語では制御構造に見えるものもメッセージ。if とか for とか while も Lobby のメソッド。素敵すぎ!
上のやつは違うみたいだ。Lobby の proto には Object が入ってるから実際には Object に定義されてるメソッドみたい。リファレンスにも getSlot とかは Object に書いてある。
Ruby はクラスベースだからホントは比べにくいと思うけど、とりあえず特異メソッド定義としてみる。特異メソッドは属するところがそのオブジェクト自身になる (普通のメソッドはそのオブジェクトのクラスに属してる) からちょっとプロトタイプっぽい。foo.clone で特異メソッドも引き継げるしね。
ECMAScipt はソレっぽい。ECMAScript の = は常にレシーバにスロットを作るっぽい。自動的にチェインを辿って該当するスロットに代入する方法はないぽい?
関係ないけど、Io のインタプリタを ck から実行すると、実行が終わったあとに全ての出力がクリアされちゃう。ついでに起動するときになんか表示してる半透明ウィンドウが全部フラッシュする。
放り込んだらそのまま動くとか書いてあったので、Linux Binaries をダウンロードして XREA にうぷろーど&実行権限付与。んで適当に foo.io とか作って実行権限とかやってみたけど必要なライブラリが足りないといわれて動かなかった。無念。
ムカツクから鯖上で build できんのかとやってみたけどリソース制限にひっかかって無理だった。もうめんどい。適当にローカルで弄ってよう。
って。ああああああ。新しい鯖だと動く。 s101 で ioServer を動かしてみたらできた。何も苦労せずにできた。泣けるよ。ひどく泣けるよ。
正規表現が標準で使えないのは痛すぎる。やばすぎる。
C-RET (C-j) で前の行のインデントを保持して改行はできるんだけど、タブとスペースが混じっている場合スペースがタブに変わっちゃうのが微妙に困る。 (自分だけで使うなら全く困らないけど、タブ幅が違う環境に持っていくと困る)
; 前の行の空白状態を保持するように。 (defun indent-relative () (interactive "*") (delete-horizontal-spaces) (insert (save-excursion (goto-bol) (skip-chars-backward " \t\n") (goto-bol) (looking-at "^[ \t]*") (buffer-substring (match-beginning 0) (match-end 0)))))
cmds.l に定義されている indent-relative() を .xyzzy か siteinit.l で再定義。弊害あるかもしれない。
改変版のほうを使っているんだけど、indent-current-buffer とかでインデントしたとき異様に遅い (カーソルが動くのが見える) ……こういうものなのかな。部分的に一括してインデントしたいときは Mark & indent-region してみてる。むー。
てか .lc 消して試してみたら同じ速度だなぁ……バイトコンパイル効いてない? 再ダンプしてなかった。 .lc 消したらむしろありえない。
DNA をデジタル化して CD か何かに記録するサービスとかやったら面白そうなのに。どっかの研究所で。
ある意味究極の個人情報だから色々めんどくさそ。
むしろ、何かこう、適当にサンプル与えるとどんどんデジタル化する機械って作れないのかな。
ここ最近気になっていたのでちゃんと解消しておこう。基礎が出来てなきゃダメダメ。
まず重要なのは、属性にはデフォルトネームスペースが適用されないのにされると勘違いしていたこと。属性と要素では属する partition が違う。接頭辞がない属性がよくある (たとえば XHTML とか) せいで完全に勘違い。
同じように見える属性でも厳密には違う場合が存在する。見た目的には接頭辞がついている属性と、付いていない属性では差がある。
<f:foo xmlns:f="http://example.com/foo"> <f:far attr="ex"/> <b:baz xmlns:b="http://example.com/baz"> <b:bar f:attr="ex"/> </b:baz> </f:foo>
この例で attr="ex" と f:attr="ex" は属している名前空間は同じにも関わらず展開すると異なる。これも partition の違い。
partition には三つあって、一つは全ての要素が属するとこ。あとは属性の属する partition で、一つはグローバルな属性が属する (上の例では f:attr) とこ、もう一つは要素ごとの別々な属性が属する (上の例で attr) とこ。かなーりややこしい!
partition の種類は三つ。一つは要素が属する partition で、これは特に問題にならないでそのまんま。属性は残りの二つのどちらかに属するんだけどこれが面倒くさい。違いは名前空間にグローバルかローカルか。接頭辞をつける属性は名前空間にグローバル。接頭辞をつけない属性は要素名を経由する (ローカル)。たぶんこれは展開された名前とかを見るとわかりやすいと思う。
<f:far attr="ex"/> の attr="ex"<b:bar f:attr="ex"/> の f:attr="ex"接頭辞をそのまま名前空間の URI に置き換える (ようは展開することなんだけど) だけでだいぶイメージしやすいと思う。
一般的な XML では (XHTML とかじゃなくて) 普通接頭辞をつけることになりそう? この辺わかってない。むしろ要素ごとに別々の意味をもつ要素を定義できるかっつうとできないような。
バカすぎるスペルミスを修正。
気になっていたことを一つ試したのでメモ。<f:foo f:attr="a1" attr="a2"/> としたときエラーになるか、ということと、実際 XPath からはどちらにもアクセスできるのかということ。結果的にはエラーにならないし、XPath からはどちらにもアクセスできる。f:foo/@f:attr = 'a1', f:foo/@attr = 'a2'
XML Schema についてで なぜ属性宣言を避けるべきか ってのがあった。これは XML 名前空間の partition を理解していればひっかかりにくい (ひっかかっても直ぐに気付ける) とこだなぁ。
そんなわけでそういう修正をしてみた。
#content .section h2:first-letter {
color: #09f;
}
#content .section h2 a:hover:after {
content: "";
line-height: 0;
} 空文字でも効果があるみたい。ようは content の指定でスタイルの指定しなおし (?) が働けばいいらしい。
line-height: 0 は何か知らないけど高さが変わって、後続するやつが全部ピコピコするのをなくすため。
関係ないけど擬似をずっと模擬って読んでいた。アフォすぎ!
なんていうか頭が悪いネタですよ。css.rdf, この RDF をそれっぽく XHTML に
何だか知らないけど 文字列から Source をそれっぽくやるハック が XREA の鯖上ではできない。uninitialized constant REXML::Parsers::TreeParser
というエラーが出てしまう。ローカルだと上手くいくんだけどなぁ……意味わからん。なんでだろう?
ってまさかと思ったら site_ruby に新しい rexml が入ってた。めんどくさ……
build メソッドを Ruby デフォルトについてくるほう (の document.rb) に書き換えた。動いてるもより。これで view-image でファイルリストも RDF として渡すように。RDF to XHTML が汚いけど仕方ない。しばらくやりたくない。
Ruby の elsif が嫌い。elsif 書くなら case & when 使う。なんか elsif ってソースのバランスが変。
if a =~ /foo/ # do elsif a =~ /bar/ # do elsif a =~ /baz/ # do end
case when a =~ /foo/ # do when a =~ /bar/ # do when a =~ /baz/ # do end
スキャナ&パーサーだけで力尽きた…… racc css.y
ホントはアクション部分も少し書いたんだけど、どうも上手くいかないので削除って、とりあえず分離させておくことにしてみた。パーサーから構文木作るところって普通はどういう風に実装するだろう。再帰定義の部分で汚くなっちゃうんだよなぁ。スーパー簡単なサンプルが欲しい……
あーあと、Invalid なものが突っ込まれたとき、その部分を無視してパースを続ける、っていうのはどうやって書くんだろう。謎ががががが。
パースエラーは error に還元される。だから、右辺の正しい場所に error を置いとけば無視できると。CSS の ruleset を処理中にパースエラーが起きたら ruleset : error とか書いておけばそこを飛ばして次のやつを探す?みたいな? 適当にやってみよう。
error トークン書くと on_error 呼ばれないのか。なんかどういう風にエラーを処理するのかわからん。
何か Killed って言われるので6時から3時にしてみた。Ruby で日記の XML をセクションごとに HTML にわけるところで Killed。mknmz も中途半端に終わったらしく NMZ.lock2 が残ってた。謎。
とりあえずカレントノードとコンテキストノード。
カレントノード = current() で、コンテキストノード = self::node()。カレントノードは XSLT のもの。XPath には current() という関数はないし、そもそも必要ない。
current() が変わるのは xsl:template 又は xsl:for-each。選択 (select) されたノードが current() になる。
self::node() が変わるのは /, [ ]。(別に変わるとは限らない……)
基準点とノードテストがまだあんまり理解できてない……
/view-img/2003/ みたいな。
RDF は画像ファイル自身に埋め込んだのを取り出していちいち動的に合成してる。現状では同じディレクトリに samp-meta.rdf があるからそっち直接読んでもいいんだけど……実験ってことで……
合成するとき REXML 使ってるから怪しい XML (名前空間接頭辞が他のファイルと違うとか) があるとたぶんパースエラーになる。稀なケースだし Ruby のライブラリでガッチリキッチリ実装した使いやすいやつを知らないので仕方ない。
ローカル側では RDF を埋め込む (ファイル名に -meta.rdf をつけたやつを突っ込む) ときに画像サイズが一定以上だったらサムネイルを作って、その情報 (foaf:thumbnail) も追加して埋め込む。
サーバー側は同じディレクトリの画像をスキャンして RDF を取り出し、@rdf:about を書き換えて合成。合成したヤツを XSLT エンジンに渡す。あとはまぁ普通に XSLT テンプレの仕事で……
ちなみにファイル名のリストは別に XML 作って渡してる。丁度いい語彙があれば RDF に RDF として突っ込んだほうがスマートだけど考えるのが面倒だった。
だいぶソースが汚い。