実装したものと実装のための情報。
このWikiを洗練させるための試作。
http://x.pmint.name/
- :i/プロトタイピング/01
- :i/プロトタイピング/01/検索
- :i/プロトタイピング/02
- :i/プロトタイピング/03
- :i/プロトタイピング/04
- :i/プロトタイピング/05
- :i/プロトタイピング/p05
- :i/プロトタイピング/Snippet
- :i/プロトタイピング/Snippet/AutoloadAccessor
- :i/プロトタイピング/Snippet/Mergeable.cs
- :i/プロトタイピング/Snippet/Nestable.cs
- :i/プロトタイピング/Snippet/NotNestable.cs
- :i/プロトタイピング/Snippet/NotNestables.cs
- :i/プロトタイピング/Snippet/Ol.cs
- :i/プロトタイピング/Snippet/PageElementMerge.cs
- :i/プロトタイピング/Snippet/PageElementMerge2.cs
- :i/プロトタイピング/Snippet/Tokenize0.cs
- :i/プロトタイピング/Snippet/ToWikitext.cs
プロトタイピング05 †
どこから実装するか †
MV*のモデル層の責務分担と構造(依存関係と多重度)から。でもXのモデルはページとページ/要素ぐらい。
その後は自由に、思いついた順に。
実現可能かはいつでもサンプルを作成して確認。
検索/フォーマットはPage.Elements.Findに含める。
利用者はUserクラス、データはPageになっているのでそれを読み込み。権限はページ属性で。
資料 †
やること †
プロトタイピング/05 †
やること †
- ページの永続化と復帰
→ フレームワーク/WikiEngine
ページ/名前が必要。 - ページ/名前
X/Pages/Name
外部名4区分と内部名、順不同パス(4区分中の"Entry") - ビューとテンプレート
WikiEngineレベルでのビュー。
ページ/属性が必要。 - ページ/属性
属性の継承
権限の継承
データアクセスとデータコンテキスト(属性コンテキスト)
X/Elementが必要。 -
下位展開 -
プレビューモード
セッションが必要。 -
セッション
→ フレームワーク/Webアプリケーション
認証が必要。 -
認証 - X/Element
全てURIで、セレクター(参照記法) - :i/プロトタイピング/p05
プロトタイプ05+04+03 †
05の次。
概要図 †
docs.google.com
順不同パス †
まだ紹介してない。
「はてなブックマークのタグ絞り込みのように順不同」
multi-gram→ページ名 †
fw/Web †
docs.google.com
プレビュー †
- PagenameのWiki(-name)部分補完
下位展開 †
クラス構成 †
自動リンク †
リンク規則、danglingリンク規則、ページ名(フルパス)→内部名
各クラスのプラグインは書かない。
あとはVisitorをElement周辺に付け足すだけでクラスが揃う。
ページ名…Pagename
fw/WebApp → フレームワーク/UserAgent
資料 †
フレームワーク †
:t/Webフレームワーク部分と、その上の:t/Wikiフレームワーク部分。
ページ/:t/要素が動く環境を作る。
ユーザーからのリクエストを対応する要素に伝えて、その結果をレスポンスに変える。
権限 †
権限設定と表示。
自動リンク…下位展開を考慮。一部を#化してリンク。
自動リンク規則…PlainsにAutoLink追加→HTML化のときに他のPlains系と異なる出力になるので不可。Notations系として実装するならフレームワークにPatternを提供しないと。
ページ作成記法、ページ編集記法…パラメーターはデフォルト値。作成は状況により編集に、編集は状況により追記になる。
自動リンク規則は相対パス→絶対パス変換に一手間加えたもの。
:t/権限は「錠」と「鍵」の2種類。
:t/属性に書く。
プレビューとタイムマシンとサブセット †
プレビューWiki
Wiki(-name)の補完ルールを変える。Pagenameクラスで対応すればいいだけ。
リクエスト-レスポンス間にWiki(-name)は一定。
存在しないページはデフォルトWikiから探す。デフォルトWikiにも存在しないなら、プレビュー用Wikiのページが存在しないときの処理。
:t/汎用記法で:t/埋め込み機能を呼び出して権限情報を表示。
ページとその属性名を全て:t/URIで指定・参照・ページ上にレンダリング。
下位展開 †
:t/下位展開は複数のページをまとめて見せる機能。
タイムマシンWiki
自分が見てきた履歴。ページ/履歴は(同じ見解を見てる)みんなの履歴。
Revisionの補完ルールを変える。Pagenameクラスで対応すればいいだけ。
リクエスト-レスポンス間にRevisionは一定。
存在しないページは存在しないものとする。
対象になるページは:t/順不同な:t/名前での下位に位置するページ。
ほか †
- 主要機能
- ページ/章
投稿時の処理。 - 利用者 User
ページの一種。ただしフレームワークから直接、利用者の情報として利用。 - 構築 クラスなし
設定をページに記録すること。 - 見解と投票 Pageで
ページ間の:t/リンクも下位展開に対応する必要がある。
まとめられたページは:t/見出しとして表示されるので、リンク先もそこへつなげなければならない。
ページごとに:t/権限判定と:t/代表の適用が必要。
プレビューモード †
:t/プレビューモードは:t/名前の補完ルールに細工をすることで実現。
タイムマシンモードも同じ発想。
プラグイン †
名称「PageElement」または「Element」。「Notation」は記法なのでRegexを使って定義するもの。「プラグイン」は実装の仕方なので使わない。
紹介 †
相変わらずページの保存が出来ないバージョン。
サンプルデータとして http://wiki.pmint.name/ のページをインポートしてみた。
実装したこと †
- 下位展開
このシステムはページが他のページを含むツリー構造になっている。1つのページに含まれるページ階層を深い階層まで一括表示。 - 下位展開を利用した自動リンク先
深い階層のページは浅い階層の一部(見出し)として表示されるので、素直にはリンクしない。浅いページ/深いページ[?]を、浅いページ#深いページへのリンクに。 - プレビューモード
編集プレビュー中に他のページを開いて、編集の影響を見ることが出来る。「仮の未来」を見る機能。 - タイムマシンモード
過去のある時点でのWikiを再現。「実在した過去」を見る機能。 - アクセス制御
アクセスコントロール。ページ側に「錠」となる属性、ユーザー側に「鍵」となる属性を与えて随時適合するかどうか判定。適合することを各ユースケースの事前条件に。 - リンク一覧
内部リンク(同一Wiki内リンク)のリンク先一覧。リンクの属性「関連名」でフィルタリング。これで「あるユーザーが閲覧できるページ一覧」と「あるページを閲覧できるユーザー一覧」を生成。
記法は特に考えず#links(リンク先のほう|リンク対象テキストのほう|全部)
プラグイン側で定義できるものはクラス定義で †
そのほか †
- multi-gram
自動リンク処理で行なっていた”bi-gramを使ったページ名探索”。連続する2文字をインデックス化していたが、数字列では1つのキーに集まり過ぎ、漢字を使う単語では分散し過ぎだったので、文字種により0文字から3文字を使うよう変更。
実装方法 †
- ページ作成フォーム記法
新規ページ作成の入力欄生成。入力受け付け、ページ生成。
とりあえず #newpage()
[Notationsにクラス作成] - 自動リンクの下位展開対応[Autolink]
/ページ名#セクションID
リンク対象文字列が /セクション名/ページB/ページA ならリンク先は /ページA/ページB#セクションID/ページ名#セクションIDでもリンク対象になるように。リンク先をコピペしてもリンクするように。
- ページ名を4区分に[Pagename]
Wiki, Entry, Side, Revision - ページ→ページ(→セクション0〜1コ)
Compositeパターン - 閲覧時展開[Section.toHtml()]/編集時展開[Section.toWikitext()]
- プレビューWiki
[Pagename、Wikiを明示指定]
Previewモード
指定されたWikiにページが無ければ、デフォルトWikiのページを使う。
デフォルトWikiにも無ければ、指定されたWikiでページが存在しない処理。 - タイムマシンWiki
[Pagename、版の補完方法で](プレビューとは実装方法が違う)
Back way to ... モード
日時指定→版の補完時に版番号に置き換え
日時指定用のUI: 版の中から選択、あらかじめページ名と見解が指定されていないと
ページ(Entry)が無ければ、普通にページが存在しないときの処理。
- -------------------------------------
データ変換 †
テキスト→オブジェクト→HTML
オブジェクト→永続オブジェクト
「C#に依存するコードが増えてきましたが」
そのうちやること †
自動リンク †
もし記法やプラグインをまったく使えないWikiEngineを作ったら…
テキストを記録するだけ。
ファイル名とテキストを与えると記録、ファイル名のみならテキストを出力。
これにプラグイン独自のデータと処理を加えて、プラグインごとに違うHTML出力ができるようにする。
中心はプラグインを作るためのAPI。
アカウント †
利用者
派閥 †
派閥[?]
プラグインは既存クラスの「プラグイン版」 †
- Usecaseプラグイン
Plugin/Usecaseを実装。
SubUsecaseも使うならクラス名自由。
フレームワークは関わらないので。リクエストの任意のパラメーターを使っていい。 - PageElementプラグイン
Plugin/PageElementを実装。
継承をするよりもコードテンプレート
クラス †
→クラス[?]
→X
- X(Wiki)
フレームワーク/WebアプリケーションのComponentにあたる。
クラス名は…
View::ユースケース名::リクエスト名、Control::ユースケース名
- PageElements
記法別クラスの上位クラス。
記法別クラス(Notations)はWikiTextを読んで自身が理解できる記法だけオブジェクト化する。
WikiTextの先頭からではなく、記法別にオブジェクト化。
図 †
クラス図
クラス図
フレームワーク間の関係 †
HTMLを要求するのはフレームワーク/Webアプリケーションのほう。
WebアプリケーションはWikiEngineを3回呼ぶ。
- エントリーポイント
- フレームワーク/Webアプリケーション
Xオブジェクトを生成。 - フレームワーク/WikiEngine
Xオブジェクトを作る(だけ)。 - フレームワーク/Webアプリケーション
Xオブジェクトにリクエストを伝える(そのまま渡すのではなく、変数の形で) - フレームワーク/WikiEngine
自身の状態を変化させる。状態は永続化する。 - フレームワーク/Webアプリケーション
XにHTMLを要求。 - フレームワーク/WikiEngine
HTMLを生成。 - フレームワーク/Webアプリケーション
HTMLにヘッダーを付けてWebページ化。
Wiki、Entry、Side、Revision †
いずれもPageクラスのインスタンス名。
ただし、実体があるのはRevisionだけ。その名を変えたのがEntry、Side。
- -------
排他制御 †
永続化クラスを排他制御不要な方式に。
WikiはEntryの構造体。
ルートページから始まるツリー構造。
モデル系クラスでは自分で自身を書き換える。他のクラスを扱うのはPageFactoryくらい。
各Entryもそれぞれツリー構造。
つまりツリーの要素からまたツリーが始まる2段ツリー構造。
エラーレベル †
- 利用者向け情報 Info
不正なリクエストなど。ページのメッセージ欄に出力。
X/Error/Info[?] - 警告 Warning
デバッグ用ログ出力と管理者グループ宛メールに出力。
処理続行。
X/Error/Warning[?] - 致命的エラー Fatal
処理中断。
開発時のアサーション違反はエラー、運用中は警告だけ。
X/Error/Fatal[?]
実装からTips作成 †
実装からTips作成、よりよいコードのヒント集め。
実装以外にも、アイデア、方式、UIなどでも。
排他制御 †
更新コマンドのキューイング。
キューと要素の関係。
キュー→ファイル(名前順)
要素→永続化されたCommandオブジェクト。
ファイルロックは…PageFactoryが永続化されたオブジェクトを復帰/保存するときと、オブジェクトが自身の関連ファイル(他のオブジェクトの所有物でないファイル)を操作するときくらい。
モデル系クラスでは自分で自身を書き換える。他のクラスを扱うのはPageFactoryくらい。
仕様の分け方 †
フレームワークは空気。ページが本体でユーザーがそれを利用できるようにするのがフレームワークの役目。
UIの内訳
1. 読みUI
ページ/履歴含む。
2. 書きUI
エディターなども。
3. 探しUI
検索の他に関連情報やおすすめの類も。
4. 組み立てUI
管理とWiki構築。テンプレートやデータコンテキストなどページ/要素を使ったプログラミング部分。
フレームワーク/Webアプリケーション
Componentの使い方 †
- WikiEngine(の代表的なクラス)を1つのComponent(MVCセット)にする
WikiEngine内部ではクラス間は記法で関連するので。似ているけど別の仕組み。
UsecaseやRequest、Query(検索/クエリーではない)もWikiEngineの一部。Componentの<<control>>や<<model>>部分になる。
WikiEngineの全クラスをComponentにしなくていい。フレームワーク/Webアプリケーションと関わりのあるクラスだけComponentを継承。 - サイトのグローバルナビを1つのComponentにする
ASP.NETを使うなら †
非ASP.NET MVC。Wiki - View(.aspx) - Controller。Viewはマスターページのようなものを1つだけ。
プラグイン無し。ControllerでReadなどを実装。というかControllerがプラグインのようなもの。
フレームワーク/WebアプリケーションはASP.NETと競合するので後回し。
フレームワーク/WikiEngine以上を作る。
実装からTips作成 †
実装からTips作成、よりよいコードのヒント集め。
実装以外にも、アイデア、方式、UIなどでも。
PageElement系クラス †
- Wikitext
処理前の文字列状態。
stringをPageElementとして扱えるようにするクラス。stringからPageElementツリーを作るクラス。 @done - Document
1ページに1つだけ。PageElementツリーのルート要素。 - Notation系
- Nestable系 @done
中に他のPageElementを含むことができる。 @done
- Nestable系 @done
- Autolink
自動リンク。Plaintextを含む。 - Plain系
Plaintextを末端とするネスト構造。Plain系のなにか→Plain系のなにか→Plaintext。
Plaintextは別。PageElements構造の末端。
ページの設計 †
物理:
- 領域
テキストファイルを複数組み合わせて1ページ
保存しなければならないのは投稿されたままのデータ
- 表
- 属性領域
- 本文
- 裏
- 属性領域
- 書き込みキュー
- 1トランザクションのなかでキューをページに反映
- 最新版
キューを全て反映したページ
- 現在版
古いかも?参照用
- キューの内容は新しいページそのもの
差分ではなく単体で新しいページになれる。処理の単純化のため。
反映時は全面書き換え。
────────────────── 属性:
ページの属性はただNotationを書くだけ。参照時に内容と統合されて1つのelement構造になる。書くところが分かれているだけ。
- 裏
- 内部名
- 凍結
凍結してるか?はページ/属性。
編集不可能→編集権限を無視してどんな場合も権限なしと判断。
凍結解除してから編集、再凍結までを一度に行うことで編集可能に見せることはできる。
編集ビューは凍結されていても閲覧権限で見られる。
- 不特定多数には非公開属性=特定者にのみ公開属性
公開範囲別に複数の属性になる?
- 隠し属性、ページ名が明示されたときに見える。
- 古い自動生成ページを自動更新
- 自動更新間隔。elementが更新間隔を持つ。更新はページごとなので、ページ内で最も短い間隔で自動更新。自動生成ページだけでなく一般化。
ページの属性
- 基本がリンクか埋め込みか。という属性。
- 属性値を書く欄。ほかにページ名の接頭辞も属性値の一部。
───────────────────── 内容:
- 見出し始まり、無ければ自動で作る
- ページの分割、統合、入れ替え支援
- バックリンク
- ウォッチリスト
- Web標準
- 更新日時一覧には編集対象ページ(編集対象としてパラメーターになったページ)と、実際に更新されたページの両方を載せる。
できること:
- 自分宛のクエリーを読める
- 自分宛のクエリーはHTML出力で作る
- 添付ファイルもページ化
- HTMLテンプレートもページに書く
- データベースでもある。elementクラス別のデータベースでもある。
- サイトのアクセスログでもある。ページに記録
- クリップボードでもある。
- 多階層ビュー、埋め込みのネスト。html1ページはヘッダーやシステムメッセージ領域など、複数層の埋め込みでできている。
- 存在しないページはない
- 更新できるのは自身だけ。遅延書き込みと前バージョン参照
- DOMアクセス
名前で3層組み合わせ:
内部名と表示名
項目→ディレクトリ、見解→ディレクトリ、版→ファイル
内部名を使って
版、見解はページの応用。
- 代表
ワイルドカードを使った一覧から1つ選ぶ仕組み。
- ワイルドカードで一覧
ワイルドカードを使った不完全な指定、で、代表を要求しない
- 項目指定なし、つまり何にもなしのリスト要求
全ページ一覧
代表要求するとルート(FrontPage)
- 見解指定なしのリスト要求
見解一覧
投稿できないので、一覧は表示だけ。
代表要求すると有力見解←投票で
- 履歴指定なしのリスト要求
版リスト
投稿できないので、履歴一覧表示だけ。
代表要求すると最新版
履歴(版だけ組み合わせ):
履歴はモデルに含めない。履歴はワイルドカードを使って検索した一覧。
- 2履歴間の差分
- 最新の差分は閲覧ビューでも強調
クライアント側で
- 編集履歴(差分)表示
異なる見解の最新版比較(差分表示)も?
通常の差分は同項目・同見解・異版間のもの。
下位:
- 属性の継承
下位展開と関係ある?
- 属性の継承、下位ページに
- 下位展開(閲覧時/編集時)
下位ページ展開
- 下位ページの更新は上位の更新日時を変えない。更新日時一覧に上位ページ名も載せる。それで同じ効果。
投票:
見解に投票
───────────────────── Archive:
- 複数のビュー。elementクラスごとに分ける・分けない、どれとどれが同じかなどいろいろ。 @done @project(できること)
版、履歴: @done @project(物理 / 版、履歴 @done)
Merge可能かどうかをインターフェイスで。: @project(Merge可能かどうかをインターフェイスで。) @done
インスタンス生成せずに呼び出すメソッドはインターフェイス化できない。
プロトタイピング/ †
- :i/プロトタイピング/01
- :i/プロトタイピング/01/検索
- :i/プロトタイピング/02
- :i/プロトタイピング/03
- :i/プロトタイピング/04
- :i/プロトタイピング/05
- :i/プロトタイピング/p05
- :i/プロトタイピング/Snippet
- :i/プロトタイピング/Snippet/AutoloadAccessor
- :i/プロトタイピング/Snippet/Mergeable.cs
- :i/プロトタイピング/Snippet/Nestable.cs
- :i/プロトタイピング/Snippet/NotNestable.cs
- :i/プロトタイピング/Snippet/NotNestables.cs
- :i/プロトタイピング/Snippet/Ol.cs
- :i/プロトタイピング/Snippet/PageElementMerge.cs
- :i/プロトタイピング/Snippet/PageElementMerge2.cs
- :i/プロトタイピング/Snippet/Tokenize0.cs
- :i/プロトタイピング/Snippet/ToWikitext.cs