SKSceneとUIViewとの座標変換

SpriteKitのSKSceneの座標系は、UIViewの左上座標とは異なり、y軸が反転した左下座標系になっています。そのため、UIGestureRecognizerのようなUIView側の座標系をSpriteKitに持ち込むには、座標系を変換してあげなくてはいけません。

具体的には、SKSceneメソッドconvertPointFromView(_:)convertPointToView(_:)を使います。

// UIView上の座標をSKScene上の座標に変換する
func convertPointFromView(_ point: CGPoint) -> CGPoint

// SKScene上の座標をUIView上の座標に変換する
func convertPointToView(_ point: CGPoint) -> CGPoint

UIPanGestureRecognizerを使ってスプライトをドラッグしようとしていて、ハマりかけました。結局、その時のコードは次のようになりました。

    @IBAction func panned(recognizer: UIPanGestureRecognizer) {
        let location = recognizer.locationInView(_spriteView)
        // タッチ座標をSKScene上の座標に変換。これを忘れていた
        let sklocation = _spriteView.scene!.convertPointFromView(location)

        if let node = _spriteView.scene?.nodeAtPoint(sklocation)
            where node is SKSpriteNode
        {
            // ノードのイベント生起
        }
    }

svn commit時に英語でメッセージ書くためのヒントを表示する

Qiitaに次のような投稿がありました。

qiita.com

git commitをするときに英語の例文をコメントとして表示するようにして、英語コミット力を上げようという内容です。これはいいなと、同じようなことがSubversionでも出来ないかなと調べてみました。結果としてうまくできたので、今回はそのときの調査メモと、実現方法を記します。

調査編

テンプレートが指定できない?

svnのオプションなどを調べ始めてすぐに気付いたのですが、Subversionにはそもそもテンプレートを表示する設定・外部変数のような概念は存在していないようです。環境変数SVN_EDITOR」を使い、コミットで使うエディタを指定できる程度で、それ以上のカスタマイズはできません。ネット上の情報にも当たってみましたが、ほとんどがエディタのコマンドだけを指定しているだけで、特殊変数のようなものは使っていませんでした。

とはいえ、コミット時のエディタ上には対象ファイル/ディレクトリの一覧と、入力欄とを区切る一文が表示されています。これはどのようにして渡ってきているのかと、以下のようなシェルスクリプトを作成して引数を調べてみました。

#!/bin/sh

echo "num args: $#"
for arg in $@; do
        echo "-----"
        echo $arg
done
env
exit 0

コマンド引数の数と、その内容、そして環境変数を出力するだけのスクリプトです。これをSVN_EDITORに指定してsvn commitを実行してみると…

$ SVN_EDITOR=/Users/user/bin/commit.sh svn commit
num args: 1
-----
svn-commit.tmp
  :
…環境変数の一覧…

というように、ファイル名として「svn-commit.tmp」が指定したプログラムに渡されていて、それ以外は環境変数も含めて何もしていないことがわかりました。ちなみにsvn-commit.tmpはコミット作業中にしか存在しない一時ファイルで、中身はコミット時に出ているメッセージそのものでした。

% cat ~/tmp/foo/svn-commit.tmp

--This line, and those below, will be ignored--

…更新ファイルの一覧…

