MultilineクラスとMultilineメソッド

Preview:

DESCRIPTION

クラス名やメソッド名に改行がつかえるようにSmalltalkを拡張するとどうなるかという話。アスキーアートでメッセージ送信

Citation preview

第27回 Smalltalk勉強会 - Smalltalkの超能力

2010 Masashi Umezawa

動機

もっとクラス名、メソッド名をわかりやすくできないか? 長い名前とか、読むのが大変

ぱっと見ただけでわかるほうがいい

クラス名やメソッド名で改行つきの文字列を

使えれば、表現力が格段と高まるのではないか?

いらないクラスということがすぐにわかる

Object subclass: #'/ \

/ ─ ─\/ (●) (●) \ よく考えたら俺いらないな| (__人__) |/ ∩ノ ⊃ /( \ / _ノ | | .\ “ /__| |

\ /___ /'

instanceVariableNames: ''classVariableNames: ''poolDictionaries: ''category: 'Test-Multilines'

実装にあたって技術的には簡単

もともとクラス名やメソッド名はSymbolのインスタンス

Symbol自体には改行を含めることができる

○ #'改行文字列' のようにシングルクォートでくくればよい

開発環境の制限を外していくだけ

Multiline class

クラス名の先頭文字と使える文字に改行を追加

Character >> canBeGlobalVarInitialself = Character cr ifTrue: [^true].^ (EncodedCharSet charsetAt: self leadingChar)

canBeGlobalVarInitial: self.

基本これだけ

Multiline method (1)

開発環境の抵抗がなかなか強かったので、メソッド追加で対処

ClassDescriptiopn >> addAAMethod: aa body: bodyCode| code aaSymbol |code := 'tmp' , String cr , bodyCode.aaSymbol := aa asSymbol.self compile: code classified: ''.self addAndClassifySelector: aaSymbol

withMethod: (self methodDict at: #tmp)inProtocol: 'AA' notifying: nil.

self removeSelector: #tmp

Multiline Method (2)

各クラスのMethodDictionaryをいじってあげればよい tmpという名前でまずメソッドをコンパイル

コンパイルされたバイトコード(CompiledMethod)をアスキーアート(AA)をキーとして登録しなおす

tempのメソッドは消しておく

これでできた!

パーサライブラリの拡張 (1)

ワークスペース等で実行しやすいように既存のSmalltalkパーサライブラリを拡張する

DSL系を実装するには常套手段

Smalltalkでは自分をコンパイルするコンパイラクラスをクラス毎に指定できる

○ compilerClassメソッドのオーバーライド

今回は単にデフォルトのスキャナに手を入れるだけ

パーサライブラリの拡張 (2) スキャナにバッククォートのトークンを加える

AAをバッククォートで囲むと、クラスやメソッドの識別子としてパースされるようにしたいため

Scanner class >> initialize...newTable at: $` asciiValue put: #xBackQuote....

バッククォートを選んだ理由 他で使われていない

存在感が薄いのでアスキーアートを邪魔しない

パーサライブラリの拡張 (3)Scanner >> xBackQuote

self step.buffer reset.[hereChar = $`

and: [aheadChar = $`ifTrue: [self step. false]ifFalse: [true]]]

whileFalse: [buffer nextPut: self step.(hereChar = 30 asCharacter and: [source atEnd])

ifTrue: [^self offEnd: 'Unmatched string quote']].self step.token := buffer contents asSymbol.tokenType := #word

まじめに読む必要なし

xSingleQuoteメソッドをパクる

tokenTypeを#wordにする => 識別子になる

デモ AAクラスの定義

AAメソッドの定義

実行`

|┃三 ∩___∩|┃ | ノ ヽ|┃ ≡ / ● ● | きたクマー!

____,|ミ\___| (..●..) ミ|┃=___ |∪| \|┃ ≡ / ヽノ 人 \ ガラッ` new

`/⌒ヽ

∩ ^ω ^) うはwww| ⊂ノ

| _⊃ し ⌒`

まとめ

Smalltalkで、内部DSLをつくるのは非常に簡単

グラフィカルな表現もお手のもの

まじめな開発ではAAクラスとか使わないでください

Recommended