Sublime Text 3のスニペットが便利

この間から、CodeEval をチョコチョコとやっていて、いつのまにやら日本国内でのランクが5になっていたよ。ま、人数が少ないようだけど。
で、たまに Ruby を使うけどたいていは Python でコードを書いている。そのコードなんだけど、プログラムの要求条件がファイルから入力して1行ずつ処理する、というのがほとんどだ。ということは毎回同じコードを書くことになるわけだけど、ここで Sublime Text のスニペットを使うと便利なので、今日はその作り方のメモ。

メニューから [ツール] → [スニペット追加] を選ぶと、次のような雛形が表示される。これを編集して、保存すればいいわけだ。

<![CDATA[
  Hello, ${1:this} is a ${2:snippet}.
]]>
<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
<!-- <tabTrigger>hello</tabTrigger> -->
<!-- Optional: Set a scope to limit where the snippet will trigger -->
<!-- <scope>source.python</scope> -->

で、どこをどう編集すればいいのかというと、まずは CDATA の中身(Hello,~となっているところ)。ここが実際に貼り付けられるコード片になる。${1:this} とか ${2:snippet} となっているところは一種の変数のようなもので、貼り付けたあと続けて書き換えられるようにカーソルが移動する。もちろんなくてもいい。${0} と書いておくと貼り付けた後そこにカーソルが移動する。
<tabTrigger> の中はスニペットを呼び出すショートカットのようなもので、これを入力してタブキーを押すとスニペットが貼り付けられる。
<scope> はどんな状況で有効になるか、らしい。source.python とあるのは Python のソースコードを書いているときに有効になる。

結局、こういうのを書いた。

<![CDATA[
import sys

test_cases = open(sys.argv[1], 'r')<br /]]> for test in test_cases:
${0}

test_cases.close()

]]>
<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
codeeval-python2
<!-- Optional: Set a scope to limit where the snippet will trigger -->
source.python

これを、C:\Users\takatoh\AppData\Roaming\Sublime Text 3\Packages\User フォルダの下に、codeeval-python2.sublime-snippet という名前で保存する。Sublime Text は .sublime-snippet という(長い)拡張子のファイルをスニペットと認識するようだ。フォルダは上記のフォルダ直下でなくてもいいみたいなので、Sunippets というフォルダを作ってその中に保存した。

さあ、準備は完了したので使ってみよう。Sublime Text を立ち上げて新規ファイルを開く。何も書く前に test.py とでも名前をつけて保存する。これで Python を編集するモードになって、上のスニペットが使えるようになったはずだ。
codeeval-python2 とタイプしてタブキーを押すとスニペットが貼り付けられるはず・・・だけど c をタイプした時点で候補に出てきた。これは便利。

Windows7でSublime Text 3を使ってみる

普段は秀丸エディタを使ってるんだけど、Sublime Text 3 を導入してみたのでメモ。といってもググればいくらでも出てくるので、要点だけ。参考にしたページは主にここ。

 cf. 『初心者向け』 Sublime Text 3 導入と日本語化について – Naverまとめ

ダウンロードとインストール

ダウンロードはここから。

Windows の 64bit 版をダウンロード。
ダウンロードしたファイルをダブルクリックしてインストール。インストール自体は簡単そのもの。

Package Control