しかもこの「svn-commit[.XX].tmp」という名前はSubversionのソースにハードコーディングされていて(!)、気軽に変更できるようなものではありませんでした。

 if (! lmb->non_interactive)
   {
     err = svn_cmdline__edit_string_externally(&msg_string, &lmb->tmpfile_left,
                                               lmb->editor_cmd,
                                               lmb->base_dir ? lmb->base_dir : "",
                                               msg_string, "svn-commit",  // ←ココ!
                                               lmb->config, TRUE,
                                               lmb->message_encoding,
                                               pool);
   }
 else /* non_interactive flag says we can't pop up an editor, so error */
   {

…番号で重複を避けているとはいえ、このカスタマイズを一切許さない設計はどうなんだろう。

ともかく、gitと同じ方法では実現できなさそうです。

どうやってコミット内容だけを取り出しているか

それではと、次にコミットファイル「svn-commit.tmp」の内容に注目し、このファイルからどうやってコミットメッセージだけを取り出しているかを調べてみることにしました。ファイル内には「--This line, and those below, will be ignored--」から始まる文字列が含まれていますが、コミット後のログメッセージにはその内容が一切含まれていません。ということは、コミット処理のときに何かしらの方法で取り除いているはずです。

それが分かれば、gitの方法#で始まる行が無視されることを利用して例文を挿入しているのと同じことが実現できるはず、という魂胆です。

本ファイル作成処理は先ほど述べたようにSubversionソースコードとして書かれていたので、どうせその近辺に処理があるだろうと読んでみます。

すると、trunk/subversion/svn/util.cの337行目にて、svn-commit.tmpに書かれている「--This line, and those below, will be ignored--」そのものがマクロで定義されていました。当然のようにハードコーディングされています。ローカライズの余地すらありません。

#define EDITOR_EOF_PREFIX  _("--This line, and those below, will be ignored--")

さらに読んでみると、この行より後ろに書かれた内容はすべて切り捨てていて、一切無視していることがわかりました。最初に現れるこの行以降はすべて無視される仕様です。

なるほど。

調査のまとめ

ここまでの調査をまとめます。

  • subversionではgitにあるようなテンプレートを指定する設定はない
  • エディタは環境変数SVN_EDITORで指定できる。…が、第1引数にファイル名svn-commit.tmpが渡されるだけ
    • ファイルの中身は、どのファイルが更新されるかが書かれた、いつものメッセージ
  • ファイル名、ファイルの内容はソースコードにハードコーディングされていて、再コンパイルしなければ変更できない
  • コミットメッセージとコメントは、コミットメッセージの最初に現れる「--This line, and those below, will be ignored--」行よりも前か後ろかで判断する

ということで、ファイル名と魔法の文字列とがキーになることがわかりました。ここまで分かれば色々とできそうです。

実現編:例文コメントの 実現

というわけで、調査結果をふまえると、次のような方針であれば実現出来そうだと期待できます。それは、

環境変数SVN_EDITORにsvn-commit.tmpを書き換えた上でエディタを起動するコマンドをいれ、コメントにしたい文は"--This line, and those below, will be ignored--"の後に入れておく」

という方法です。svnプログラムが把握しているのはコミットメッセージの対象ファイルのみですから、エディタが終了するまでの間に適当なファイルないように書き換えてしまえば、コメントだろうとテンプレートだろうと、こちらの狙ったメッセージを入れ込むことができるだろうと考えました。

さっそくそんな感じの処理を実現する以下のスクリプトを書いてみました。

#!/bin/sh

mv "$1" "$1".orig
echo "\n--This line, and those below, will be ignored--" > "$1"
echo "Hello, world!" >> "$1"
cat "$1".orig >> "$1"
rm "$1".orig
vi "$1"

exit 0

まず元のファイルを.origと付けて退避しておきます。そして、魔法の言葉「--This line, and those below, will be ignored--」を挟んでからコメント(ここではとりあえず"Hello, world!")を入れ、最後に退避しておいた元のデータを書き加え、退避データは削除します。

・・・さあ、上記のファイルを~/tmp/commit.shに保存して、うまく動くかどうか試してみましょう。

(SVN_EDITOR=~/tmp/commit.sh svn commitの実行画面)
コミットメッセージを書いてみる

--This line, and those below, will be ignored--
Hello, world!

--This line, and those below, will be ignored--

M    myfile

おお。

% svn up
Updating '.':
At revision 4.
% svn log
------------------------------------------------------------------------
r4 | XXXXX | 2016-01-23 14:02:30 +0900 (土, 23  1 2016) | 2 lines

コミットメッセージを書いてみる
------------------------------------------------------------------------
:

おおお。うまくいきました!

まとめ&出来上がったスクリプト

当初はsvnでは環境変数がないため実現できないかも、と思った今回の調査でしたが、SVN_EDITORに渡すコマンドとコメント判別ルールを利用することで、git版と同様の機能を実現することができました。

最後に、svngit版の記事と同じようなコミットコメントを実現するスクリプトを記します。先ほどのテストでは「-- This line, …」が2回も出てきてうっとうしかったので、それを消すような処理も加えてあります。

#!/bin/sh

echo "num args: $#"
for arg in $@; do
    echo "-----"
    echo $arg
done

mv "$1" "$1".orig

# コミット時のコメントを作成
cat <<'_EOT_' > "$1"

--This line, and those below, will be ignored--

fix, add, changeといった事実ではなく、このcommitで実現する要件や仕様を書きましょう。(リファクタなどは除く)

 例文)
 - Fix typo in docs
 - Remove unused code
 - Remove use of deprecated method
 - Update Modernizr to v1.6
 - Make it possible to have IDs per request
 - Make sure to reset default_url_options(必ずリセットする)
 - Don't use "assert_not_nil"
 - Allow the user to drag faster
 - Remove methods to avoid warnings.
