VimScriptざっくりチュートリアル(if文と真偽値編)

if 文

if test == 1
  echo 'true'
else
  ehco 'false'
endif
比較演算子
  • ==, !=, >, <, >=, <=, =~, !~
    • ignorecase に依存
    • ignorecase は文字列比較時に大文字/小文字を考慮しなくするオプション
  • is: 同一のインスタンス
  • isnot: 異なるインスタンス
  • ==#, !=#, =~#, !~#
    • ignorecase に関わらず大文字/小文字考慮
  • ==?, !=?, =~?, !~?
    • ignorecase に関わらず大文字/小文字無視
  • 後、! で論理否定ができる
and, or


&& と ||

真偽値について


真偽値型は無くて、数値の 0 とそれ以外で真偽を判定する

  • 0 : 偽
  • 0以外 : 真


文字列を真偽値に使った場合、数値以外であった場合は、0 に変換される

  • "0" : 偽
  • "" : 偽
  • "9999" : 真
  • "true" : 偽

三項演算子

echo test==1 ? "true" : "false"

VimScriptざっくりチュートリアル(データ型)


まずはここを読む

help eval

データ型の確認方法

let test = 1
echo type(test)


以下の6種類が数値で返ってくる

  • 数値 : 0
  • 文字列 : 1
  • Funcref : 2 (関数リファレンス)
  • リスト : 3
  • 辞書 : 4
  • 浮動小数点数 : 5

数値型


32bit or 64bit の符号付き整数

  • 32bit なら、−2147483648 〜 2147483647
" 16進
echo 0x10

" 10進
echo 16

" 8進
echo 020
" サイズ越えの場合 -1 を返す
echo 999999999999999999999999999999999999999999999999
数値演算
" 四則演算
echo (1+1)-1*10/10
" 余り
echo 100%3
" 整数型の割り算は整数型を返す
echo 10/3 "| -> 3
" 0 除算すると 0 を返す
echo 1/0
"複合演算子は、+= と、-= だけ
let test = 0
let test += 1
echo test-=1
数値⇔文字列


文字列 -> 数値

" それぞれ 16 を返す
echo str2nr("0x10", 16)
echo str2nr("16", 10)
echo str2nr("020", 8)

" 123 を返す
echo str2nr("123abc", 10)

" 0 を返す
echo str2nr("abc123", 10)


数値 -> 文字列

echo printf("0x%x",16) | " -> "0x10"
echo printf("%d",16)   | " -> "16"
echo printf("0%o",16)  | " -> "020"
echo printf("%02d",8)  | " ->" "08"

文字列型

宣言
let test = "123"
let test = '123'

" ダブルクォーテーション文字列の場合、特殊文字を入力できる
let test = "改行:\n タブ:\t バックスラッシュ:\\ 等..."


" ダブルクォーテーション文字列中にダブルクォーテーションを入れたい場合
let test = "\"123\""
let test = '"123"'

" シングルクォーテーション文字列中にシングルクォーテーションを入れたい場合
let test = 'test''test'


ヒアドキュメントは無い

文字列操作
" 結合
echo 'abc'. '123'
" バイト数取得
echo strlen('abc')                       |" -> 3
echo strlen('2バイト文字')               |" -> 16
" 正規表現検索
echo stridx('123abc', 'bc')              |" -> indexが返る(ない場合は-1)
" 正規表現置換
echo substitute('123abc', 'a', 'z', 'g') |" -> 123zbc


正規表現については、後述

Funcref型


関数の項で解説

リスト型

宣言
let test = [1,'abc',[1,2,3]]
参照
echo test[0]                 " 要素の参照
echo test[99]                " 範囲外を参照するとエラー
" get 関数を使用すると、範囲外の場合 0 を返す
echo get(test, 99)
" デフォルト値も定義可能
echo get(test, 99, 'NONE')
" 部分リスト
echo test[1:2]
echo test[1:]  " 1〜末尾まで
echo test[:1]  " 先頭〜1まで
リスト操作
" 要素を変更したい時は let を使う
let test[1] = "123"

" 要素数
echo len(test)

" 空であるか?
echo empty(test)
echo empty([])

echo add(test, 'add')    | " 末尾に追加
echo insert(test, 'add') | " 先頭に追加
echo remove(test, -1)    | " 末尾を削除(remove の戻り値は消した要素)
echo remove(test, 0)     | " 先頭を削除

" ソート
echo sort(test)

" split/join
" -> "1\t2\t3\t4"
echo join(split('1,2,3,4', ','), "\t")
配列の繰り返し(for,map)
for i in [1,2,3,4]
  echo i
  unlet i " i にいろんなデータ型が来るとエラーになるので毎回 unlet する必要がある
endfor
echo map([1,2,3,4], '1+v:val')