Sublime Text 3 本体のインストールが終わったら、とにもかくにも Package Control をインストールする。Sublime Text には多くのパッケージ、プラグインが用意されていて、それを管理するもののようだ。メニューから [View] → [Show Console] を選ぶか、[Ctrl]+[`] キーを押してコンソールを表示する。次のページから、Package Control インストール用の Python スクリプトをコピペして Enter。

すると、[Tools] → [Command Palette] の中に Package Control が追加される。

日本語化

メニュー等の日本語化。上で追加された Package Control を使って Japanize というパッケじをインストールする。
インストール自体が無事に終わると、設定の仕方がエディタの画面に現れるので、そのとおりにする。以下メッセージから引用。

適用手順
1.C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\Japanizeにインストールされている*.jpファイルを、
   C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\Default
  にコピーします。※Defaultフォルダがない場合は作成してください。
2.コピーしたファイルをオリジナルのファイル(.jpが付かないファイル)と置き換えます。(念のため、オリジナルのファイルが有る場合は.orgなどを付けて保管しておきましょう。)
3.C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\Japanize\Main.sublime-menu(.jpが付かない方)を、
   C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\User
  にコピーします。すると、他のプラグインで上書きされてしまっているトップメニューも日本語化されます。
以上です。

これでメニュー等の日本語化は終了。

その他のパッケージ

とりあえずインストールしたパッケージは次の2つ。

  • ConvertToUTF8
  • IMESupport

Sublime Text は UTF-8 が規定の文字コードなので、Shift JIS のファイルを編集するときには不都合がある。ConvertToUTF8 はファイルを開くときに UTF-8 に変換し、保存するときには Shift JIS で保存してくれる。
IMESupport は日本語入力をインラインでできるようにするパッケージ。

その他の設定

設定は基本的に Json のテキストファイルでするようになっている。メニューから [基本設定] → [基本設定 – ユーザ] を選ぶと、Preferences.sublime-settings というファイルが開く。以下の設定を追加してファイルを保存すると、設定が反映される。

"tab_size": 2,
"translate_tabs_to_spaces": true,
"highlight_line": true,
"highlight_modified_tabs": true,
"draw_white_space": "all",
"show_encoding": true

言語ごとの設定

たとえば、Python のスクリプトを編集するときにだけ適用したい設定を書くには、Python ファイルを開いた状態で [基本設定] → [基本設定 – 拡張] → [シンタックス指定 – ユーザ] を選ぶと、Python.sublime-settings というファイルが開く。ここに上とおなじ要領で設定を書くと Python スクリプトだけに適用される。Python ではタブサイズを 4 にした。

さて、これでしばらく使ってみよう。

SchemeでCodeEvalのPascals Triangle

↓こういうのを見つけたので Scheme でやってみよう、と思ったら CodeEval って Scheme ないんでやんの。

 cf. Python2でCodeEvalのPascals Triangle – brainstorm
 cf. Pascals Triangle – CodeEval

しょうがないから勝手にやる。

(define pascals-triangle
  (lambda (depth)
    (let loop ((n depth) (pas '((1))))
      (if (= n 1)
          (reverse pas)
          (let ((next (map + (cons 0 (car pas)) (append (car pas) '(0)))))
            (loop (- n 1) (cons next pas)))))))

(define flatten
  (lambda (list-of-list)
    (fold-left append '() list-of-list)))

(define print-pascals-triangle
  (lambda (depth)
    (print (string-join (map number-&gt;string (flatten (pascals-triangle (string-&gt;number depth)))) " "))))

(define main
  (lambda (args)
    (with-input-from-file (cadr args)
      (lambda ()
        (port-for-each print-pascals-triangle read-line)))))
^o^ > type input-pascal.txt
6

^o^ > gosh pascal.scm input-pascal.txt
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1

たぶんあってる。

Schemeでファイルから行を読み込む

cf. http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3A%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E5%87%A6%E7%90%86#H-1d1usg4

ファイルから1行ずつ読み込んで処理をするやり方。

(define main
  (lambda (args)
    (with-input-from-file (cadr args)
      (lambda ()
        (port-for-each print read-line)))))

この例では print してるだけだけど、代わりにここに行を処理する関数を入れてやればいい。

^o^ > type foo.txt
foo
bar
baz

^o^ > gosh read-each-lines.scm foo.txt
foo
bar
baz

次は行ごとのリストにする方法。

(define main
  (lambda (args)
    (print (call-with-input-file (cadr args) port->string-list))))
^o^ > gosh read-lines-list.scm foo.txt
(foo bar baz)

最後に、ファイル全体を文字列にするには:

(define main
  (lambda (args)
    (print (call-with-input-file (cadr args) port->string))))
^o^ > gosh read-lines-string.scm foo.txt
foo
bar
baz

Sinatraで”invalid byte sequence in Windows-31J”

先週に引き続き古い Web アプリを Ruby2.0 対応(一番最近のコミットが2010年の11月だった)。今回は Sinatra。
で、スクリプトのエンコードを UTF-8 にして、require 'jcode' を消して、などと一通り修正して完了。無事動くようになったんだけど、日本語を含む URL のときにタイトルのエラーが発生した。しかも、どうもアプリじゃなくて Rack の中で起きているらしい。
こんなのどうすりゃいいんだよ、と思いながらググってみたらずばりそのもののページを見つけた。

 cf. Sinatra が ”invalid byte sequence in Windows-31J” でエラーページを表示しない(@Windows) – Qiita

どうやら、Rack は外から来る文字列のエンコーディングを Encoding.default_external の値だとして変換するらしい。で、その Encoding.default_external の値が Windows-31J なわけだ。でも実際は UTF-8 の文字列だから変換中にエラーが発生する、と。

というわけで、app.rb の中に1行追加した。

Encoding.default_external = 'utf-8'


上記のページでは config.ru の中に追加してるけど、こっちのほうがいいような気がする。気のせいかもしれないけど。

さて、これでめでたく日本語が入ってても動くようになった。

RDiscountでmarkdownをためす

昔書いた CGI にちょっと手を入れたついでに、ドキュメントを Markdown に書き直そうと思って調べてみたら、Ruby では RDiscount ってのがよさそうだったので試してみた。今日はそのメモ。

拡張ライブラリが含まれているというのでちょっと心配だったけど、インストールはあっさりすんだ。

^o^ > gem install rdiscount
Fetching: rdiscount-2.1.7.1.gem (100%)
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
Successfully installed rdiscount-2.1.7.1
Parsing documentation for rdiscount-2.1.7.1
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/rdiscount.so, skipping

Installing ri documentation for rdiscount-2.1.7.1
1 gem installed

Markdown の例はこんな感じ。記法についてはググればいくらでもページが見つかるので割愛。

見出し1
========

見出し2
--------

ここは本文。

### 見出し3

見出し3以上は # を行頭につける。見出し6までいけるみたい。

### 番号なしリスト

行頭に * か - で番号なしのリストになる。

- リスト1
- リスト2
- リスト3

### 番号つきリスト

番号つきリストは行頭に 1. というふうに番号をつける。

1. リスト1
2. リスト2
3. リスト3

----

3つ以上の - で水平線。

これを HTML に変換するには、rdiscount コマンドを使えばいい。標準出力に吐き出すので、適当なファイルにリダイレクトしてやる。

^o^ > rdiscount example.md > example.html

Ruby のスクリプト内で使うには、RDiscount クラスのインスタンスを作って to_html メソッドで変換する。

require 'rdiscount'

markdown = RDiscount.new(File.open(ARGV.shift, "r"){|f| f.read})
print markdown.to_html

ま、とりあえず使うのはこんなところ。

cut

昨日、あとで調べてみよう、と書いた cut について調べてみた。

 cf. 4.3 手続きを作る – Gauche ユーザリファレンス

[SRFI-26] 手続きを簡潔に書ける便利なマクロです。 いわゆる部分適用を実現するために使えます。

SRFI-26 とあるけど、Gauche では標準で使えるようになっている。

たとえば、文字列3つを引数にとって、”-” でつなげる手続きを考えよう。

gosh> (define foo
  (lambda (a b c)
    (string-join (list a b c) "-")))
foo
gosh> (foo "hoge" "fuga" "piyo")
"hoge-fuga-piyo"

この手続き foo の引数のうち、2つめだけをあとから与えるようにしたいとする。つまり、1つめと3つめだけ先に部分適用したい、と。そういうときに cut を使えば実現できる。

gosh> (cut foo "hoge" <> "piyo")
#<closure #f>

シンボル <> が後から与えられる引数の代わりになっている。実際に使ってみると:

gosh> ((cut foo "hoge" <> "piyo") "fuga")
"hoge-fuga-piyo"

確かに2つめの引数をあとから与えることができている。
シンボル <> はいくつあってもいいらしい。後から与えられる引数と対応した <> に当てはめられる。

シンボル <...> を使うと可変長引数をとることができるようになる。

gosh> (cut list <...>)
#<closure #f>
gosh> ((cut list <...>) "foo" "bar" "baz")
("foo" "bar" "baz")

なるほどねぇ。つまり昨日の (cut show-help (car args)) は手続き(ただし、引数なし)を作っていたわけだ。