qwikWeb の仕組み 【第 3 回】 ページの一部分だけ編集できるようにしてみる

書いた人:えと こういちろう

ページの一部分だけ編集できるようにしてみる

前回は qwikWeb のプラグインの書き方について解説した。今回はそこから発 展させ、ページの一部分だけを編集できるようにしてみる。

目的

一般に文書は、テキストだけではなく他の要素の集合として成り立つ。例えば ある一つの文書には、テキスト要素の他に、図やグラフ、表などの要素が含ま れていることがある。

HTML による文書の場合、文書内に図を挿入したい時は IMG タグを使ってイン ライン画像として挿入する。HTML そのものには図を記述する能力はない。 IMG タグを使って外部の画像を読み込むしかない。 1 XHTML の場合も同様にテキストを記述することしかできないが、XML は他の XML 要素を混在させることができるため、例えば XHTML の記述の中に SVG による 図を混ぜることができる。つまり、地の文と図版とを、同じ一つのファイル中 に同居させることができる。

前者の場合、図が埋め込まれた一つの文書は HTML ファイルと画像ファイルの 二つに分割されることになる。HTML はエディタで修正し、画像ファイルは画 像編集ソフトでの編集と、編集手段も二つに分かれる。XHTML のファイル内 に SVG を混在させた場合は、その両者ともテキストエディタで同時に編集で きる。つまりエディタによる編集という一つの手段で両者を一度に編集できる ことになる。 2

一般に Wiki エンジンでは、Wiki 記法によってテキストを編集して、それが HTML または XHTML としてレンダリングされる。その中に図を埋め込む場合は、 画像ファイルを別要素として埋め込むことになる。つまり HTML と同じ方式で ある。 3

Wiki はネット上で気軽に使える共同編集環境であるが、現状では主にテキス トの共同編集に留まっている。テキスト以外の、図などの要素も含めて、同じ ように共同編集が行えるとすばらしいのではないだろうか。

また、それらのテキスト以外の要素は、本体となる Wiki ページの編集とは独 立して編集できると都合がいいだろう。例えば表の編集は、表の見た目のまま 編集したい。図の編集は、図を見たとおりのまま編集できるとうれしい。この ような埋め込まれた要素の編集は、その要素がページを構成する一部分である ととらえるとすると、ページの部分編集であるととらえることができる。その ような、ページの部分編集を行えるような仕組みを考えてみたい。

本稿ではそのようなテキスト以外の要素を埋め込み、またそれら個別の要素を それぞれ部分的に編集できるようにするプラグインを作成してみることを目標 とする。

セットアップ方法

今回もまた、セットアップ方法について解説しておく。

qwikWeb は、メーリングリストと Wiki が統合されているという特徴を持って いるが、プログラムの構成としてはメーリングリストサーバと Wiki サーバは、 それぞれ独立した別のプロセスとして動く仕組みになっている。 そのため、 メーリングリストサーバだけ、Wiki サーバだけをそれぞれ別個に起動させる ことができる。今回この連載では、Wiki サーバにおける機能拡張の方法だけ 扱っているため、Wiki サーバ部分のセットアップ方法だけを解説する。

メーリングリストサーバのインストールは、Wiki サーバのインストールと比 較して難しい。DNS、メールサーバなどの設定を適切に行う必要があり、それ ら全てを適切に設定しないと動くようにならないからである。技術評論社の Software Design 2006 年 5 月号に qwikWeb の徹底解説記事を書いた。本記事に は qwikWeb のメーリングリスト機能を含めたインストール方法を解説してお り、こちらを御参照下さい。また、下記 URL に Debian 環境でのインストー ル方法を解説しており、記事内容とほぼ同等の記述があるので、こちらも御参 照下さい。

下記では、qwikWeb の開発版をインストールし、Wiki サーバ部分だけを動か せるようにする方法について説明する。まず「 ~/qwik 」以下に qwikWeb を インストールすると仮定する。リポジトリより最新版を取得する。

% cd
% svn checkout svn://rubyforge.org//var/svn/qwik/qwik

このようにして最新版を取得する。次に、qwikWeb を起動する。

% cd qwik
% make
[2006-01-26 08:53:26] INFO  WEBrick 1.3.1
[2006-01-26 08:53:26] INFO  ruby 1.8.4 (2005-10-29) [i486-linux]
[2006-01-26 08:53:36] INFO  Qwik::Server#start: pid=2345 port=9190

このようにして、取得したディレクトリからデバッグモードで起動することが できる。make コマンドが使えない環境では、