第1引数の各要素を、第2引数の文字列をevalした結果に置き換えた結果を返す
v:val は、要素の値を格納する組み込み変数

辞書型


hashみたいなの

宣言
" キーは数値も定義できるけど、文字列に置換される
let hash = {'key1': 'val1', 2: 'val2'}
参照
echo hash['key1']
" キーがアルファベット、数値、アンダースコアだけの場合、以下でも参照できる
echo hash.key1
要素の再定義、追加
let hash.key2 = 'val'
let hash.key3 = 'val3'
echo hash
辞書操作
echo keys(hash)  | " キーをリストに
echo keys(hash)  | " 値をリストに
echo items(hash) | " 辞書をリストのリストに変換
" items を使って、辞書のループ
for [key, value] in items(hash)
 echo key . ': ' . value
endfor
echo has_key(hash, 'key1') | " 存在確認
echo remove(hash, 'key1')  | " 削除

不動小数点数型


int と同じく、64 or 32bit

let test = 0.1
let test = 1.0e3 " 指数もOK
" 数値型で割り算すると戻り値は数値型
echo 1/10
" 浮動小数点数型で割り算すれば良い
echo 1.0/10

異なる型の変数への再代入


文字列型 ⇔ 数値型は交互に再代入ができる



let test = 1
let test = "abc"
let test = 1


それ以外は例外になる

  • 古いvimでは、文字列型と数値型しか無かったのが理由???



let test = 1
let test = ["abc", "def"] |" 変数の型が一致しません

" 一度変数を削除する必要がある
unlet test
let test = ["abc", "def"] |" OK


異なる型の配列を for する時に大事



for i in [1,'test',0.1,[1,2,3]] # 毎回内部でletされている
echo i
unlet i
endfor

VimScriptざっくりチュートリアル(初回編)


10年近く Vim 使ってきていまだに習得していないのでそろそろ

目的とゴール


Vimプラグインを書けるようになりたい!

ターゲット


数年vim使ってて、プラグイン入れたり、.vimrc いじったりしてるけど、
VimScriptについては敬遠してる人

VimScriptって何?


Vimの設定を記述する為の独自言語
実態はExコマンドの羅列で、 if 等の制御構文も全てがExコマンド

何が出来るの?


Exコマンドでできること全部。引いては Vim でできること、設定できること全部

  • テキストの編集
  • 各種設定の変更
  • etc...


詳しくは以下

:help ex-cmd-index


ざっくり言えば、vimの機能拡張や、テキストの編集が出来るよ! で良いのかな?

Exコマンドって何?


Vimコマンドラインモードで実行できるコマンド群のこと
Vim起動して、 押して、以下のように入力すれば実行できる

:echo "hello!"


何でExコマンドって言うかというと、Vimの元ネタのラインエディタ ex で使えたコマンドが元になっているから

【vimの歴史】
ex(ラインエディタ) -> vi(exの機能を内包したテキストエディタ) -> Vim(viの改良版clone)


ちなみに、vi が入力モードとコマンドモードに分かれているのも、コマンドモードでは、ex の機能。入力モードでは、vi の機能という分け方をしたため

ラインエディタって?


モニターではなく1行づつコマンドの結果をプリントするテレタイプ端末というもので実行することを前提としたエディタ
なので、そういう命令を打たない限り全体を表示しないし、各種コマンドを入力することで、テキストの編集を行うエディタ


VimScriptのリファレンスとかあるの?

help usr_41

hello world

:echo "hello world"


echo は、引数の文字列を表示する Exコマンド

コメント

:echo " ダブルクォーテーションはコメント
:echo "test" " 引用符が前にあったり、いくつかのコマンドの後ろにはコメントは付けられない
:echo "test" |" こうすればどのコマンドの後ろにもコメント可(パイプは、コマンドを区切って次のコマンドに行く)

ファイルからVimScriptを実行

:source 01.vim " 拡張子は vim

変数宣言のやり方

:let test = 1   " グローバル変数(デフォルト)
:let g:test = 1 " グローバル変数(明示的)
:let s:test = 1 " スクリプトローカル変数(1スクリプトファイル内でのみ有効)
:let l:test = 1 " 関数内ローカル変数(関数内のデフォルト)
:let b:test = 1 " バッファローカル変数
:let w:test = 1 " ウインドウローカル変数
:let t:test = 1 " タブローカル変数
上にあるバッファ、ウインドウ、タブって?
  • バッファ : ファイルを編集する仮想的な領域。ファイルを開くとバッファに格納される
  • ウインドウ : バッファを編集する表示領域。:sp で分割すると2つになる
  • タブ : ウィンドウの配置の状態を保持する領域。
