[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6 新聞モジュールの作り方

Shimbun’ は emacs-w3m の付属ライブラリで、Gnus や Wanderlust、 Mew などの MUA を利用し、ウェブコンテンツをメールと同じユーザインターフェー スで読むことを可能にするものです。ここでは ‘shimbun’ モジュールを作 成する典型的な方法を説明します。


[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6.1 概略

http://www.foobar.net のコンテンツを閲覧する新た な ‘shimbun’ モジュール ‘foobar’ を作成するとして、まず最初に 貴方がしなればならないことは、‘sb-foobar.el’ の冒頭に

 
(require 'shimbun)
(luna-define-class shimbun-foobar (shimbun) ())

のような宣言を入れておくことです。徐々に分かると思いますので、今はおまじ ないと思っておいてください。注意すべきことは、‘shimbun’ モジュール を入れるファイル名の ‘sb-foobar.el’ の ‘foobar’ の名前と、 luna-define-class の第一引数 の shimbun-foobar の ‘foobar’ の名前は合わせておく必要がある ことです。

Shimbun’ モジュール ‘shimbun-foobar’ がこなすべき仕事は大き く四つあります (あなたが Gnus のユーザならば、「フォルダ」を「グループ」 に読み換えてください):

  1. MUA が ‘foobar’ フォルダを開いたら、記事の標題などをリストアップす るために http://www.foobar.net からウェブページのソースを取得する こと。
  2. 取得したウェブページのソースに対し、記事の見出しに必要ないくつかの情報と ともに取得して、headers というリストに代入して返すこと。
  3. MUA が ‘foobar’ フォルダの記事の閲覧を要求したら、実際の記事内容を 記載したウェブページのソースを (例え ば http://www.foobar.net/030530.html から) 取得すること。
  4. http://www.foobar.net/030530.html から取得したウェブページのソー スを、必要に応じ閲覧しやすいように整形すること。

最初の作業は ‘shimbun.el’ の shimbun-headers が、二番目の作 業は shimbun-get-headers が担当します。そして三番目の作業 は shimbun-article が、最後の作業 は shimbun-make-contents が担当します。

shimbun.el’ の中をご覧ください。defun による関数定義の他に、 見慣れない luna-define-generic, luna-define-method などの 宣言がありますよね。どうも使用方法は defun のそれと似ているようで す。そして、前者は何だか doc-string だけを書いてあるようで、同名のシンボ ルについて後者によって再度宣言しているように見えます。更に、あるシンボル について、luna-define-generic の宣言だけがあって、 luna-define-method の宣言がないものもあります。

実は、‘shimbun.el’ 及び各 ‘shimbun’ モジュールは、 Emacs Lisp にてオブジェクト指向プログラミングを可能とする ‘luna.el(13) を利用して書かれています。

shimbun.el’ の中では、shimbun-headers があ る URL のウェブページのソースを取得し、shimbun-get-headers がその ウェブページのソースから標題などを抜き出し… という前述の手順がハー ドコーディングされています。しかし、決め打ちするだけでは、千差万別のウェ ブページのソースを、その構造に合わせて変化させることができません。

そこで luna により、メソッドがコールされる手順だけ決めておいて、 ‘shimbun’ により変化させるべきメソッドの実体定義を 各 ‘shimbun’ モジュールに任せているのです。各 ‘shimbun’ モジュー ルで共通で使えそうなメソッドは ‘shimbun.el’ の中にメソッドの実体も 定義してありますが、それすら各 ‘shimbun’ モジュールにおいて再定義を することが可能です。

もうお分かりのように、luna-define-generic は、言わば殼だけの宣言、 luna-define-method は ‘shimbun’ モジュール毎に作成できる実体 の宣言。そして ‘sb-foobar.el’ の冒頭に入れ た luna-define-class での宣言は、luna 上での新たなクラスの 宣言だったわけです。


[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6.2 ウェブページのソース及びヘッダ情報を取得する

まず記事見出しを取得する対象となるウェブページを決めることから始めます。 フレーム表示されている場合は、フレームの中で必要なページだけを単独で指し 示す URL を特定するべきです。特定できたら、新たに作成す る ‘shimbun’ モジュールの中で luna-define-method を使い、 shimbun-index-url の定義を作成しましょう。単純に URL を返すように すれば良いですよ。後で説明しますので、変 数 shimbun-foobar-groups も用意しておきましょ う(14)

 
(defvar shimbun-foobar-url "http://www.foobar.net")

(luna-define-method shimbun-index-url ((shimbun shimbun-foobar))
  shimbun-foobar-url)

(defvar shimbun-foobar-groups '("news"))

shimbun-headers メソッドは ‘shimbun.el’ の中に既に定義されて いますから、‘sb-foobar.el’ で shimbun-index-url メソッドの定 義を作成すればウェブページのソースの取得ができるようになります。 shimbun-headers はウェブページのソースを取得した後、 shimbun-get-headers メソッドを呼び、ヘッダ情報の収集に入ります。 ‘shimbun.el’ の中には shimbun-get-headers のメソッド宣言があ りせんから、‘sb-foobar.el’ の中で独自にメソッドを作成しなければなり ません。

sb-foobar.el’ に shimbun-get-headers のメソッドを作成するた めに、取得したページのソースを分析しましょう。どのような正規表現で記事の ヘッダ情報を収集するかを検討します。記事の見出しとして特に必要な情報は、 標題、日付、作成者、その記事の URL、そして message-id です。これ らの情報は、それぞれの MUA において、Subject, Date, From, Xref, Message-ID として表示されます。例えば、下記の

 
<a href="030530.html">5月30日の話題(投稿者-みきお &lt;foo@bar.net&gt;)</a>

のような行を集めて記事にしたいのでしたら、

 
"<a href=\"\\(\\([0-9][0-9][0-9][0-9]\\)[0-9][0-9]\\.html\\)\">\\([^<(]+\\)(投稿者-\\([^<]+\\))<\/a>"

のような正規表現になるでしょう。そして記事の Xref の値は (match-string 1) で取得できます、Date は (match-string 2) の値を加工すれば良いでしょう。Subject は (match-string 3) で取得できますね。From は (match-string 4) を加工すれば良いでしょう。これらの値 は MUA で見易いように更に加工しても構いません。

上記のように記事の URL が相対パス表示されている場合は、 shimbun-expand-url を使用し、絶対パス表示に変更してからヘッダに収 めましょう。記事の URL がヘッダの URL と同じ、つまり記事毎に 個別に URL を持たない構造のウェブページもあります。この場合は少しやっか いで、ヘッダ情報取得の段階で、記事の内容も取得しておき、Emacs のメモリに 収めておく必要があります。具体的には ‘sb-palmfan.el’, ‘sb-dennou.el’, ‘sb-tcup.el’ の ‘shimbun-headers’ メソッ ドの定義を参照してください。

ウェブページによっては Date が特定できないものがあります。そういう場合は 無理に特定せずとも "" を入れておけば OK です。記事の内容を見て初 めて Date が特定できるなら、shimbun-make-contents メソッドの中で 改めてヘッダに Date の情報を入れても OK です。それから、From を決め打ち しても良い場合もあります。

message-id の作成には注意を要します。一部の記事が読めなかったりし ますので(15)、必 ず単一性 (uniqueness) を保証しなければなりません。日付やドメイン、そのペー ジの URL の一部を使って文字列を生成することで単一性を確保しましょう。そ の他、message-id の一部に必ず ‘@’ を含めるようにし、逆 に ‘:’ は含まないようにしましょう。このルールを守らないとインライン 画像がきちんと出力されませんよ。詳しくは RFC2387, RFC822 を参照してくだ さい。

苦労して取得したこれらの情報は shimbun-create-header という関数を 利用してヘッダに収めます。

結局 ‘sb-foobar.el’ の中での shimbun-get-headers の定義の骨 組みはこんな風になりますね。

 
(luna-define-method shimbun-get-headers ((shimbun shimbun-foobar)
                                         &optional range)
  (let ((regexp "....")
        subject from date id url headers)
    ...
    (catch 'stop
      (while (re-search-forward regexp nil t nil)
        ...
        (when (shimbun-search-id shimbun id)
          (throw 'stop nil))
        (push (shimbun-create-header
               0 subject from date id "" 0 0 url)
              headers)))
    headers))

なお、このメソッドの中では shimbun という一時変数で、 ‘shimbun’ モジュール ‘shimbun-foobar’ のインスタンスにアクセス できます。

ところで、先程保留にした変数 shimbun-foobar-groups について説明し ましょう。

仮に http://www.foobar.net の中に読みたい記事グループが二つあっ て、それぞれの記事のヘッダ情報を得るウェブページが別々の場所にあったとし ましょう。http://www.foobar.net/whatsnew/index.hmtl にサイト の更新情報が、http://www.foobar.net/ml/index.html に ML の記 事アーカイブの一覧があるときなどです。こういう場合は、‘shimbun’ モ ジュール foobar のグループとして、foobar.whatsnew, ‘foobar.ml’ としてアクセスできると便利ですよね。そういう場合は下記 のようにしてみましょう。

 
(defvar shimbun-foobar-url "http://www.foobar.net")

(defvar shimbun-foobar-group-path-alist
  '(("whatsnew" . "/whatsnew/index.html")
    ("ml" . "/ml/index.html")))

(defvar shimbun-foobar-groups
  (mapcar 'car shimbun-foobar-group-path-alist))

(luna-define-method shimbun-index-url ((shimbun shimbun-foobar))
  (concat shimbun-foobar-url
          (cdr (assoc (shimbun-current-group-internal shimbun)
                      shimbun-foobar-group-path-alist))))

現在ユーザがアクセスしているグループに は shimbun-current-group-internal を使えば分かります。 shimbun-get-headers などでもグループが違えば作業内容が違ってくる 可能性もありますね。

なお、‘shimbun’ モジュール一つにつき、最低でも一つのグループが必要 です。グループの名前の決め方に特に決まりはありませんが、グループ名に悩ん だら、‘news’ とか ‘main’ などと付けておきましょう。


[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6.3 記事の表示

shimbun.el’ に定義された shimbun-article メソッドは、ヘッダ 情報から Xref を取り出し、その URL のウェブページのソースを取得した後に、 そのソースを入れたワーキングバッファの中 で shimbun-make-contents を呼びます。具体的な記事の加工 は shimbun-make-contents の仕事です。

記事となるウェブページのソースが、どばっとワーキングバッファにぶちまけら れていると想像してください。‘shimbun.el’ の標準 の shimbun-make-contents は、そのバッファの先頭にまずヘッダ情報を 挿入し、その直後に ‘<html>’ や ‘<body>’ などを、また、バッファ の末尾に ‘</body>’, ‘</html>’ を挿入してくれます。そうやっ て HTML メールとして表示させるのです。

HTML の記事だけでなく、‘text/plain’ 形式の記事が生成されるようにす ることもできます。See section text/plain の記事を作るには.

記事を何も加工する必要がなければ ‘sb-foobar.el’ の中で は shimbun-make-contents について新たに定義する必要はありません。

単純に記事の前後に捨てたい部分があるだけならば、 shimbun-foobar-content-start, shimbun-foobar-content-end に捨てたい部分を検索可能な正規表現を指 定しておきましょう。

 
(defvar shimbun-foobar-content-start "^<body>$")
(defvar shimbun-foobar-content-end "^<\/body>$")

標準の shimbun-make-contents から 呼び出された shimbun-clear-contents は、これらの正規表現を利用し て、point-min から shimbun-foobar-content-start まで、 shimbun-foobar-content-end から point-max までを切り捨てて くれますよ。但し、これら二つのマッチはいずれかが成功しないと切り捨ては行 われませんので注意が必要です。

広告などの不要な情報があって、それを細かく検索して捨てたい場合は、 ‘sb-foobar.el’ の中で独自の shimbun-clear-contents を定義し ておきます。

 
(luna-define-method shimbun-clear-contents :around ((shimbun shimbun-foobar)
                                                    header)
  ;; cleaning up
  (while (re-search-forward "..." nil t nil)
    (delete-region (match-beginning 0) (match-end 0)))
  (luna-call-next-method))

より具体的な方法は、‘sb-ibm-dev.el’ が参考になるかもしれません。

先程、ウェブページのソース及びヘッダ情報を取得する の節で、記事毎に個 別に URL を持たない構造のウェブページの場合、ヘッダ情報取得の段階で、記 事の内容も取得しておき、Emacs のメモリに収めておく必要があると申し上げま した。この場合、‘shimbun-article’ では上記のような Xref 情報から の web page の取得は必要になりませんので、ただ Emacs のメモリから取り出 して、バッファに整形して挿入すれば足ります。具体的に は ‘sb-palmfan.el’, ‘sb-dennou.el’, ‘sb-tcup.el’ の ‘shimbun-article’ メソッドの定義を参照してくだ さい。


[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6.4 Shimbun モジュールの継承

メーリングリストマネージャ (アーカイバ) として有名なものがいくつかありま す。

貴方が ウェブページのソース及びヘッダ情報を取得する のステップで取得し たウェブページのソースを分析しているときに、そのソースの中にこれらメーリ ングリストマネージャの名前を見つけたら(16)、 それはすごくラッキーなことです。‘sb-mailman.el’, ‘sb-mhonarc.el’, ‘sb-fml.el’, ‘sb-mailarc.el’ に既 に shimbun-get-headers などの必要なメソッドが定義されています。こ れらを利用してなお足りない部分だけの差分プログラミングをすれば、貴方 の ‘sb-foobar.el’ は早速動きます。

例えば ‘sb-mailman.el’ を利用するなら ‘sb-foobar.el’ の冒頭は、

 
(require 'sb-mailman)
(luna-define-class shimbun-foobar (shimbun-mailman) ())

こんな風になります。これで ‘shimbun’ モジュー ル ‘shimbun-foobar’ は shimbun-mailman クラスを継承 し(17)、 ‘shimbun-foobar’ の中では、‘sb-mailman.el’ の中で定義されてい るメソッドが標準で使用されることとなります (更にメソッドの一部を上書きす ることも可能です)。

sb-mailman.el’ を実際に利用したサンプルとして、 ‘sb-pilot-mailsync.el’ などをご覧ください。如何に楽ができるかがお分 かりになるでしょう。

気を付けることが一つあるとすれば、これらのメーリングリストマネージャの中 には地域化 (localize) されて、例えば日付表示を日本語で行うように改造され ているものがあることです。‘sb-mailman.el’, ‘sb-mhonarc.el’, ‘sb-fml.el’, ‘sb-mailarc.el’ はいずれも標準の、英語版のものに 対応しています。これら地域化されたメーリングリストマネージャを利用してい るウェブサイトを ‘shimbun’ で読みたいときは、いくつかのメソッドを上 書きしなければならないかもしれません。


[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6.5 text/plain の記事を作るには

たとえ MUA が HTML の記事を読むことができるように emacs-w3m によって強化 されていても、いくつかの場合には ‘text/plain’ の記事が便利なことも あるかもしれません。‘sb-foobar’ モジュールに ‘text/html’ では なくて ‘text/plain’ の記事を作らせるには、二つの方法があります。

どちらの方式を使うにしても、‘text/plain’ の記事は、画像やリンクなど を含むことができないことに注意してください。


[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6.6 全角文字を半角文字に変換する

「全角」または「全角文字」は、幅が広い日本語の文字を呼ぶための俗称です。 また「半角」は、通常の ASCII 文字のための対語です。少なくとも ASCII 文字 セットに対応する、全角文字の完全なセットがあります。

いくつかの日本のウェブサイトは全角文字を多用する傾向があり、それらの記事 は必ずしも読み易くないかもしれません。もしそう感じたら、それら全角の英数 字を半角に変換するこの機能を使うことができます。それに は shimbun-foobar-japanese-hankaku 変数を t に設定してくだ さい。ここで foobar は、新聞の記事を講読するサーバー名です。つま り、サーバー毎にそうしなければならないということです。

全角から半角への変換を記事のボディだけで行なわせたいならば、t の 代わりに値 body を使ってください。逆に値 header また は subject は、サブジェクトだけでそれを行なうことを指定します。


[ < ] [ > ]   [ << ] [上] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

9.6.7 Shimbun ライブラリのコーディング規約


[ < ] [ > ]   [ << ] [上] [ >> ]

この文書はTSUCHIYA Masatoshiによって2019年1月月30日にtexi2html 1.82を用いて生成されました。