% cd qwik
% ruby bin/qwikweb-server -d -c etc/config.txt

としても同じことになる。

qwikWeb が起動すると WEBrick の起動メッセージが表示される。

にアクセスしてみると、qwikWeb の入口となるページが表示される。

qwikWeb サーバは通常はポート 9190 で立ち上がるが、ポート 80 からアクセ スできるようにしたい場合には二つ方法がある。まず、設定を書換えてポート 80 で立ち上がるようにすることができる。しかし通常はポート 80 では Apache などの別のサーバがすでに動いているため、そちらを停止する必要が ある。もう一つの方法としては、その Apache などの httpd をリバースプロ キシとして動くように設定する方法がある。設定方法は、下記 URL を御参照下 さい。

部分編集プラグインの作り方

前回は、qwikWeb の基本的なプラグインの作り方について述べた。

インラインプラグインとブロックプラグインの違い

プラグインには、通常のプラグイン(インラインプラグイン)と、複数行プラグ イン(ブロックプラグイン)との二種類あることはすでに前回説明した。もう一度、 簡単にその違いを見てみる。

実例で比較すると、インラインプラグインは、このようになる。

{{hello(world)}}

ブロックプラグインは、このようになる。

{{bhello
 world
 }}

どちらも、「hello」というプラグインに「world」という引数を与えている ことには変わりないが、その書き方が違う。また出現可能な要素も違う。

前者のインラインプラグインでは、

私は「{{hello(world)}}」と言った。

などと、文中に埋込む形でこのプラグインを使うことができる。 そのため、これをインラインプラグインと呼んでいる。

後者のブロックプラグインでは、このように文中に埋め込んで使う方法は とれない。その代りに、引数として複数行とることができる。

{{bhello
 world
 japan
 tokyo
 }}

などというように、プラグインに三行分の情報を渡すことができる。 4

このように、この二つのプラグインは、見た目としては結構似ているが、与え ることができる情報には大きな違いがある。

今回は、主にこの後者のブロックプラグインを対象として扱う。

ブロックプラグインの詳細

ブロックレベルプラグインは、どのように情報を受け取るのか。試しに、最も 簡単な pre プラグインを見てみよう。

  • qwik/lib/qwik/act-basic.rb
module Qwik
  class Action
    def plg_pre
      content = yield
      return [:pre, content]
    end
  end
end

このようになる。これが pre プラグインの全体像である。一行づつ見てみる。

     content = yield

yield で、ブロックにかこまれたテキストを取得する。

     return [:pre, content]

pre タグで囲ってその内容を返す。これだけである。

ちなみにインラインレベルの場合は、プラグインへの引数として渡される。 インラインプラグインとブロックプラグインの違いは、 Ruby における、引数渡しと、ブロック渡しの違いとほぼ同じような違いとし て実装している。

先程の例にあげた、bhello プラグインについて見てみよう。 これはブロックプラグインであり、一行づつにhelloをつけて出力するプラグインである。

  • qwik/lib/qwik/act-hello.rb
module Qwik
  class Action
    def plg_bhello
      content = yield
      content = content.map {|line|
	"hello, #{line.chomp}!\n"
      }.join
      return [:pre, content]
    end
  end
end

一行づつ見てみる。

     content = yield

囲まれた内容を取得する。

     content = content.map {|line|
       "hello, #{line.chomp}!\n"
     }.join

一行づつ取り出し、その行を「hello, …!」で囲い、また連結する。

     return [:pre, content]

pre タグで囲って返す。

このようにして、ブロックプラグインを書くことができる。

ページの部分編集を可能とする

一番簡単なサンプルとして textarea プラグインを見てみよう。

これが使い方である。

{{textarea
 This is an example for textarea.
 }}

といった感じにプラグインを埋め込むと、そこに編集可能なテキストエリアが 表れる。ソースを見てみる。

  • qwik/lib/qwik/act-textarea.rb