わかりにくいので実例
:enew    " 新規にバッファを開く
:sp      " ウインドウを分割
:tabedit " 新規にタブを生成
:tabNext " 次のタブに移動(上で分割したウィンドウが保持される)
:ls      " バッファの一覧
:tabs    " タブの一覧
変数の削除
:unlet test  " test が宣言されていないとエラー
:unlet! test " test が宣言されていなくても OK
変数の存在確認
" existsは、exコマンドではなく関数。
" echo 関数 で、関数の戻り値を echo する
" 関数については後述
:echo exists("test") |" 0:なし 1:あり
変数の再代入
:let test = 1
:let test = 2 " もう一度代入する場合は、毎回 let が必要


今日はここまで

vimperator の環境整備


環境を整備したのでその時のTIPS等を

バージョンあげたら、copy.js が動かなくなった


githubに最新のが上がってるので取得した

ついでに国内の vimperator 使いのプラグインが色々上がってたので git clone して必要なのをシンボリックリンクで plugin ディレクトリに入れた

使ってるプラグイン

copy.js


title や URL をいろんなテンプレートでコピーできるプラグイン
はてな記法や、redmine 用の設定を用意して使ってる

javascript <<EOM
liberator.globalVariables.copy_templates = [
  {label:'Url', value:'%URL%'},
  {label:'TitleAndUrl', value:'%TITLE% %URL%'},
  {label:'hatena', value:'[%URL%:title=%TITLE%]'},
  {label:'wiki', value:'[[%TITLE%|%URL%]]'},
  {label:'redmine', value:'"%TITLE%":%URL%'},
  {label:'Title', value:'%TITLE%'},
  {label:'HTML', value:'<a href=%URL%>%TITLE%</a>'} 
]
EOM

noremap <C-h> :copy hatena<CR><CR>
noremap <C-w> :copy wiki<CR><CR>
noremap <C-r> :copy redmine<CR><CR>
feedSomeKey_3.js


livedoorreader や gmail で設定したキーはスルーして、ブラウザに渡すようにするプラグイン
いろんな所で紹介されている設定だと上手く動作しなかったので必要最低限にしている

command! -nargs=+ lazy autocmd VimperatorEnter .* <args>
lazy fmaps -u='mail\.google\.com/mail' j k n
lazy fmaps -u='http://reader\.livedoor\.com/reader/' j k s <Space>
multi_requester.js


alcなどちょっとした検索結果等を、画面遷移せずに取得するプラグイン
まだ使いこなせてない

githubで設定を公開するときにハマったところ

svn:externals みたいに他のリポジトリのリンクを貼りたい


git submodule を使う

$ git submodule add git://github.com/vimpr/vimperator-plugins.git vimperator-plugins
サブモジュールの更新
$ git submodule foreach 'git pull origin master'
$ git submodule update


だいたいそんな感じ

node.jsデプロイQ&A


実践に当たって軽く調査。実践編はまた今度

nodeで書いたwebサーバを公開したいけど、デプロイってみんなどうしてるの?


forever っていうデーモン化ツールがあるから、それを使うのが一般的っぽい

nodeアプリって通常はシングルスレッドだから、マルチコアのCPUパワーを100%生かせない?


Clusterモジュールを使えば、複数のプロセスの起動と、通信をサポートしてくれる

複数マシンでスケールしたいんだけど


node-http-proxyってnpmがあるから、それを使うとnode.jsで、リバースプロキシと、ロードバランサーが実装できる

リバースプロキシ?


クライアントからのリクエストを受けて、特定のサーバに転送する役割のサーバ

ロードバランサ?


クライアントからのリクエストを複数のサーバに分散して、転送するサーバ

静的ファイルはnode使わないで、通常のhttpサーバを使ってnode側の負荷を軽減したい


nginx 使って特定のリクエストは、nodeサーバにリバースプロキシしてあげれば良いよ
ver 1.3.13 から、WebSocketもリバースプロキシしてくれるようになったよ!

Apacheでは?


ざっと見た感じ、WebSocketに対応していないっぽい?

複数マシンでnodeを分散した場合、セッションってどうなるの?


後で調査

nodeで書いたサーバを更新したい

  • forever ならば、-w オプションでコードの更新をチェックして、リスタートしてくれる

ホットデプロイしたい!


qilinモジュールなるものがアツいらしい


ワーカープロセスを複数個起動して、そこでサーバを走らせる
メインプロセスにSIGUSR2(ユーザ定義シグナル)を送ると、子プロセスの内、リクエストが無くなったものから再起動してくれる

  • upモジュールなるものもあるらしいけど、未調査。性能に多少難があるとかなんとか

自前で環境作成するのが面倒なのでnode使えるPaaS教えて

macのライブラリ関係覚え書き

拡張子 .dylib って?