---
_EOT_

# 元コメントの3行目以降(=変更ファイル一覧)を追加
tail -n +3 "$1".orig >> "$1"
rm "$1".orig

# エディタの起動
vi "$1"
exit 0

これでsvnしか使えないプロジェクトでも幸せになれますね!

NSNumberで扱われるSwiftの数値型

SwiftのIntやFloatのようなプリミティブな数値型をCやObjective-Cとで相互に扱う場合、その型は基本的に同じ値域の型で表されます。具体的には「Using Swift with Cocoa and Objective-C (Swift 2.1)」の「Interacting with C APIs」-「Primitive Types」にある、以下の表の通りです。

Cでの型 Swiftの型
_Bool,bool(C++) Bool, CBool
char, signed char Int8, CChar
unsigned char UInt8, CUnsignedChar
short Int16, CShort
unsigned short UInt16, CUnsignedShort
int Int32, CInt
unsigned int UInt32, CUnsignedInt
long Int, CLong
unsigned long UInt, CUnsignedLong
long long Int64, CLongLong
unsigned long long UInt64, CUnsignedLongLong
wchar_t UnicodeScalar, CWideChar
char16_t UInt16, CChar16
char32_t UnicodeScalar, CChar32
float Float, CFloat
double Double, CDouble

表の多くの項目で複数の型が書かれているのは、「C〜」で始まる型がそうでない型のtypealiasであるためです。

このように相互変換の可能な型が一通りそろっているものの、SwiftにはC言語にあるような暗黙の型変換がないため、Cの慣用的な型の考え方以上に型を強く意識すること(あるいはIntでまとめてしまうこと)が求められます。また、SwiftのIntはCのlong、CのintはSwiftだとInt32(またはCInt)に相当しているので混乱しないよう注意すべきです。

ところで、Objective-Cでは数値をオブジェクトとして扱うための型「NSNumber」があります。この型は、Swiftでは数値としてアンラップした状態で利用できます。「Using Swift with Cocoa and Objective-C (Swift 2.1)」から引用すると、以下の5つの型がNSNumberで扱われます。

  • Int
  • UInt
  • Float
  • Double
  • Bool

gitbookでPDF/epub出力できるようにする(calibre)

前回の記事によりmarkdownファイルをgitbookでHTML化できるようになったわけですが、せっかくなのでPDFでも出力できるようにします。

gitbookからPDF化するにはCalibreを使う

gitbookのgithubページには、eBookへの出力について次のように書いてあります。

eBook: You need to have ebook-convert installed. You can specify the eBook filename as the second argument, otherwise book will be used.

gitbookではコンバートに「Calibre」というツールに含まれる「ebook-convert」コマンドを使うとのこと。CalibreはGUIを持った高機能な電子書籍管理アプリで、コンバート機能は補助的なもののようです。

calibre - About

calibre is a free and open source e-book library management application developed by users of e-books for users of e-books. It has a cornucopia of features divided into the following main categories:

参考までにWikipediaからも引用。

calibre - Wikipedia

Calibreとはフリー・アンド・オープンソース電子書籍ソフトウェアであり、電子書籍を保存や管理を行うことが可能で、多数のフォーマットに対応している。またDRMのかかった電子書籍を他のフォーマットへ変換でき、数種類の主な電子ブックリーダーと同期することができる。

Calibreのインストール

ということで、Calibreをインストールします。ダウンロードページからOS X版のインストーラが入ったdmgファイルをダウンロードします。バージョンは2.49.0でした(2016/01/20時点)。dmgの中には.appファイルが入っているので(ちゃんと署名されていました)、/Applicationsにコピーするだけです。

f:id:swiftlife:20160120132017p:plain

Calibreの初回起動時は管理ディレクトリやcontent serverの起動を尋ねられますが、今回はコンバートにだけ利用する予定なので、何もさせないよう適当な値を入れつつインストールしました。ただしそれだけだと目的のebook-convertコマンドが使えないので、calibre.app下にパスを通しておきます。

export PATH=/Applications/calibre.app/Contents/MacOS:$PATH

あ、公式ドキュメントの「2.3 ebook-convert」にもパスの通し方について記載がありました。こちらはebook-convertコマンドだけをシンボリックリンクで外に出していますね。