module Qwik
  class Action
    TEXTAREA_MIN_COLS = 50
    TEXTAREA_MIN_ROWS = 4
    TEXTAREA_MAX_COLS = 100
    TEXTAREA_MAX_ROWS = 50
    def plg_textarea
      # @textarea_num is global for an action.
      @textarea_num = 0 if ! defined?(@textarea_num)
      @textarea_num += 1
      action = "#{@req.base}.#{@textarea_num}.textarea"

      content = ''
      content = yield if block_given?

      cols = rows = 1
      content.each {|line|
	len = line.chomp.length
	cols = len if cols < len
	rows += 1
      }
      cols = TEXTAREA_MIN_COLS if cols < TEXTAREA_MIN_COLS
      rows = TEXTAREA_MIN_ROWS if rows < TEXTAREA_MIN_ROWS
      cols = TEXTAREA_MAX_COLS if TEXTAREA_MAX_COLS < cols
      rows = TEXTAREA_MAX_ROWS if TEXTAREA_MAX_ROWS < rows

      return [:div, {:class=>'textarea'},
	[:form, {:method=>'POST', :action=>action},
	  [:textarea, {:name=>'t', :cols=>cols, :rows=>rows}, content],
	  [:br],
	  [:input, {:type=>'submit', :value=>_('Update')}]]]
    end
  end
end

部分毎に見てみる。

     # @textarea_num is global for an action.
     @textarea_num = 0 if ! defined?(@textarea_num)
     @textarea_num += 1
     action = "#{@req.base}.#{@textarea_num}.textarea"

一つのページ中に、テキストエリアプラグインは何個も埋め込める。そのため、 それぞれに連番を振って対処している。そのための連番を指定して、それに対 応する action の URL を組み立てている。

     content = ''
     content = yield if block_given?

ブロックの中身を取得している。

     cols = rows = 1
     content.each {|line|
        len = line.chomp.length
        cols = len if cols < len
        rows += 1
     }

content の内容から、cols と rows の大きさを取得している。それぞれ行の 長さと行数のそれぞれを取得して、content の大きさにあわせて textarea の 大きさが変化するようにしている。

     cols = TEXTAREA_MIN_COLS if cols < TEXTAREA_MIN_COLS
     rows = TEXTAREA_MIN_ROWS if rows < TEXTAREA_MIN_ROWS
     cols = TEXTAREA_MAX_COLS if TEXTAREA_MAX_COLS < cols
     rows = TEXTAREA_MAX_ROWS if TEXTAREA_MAX_ROWS < rows

それぞれ、最小値と最大値の間におさまるようにしている。

     return [:div, {:class=>'textarea'},
        [:form, {:method=>'POST', :action=>action},
          [:textarea, {:name=>'t', :cols=>cols, :rows=>rows}, content],
          [:br],
          [:input, {:type=>'submit', :value=>_('Update')}]]]

ここで html を出力する。まずテストするときに切り出しが楽なように、 textarea クラスの div で囲う。次に form 要素を作る。先程組み立てた URL を action とする。肝心の textarea 要素を cols, rows, content で作る。 name は適当に決めておく。更新のための submit ボタンを作る。

これで全てである。このプラグインを表示すると、テキストエリアが表示され、 そこに適当なテキストを入力することができる。それだけならば単にテキスト エリアが表示されているというだけなのだが、それだけではなく、それを更新 することができる。更新ボタンを押すと、ページのそのテキストエリアの部分 だけが更新されるのだ。

その更新処理は、ext_textarea メソッドで行っている。実際の処理を見てみる。

  • qwik/lib/qwik/act-textarea.rb
module Qwik
  class Action
    def ext_textarea
      c_require_post
      c_require_page_exist

      num = @req.ext_args[0].to_i
      return c_nerror(_('Error')) if num < 1

      text = @req.query['t']
      return c_nerror(_('No text')) if text.nil? || text.empty?
      text = text.normalize_newline

      begin
	plugin_edit(:textarea, num) {|content|
	  text
	}
      rescue NoCorrespondingPlugin
	return c_nerror(_('Failed'))
      rescue PageCollisionError
	return mcomment_error(_('Page collision detected.'))
      end

      c_make_log('textarea')	# TEXTAREA

      url = "#{@req.base}.html"
      return c_notice(_('Edit text done.'), url){
	[[:h2, _('Edit text done.')],
	  [:p, [:a, {:href=>url}, _('Go back')]]]
      }
    end
  end
end

どんな処理をしているのか見てみる。

     c_require_post
     c_require_page_exist

リクエストは POST である必要がある。また、対象となるページが存在してい る必要がある。

     num = @req.ext_args[0].to_i
     return c_nerror(_('Error')) if num < 1

この ext_args というメソッドは、リクエスト URL のうち base と ext に挾 まれた引数を持ってくるというメソッドである。実例を示すと、

http://qwik.jp/test/FrontPage.1.textarea

という URL では、

@req.base => "FrontPage"
@req.ext_args => ["1"]
@req.ext => "textarea"