ダイナミックリンクライブラリ
windowsなら、dll。linuxなら、so。
.so を使うこともできるらしい

拡張子.bundleって?


ローダブルバンドル
ダイナミックリンクライブラリへのリンクと関連ファイルやデータをひとまとめにしたものらしい

.bundleがリンクしている.bylibをリストアップしたい


otoolコマンドを使う

$ otool -L /Users/kobayashi/.rvm/rubies/ruby-1.8.7-p174/lib/ruby/1.8/i686-darwin10.8.0/iconv.bundle
/Users/kobayashi/.rvm/rubies/ruby-1.8.7-p174/lib/ruby/1.8/i686-darwin10.8.0/iconv.bundle:
        /Users/kobayashi/.rvm/rubies/ruby-1.8.7-p174/lib/libruby.dylib (compatibility version 1.8.0, current version 1.8.7)
        /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11)
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)

.bundleがリンクしている.bylibを変更する


標準のライブラリから、Homebrewでインストールしたライブラリを使いたい時とか

install_name_tool -change を使う


例 : .rvmにある、iconv.bundle がリンクしている標準の libiconv.2.dylibから、Homebrewのライブラリに変更

$ install_name_tool -change /Users/kobayashi/.rvm/rubies/ruby-1.8.7-p174/lib/ruby/1.8/i686-darwin10.8.0/iconv.bundle \
  /usr/lib/libiconv.2.dylib \
  /usr/local/Cellar/libiconv/1.13/lib/libiconv.2.dylib

node.js覚書


いろいろ調べたのでメモする

node.js ってなあに?


JavaScriptを用いた Non-blocking I/O な環境

Non-blocking I/O?


CPUと他の入出力装置(I/O)において、データの送受信を待たずに、次の処理に移行する方式のこと。
逆に、入出力が完了するまで待つことを「ブロッキング」と呼ぶ
例えば、こんなのがブロッキング

require 'open-uri'
p "1: #{Time.now}"
open("http://www.ruby-lang.org/") {|f|
  p "2: #{Time.now}"
}
p "3: #{Time.now}"

# output
"1: 2013-03-10 11:58:16 +0900"
"2: 2013-03-10 11:58:19 +0900"
"3: 2013-03-10 11:58:19 +0900"


上記の場合、2の処理が終わるまで、3が実行されない(ブロックされてる)

node.js の場合はどうなるの?


こうなる

var http = require("http");
console.log('1' + new Date());
http.get(
  {
    host : 'www.google.com',
    path : '/'
  }, function(res){
    console.log('2' + new Date());
  }
);
console.log('3' + new Date());

# output
1Sun Mar 10 2013 12:04:00 GMT+0900 (JST)
3Sun Mar 10 2013 12:04:00 GMT+0900 (JST)
2Sun Mar 10 2013 12:04:01 GMT+0900 (JST)


http.get でブロックされずに、先に3の処理が実行されている

ブロックされないのは分かったけど、それだと何がお得なの?


Non-blocking だと、待ちが無いので、結果が帰ってくるまでの間、他の処理が実行できる
つまり、シングルスレッドで複数のリクエストを同時に捌く事が可能になる

それだと何が良いの? ハイスペックなマシンでスレッドたくさん作って富豪的に解決すれば良いんじゃ?


1台のマシンだと大量のスレッドを作成すると、1個1個のスレッドの処理が軽くて、
メモリ的に余裕があっても、大量のスレッドそのものがマシン性能を圧迫する問題がある
→ C10K問題

C10K問題の回答の一つとして、Non-blocking である node.js が作られた

なんで JavaScript なの?


nodeを作るに当たって、実装側でブロックが発生する処理は書けないようにしたかった
他の言語だとファイルシステムへのアクセスとか、ブロックが発生しえる処理が実装出来てしまうけど、
JavaScriptにはそれがなかった(標準入出力の仕様が無い)し、基本的にイベント駆動な書き方しか出来ないので、nodeの思想と相性が良かったから


後、JavaScriptにした副作用として

  • 採用したV8エンジンが早い
  • クライアントサイドと、言語が統一された
  • jQueryとか既存の便利なライブラリが使える

node.js 向けのアプリってどんなの?

  • webAPIみたいな処理は少ないけど、大量のアクセスがあるアプリ
  • いろんなサーバにアクセスして、結果が帰ってくるのを待つ必要がある、クローラー
    • jQueryとか使えるから、DOM操作も楽だよ!
  • webSoketを生かしたリアルタイムコミュニケーション

逆に向かない処理は?

インストール方法は?


こちらを参照

ざっと動かしてみたい


こちらを参照

最後に一言


サーバサイド JavaScript っていうのは結果であって、それが売りじゃないよ!
本当の売りは、Non-blocking I/O だよ! って中の人が言ってた