Vim 8.0 で強化された機能 辞書関数

さて、以前の辞書関数は次のように call() と辞書を経由して呼び出す必要がありました。

let s:dict = { "value" : 0 }
function! s:dict.up()
    let self.value += 1
    return self.value
endfunction

let s:f = s:dict.up
echo call(s:f, [], s:dict)
" => 1
echo call(s:f, [], s:dict)
" => 2
echo call(s:f, [], s:dict)
" => 3

Vim 8.0 ではこの縛りが緩和されて、辞書関数を直接呼び出すことができるようになりました。

let s:dict = { "value" : 0 }
function! s:dict.up()
    let self.value += 1
    return self.value
endfunction

let s:f = s:dict.up
echo s:f()
" => 1
echo s:f()
" => 2
echo s:f()
" => 3

めちゃくちゃ便利…。

RSpec で not_change マッチャを定義する

通常、Rspec で『変更されないことを検証する』場合、change マッチャを使用します。

# subject を呼び出しても hoge が変更されないことを検証する
it { is_expected.not_to change{ hoge } }

[not_change マッチャを定義する]

上記のコードでも問題ないのですが、 RSpec::Matchers.define_negated_matcher を使用すると書き方を変えることができます。

# change マッチャの否定を定義する
RSpec::Matchers.define_negated_matcher :not_change, :change

# to を呼び出し、マッチャの名前を変更する
it { is_expected.to not_change{ hoge } }

おもしろい

Ruby の ObjectSpace を利用して、オブジェクト名からクラスオブジェクトを探す

Ruby で例えば "String" という文字列からその名前のクラスオブジェクトを取得したい場合があるとします。 そういう場合は ObjectSpace から逆算して検出することができます。

# クラスオブジェクトの一覧を取得する
classes =ObjectSpace.each_object(::Class)

# クラスオブジェクトの一覧から該当するクラスオブジェクトを探す
target = "String"
result = classes.find { |klass| klass.name == target }
p result == String
# => truk

また、Rails では String#constantize というメソッドが定義されており、上記と同等の機能があります。

"String".constantize   
# => String

[参照]

http://railsdoc.com/references/constantize

Vim 8.0 で追加された Vim script の機能 Lambda

Vim 8.0 ではついに Vim script に Lambda が追加されました! Lambda を定義する場合は { args -> expr } という構文を使用します。

" Lambda は関数参照を返す
" epxr にはその名の通り "式" のみ書くことができる
let F = { a, b -> a + b }

echo F(1, 2)
" => 3

また filter() 関数などに直接 Lambda を渡すことも出来ます。

echo filter(range(1, 10), { index, val -> val % 2 == 0 })
" => [2, 4, 6, 8, 10]

[変数のキャプチャ]

次のように Lambda 外のローカル変数もキャプチャされます。

function! s:main()
    let value = 10
    let F = { a -> value + a }
    echo F(5)
   " => 15
endfunction
call s:main()

[Lambda 内では式しか定義できない]

Lambda 内では式のみ定義できるので、コマンドなどを直接呼び出すことは出来ません。

" このような使い方は出来ない
let Nonumber = { -> set nonumber }

この場合は、同じく Vim 8.0 で追加された execute() 関数を使用します。 execute() は引数のコマンドを実行する関数になります。

" execute() を経由してコマンドを呼び出す
let Nonumber = { -> execute("set nonumber") }

このように execute() を経由することでコマンドを式として呼び出すことが出来ます。

[引数に a: をつける必要はない]

Lambda 内で使用する引数には a: をつける必要はありません。 ですので次のように外部の引数を参照することも出来ます。

function! s:main(arg)
    let F = { a -> a:arg + a }
    echo F(5)
   " => 15
endfunction
call s:main(10)

Vim 8.0 で追加された新しいシンタックス

Vim 8.0 では新しく以下の言語に対応しました。

New Syntax/Indent/FTplugin files:

AVR Assembler (Avra) syntax
Arduino syntax
Bazel syntax and indent and ftplugin
Dockerfile syntax and ftplugin
Eiffel ftplugin
Euphoria 3 and 4 syntax
Go syntax and indent and ftplugin
Godoc syntax
Groovy ftplugin
HGcommit ftplugin
Hog indent and ftplugin
Innovation Data Processing upstream.pt syntax
J syntax and indent and ftplugin
Jproperties ftplugin
Json syntax and indent and ftplugin
Kivy syntax
Less syntax and indent
Mix syntax
Motorola S-Record syntax
R ftplugin
ReStructuredText syntax and indent and ftplugin
Registry ftplugin
Rhelp indent and ftplugin
Rmd (markdown with R code chunks) syntax and indent
Rmd ftplugin
Rnoweb ftplugin
Rnoweb indent
Scala syntax and indent and ftplugin
SystemVerilog syntax and indent and ftplugin
Systemd syntax and indent and ftplugin
Teraterm (TTL) syntax and indent
Text ftplugin
Vroom syntax and indent and ftplugin

メジャーどころだと GoJsonScalaGroovy あたりですかねえ。

Vim 8.0 で追加された機能 function() 関数

Vim 8.0 では function() 関数の引数が新たに追加されました。

[引数の束縛]

function() の第二引数に第一引数に渡す関数の引数を渡すことで、引数の束縛を行うことができるようになりました。

function! Plus(a, b)
    return a:a + a:b
endfunction

" 第一引数を束縛
let s:Plus3 = function("Plus", [3])

echo s:Plus3(2)
" => 5
echo s:Plus3(-5)
" => -2

[関数が参照する辞書を指定]

第三引数に辞書を渡すことで、関数が参照する辞書を指定することが出来ます。

function! Disp() dict
    return self.name . " : " . self.age
endfunction

let s:data = { "name" : "homu", "age" : 14 }
let s:Disp = function("Disp", [], s:data)
echo s:Disp()

関数の束縛がかなり便利。

Vim 8.0 で追加された機能 uniq() 関数

Vim 8.0 で『配列の隣り合う同じ値の要素を削除する』uniq() 関数が追加されました。

echo uniq([1, 1, 3, 2, 2, 3, 3, 1])
" => [1, 3, 2, 3, 1]

また、重複する要素をすべて削除したい場合は、 sort() と併用して使用します。

" sort() してから uniq() する
echo uniq(sort([1, 1, 3, 2, 2, 3, 3, 1]))
" => [1, 2, 3]