Mac

Download the Calibre app. After moving the calibre.app to your Applications folder create a symbolic link to the ebook-convert tool:

$ sudo ln -s ~/Applications/calibre.app/Contents/MacOS/ebook-convert /usr/bin

You can replace /usr/bin with any directory that is in your $PATH.

どちらでも好きな方でよいと思います。 以上で準備完了です。

PDFへのコンバート

コンバートするには、gitbookコマンドに「pdf」オプションを付けるだけです。htmlのときのbuildオプションの代わりに指定します。

% gitbook help
  build [book] [output]      build a book
    --format     Format to build to (Default is website; Values are website, json, ebook)
    --log    Minimum log level to display (Default is info; Values are debug, info, warn, error, disabled)

  pdf [book] [output]    build a book to pdf  ←PDF化はこちらを使う
    --log    Minimum log level to display (Default is info; Values are debug, info, warn, error, disabled)

簡単に試してみました。

$ mkdir ~/mybook && cd ~/mybook
$ gitbook init   # 初期化(README.mdとSUMMARY.mdの作成)
$ gitbook pdf  # PDF化
$ ls
README.md  SUMMARY.md book.pdf

book.pdfが出来上がっていることを確認できました。

追加調査とまとめ

簡単な文章で試したところ、日本語はおおむね大丈夫でしたが絵文字「😄」はHTMLと異なり空白で表示されるだけでした。

しかし簡単な作業でそこそこ整ったPDFができるので、これは便利そうです。

Gitbookのインストール(2016/1/19時点)

お仕事で色々と勉強している、ここには書けないことをまとめるためにいいツールはないかと探していたところ、現時点ではGitBookが良さそうだと思い、インストールしてみました。

別にTeXExcelやWordなどでもよかったのですが、書き殴りたい時にはどれも大げさなので却下しました。GitBookならmarkdownで書けますし、目次も作ってくれるので、複数の内容を整理しつつ書くのには便利そうです。GitBookの公式サイトにある説明だとプライベートなリポジトリを持つには月額いくらかを支払う必要があるものの、本記事で説明しているローカルでgitbookコマンドをインストールして使う方法であれば、そうした制限もなく自由に使えます。

セットアップ

1. Node.jsのインストール

GitBookをインストールするには、npmが必要です。手元のマシンにはNode.jsが入っていなかったので、公式サイトからパッケージをダウンロードしてインストール。ダウンロード時のOS X向け最新版は「v4.2.4 LTS」と「v5.4.1 Stable」だったので、5.4.1をインストールします。

2. gitbookのインストール(失敗)

Node.jsのインストールにより使えリュ王にsudo npm install -g gitbookと入力してgitbookをインストール。sudoしているのは、-gオプションを付けてインストール先をグローバルにするためです。ちなみにiTerm2で実行したらプログレス表示がおかしくなっていたので、OS標準のターミナルで実行しました。

…と、インストールが終わったところで試しに起動してみたところ、次のようなエラーが出てきてしまいました。

% gitbook serve
You need to install "gitbook-cli" to have access to the gitbook command anywhere on your system.
If you've installed this package globally, you need to uninstall it.
>> Run "npm uninstall -g gitbook" then "npm install -g gitbook-cli"
%

gitbookコマンドを使うにはgitbook-cliが必要なので、gitbookはアンインストールしなさいと怒られてしまいました。しょうがないのでアンインストール。

% sudo npm uninstall -g gitbook

公式サイトを調べてみると、こちらのgitbookリポジトリにあるREADMEで正式なインストール方法が載っていました。…やはりgitbook-cliをインストールしなければいけませんでした。

ちゃんと公式文書に当たらないとだめですね・・・。

3. gitbook-cliのインストール&動作確認

ということで、怒られたgitbookではなくgitbook-cliをインストールします。

% sudo npm install -g gitbook-cli

ここでインストール完了後にgitbookコマンドを実行してみたところ、本動作が始まる前に「Installing GitBook 2.6.7」のメッセージと共にgitbookのインストールが始まりました。どうやらこのタイミングでgitbookはインストールされるようです。なるほど。

% gitbook serve
Installing GitBook 2.6.7
2016-01-19 19:33:59.464 xcodebuild[5600:86029] [MT] PluginLoading: ...
 :
gitbook@2.6.7 ../../var/folders/mc/.../T/tmp-.../node_modules/gitbook
├── bash-color@0.0.3
 :
