rfコマンドの独自拡張
独自拡張
rfコマンドではタイプ数を減らしたりより利用者が便利になるように独自に拡張を行っています。独自拡張と書きましたが、DSL(ドメイン固有言語)を定義したり、Rubyの構文そのものを変更するということはせずに、あくまでRubyらしさを保ちつつ追加することをポリシーとしています。こうすることで、Rubyistがrfコマンドを使い始めたときに違和感を感じづらくなると考えています。
ここではその独自拡張について解説します。
暗黙的な値の計算
RubyではInteger/FloatとStringの計算/比較、nilとInteger/Floatとの計算は行うことができません。しかし、rfコマンドはこれらの計算ができるように拡張しています。具体例は以下の通りです。
# CRubyではエラーになる
irb> 1 + "1" #=> 'Integer#+': String can't be coerced into Integer (TypeError)
irb> "1" > 2 #=> comparison of String with 2 failed (ArgumentError)
irb> nil + 1 #=> undefined method '+' for nil (NoMethodError)
#rfコマンドではエラーにならない
> echo | rf '1 + "1"'
2
> echo | rf 'p ("1" > 2)'
false
> echo | rf 'nil + 1'
1
rfコマンドでは文字列を扱うことが多くなります。このときに、to_iやto_fといったメソッドを呼び出すとタイプ数が増えてしまうため、これを緩和するために暗黙的な変換を導入しています。
では、なぜnilも拡張しているのでしょうか?これは未定義の変数に対しての計算をエラーにしないためです。これもタイプ数を減らすための工夫として導入しています。
# CRubyではエラーになる
irb> sum += 1 # undefined method '+' for nil (NoMethodError)
# rfコマンドではエラーにならない
> echo | rf 'foo += 1; puts foo'
1
# この拡張を使わない場合||=などを使う必要がある
> echo | rf 'foo ||= 0; foo += 1; puts foo'
1
Hashの要素にメソッドアクセス可能
Hashの要素にメソッドアクセスを可能にしています。CRubyのHashi gemのMashやJavaScriptのObjectのように利用できます。これもタイプ数を減らす工夫として導入しています。この拡張の具体例は以下の通りです。
# CRubyではエラーになる
irb> {foo:"bar"}.foo #=> undefined method 'foo' for an instance of Hash (NoMethodError)
# rfコマンドではエラーにならない
>echo | rf '{foo:"bar"}.foo'
bar
IPv4アドレスにマッチする組み込み正規表現パターン
IPv4アドレスにマッチする正規表現パターンを組み込みのメタ文字として利用できます。具体的には正規表現リテラルで(?&ipv4) とするとその部分にIPv4アドレスにマッチするパターンが埋め込まれます。
実際に利用例を見てましょう。例として以下のようなファイルがあったとします。
| HostName | Address | Status |
|----------|---------------|--------|
| host1 | 192.168.0.101 | ACTIVE |
| host2 | 192.168.0.102 | ACTIVE |
| host3 | 192.168.0.103 | ACTIVE |
このファイルからAddressの値だけ取り出してみます。
> rf '/((?&ipv4))/.match($_)' server-list.md
192.168.0.101
192.168.0.102
192.168.0.103
追加した組み込み文字 (?&ipv4)を使うことで少ないタイプ数でIPv4アドレスにマッチさせることができました。
Discussion