という対応関係となる。大抵は、base が処理対象となるページ、ext が処理 内容を表わしている。その二つに囲まれる領域にも引数を追加することができ、 ext_args に配列として入る。普通だったらこれは「?」の後に情報を追加すると ころであるが、あえてその方法は使っていない。 5 ここでは、何番目の textarea プラグインを対象としているのかの値が入っている。

     text = @req.query['t']
     return c_nerror(_('No text')) if text.nil? || text.empty?
     text = text.normalize_newline

入力されたテキストを取得する。もし中身が無ければエラーとする。入力テキ ストは改行が場合によって異なるかもしれないため、統一する。

     begin
        plugin_edit(:textarea, num) {|content|
          text
        }
     rescue NoCorrespondingPlugin
        return c_nerror(_('Failed'))
     rescue PageCollisionError
        return mcomment_error(_('Page collision detected.'))
     end

ここがこのプラグインの肝である。

        plugin_edit(:textarea, num) {|content|
          text
        }

plugin_edit は、渡されたブロックの値でプラグインの中身を置き換えるメソッド である。したがって、 この三行で、num 番目の textarea というプラグインの中身を、text に置き換 えるという意味となる。content にはいるのは現在の中身である。 この例では現在の中身は使用していないが、必要であればこれを 元にして処理をさせることもできる。もしこの書換え実行時にエラー がおきたら、Exception が raise されるため、それを拾ってエラーページに 飛ばす。

     c_make_log('textarea')	# TEXTAREA

ここで、ログに記録を残す。この c_make_log を使ってログを残すと、それは 一日に一回まとめて更新記録として送られる。このプラグインのように、ペー ジの更新を行うプラグインの場合は、この c_make_log を使って更新通知が送 られるようにしておくと、グループのメンバーは全てその更新に気がつくので 便利である。

     url = "#{@req.base}.html"
     return c_notice(_('Edit text done.'), url){
        [[:h2, _('Edit text done.')],
          [:p, [:a, {:href=>url}, _('Go back')]]]
     }

ここで、無事テキストの書換えが終了したので、元のページに戻る。

このようにして、更新ボタンが押された後のページの書き換え処理を行ってい る。まずプラグインで textarea を表示して、そこで更新ボタンが押されると、 ページの内のそのプラグインの部分だけが部分的に書換えられて、更新される というわけである。このようにして、もっとも基本的なページの部分書き換え が行われている。

テーブル編集プラグイン

この最も基本的な textarea プラグインだけを見ていると、部分編集といって も何が便利なんだろうという気がしてくるかもしれない。なので、実際に実用的に 使っているテーブル編集プラグインについて見てみる。

使い方として、実際の具体例を見てみる。

{{table
 |Date|S|N|H|E|S|I|M|
 |2005-01-18am|×|×|×|×| |○|○|
 |2005-08-18pm|○|×|×|×| |○|○|
 |2005-08-19am|×|×|○|×| |○|○|
 |2005-08-19pm|×|×|△|×| |○|○|
 |2005-08-22am|○|○|×|○| |×|×|
 |2005-08-22pm|○|×|○|△| |○|○|
 |2005-08-23am|△|○|○|△| |○|○|
 |2005-08-23pm|△|△|×|○| |3時以降|○|
 }}

このように普通の Wiki テキストと同じ形式で table を書いて、それを table プラグインで囲むと、その table が編集できるようになる。Wiki テキ スト形式で table を編集するのは一般にはやりづらいが、このプラグインを 使うと、ページ中でその表を見たままの状態で編集できるようになる。

プラグインの内部を見てみてよう。

  • qwik/lib/qwik/act-table.rb
    def plg_table
      content = nil
      content = yield if block_given?

      if content.nil? || content.empty?		# no contents
	content = Action.table_default_content
      end

      w = c_parse(content)
      return p_error(_('You can only use a table.')) if 1 < w.length

      table = w[0]
      if table.nil? || table[0] != :table
	return p_error(_('You can only use a table.'))
      end

      if WabisabiTable.error_check(table)
	return p_error(_('You can only use text.'))
      end

      WabisabiTable.prepare(table)

      # @table_num is global for an action.
      @table_num = 0 if !defined?(@table_num)
      @table_num += 1
      num = @table_num

      action = "#{@req.base}.#{num}.table"
      div = [:div, {:class=>'table'},
	[:form, {:method=>'POST', :action=>action},
	  table,
	  [:div, {:class=>'submit'},
	    [:input, {:type=>'submit', :value=>_('Update')}]]]]
      return div
    end

