2010-09-18

Gauche でフィルタを書く

前回、Lisp で以下のような「行指向パターンマッチ方式」でフィルタを書くのは難しい、と書いた。

(行指向パターンマッチ方式)
while (入力がある) {
    一行読み込む;
    if (あるパターンに一致する) {
        一行分のデータに対して処理を行う;
        結果を出力する;
    } else if (別のパターンに一致する {
        別の処理を行う;
        結果を出力する;
    } ...
}

その代わりにリストを利用した「丸ごと読み込んで、全部処理して、まとめて書き出す」方式ならすっきりと書ける、と。

後者は確かにその通り。「プログラミングGauche」のコラム『「Lisp 脳」の謎に迫る - Scheme プログラマの発想』を読んでも、入力をリストにして、リストの各要素を処理して、結果をリストにする、というのは Lisp らしい書き方なんだとわかる。

けれど、前者は間違いだった。Scheme でも大して難しくはないと気付いた。

while ループは条件分岐と goto で書き直せる

説明を単純にするためにパターンマッチのない「行指向方式」に戻ろう。

(行指向方式)
while (入力がある) {
    一行読み込む;
    一行分のデータに対して処理を行う;
    結果を出力する;
}

これは、以下のように書き直すことができる。

(行指向方式 #2)
Loop:
    if (入力がない) goto Exit;
    一行読み込む;
    一行分のデータに対して処理を行う;
    結果を出力する;
    goto: Loop;
Exit:

こうなれば、Scheme でも容易に実現できることがわかる。なぜなら、Scheme では、

(「プログラミングGauche」p.6 より)

  • 手続き呼び出しは継続を伴った引数つき goto である

からだ。また、(もう少しわかりやすく)こうも書いてある。

(「プログラミングGauche」p.57 より)
処理の一番最後に再帰呼び出しをして、その結果がそのまま現在の処理の結果として返されるパターンを末尾再帰と呼びます[...snip...]

Scheme では、上記のとおり、最後に呼び出した手続きの戻り値に何も行わない場合、最後の呼び出しは通常の手続き呼び出しではなくジャンプとして扱われることになっています

末尾再帰を goto 代わりに使う

手続き呼び出しが goto なのだとわかれば、上述の「行指向方式 #2」はこう書くことができる。

 1: (define (apply-filter proc port)
 2:   (let ((line (read-line port)))
 3:     (if (not (eof-object? line))
 4:       [begin
 5:         (proc line)
 6:         (apply-filter proc port)])))

3 行目がループの脱出条件の判定に、6 行目の再帰呼び出しがループの先頭に戻る goto に相当する。proc に標準入力ポート、proc にデータを処理する手続きを指定して、apply-filter を呼び出せばフィルタプログラムができあがる。

以下は、これを利用して書いた wc っぽいフィルタだ。単語数の出力が wc と同じにならないことがあるのは単語の区切りとして空白文字しか想定していないためだ。

「BEGIN」と「END」というコメントは AWK をちょっと思い出して書いてみた。たぶん、AWK でこれと同じものを書くとすると、やはり BEGIN でグローバル変数を用意し、END で結果を出力する、というようになると思う。

「まとめて」と「少しずつ」の違い

正規表現を使った処理を scheme (Gauche) で書いてみる」で示したものは、読み込み、処理、結果出力の 3 つの段階をそれぞれ「まとめて」実行する方式だ。一方、↑で示した wc モドキでは、3 つの段階を「少しずつ」行い、全体をループするようになっている。

データ量が小さいときには、両者の方式の実行に差を見つけることは難しいだろう。実際のところ、いまどきの Mac や PC ならどちらの方式で書いてあろうが、たいていの入力に対して一瞬で完了するはず。ただ、データ量がぐっと大きくなるとその差が顕在化するはず。

極端なことを言えば、入力ファイルが GB 単位の大きさになると「まとめて」方式は(いまどきのパソコンでも)かなり苦しくなる。すべてを一度にメモリに読み込む必要があるからだ。32 ビットモードなプラットフォームなら読み込みの段階で実行時エラーになるかもしれない。一方「少しずつ」方式では、データ量が大きくなっても実行時に必要なメモリは一定の範囲に収まる。もちろん実行時間はデータ量に見合うだけのものが必要になるが、データが読み込めないというような事態にはならないはず。ま、もっとも、GB 単位のデータ(それもテキスト)を処理するなんてことは、かなり特殊な状況で、普通の人は一生、経験することはないかもしれない。

実のところフィルタにもいろいろあって、「まとめて」方式では実現できても「少しずつ方式」では実現できなかったり、難しかったりするものもある。たとえば、sort は「まとめて」なら実装しやすくて、「少しずつ」だと困難な(というか外部にデータを書き出さない限りできないよね?)フィルタだ。trgrep は、まさに「行指向パターンマッチ方式」に適した例だし、wcuniq あたりは実装に工夫(状態の保持にグローバルなデータ構造を使うとか)が必要になる例だろう。

参考文献

プログラミングGauche
Kahuaプロジェクト
オライリージャパン ( 2008-03-14 )
ISBN: 9784873113487
おすすめ度:アマゾンおすすめ度

関連リンク

関連記事

twitter より (2010-09-17)

Powered by twtr2src.

2010-09-17

フィルタプログラムとは

前回書いた「かけら」をもっと Scheme/Lisp らしくすることを考える前に、題材になっているフィルタとはどんなプログラムなのかを復習しておこう。

Unix とフィルタ

以下の一文はフィルタと呼ばれる一群のプログラムの特徴をうまく表現している。

(「UNIXプログラミング環境」p.155 より)
UNIX には,"何か入力を読み込み,それに単純な変形を加え,何らかの出力を書き出す" という仕事をするプログラムが多数存在する.例をあげると,入力の一部分を選び出す greptail,入力をソートする sort,入力のなかのワード数を数える wc がある.このようなプログラムを総称してフィルタと読んでいる.

また、フィルタは単独で使われるだけでなく、複数を組み合わせることでより複雑な処理を実現することもできる。

(「UNIXプログラミング環境」p.199 より)
わずか 1 つのフィルタを適用してやることで抱えた問題が氷解することもあるが,複数のフィルタを結合して 1 本のパイプラインにすることは、問題を解決可能な小問題に分解するのに役立つ.このようなツールの利用法こそは UNIX プログラミング環境の核心であるといわれることが多い.

Unix のシェルが備えているパイプやリダイレクトは、フィルタを組み合わせるための仕組みだ。

設計パターン

パイプやリダイレクトのような仕組みでつなげられるようにするには、それぞれのフィルタプログラムが共通する設計を持っていなければならない。それが以下の 3 つだ(厳密には最初の 2 つで十分)。

  • 共通の入力方式
  • 共通の出力方式
  • 上記入出力とは独立したメッセージ出力方式

Unix (とそれに良く似たプログラミング環境)では、上記の 3 つは、それぞれ標準入力、標準出力、そして標準エラー出力と呼ばれている。

簡単に言えば、フィルタプログラムとは、標準入力からデータを読み込み、適切な処理をした後、標準出力に結果を出力し、処理中に必要があれば(警告メッセージの表示など)標準エラー出力に書き出すようなもののことだ。

実装パターン

フィルタを実装するために汎用パターンは以下のようになる。

(汎用方式)
すべての入力を読み込む;
入力に対して処理を行う;
結果を出力する;

この場合、一般には、入力、処理、出力のそれぞれの段階でループが必要で、データを蓄えておく領域も入力と出力にそれぞれ必要になる。はっきり言えば、この方式は効率が良くない。

処理の単位が文字(バイト)ごとだとわかっていれば、以下のように入力、処理、出力を共通のループに押し込む方式が使える。

(文字指向方式)
while (入力がある) {
    一文字読み込む;
    一文字に対して処理を行う;
    結果を出力する;
}

こうすればループの回数は減るし、必要な記憶領域も小さくなる。

この変種として、文字ではなく行を処理の単位にする方式もある。

(行指向方式)
while (入力がある) {
    一行読み込む;
    一行分のデータに対して処理を行う;
    結果を出力する;
}

実際には、ほとんどの場合、処理(と出力)の部分は以下のようにパターンとの照合でガードされている。

(行指向パターンマッチ方式)
while (入力がある) {
    一行読み込む;
    if (あるパターンに一致する) {
        一行分のデータに対して処理を行う;
        結果を出力する;
    } else if (別のパターンに一致する {
        別の処理を行う;
        結果を出力する;
    } ...
}

ここまで来ると、フィルタを記述するのに必要なのは、処理が必要か否かをガードするパターンとパターンに応じた処理の記述(アクション)だけだということがわかる。残りの部分はフィルタの種類によらず共通なのだ。文字や行のような処理の単位も区切りを指定することで柔軟に変えることができる。AWK はこの発想を実現するために作られたプログラミング言語だ。

Scheme/Lisp らしく書くには

Ruby や Python なら、先の「行指向パターンマッチ方式」を素直にほぼそのままの形で実装できる。一方、Scheme/Lisp ではデータの基本構造はリストで、繰り返し処理は再帰で実現する。リストと再帰で「行指向パターンマッチ方式」を実現するのは難しい。その代わりと言っては何だが、最初に挙げた「汎用方式」をすっきりと実現できる。すなわち、以下のようにする。

  1. 入力を単位(たとえば行)ごとに並べてリストを作り
  2. 各要素に対してフィルタ関数を適用し、結果を並べたリストを作り
  3. 結果のリストを出力する

リストから別のリストを作って出力するというのは、Lisp プログラムの基本パターンだ。前回の Gauche による実装も、(たどたどしい書き方ではあるが)この方式を実現したものになっている。

ただ、すでに述べたように、この「汎用方式」による実装は効率が良くない。ループのことはともかくとして、メモリのことは気になる。もう少し効率良く書くことができないだろうか?

まあ、実際問題として、今どきのコンピュータ(Mac や PC)で、ちょっとしたテキスト処理をするぐらいのことで、効率(時間やメモリ)のことを気にする必要もないんだけどね。

参考文献

Brian W.Kernighan, Rob Pike
アスキー ( 1985-09 )
ISBN: 9784871483513
おすすめ度:アマゾンおすすめ度

関連リンク

  • AWK (Wikipedia:ja)

関連記事

twitter より (2010-09-16)

  • 17:31  iPod touch 、出荷のお知らせキターーーーー。配送状況を確認したら海外荷物受付になってる(; ゜д゜)。上海から海を越えて来るらしい。週末には届かんな...orz
  • 17:38  iMac のときは(これも上海からやってきた)、7/30 に出荷のお知らせが来て物が届いたのは 8/2。今度も同じ日数で届くとすると日曜(9/19)。ま、月曜には届くか。
  • 23:57  むむ。当たってる。なんでわかるんだろう(・д・)?→ mnbi『え、ストレス?感じるほどの環境に居ないから分からない』 問題無し http://shindanmaker.com/49492
Powered by twtr2src.

2010-09-16

正規表現を使った処理を scheme (Gauche) で書いてみる

今日は時間がないので、とりあえず、コードだけを貼っておく。これで、前回の Ruby、Python のコードと同じ結果になる。

試行錯誤の繰り返しの果てにでっちあげたものだから、もっと手を入れたかったが、あと少しで今日が終わるのでもう時間切れだ。また明日、考えることにする。Scheme/Lisp らしい書き方とか、Ruby で書いたプログラムの方を Scheme に移植しやすく直してみる、とか。

参考文献

プログラミングGauche
Kahuaプロジェクト
オライリージャパン ( 2008-03-14 )
ISBN: 9784873113487
おすすめ度:アマゾンおすすめ度

関連リンク

関連記事

2010-09-15

正規表現を使った処理を Ruby と Python で書いてみる

前回、Ruby で書いた「アプリのかけら」を Python で書き直すにあたって、言語による記述の差というか特徴を調べてみることにした。実際には差を調べるというよりは、Ruby でどう書けば Python への書き直しが楽になるかを考えた、というのが正しい。

題材として、正規表現を使った処理を選んだ。正規表現こそ、テキスト処理の真髄だと思うからだ。これが書き直せるなら、他の部分だってどうにかなる(に違いない)。処理の内容は、HTML から class 属性のついたタグの一覧を作る、というものだ。

Ruby で書いてみる

最初の実装の問題点

Ruby では正規表現は言語に組み込まれた型であり、リテラルとして記述することができる。さらには正規表現を使ったパターンマッチに専用の演算子も用意されている。一方、Python では標準添付ライブラリの一部ではあるものの、正規表現を使うには import re と明示的にライブラリを読み込む必要がある。専用の演算子もないので通常のメソッド呼び出しでマッチを行わなければならない。

つまり、Ruby では以下のように書けるが、Python ではこうは書けない。Python に書き直しやすくするためには、正規表現リテラルの使用を止め、またマッチ演算子も使わないようにした方が良い。

/<(\w+)[^<>]*class=[\'\"]([^\'\"]+)[\'\"][^<>]*>/ =~ str

たとえば、↑は以下のように書き直す。

regex = Regexp.compile('<(\w+)[^<>]*class=[\'\"]([^\'\"]+)[\'\"][^<>]*>')
regex.match(str)

このとき、一点、注意すべきことは、Regexp.compile にわたす正規表現の文字列をダブルクォートではなく、シングルクォートで囲むことだ。ダブルクォートで囲んでしまうと、バックスラッシュによるメタ文字がバックスラッシュ記法として扱われてしまい、意図した正規表現にならない。上記の例で言えば、\ww として Regexp.compile にわたってしまう。シングルクォートを使いたくないなら、\w の前にさらにバックスラッシュを足して \\w とすれば良い。後ろの方のクォート文字につけたバックスラッシュは何がメタ文字なのか自信がなくて付けたものだが、元々つけなくても影響がなかったようだ。

Ruby 特有の記述を書き換えたもの

以上を踏まえ、Python に書き直しやすいように書くとこうなる。

書き直したと言っても、Ruby のプログラムとして読みにくくなっているわけではない。

Python に書き直す

先のプログラムを、素直に Python で書き直すとこうなる。Ruby では配列を使っていたところがリストになっていたり(というより、Python のリストは Ruby の配列とほぼ同じ)、Struct で実現していたタプルが Python では専用の表記で書けたりといった細かな差異はあるものの、ほぼ 1 対 1 で書き直すことができた。

書き直しやすくすることの意義

正直言って、他の言語に書き直しやすいような記述にするなんてことに意義はない。言語で用意してくれてる(記述が簡潔になるような)記法をあえて使わないなんて、言語に対する冒涜だと言っても良いぐらいだ。ただ、言語間の書き直し(つまり移植)を行う際に、こういう中間的な段階を経ることで、目的言語に直したときの不具合を減らすことができる。

それにしてもあれだな。今回のようにほとんど同じに書けるのであれば、ライブラリの相互乗り入れぐらいは実現できないものかね(言語の統合は無理だろうが)。両方とも JavaVM の上で動くもの(Jruby と Jython)ならできるのか? まあ、差が目につかないのは、今回の例が(とても)短いプログラムだからかもしれないが。

関連リンク

関連記事

twitter より (2010-09-14)

  • 09:48  Cocoa Emacs に変えた後、マウスでドラッグしただけで region がコピーされてしまうことに悩まされていた。これを無効にするには mouse-drag-copy-region を nil にすれば良いと判明。
  • 09:51  悩まされていたのは、以下のような状況。(1) Safariなどでテキストをコピー、(2) Emacs のウィンドウをアクティブに、(3) このとき(せっかちなので)ついうっかりマウスをダブルクリックしてしまう、(4) 単語が選択されクリップボードが上書きされてしまう(´・ω・`)
  • 09:56  Cocoa Emacs になってからだと思ってたけど、Carbon Emacs でも mouse-drag-copy-region は t になってるな。なんで、前は気にならなかったんだろう? Emacs の kill-ring と OSX のクリップボードが別だったのか?
  • 09:57  いや、そんなこともないな。
  • 09:59  マウスじゃなくて、TrackPad を使うようになったことに原因があるのかもな。TrackPadだと「うっかりダブルクリック」が増えたとか。
Powered by twtr2src.

2010-09-14

Blogger で作ったブログの記事一覧を作成する

これは「アプリのかけら」。いつか、実用的なアプリになるかもしれないコードの断片。

今日のお題は、Blogger で作ったブログの記事一覧を作成すること。まずは Ruby でさらっと書いてみよう。Ruby で書けたら Python で書き直してみる。Python で書けたら GAE に載せてみる。そうしたら「ウェブアプリのかけら」になる。

Blogger APIs

Blogger も Google の提供するサービスなので、データをやったり取ったりするための API が用意されている。公式サイト(Google Code 内)には以下のように書かれている。

(What is the Blogger Data API? より)
Here are some of the things you can do with the Blogger Data API:

  • Add a running list of blog posts and comments to a site.
  • Create a desktop application or plugin that allows users to create and post entries from the desktop.
  • Create a blog aggregator application.

今回のような使い方を、(無理矢理)あてはめるとすれば 3 つ目の「a blog aggregator application」になるか。ただし、実際には公開されている RSS フィードを取得するだけなので、API を使っているという感じは薄い。

フィードの取得に関する説明は「Developer's Guide: Protocol」の「Retrieving posts」に書かれている。

要は、以下のように HTTP 経由でリクエストを投げれば良い。

GET http://www.blogger.com/feeds/blogID/posts/default

ただし、これだと最近の 25 件分のデータしか取れない。それ以前のものを取るには start-index をクエリーに追加する。こんな風になる。

GET http://www.blogger.com/feeds/blogID/posts/default?start-index=26

start-index は 1 から始まるので、これでデフォルトの 25 件の次(というか、次に古い)データが 25 件分取れる。さらに前のデータなら 1 + 25 + 25 = 51 を指定する。

全記事のデータを取得するにはもう少し工夫が必要だ。Blogger から返される RSS フィードには、記事のトータル件数がふくまれている。それを取り出して、トータル件数分だけ start-index を調整しながらリクエストを繰り返す。

max-results というクエリーを使う方法もある。これで全記事数よりも大きな数値を指定すれば一度のリクエストですむ。スマートとは言えないけどね。

Ruby で実装

Ruby で HTTP リクエストを投げる

標準添付ライブラリの net/http を使う。実際に HTTP リクエストを投げる部分は繰り返し実行するので関数にしておく。

Blogger のフィードはデフォルトでは Atom 形式のデータになっている。Ruby の標準添付ライブラリには Atom を扱うものはないが、RSS の方ならある。今回は、Blogger に RSS をリクエストする。これには alt=rss をリクエストのクエリーに追加すれば良い。

(get_titles.rb より)
12: def get_rss(start_index = 1)
13:   url = URI.parse('http://www.blogger.com/')
14:   res = Net::HTTP.start(url.host, url.port) { |http|
15:     http.get("/feeds/#{BLOGID}/posts/default?alt=rss&start-index=#{start_index}")
16:   }
17:   res.body
18: end

定数 BLOGID には Blogger のブログIDを設定しておく。自分のブログなら Blogger にログインしてダッシュボードあたりで見ることができるが、他のユーザのブログについては、ID を知ることができるのかな?

記事数を取り出す

まずは、全記事数を取り出す。openSearch:totalResults というタグに囲まれているので、正規表現を使ってさらっと抽出。

(get_titles.rb より)
29: raw_data = get_rss(1)
30: /<openSearch:totalResults>(\d+)<\/openSearch:totalResults>/ =~ raw_data
31: total_posts = Regexp.last_match[1].to_i
Ruby で RSS データを読み込む

標準添付ライブラリの rss を使う。RSS::Parserparse してやれば、返ってくるオブジェクトが RSS フィードの構造をそのまま写し取ったものになっている。具体的には、rss が返り値のとき、rss.channel.items がフィードにふくまれる記事データの配列になっている。さらに個々の記事データを item とすれば、その属性は item.titleitem.link で取り出せる。

以下のコードでは、先に取り出した全記事数をもとにリクエストを繰り返してすべての記事のデータを取得している。33 〜 39 行目が while ループの外にあるのは、全記事数を取り出すのに使ったリクエストのデータも最初のページとして読み込むため。記事数だけ別のリクエストで取れれば良いんだが、公開されたフィードにアクセスする方法では、そういう特殊なリクエストは受け付けてくれないようだ。

(get_titles.rb より)
33: posts[current_page] = Array.new
34: rss = RSS::Parser.parse(raw_data, false)
35: rss.channel.items.each { |item|
36:   posts[current_page].push item
37: }
38: current_page += 1
39: current_post += rss.channel.items.length
40: 
41: # get more pages
42: while current_post < total_posts
43:   posts[current_page] = Array.new
44:   rss = RSS::Parser.parse(get_rss(current_post + 1), false)
45:   rss.channel.items.each { |item|
46:     posts[current_page].push item
47:   }
48:   current_page += 1
49:   current_post += rss.channel.items.length
50: end
51: 
52: total_pages = current_page

posts は 2 重の配列で、リクエストごとの記事データを収めた配列を要素とする配列になっている。2 重の配列にしたことに特別な意味はない。リクエストが複数回に分かれていることをデータ構造にも反映したかっただけ。

まとめてみる

コード全体は以下のようになった。肝心のリストは HTML として生成している。

こうして眺めてみるとあれこれリファクタリングしたくなってくるが、とりあえず動くんだからこれで良しとする。そんなことよりも Python で書き直したり、GAE に載せてみたりする方が先だな。

関連リンク

twitter より (2010-09-13)

  • 18:18  RT @Hayakawashobo: #haya100 で、今年の「強い物語。ハヤカワ文庫の100冊」フェアの小冊子、PDFをご用意いたしましたー。ニュースページ http://bit.ly/cPmgE8 からどうぞ! iPhoneをお持ちの方は、ダウンロード後iBook ...
Powered by twtr2src.

2010-09-13

ebook を作ってみよう

ネタはこの本の第4章「ePub形式の電子書籍を作る」。ePub フォーマットの説明に始まり、オーサリングツールを使った epub ファイルの作成までを説明している。

iPad電子書籍アプリ開発ガイドブック
中島聡, まえだひさこ, 新井英資, 向井領治, 大原ケイ, クレイグ・モッド
インプレスジャパン ( 2010-08-23 )
ISBN: 9784844329060
おすすめ度:アマゾンおすすめ度

ePub とはどんなフォーマットか

(iPad電子書籍アプリ開発ガイドブック; p.267より)
結論を先に言えば、現在の ePub 2.0 で制作できるコンテンツは、XHTML 1.1 と CSS 2.0 に準じた、数年前の Web ページと同レベルというイメージです。

(X)HTML だと言うのは少し意外だった。ページの概念を排除したウェブとページ前提の ePub では、いろいろと違うはずだと思い込んでいたのだ。これは言い換えれば、Safari や Firefox と言ったブラウザにもページの概念を持ち込むことができる、ということにならないか?

まあ、ページのことは別にしても、ePub をブラウザで表示できても良いよな。実際、Firefox には ePub を読み込んで表示する機能拡張が存在するし(→ EPUBReader)。

試しに ePub ファイルを作ってみよう

何事も自分で試してみると理解が進む。この LOG+REPO の記事をいくつか ePub ファイルにまとめてみることにした。

始めは、↑の本を参考にしつつ、手で XHTML と XML を打ち込んでみたが、どうにもエラーばかり出てしまうので、オーサリングツールを使うことにした。ツールは、↑の本で説明されている eCub だ。

↑の本の記述(p.283 からの「4-3-3 eCubプロジェクトを作る」)にしたがって作業すると、コンテンツになる XHTML のインポートで「UTF-8 からは変換できない」というエラーが出たり、目次に入る XHTML のタイトルが文字化けしてしていたり、と若干の問題があったものの、何とか logrepo.epub を作ることができた。

iTunes 経由で iPhone、iPad に転送してみたが、ちゃんと iBooks で読める。Safari で見る場合とくらべて、大きく見た目が変わるわけではないが(CSS は適当にでっちあげたし)、スクロールではなくページ送りで読むのは新鮮な感じを受ける。

これも自炊の一種か?

ネットの一部(2ch 界隈)では、紙の本を裁断してスキャナで電子化することを「自炊」と呼ぶ。元が紙かどうかの違いはあるが、ネット上のコンテンツを ePub 化するのも自炊と呼んでも良いだろう。無論、著作権等の扱いには注意を払うことを前提にして。

コンテンツを丸ごと配布できるというのは、現在のウェブにはないメリットだ。いまのところ、オフィスや自宅にいるときを除けば、本当の意味でネットに常時接続していられる環境はまだない。3G にしろ、無線ホットスポットにしろ届かないエリアは少なくない。東京でも地下鉄に乗ったらもうあきらめるしかない。あらかじめコンテンツをデバイスに詰め込んでおく方法は、これからも当分の間はすたれたりしないだろう。

むしろ、配布するシステム側が ePub に対応するのはどうだろう? たとえば、Apache が ePub をウェブリソースとして認識して、丸ごとのダウンロードにも個別のページの配信にも対応する。iPad や iPhone は丸ごとダウンロードして iBook などに詰め込み、Mac (や PC) のブラウザは個別のページを要求して、従来どおりの表示を行う。

ま、少くとも自分のブログを ePub 化することには何の問題もない。配布したって大丈夫。むしろ、iPhone や iPad で読む(読んでもらう)ことを前提にするなら、ePub 化したファイルを配布する方が良いのかもしれない。

自分が書いたものを読むのにネットにつながなきゃならないってのもおかしな話だ。手元に取ってある HTML の原稿から ePub が生成できれば iPhone や iPad に詰めて持ち歩ける。なんか、それって良い方法かもしれないな。画像をどうするか。このブログの画像はすべて Picasa Web Albums に上げたものにリンクしている。無論、手元にもファイルとして残してあるが、それを利用しようにもリンクを書き換えなければならないし。

ePub 化することを前提にしたブログを書く環境が必要ということか……。ふむふむ。

関連リンク

関連記事

twitter より (2010-09-12)

  • 14:58  Amazonに発注したiPadスタンドが届いたので早速使ってみた。なんてゆうか、やられたわ。iPadってこうやって使うべきものだったんだ。iPadに対する印象がすっかり変わるゾ。→ http://bit.ly/9OgV92
  • 15:31  う〜ん。iPadのスタンドにはまいった。想像だけではユーザ体験は語れないってことの証拠になる。無意識のうちに、iPadを「ちょっと大きいiPhone」と認識していたのかもな。だからiPhoneと同じような使い方をしなきゃならないと思い込んでいた。スタンドなんて邪道だよ、と。
  • 15:36  しかし、大きさという特性は利用の仕方も変えるものだったんだ。iPhoneにスタンドは不要だが、iPadにはスタンドはぜひとも必要。そしてiPad+スタンドは「読む」という体験を根本から変える。「本を手に持たずに読む」ことが実用的になる。むしろ本はこう読むべきだったと気付く。
  • 15:39  紙の本を「手に持たずに読む」には 2 通りの方法が考えられる。(1) 机の上に本を水平に置く、(2) ブックスタンドを使う。(1) は首を下に向けて読むことになるから首に負担がかかる。(2) はiPad+スタンドに近い体験となるが、ページがめくりにくいという欠点がある。
  • 15:44  参考書を机に広げて作業することを考えると、iPadが複数台あっても良い気がしてきた。もうこれ以上、机の上にディスプレイは置けないけど、iPad なら置けるしな。加えて、iPadなら指先で直接触れられる分、画面にPDFを表示させるよりもページ送りなんかの操作感は上だ。
  • 15:45  とはいえ、さすがに同じものを2台、3台と買う気にはなれないので、早く新しいiPadを出してください。> Apple
  • 21:04  バイオハザードか。3は見てないんだよな。
Powered by twtr2src.

2010-09-12

すべての無効化を許可、ってどういう意味?

Snow Leopard Server には、サーバ OS が提供する各種サービスを管理するアプリが用意されている(「サーバ管理.app」)。サーバ OS が稼動している Mac で使えるのはもちろん、(クライアント OS で動いている)別の Mac にインストールして使うこともできる。ウチの環境では Mac mini 上の Snow Leopard Server を管理するのに、iMacMacBook にインストールしてある。最近はもっぱら iMac からこのアプリ「サーバ管理.app」を使って、mini Server の設定変更等を行っている。

さて、このスクショを見てほしい。これは「サーバ管理.app」でウェブサーバのオプションを設定する部分だ。一番下に「すべての無効化を許可」という項目がある。これが何を設定するものなのかわかるだろうか? わたしにはさっぱりわからなかった。

Snow Leopard Server のウェブサーバとは Apache のことであり、「サーバ管理.app」で設定できるのも Apache のオプションだ。一般的には httpd.conf を書き換えることで行うことだが、Mac OS X Server では GUI を使って行える(すべての項目が GUI で設定できるわけではない)。

いくらウィンドウを眺めていてもわからないので、仕方なく英語版のマニュアルを見た。そこに書かれていた英語の表記のおかげでようやく意味が推測できた。

Allow All Overrides、の訳らしい

前述の英語版マニュアルの p.38 には「Configuring Website Apache Options」という解説があり、そこで↑のスクショにある各項目の説明が載っている。その中で「すべての無効化を許可」に相当する項目の説明はこうなっている。

(Mac OS X Server -- Web Technologies Administration Version 10.6 Snow Leopard; p.38)
Allow All Overrides: Instructs Web service to look for additional configuration files inside the web folder for each request.

「Override」を「無効化」と訳したのか……。訳語の選択にケチをつけたいわけじゃない。しかし、どんなオプションがセットされるのかが、この言葉からは想像できない。オプションの説明として付けられた文章も混乱を減らしてはくれない。

正直、説明部分の意味はよくわからない。むしろ、これは Apache の内部で起きることの説明だと思える。Apache は、「AllowOverride All」が設定されているリソースに対しては、リクエスト時に毎回設定ファイル(.htaccess)を見にいっているのだろう。けれど、それは管理者に説明するような内容だろうか? 管理者に必要な情報は、「AllowOverride All」を設定すれば、リソースごとに用意する設定ファイルでサーバオプションの上書きができる(それもサーバを再起動することなく)、ということじゃないか?

ちなみに、英語モードで「サーバ管理.app」を起動すれば、先のスクショと同じ部分がこうなる。

英語の方がマシなのは項目名が Allow All Overrides だという点。これは Apache のディレクティブ(AllowOverride)との対応が容易だから。このオプションをオンにすれば AllowOverride All になるんだろう、と想像がつく。

翻訳は難しい

Apache ドキュメントの公式な翻訳では「Override」に「上書き」という言葉を使っている(→ Apache コア機能: AllowOverride ディレクティブ)。こっちの方が一般的な訳語だと思うよ。

後から知ったことだけど、このオプションの意味がわからなかったのはわたしだけではないようだ(→ .htaccessが動きません)。

わたしが感じた混乱は、Apache のこと少しは知っている → AllowOverride なら下手に訳さない方が意味がわかる → 「すべての無効化を許可」って何?、という流れで起きたものだったのかもしれない。いっそ、Apache の設定のことをまったく知らなければ、素直に理解できたのかも。……。いやいやいや、それはないって (; ゜Д゜)。

関連リンク

関連記事