└── npm@2.4.1
Live reload server started on port: 35729
Press CTRL+C to quit ...

info: loading book configuration....OK 
info: load plugin gitbook-plugin-highlight ....OK 
info: load plugin gitbook-plugin-search ....OK 
info: load plugin gitbook-plugin-sharing ....OK 
info: load plugin gitbook-plugin-fontsettings ....OK 
info: load plugin gitbook-plugin-livereload ....OK 
info: >> 5 plugins loaded 

ログに「Live reload server started on port: 35729」とあるので、試しにSafariで「http://localhost:35729 」にアクセスしてみました。そうしたら「{"tinylr":"Welcome","version":"0.2.1"}」と応答を確認できました。

以上でインストールは完了です。

使い始め

GitBook上でドキュメントを作成していくには、何はなくとも「SUMMARY.md」と「README.md」の2つのファイルが必要です。

ファイル 用途
SUMMARY.md 目次。ブラウザだと左ペインに表示される内容を記述
README.md 本全体、各章の冒頭に記す短めの文章。巻頭言に使う

これらのファイルは自分で作っても良いですが、gitbook initコマンドで作成してくれるテンプレートを利用するのが簡単なので、そちらを利用してしまいましょう。

% mkdir my_greatbook && cd my_greatbook
% gitbook init
info: init book at /Users/username/my_greatbook
info: detect structure from SUMMARY (if it exists)
info: create SUMMARY.md
info: create README.md
info: initialization is finished

Done, without error

% ls
README.md  SUMMARY.md

この状態であれば、あとはgitbook serveコマンドで閲覧できます。

% gitbook serve                                                                                     [~/my_greatbook]
Live reload server started on port: 35729
Press CTRL+C to quit ...

info: loading book configuration....OK
info: load plugin gitbook-plugin-highlight ....OK
info: load plugin gitbook-plugin-search ....OK
info: load plugin gitbook-plugin-sharing ....OK
info: load plugin gitbook-plugin-fontsettings ....OK
info: load plugin gitbook-plugin-livereload ....OK
info: >> 5 plugins loaded
info: start generation with website generator
info: clean website generatorOK
info: generation is finished

Starting server ...
Serving book on http://localhost:4000

そしてブラウザで「http://localhost:4000 」にアクセスします。

f:id:swiftlife:20160119200943p:plain

うまくいきました。

以降はトップフォルダでgitbook serveを実行しておくだけで、自動的にmdファイル・SUMMARY.mdの追加変更を検知して_booksの内容を更新してくれるます。ビルドだけしたい場合は「gitbook build」コマンドを使います

ずっと以前にgitbookを触ったことがあったのですが、当時は日本語のファイル名など目次がうまく取り扱えていなかったため使用を諦めていました。しかし今は軽く触ってみた限りですが何の問題もなさそうでした。もともと気軽に構造化された文章を扱える環境だったので、これは便利でいいですね。

参考サイト

npmのプロキシ設定

ツールごとにプロキシサーバーの設定が異なり、必要なときにいつも忘れてしまうので、備忘録として。

npmでプロキシサーバーを設定するには、npmコマンドから、config set proxyconfig set https-proxyを使います。

% npm config set proxy http://XXX.XXX.XXX.XXX:8080
% npm config set https-proxy http://XXX.XXX.XXX.XXX:8080

設定が完了したかどうかは、npm configlsオプションを付けて調べます。もちろん~/.npmrcを調べるのでも構いませんが、npm config ls -lとすれば.npmrcになり全ての設定を見られるので便利です。

% npm config ls
; cli configs
user-agent = "npm/3.3.12 node/v5.4.1 darwin x64"

; userconfig /Users/username/.npmrc
https-proxy = "http://XXX.XXX.XXX.XXX:8080/"
proxy = "http://XXX.XXX.XXX.XXX:8080/"

; node bin location = /usr/local/bin/node
; cwd = /Users/username
; HOME = /Users/username
; "npm config ls -l" to show all defaults.

詳細はhelpに載っていますので、詳しくはそちらをどうぞ。

% npm help config

Swiftでインラインアセンブラを書く

残念ですが書けません。インラインアセンブラC/C++/Objective-C側で書く必要があります。

(・・・最近ARMアセンブラを勉強しているので、iOSでCPSRレジスタとか操作する処理書けないかなとか期待したのですが、そういや最近のiPhoneて64bitだったと気づいてがっかりして1分で書いたダメ記事です)