「入門 UML 2.0」を読んだ。 UMLってユースケースを表現するためのものでしょ?と思っていて、図を使ってユースケースを書く必要に迫られることも無かったのであまり勉強する気にもなっていなかったのですが、Plant UMLというテキストでUMLを既述できるものを知り、図を描くのにテキストで記述できるのは便利そうということで読んでみることにしました。
読んでみると、そもそもユースケース図を描くたものものという認識が誤りで、ユースケース図を表現することにも使えるが、それ以外の様々なものを表現するために使えるものであるということがわかりました。また、表現の仕方が定義されていて、UMLを知っている人であれば書き方を説明せずに記述できるということもよく分かりました。そのため、記述ルールについての凡例を書く必要もないのです。
UMLは既述したい目的毎に図の書き方がいくつも用意されています。そして、その目的や使い分けについて説明しています。しかし、その使い方は限定的ではありません。ある特定の種類の図ですべてを表現する必要はなく、その図で表現したい箇所だけをその図で表現し、そのほかの場所は異なる種類の図で表現しても良いとされています。結局は表現すべき重要な事柄を、それを表現するのに適切な図を使って表現すべきとしています。 つまり、何を表現すべきかを考えて使い分けるということです。
この本を読むことで、システム設計においてどのような情報を表現するべきかということがわかると思います。全体の概要を示したい場合や、特定部分の詳細について説明したい場合がありますが、それらがどのような種類の情報であるか、また混ぜるべきではない情報というのはどういうものかというのがなんとなくわかると思います。実際に書いて表現することを繰り返すことで、システムのどの部分をどのように表現するべきかというのがより直感的にわかるようになってくるのだと思います。
ところで、Plant UMLはテキストで記述したものをUML図に変換する仕組み(Webサービス、Javaプログラムとして提供されています)ですが、テキストをエディタで変更すると即座にその結果のUML図が変更されるという使い方ができます。
Vimでは、previmというpluginを使うことで実現できます。 previmはそもそもMarkdownに対してのプレビューを提供するものでしたが、PlantUMLにも対応したのです。
これを使いたかったという気持ちもあります。
そんなわけで、今後、図を記述する必要がある場合にはPlantUMLを積極的に使っていきたいと思っています。
vim plugin を作っていてなかなか解決できなかった課題のメモです。
vim ではファイルタイププラグインという種類のプラグインが作成できます。
ファイルタイププラグインはファイルタイプに合わせて挙動を変えることができるようにするためのプラグインです。
vim はファイルを開いた際に、そのファイルがどのファイルタイプか判別します。
ファイルタイプはC言語のようなプログラミング言語毎にあらかじめ定義されていますし、自分で作成することもできます。
自分で作成する場合には、ファイルタイプ名を決めて、そのファイルタイプの場合にどのような挙動にするかを定義したプラグインファイルを作成します。
例えば、ファイルタイプ毎に異なるマップを定義することができます。
その場合、プラグインファイルには定義したいマップコマンドを記述します。そうすることで、特定のファイルタイプの場合にのみそのマップコマンドが実行されるようになります。
ところで、ファイルを開くたびにそのファイルがどのファイルタイプかを判別する必要がありますが、自分で作成したファイルタイプのことはvimは知らないので、どのファイルが自作のファイルタイプに該当するかを定義する必要があります。
それには何らかの方法で以下のようにしてファイルタイプを指定する必要があります。これを実現する方法はいくつかありますが、その一つに ftdetect/*.vim というファイルを使う方法があります。
set filetype=aaaa
ftdetect/*.vim というファイルは、ファイルを開いた際(厳密にはバッファを開いた際)に自動的に読み込まれて実行されるファイルの一つです。
runtimepath配下にあるftdetect/*.vimを実行します。
このファイルは、以下の設定がされていないと読み込まれないようですが、これだけを設定していても読み込まれない場合がありました。
set runtimepath+=~/where/to/pluginpath/
filetype plugin on
読み込まれるようにするためには以下のように、runtimepathの設定の前に filetype offを設定する必要がありました。
filetype off
set runtimepath+=~/where/to/pluginpath/
filetype plugin on
どこに書くか
blogを書き始めようとするときに、まずはどこに書くかを決める必要があります。
世界中で人気のWord Pressというソフトウェアを使う手もありますが、ややニッチ(?)なMovable Typeというソフトウェアもあります。 Movable TypeはSix Apartという会社が開発しているソフトウェアで、商用ブログサービスとしてType Padというものもあります。 私はMovable Typeに書くことにしているのでMovable Typeを使います。
何で書くか
Movable
TypeはWebインタフェースがあるので、ブラウザで書くのが通常ですがブラウザのテキストフォームに書くような形になるので使いづらいです。使いやすくするにはjavascriptを書いて機能拡張するなどの工夫が必要です。しかし、世の中には文章を書くためのツールとしてエディタがいくつもあり、それらを使う方が文書を書くには都合が良いのです。当たり前ですね。Movable
TypeにはWebのGUIインタフェース以外にWeb APIも提供しています。このWeb
APIはData APIという名前で定義されていて、これを使うと記事の新規作成や編集なども行えます。
そういうわけで、エディタで書いた文章をData APIを使ってMovable
Typeに投稿する仕組みが実現できそうです。
これができればエディタで気持ちよく文章を書いて、そのままMovable
Typeのblogエントリとして投稿できるはずです。
欠点があるとすれば、写真などの画像を入れようとすると難しくて、WebのGUIインタフェースの方が直感的に配置できたり、アップロードもできるので操作性は上です。
ですので、画像の取り扱いはWeb
GUI、文字はエディタと使い分けることにします。
さて、エディタで書いた文章をData APIを使ってMovable
Typeに投稿しようと思いますが、どのような操作性が良いでしょうか。
気軽に編集できるようにするには、エディタでテキストファイルを保存するような操作でData
APIを使って投稿できる、修正できるというのが良いでしょうか。
ローカルに編集したり、Data
APIを使って編集を反映したりと使い分けられるようにするのも手です。
とりあえずはローカルにあるファイルを編集し、上書き保存すると、Data
APIを使ってMovable
Typeの記事も編集(変更)されるという仕組みを目指します。
足りない機能
エディタでファイルを保存すると自動的にData
APIにアクセスする仕組みを実現する必要が出てきました。
自動で行うというのがポイントですが、そのためには以下のような方法が考えられます。
- ファイルの更新チェックをリアルタイムで行うようにカーネルフックモジュールを用意する
- ファイルの更新チェックを行うデーモンを用意する
- エディタの保存処理をフックする仕組みを用意する
カーネルフックモジュールで実装すると、色々と無駄で遅くなりそうです。
デーモンを用意するのも大げさな感じですし、無駄な感じです。
そこで今回はエディタの保存処理をフックする仕組みを用意することにします。
保存処理をフックできるようなエディタはいくつもありますが、筆者はvimが好きなのでvimを採用します。
vimはemacsと同じく拡張が用意で基本的になんでもできます。
vimの場合は、vim
scriptという形で保存処理をフックする仕組みを記述すれば実現できます。 vim
の設定ファイルはvimrcに記述しますが、この設定ファイルもvim
script形式です。
そのため、vimrcに保存処理のフックすく仕組みを書けば解決できますが、その仕組みが巨大であったり、汎用的にできたり、公開したい場合にはプラグインとして作成することもできます。
今回はMovable
Type利用者でかつ、vim利用者のためのプラグインを作成することにします。
足りない機能を補う
vim プラグインに必要な機能はData
APIへのアクセスに関するものと、ローカルファイルの取り扱いに関するものに分けられます。
Data
APIはHTTPアクセスなのでHTTPリクエストとレスポンスの取り扱いが必要です。
この部分はvital.vimを使います。
ローカルファイルの取り扱いは自分で用意します。
Data
APIで取得したエントリはJSON形式で取得できますが、それをローカルファイルに保存する前にエディタで編集しやすい形に整形する必要があります。
また、その逆にローカルファイルの内容をData
APIで投稿する際には逆の整形を行う必要があります。
こうした処理をちまちま書いていくといずれ出来上がります。
プラグインの処理の詳細は別の記事に書きますので、そちらを参照してください。
作成中の vim プラグイン vim-mtdataapi
記事を投稿する
プラグインが完成したら、ようやく記事を投稿できます。 長い道のりでした。
実践Vimを読みました。 本書は初心者向けの内容ということですが、触ったこともないような初心者向けというよりは、vimtutorを終えて基本的な操作がわかった人向けという感触です。 タイトル通り、実践的な内容となっていて、実現したいことの実現方法をいくつも紹介しながらメリット、デメリットを紹介していて、それぞれで使用するオペレータやモーションの理解が深まるようになっています。そのため、どういう場合にどういうオペレータを使うべきかを理解できるようになっています。 なるべく繰り返し操作がしやすいような操作を求めていくと、実現したいことにぴったり一致するオペレータを知る必要が出てきますが、いろいろなオペレータを紹介することで、よくある操作を実行するのに必要なオペレータは既にあるということをうまく示せているように思います。繰り返しを基本とするように考えていくと、段々とどんなオペレータがあるのか調べる必要が出てくるので、今後の上達にもつながっていくと感じます。
印象に残った使い方としては、マークの使い方(vimgrepの実行前とかquickfix関連の実行前とかにマーク設定)とか、挿入モードやコマンドラインモードでのC-rを使った文字入力(C-r0とかC-rC-wとか)とか、globalコマンドの使い方(実行するexコマンドに、rangeを与えて範囲を広く指定するとか)です。でも、そもそも繰り返し可能にするためにどういうオペレータにすべきかとか、マクロの直列実行、並列実行とかそういう考え方が整理されて記述されているのがとても理解の助けになりました。
今後もvimの上達に向けて精進したいと思います。
msys2を使ってみることにして、とりあえずvimのビルドしようと思ったらrubyがなかったので、rbenvを入れようとしたらなぜか動かない。
$ ~/.rbenv/bin/rbenv init
.rbenv/bin/rbenv: 行 1: ../libexec/rbenv: No such file or directory
ファイルは存在しているのに無いと言われてしまう。 同じ悩みを持つひとは、これをシンボリックリンクに変えて対処したようだ。こちら参照。 同じようにシンボリックリンクにしてみると確かに動く。 .rbenv/bin/rbenvの中身は確かに1行しかなくて、これを実行するだけなのでリンクに置き換えても問題なさそう。 問題は相対パスで書かれたものを実行できないということなのか。
切り分けのために、rbenvの中身を絶対パスに変更してみると。。
うん。動く。と思ったら引数が渡らない。 リンクのように振舞っているということか?相対パスの始まりが、コマンド実行時のカレントディレクトリになっているみたい。 試しに ~/.rbenv/bin に移動してから実行するとやはり動く。 相対パスの解釈の仕方が問題のようだ。 でも、この後の調べ方がわからない。相対パスを実行しようとするのは誰なのか。bashか? bash -xで見ても特に何も出ない。
mtdataapiというvimのpluginからMovable Typeへの記事投稿の際、markdown形式で投稿できるようにしました。 変換にはpandocを使っています。
mtdataapi
Movable Type というCMSを使ってブログを書いていますが、基本的にブラウザで入力するため文章入力が非効率に感じることが多々あったので、vimから投稿できるようにvim pluginを開発しています。
単純な更新ができるようになってきたので、一旦githubに公開しましたが、とても一般の方が使える状態ではありません。
需要があるようでしたら、issueやSNSなどで連絡もらえると嬉しいです。
Movable Type 用 Vim Plugin: mtdataapi.vim
前回の続きです。
usr42はGUIメニューについて。
あまりGUIにこだわりはないので情報少なめ。
前回の続きです。
この賞はVim scriptの記法について。
- let
変数定義に使います。
以下のようにs:を付けるとスクリプトローカルな変数を定義できます。
let s:count
使わなくなったら、unlet s:countで変数を削除してメモリを解放します。
exists()
変数の存在確認結果を返す。
引数は変数名の文字列を指定するため、以下のように実行します。
if exists("s:count")
$HOME
$で始まるのは環境変数。
&ic
&で始まるのはオプション。
&icはignorecaseオプションのこと。
@r
@で始まるのはレジスタ。
.
ピリオドを使って文字の連結ができます。
Perlと同じ。
a ? b : c
aならばb、aでないならc。
よくある3項演算子。
a =~ b
aがbパターンにマッチする。 =~ではなく、!~ならマッチしない。
Perlと同じ。ただし、大文字小文字を区別しない。
パターンは文字列として指定する。
"test" =~ "e"
a =~# b
aがbパターンにマッチする。大文字小文字を区別する。
Perlと同じ。
=~?とすると大文字小文字を区別しない。
continue.break
while文のループ中で、次のループへ遷移したりループを終了する。
eval
文字列を評価した結果を返す。
executeコマンドは結果をコマンドとして実行するが、evalは評価のみで価を返す。
function
関数定義。
関数名は大文字で開始。
関数の中で引数を参照するときは、a:countという形でa:を付ける。
関数の中でletコマンドによって定義した変数は関数ローカルな価となる。
s:等を付けた場合はそれに従う。
function FunctionName() range
rangeを付けると範囲指定を受け付ける。以下のように実行できる。
10,30call FunctionName
範囲は、a:firstline、a:lastlineで参照する。
rangeを付けなかった関数を10,30callで呼ぶと、同じ関数を21回呼ぶことになる。
function FunctionName(Start, ...)
...で可変長引数を指定。
a:0は可変長引数の数。a:000は可変長引数のリスト。
a:1は可変長引数の最初の値。
function()
引数に指定した関数名の関数への参照を返す。
let Func1 = function( 'FunctionName')
参照を代入する変数名は大文字で始める。
関数参照を実行するにはcall()関数を使う。
call()
call( Func1 , [])
第2引数は参照している関数の引数リスト。
[]
リスト。
['a'] + ['b','c'] "これは['a' , 'b' , 'c']
extend(['b','c'])でも同じ。
add()を使うと、入れ子になる。
for n in []
リストの要素をnに代入しながらループ。
rangeと組み合わせて指定回数ループ可能。
range()
range(3)とすると[0,1,2]のリストが返る。
{}
辞書。
let dict = {'a':'b', 'c':'d'}
echo dict['a']
echo dict.a
for n in sort(keys(dict))
辞書のキーでループ。
function dict.FunctionName dict
辞書に対する関数として定義。
以下のように実行すると、self変数に辞書そのものを格納して関数を実行する。
let dict = {}
function dict.FunctionName dict
endfunction
echo dict.FunctionName
get()
辞書にキーがあれば価を返し、なければデフォルト価を返す。
get(dict, key , default)
map()
リストの各要素に第二引数の処理を加えたリストを返す。
map(alist,'command')
第2引数は文字列として渡す。
copy()
辞書をコピーする。
try, catch, finally, endtry
エラーを例外とする。
ma"aYHmbgg"aPbzt
a
ビューの復元のサンプル。
YとPは違うコマンドでも良い。
aとbのマークを付けて、aで移動してztでスクロールして、
aでカーソル移動。
前回の続きです。
この賞は「新しいコマンドを作る」ということで、「map」、「command」、「autocmd」が説明されています。
map、unmap
キーのマップを定義します。
をほかのキーに割り当てたりすることで、便利なキーとして登録できます。
unmapでマップを削除します。
command
コマンドを定義します。
コマンド名は大文字で始める必要があります。
autocmd
イベント発生時に自動的に実行するコマンドを指定します。
commandで作成したコマンドやcallコマンドを使って関数を実行できます。
executeコマンドを使うと実行するコマンドを動的に作成して実行することができます。
前回に引き続き、helpをみてそれまで知らなかったけれども使えそうと思ったコマンドを紹介。
qa
レジスタaにマクロとして操作を保存。
実行は@a
レジスタはヤンクで使われるものと同じなので、バッファの文字列をレジスタにヤンクしてマクロとして実行することも可能。
"ayyみたいに。
?pattern1?+1,/pattern2/-2s/foo/bar/g
上方向(後方)にpattern1を検索し見つかった行の次の行から、下方向(前方)にpattern2を検索し2行手前(上の行)までを対象に、fooをbarにすべて置換する。
!Gsort
バッファの内容をsortコマンドの結果で置き換える。
一時ファイルを用意する必要ないので便利
:read !ls
コマンドの実行結果をバッファに挿入。
以下だと現在位置を書き換え
:.!ls
:wirte !wc
ファイルの中身をコマンドに渡す。
結果が表示されるが、その後enterを押すと表示が消える。
vimのヘルプの、「07.3 他のファイルにジャンプする」にあるCTRL-^が期待通りに動かない。。なんでだろ。
:argsで現在ファイルを確認して、:nextや:previousでファイルを変更してからCTRL-^を入力しても何も変わらない。
何がうれしいかって、blogにコードを張るときにhtmlコードをそのままコピペできる点。
でも、出来上がるhtmlファイルはそれ単体で完結している作りなので部分的にコピペが必要で勝手はいまいち。スタイルシートはblogに事前に設定しておけば変更不要なのでそこの手間は不要。
以下のコマンドで変換できる。
:TOhtml
以下が例。
1 if exists('g:loaded_helloworld')
2 finish
3 endif
4 let g:loaded_helloworld = 1
5 command! HWorld call helloworld#hello_world()
vimを使いこなせていない自信があったのでヘルプを見て勉強し直したら便利な使い方がたくさん載っていたのでここにメモ。
とりあえずusr_04.txtの範囲まで。
*
カーソル位置の単語と一致する単語を検索
g*
カーソル位置の単語を含むものを検索
H
画面上部にカーソル移動
M
画面中央にカーソル移動
-L
画面下部にカーソル移動
CTRL-O、CTRL-I(Tab)
前、後の位置にジャンプ(カーソル移動)
ma、a
maでマークして、
aで移動。
CTRL-O、CTRL-Iでジャンプもできる
``
一つ前の位置にジャンプする(最初はCTRL-Oと同じ挙動)
~
大文字小文字変換
ビジュアルモードでも利用可
(ビジュアルモード)o、O
選択範囲の変更のために、カーソルを反対側に移動
始点の変更ができる。矩形選択の場合はOも使って範囲変更可能。
"*
yやpと合わせてクリップボードを使用
icebergというcolorschemeを作った人の発表をvimconf2017で聞いたら、colorshcemeが大好きなちょっと?変わった人だったので、きっとこれは良いに違いないと導入を決めました。
dein.vimを使っているとどうもうまく反映されないので以下のページを参考にautocmdを使って設定したらうまくいきました。
au MyAutoCmd VimEnter * nested colorscheme iceberg
syntax enable
参考URL
dein.vimによるプラグイン管理のマイベストプラクティス