先程のプラグインとの繰り返しが多いため、一部分だけ解説する。

     w = c_parse(content)

これで、content の中身をわびさび形式の配列に直している。

     WabisabiTable.prepare(table)

実際のところ、重要な処理をしているのはこの一行だけである。 WabisabiTable.prepare の具体的な中身を見てみる。

  • qwik/lib/qwik/act-table.rb
   def self.prepare(table)
     fill_empty_td(table)
     add_new_col(table)
     add_new_row(table)
     replace_with_input(table)
     make_th(table)
     set_new_col_and_new_row(table)
     add_new_col_button(table)
     add_new_row_button(table)
     return table
   end

処理ごとに関数に分けている。わびさび形式の table 要素を受け取り、それ を適宜必要な形式に変換していっている。これはまさしく初回の記事で紹介し た、HTML を受け取り、必要な HTML に変換して返すという処理である。つま り、この WabisabiTable.prepare は、特別なデータを受け取って HTML にして返 しているのではなく、任意の HTML による table 要素を必要な形式に変換す ることができる関数となっている。このようにして、処理の汎用化を進めてい る。このようにして、table 要素を受け取り、table 形式のフォームに変換し て出力している。

次に、更新が押されたらどのような処理が行われるのかを見てみる。

    def ext_table
      num = @req.ext_args[0].to_i
      return c_nerror(_('Error')) if num < 1

      query = @req.query
      new_table_str = table_construct(query)

      begin
	plugin_edit(:table, num) {
	  new_table_str
	}
      rescue NoCorrespondingPlugin
	return c_nerror(_('Failed'))
      rescue PageCollisionError
	url = "#{@req.base}.html"
	editing_content = [:pre, new_table_str]
	message = edit_conflict_message(url, editing_content)
	return mcomment_error(_('Page collision detected.')) {
	  message
	}
      end

      c_make_log('table')	# TABLE

      url = "#{@req.base}.html"
      return c_notice(_('Edit done.'), url){
	[[:h2, _('Edit done.')],
	  [:p, [:a, {:href=>url}, _('Go back')]]]
      }
    end

実は先程のテキストエリアプラグインと処理はほとんど同じである。

     query = @req.query
     new_table_str = table_construct(query)

     begin
        plugin_edit(:table, num) {
          new_table_str
        }

ここが処理の肝である。クエリの内容から再度 Wiki テキスト表記による table に書き戻し、それから、その対応するプラグインの中身を置き換えているわ けである。このようにして、テーブル編集プラグインは実現されている。 6

先程の textarea プラグインの場合は、編集したテキストがそのまま入力となった。 しかし、テーブル編集プラグインの場合は、編集時のスタイル (HTML で描画されたテーブル) と、 入力となるテキスト (テーブルの Wiki 記法) が異なっている。 このように、プラグインの中身の性質の違いによって、 編集のスタイルを変更できるというのが、ページの部分的編集の肝なのである。

POV-Ray プラグイン

さて、このようにページの部分編集を行うプラグインを二種類見てきた。これ をふまえた上で、ページの部分編集を行うプラグインを新たに一つ作ってみる。 POV-Ray プラグインというのを作ってみることにした。POV-Ray とは、レイト レーシングによって 3D CG をレンダリングするアプリケーションである。

POV-Ray の説明は、下記ページを見てほしい。

POV-Ray の本拠地である。

サンプルなどについては、このページにまとめておいた。

# apt-get install povray-3.6 povray-3.6-examples

Debian の場合はこのようにして install できる。 7

このページに完成した POB-Ray プラグインの使い方がでている。

{{povray
 union{sphere{z*9-1,2}plane{y,-3}finish{reflection{,1}}}background{1+z/9}
}}

ページ中にこのようにプラグインを記述すると、そのプラグインに書かれた記 述を元に POV-Ray が起動し、その結果としての画像が埋め込まれる仕組みに なっている。また上記のテキストエリアプラグインとほぼ同じように、 POV-Ray に入力するレイトレーシングのソースコードをその場で編集して更新 できる。このようにすると、3D CG のコードをその場で書換えながらちょっと づつ直していくことができる。 (このサンプルは、POVRay Short Code Contest, Round 3より引用させていただきました。 )

  • qwik/lib/qwik/act-povray.rb

こちらにソースコードがある。 肝となる、コードの実行部分だけ見てみよう。

   def povray_generate(content)
     files = @site.files(@req.base)
     base = content.md5hex
     filename = "#{base}.pov"
     pngfilename = "#{base}.png"
     return pngfilename if files.exist?(filename)

     files.overwrite(filename, content)
     # Render it background.
     t = Thread.new {
        path = files.path(filename)
        pngpath = files.path(pngfilename)
        pngtmppath = "/tmp/#{pngfilename}"
        system "#{POVRAY_CMD} #{path} -O#{pngtmppath}"
        system "#{MV_CMD} #{pngtmppath} #{pngpath}"
     }
     return pngfilename
   end

このようにして、テキストの内容の md5hex を取得して、それを元にファイル 名を作っている。こうすることによって、テキスト内容が変更したら再度レン ダリングするという仕組みを容易に実現している。

授業における Wiki の利用

普通に考えると、このような 3D CG のレンダリングだったら、直接自分のマ シンで動かした方が良さそうに思えるかもしれない。しかし、教育目的を考え ると、この仕組みは大変使えるように思う。例えば POV-Ray を使って作品を 作る授業を考えてみよう。通常であれば、まず最初にアプリケーションのイン ストールから授業を始めるのだが、この仕組みがあれば最初は Wiki ページ中 の POV-Ray プラグインを使って使いはじめることができる。そして、少し慣 れてきてからアプリケーションのインストール方法を教えるというように、段 階を追って進めることができる。

「アプリケーションをインストールするくらい簡単じゃん」と思う人もいるか もしれない。しかし、例えば大学一年生への授業を考えると、まだコンピュー タを持ってない人も結構いる。場合によっては、まだ一度もパソコンを触った ことが無い人さえいる。そのような場合には、このように入口の敷居を低くす るための仕組みは、大変有効である。

また、POV-Ray の使い方を説明するためのドキュメントを作るのにも役に立つ だろう。普通は、POV-Ray のソースとレンダリング結果の組が繰り返し出てく るものになる。そのような文章を編集するには、この仕組みは大変役立つだろ う。最終的にみんなの作品をオンラインで見ることができるようにするのにも 使えるだろう。

Wiki ページとして実現していることの利点は他にもある。自動的に編集履歴 が残るため、作品制作の過程がそのまま残ることになる。つまり、これまでレ ンダリングしてきたソースと画像の組が全て自動的に残るのである。qwikWeb にはタイムマシーンモードという過去の編集履歴をインタラクティブに見るこ とができる仕組みが用意されているため、このモードと組み合わせると過去の レンダリングの変遷をまるで動画のように見ることができる。これは実際にやっ てみると予想以上に面白かったのでおすすめである。

ここにあげた仕組みは、テキストによるソースと、その結果の表示の繰り返し からなるアプリケーションであれば同様に扱うことができる。あてはまる事例 がありましたら、ぜひトライしてみるといいかもしれません。

まとめ

Wiki ページ中には、プラグインによって複数の種類の要素を埋め込むことが できる。その埋め込まれたそれぞれの要素を、個別に編集できるようにすると 大変便利である。Web ブラウザだけでその埋め込まれた要素を編集できるよう になるので、一番最初に取り組む際の敷居を下げることができる。授業などに おける利用を考えると、このような仕組みは大きな意義があると考えられる。

著者について

えと こういちろう (Rubyist)。

Rubyist の割には、YAPC に参加してるし、Shibuya.js では発表までしてます。

qwikWeb の仕組み 連載一覧


  1. 一応、アスキーアートで表現するという手もありますね。 

  2. 実際のところ、SVG のような画像をエディタで編集するのは難しい。不可能に近い。しかし、ここでは可能性について論じていると解釈してほしい。 

  3. Wiki エンジンとしては例外的に、MediaWiki ではページ中への図の埋め込みに対応している。Wiki のテキストに同じように図を指定すると、SVG 要素としてページに埋め込まれるようになる。 

  4. ここではあえて、hello と bhello と二つのプラグイン名を変えている。しかし、一つのプラグインでインラインとブロックの両方に対応するようにすることもできる。 

  5. 「?」が嫌いだからなんですね。というか、URL が汚なくなるのが嫌いなんですね。 

  6. このようにほとんど同じような処理がほんのちょっとだけ変えられて出現するのは好ましくない。リファクタリングしたいところである。 

  7. この POV-Ray は、実はいわゆるオープンソースではない。正確には、Debian フリーソフトウェアガイドラインに準拠したライセンスではない。そのため non-free を使えるようにしていないと、apt-get では入れられない。なぜ POV-Ray がいわゆるオープンソースではないのかは、POV-Ray 法規のページで確認できる。