Ruby コミュニティにコードを contribute する方法

うっかり Ruby の標準添付ライブラリに好ましくないと思われる挙動を見つけてしまって、直してはみたもののその修正をどうやって contribute すればよいのかと思って調べてみたけどよくわからなかったので http://www.ruby-lang.org/en/ の説明をいろいろ漁ってこんな感じかな〜と思った手順をまとめてみます。(日本語 http://www.ruby-lang.org/ja/ の方は英語版と若干異なる内容だったのと、なんとなく情報量少なめだったので英語の方を参考にしました。ただ、英語のほうも svn 主体の説明になっていてなんとなく outdated な感じでした)

私がやってみたのは以下のような手順です。

  1. Ruby のコードに修正したいバグ(もしくは追加したい機能)を見つける
  2. Redmineruby-trunk プロジェクト (https://bugs.ruby-lang.org/projects/ruby-trunk) に報告する(新しいチケットを作る)
  3. GitHubruby/ruby (https://github.com/ruby/ruby) を fork する
  4. fork したリポジトリをローカルに clone してきて trunk ブランチを checkout する
  5. バグを修正する(もしくは機能を追加する)
  6. もちろんテストも書く
  7. GitHub でプルリクする ← イマココ

まだ PR が取り込まれたわけではないのでこの手順で合ってるかどうかよくわかりません。


今後も継続的に開発に参加するつもりならメーリングリストを購読したりすべきなんでしょうけど、普段は Ruby のユーザで、自分のプログラムのバグかと思って問題を追いかけていたらたまたま Ruby 本体のバグにあたってしまった、というような状況の私みたいな人には、ML に参加して云々というのはちょっと敷居が高いですね。

Redmine で Issue 発行して GitHub でプルリクするだけなら、私のような一見さんでも気軽に貢献できるというものです。

ただ、自分の修正をテストするときに、ローカルで変更した Ruby を使ってテストを走らせるようにする方法がよくわかりませんでした。

なので私は仕方が無いので ~/.rbenv/ の下の当該 .rb ファイルを直接書き換えたりしてテストしました・・・
単一の .rb ファイルで変更はそれほど多くなかったからそのような方法でなんとかなったものの、.c とかを修正したらどうやってテストすればいいのでしょうかね。

そのあたりの情報、どなたか教えてプリーズ

[追記]
多分、以下のような方法で自前 Ruby を rbenv に取り込んで、そいつを使ってデバッグしたりすると既存の環境を壊したりしなくて済むので良い気がします。

Ruby をソースからビルドして rbenv で使う方法 - bearmini's blog

Android SDK のコマンドを実行しようとしたら No such file or directory と言われて焦った件

dexdump を使おうとして、2 回もハマったので、自分用メモ。

結論から言うと、

$ sudo apt-get install ia32-libs

で解決。

私は Ubuntu 12.04 の x86_64 バージョンを使っているので Android SDK も 64bit 版のものをダウンロードして使っていますが、Android SDK のツールの中には 32bit のものがあるんですね。これを実行するのに多分 ia32-libs が要るんだと思います。

$ which dexdump 

してもちゃんと見つかるし、

$ dexdump
-bash: /home/username/adb-bundle-linux-x86_64/sdk/build-tools/android-4.3/dexdump: No such file or directory

という感じにそもそも bash のエラーメッセージにはちゃんと dexdump までのパスが表示されてるので、PATH が解決できてないというわけでもなさそう。

ls -l でパーミッションとかオーナーとか見ても問題なし、どうして見つからないのか??と小一時間悩んだ挙句、StackOverflow で http://stackoverflow.com/questions/13571145/android-adb-not-found を発見して無事解決。

Tizen Native API のメソッド名末尾についてる N の意味

この記事は Tizen Advent Calendar 2013 に参加予定の記事です。



Tizen で Native アプリを開発していると、ときどき API の関数名の末尾に N が付いているのを見かけます。

たとえば身近なところでいうと

  • Tizen::Base::Collection::ArrayList::GetEnumeratorN()
  • Tizen::Net::Http::HttpRequest::ReadBodyN()
  • Tizen::Ui::Control::GetCanvasN()

といったようなメソッドたちです。

これは、「このメソッドの中で new によってメモリの確保が行われるので呼び出し元が責任を持ってそのメモリを解放してね♥」 という意味です。

覚え方: New の N(メソッドの中でオブジェクトを new している)

N で終わるメソッドを呼び出すときは可能ならば戻り値を std::auto_ptr とか std::shared_ptr とか std::unique_ptr とかを使って受け取るなどして、解放忘れを防ぎましょう。


なお、イベントハンドラ名に N が付いている場合、そこに渡されてくる引数のポインタを delete しなければならないという意味になります。

たとえば身近なところでいうと

  • Tizen::App::App::OnUserEventReceivedN()
  • Tizen::Io::IMessagePortListener::OnMessageReceivedN()

などがあります。

これらのメソッドをオーバーライドして実装するときは、引数のポインタを忘れずに delete しましょう。


余談ですが、このようにプラットフォームが確保したメモリをユーザコードの中で解放する、あるいは逆にユーザコードの中で確保したメモリをプラットフォーム側で解放する(Tizen::Ui::Container::AddControl() など)、というコーディング規約は当初すっごく気持ち悪く感じました。(今でもだいぶ気持ち悪いけど)

あと、Tizen::Ui::Container::AddControl() で思い出しましたが、今でこそ Deprecated になった Tizen::Ui::Container::AddControl(const Control& control) というメソッドは、そのメソッドの仕様を二度見、三度見(えっ、・・・えっ・・・、えっ・・?!?)しましたし、軽く冷や汗をかいてひと通り我が目を疑った後にこのライブラリと今後しばらく付き合っていくのかと考えると意識がうっすらと遠のいたのを今でも覚えています。
const 参照で渡したコントロールのインスタンスを、コンテナ側で delete してくれるってどういうことよ!?っていう。
今は Tizen::Ui::Container::AddControl(Control* pControl) になったのでいくらかマシですね。


クラスライブラリの設計の筋の良さ的にはぜひ Qt for Tizen に普及してもらいたいです。

Tizen の sdb コマンド向け bash completion のご紹介

この記事は Tizen Advent Calendar 2013 に参加予定の記事です。


Tizen でアプリを開発していると、コマンドラインからアプリのインストールやアンインストール、ファイルのコピー、デバイスのシェルへのアクセスなど、いろいろと便利な sdb コマンドを使い倒されている方も多いかと思います。sdb コマンドは Android の adb コマンドみたいなものですね。

sdb コマンド自体は大変便利なのですが、デバイス上のファイルを開発用 PC にコピーしてきたいといった時にファイルのパスが補完されなくてちょっと残念です。

ということで、sdb コマンドでも補完を使うための bash completion を以前作りました。

https://github.com/bearmini/tizen_bash_completion

(もし標準でもっと高機能なのがあったり、他の誰かがすでに作ってたりしたら恥ずかしいなぁ。まあ見つけられなかったから作ったんだけど・・・)

使い方は github から clone したあと tizen_sdb_bash_completion.sh を .bashrc かどこかで source するだけです。
(GitHub の README には、/etc/bash_completion.d/ にコピーしろという侵襲的な説明を書いてしまいましたが、そんなことしなくても使えます)


今のところ、補完対象サブコマンドは以下のとおりです:

  • install

ローカル側のファイル名(*.tpk, *.wgt など)を補完してインストールできます。

  • uninstall

デバイスにインストール済みのアプリのパッケージ ID 一覧を補完してアンインストールできます。

  • push

ローカル側のファイルパスおよびデバイス側の push 先パスを補完できます。

  • pull

デバイス上のファイルパスおよびローカル側の pull 先パスを補完できます。

  • その他 dlog とか root とかもサポートしていますがおまけみたいなものですね

複数のデバイスが接続されているときは -d/-e/-s などでデバイスを特定する必要があります。-s に指定するシリアル番号も補完対象です。

sdb pull の補完では末尾に余計な記号がついちゃう場合があります。
(ディレクトリ名の末尾に / を付けたかったので、デバイス上で実行する ls コマンドに F オプションをつけたのですが、そうすると他の種類のファイルの末尾に * とか @ とかがついてしまうことがあります。これがついたまま実行すると、エラーになりがちです。)
これはなんとかしたいですね。
(scp の補完も同じ感じだった気がするから難しいのかもしれないけど・・・)






上記 4 つのコマンドの補完が効くだけでも大幅に効率アップすること請け合いですが、追加でサポートしてほしいサブコマンドや sdb 以外のコマンドのご要望がありましたらコメントなり何なりでお知らせください。
pull request も絶賛受付中です。

Linux (Ubuntu) から NTFS でフォーマットされた外付け USB HDD へファイルをコピーしたらシンボリックリンクがシンボリックリンクのままだったでござるの巻

表題の通りなんですが、シンボリックリンク先の実体は外付け HDD にはコピーされていなかったので意味のない状態になってしまい、困りました。

ちなみにコピー先が NTFS ではなく FAT32 でフォーマットされた外付け HDD だと「シンボリックリンクを作れない」というようなエラーになりました。

GUI のファイルブラウザでコピーしても cp コマンドで(オプションは特に指定せず)コピーしてもそうなったので、まあそういうものなんでしょう。


cp コマンドに -L オプションをつけることで解決。
シンボリックリンクがリンク先の実体としてコピーされる)

btrfs で複数のデバイスを使うときにやったことメモ

1TB の HDD のおさがりをもらったのでさっそく Linux PC に搭載して、前から気になっていた btrfs でフォーマットして使ってみました。

この記事に書く予定のシナリオとしては、

1. ディスク単体で btrfs フォーマットしてマウントして使用開始
2. ディスクを増設して一つのボリューム(?)として使用継続

という程度のもので、スナップショットがどうしたとか透過的圧縮がこうしたとかルートファイルシステムをどうのこうのとかいったような高度な話は一切出て来ません。

それでも例によっていろいろハマったので、後の自分のためにハマりポイントなどをメモ。

環境は Ubuntu 12.04.3 LTS。




最初に btrfs-tools パッケージをインストールした気がします。
(記憶があやふや)


それからディスクを btrfs でフォーマット。

$ sudo mkfs.btrfs <device file>

な感じですね。ここまではちょっとググればすぐにわかります。

<device file> には /dev/sdb とかそんな感じのデバイスファイル名を指定します。
ここからは /dev/sdb で話を進めます。(この記事を読んでくださっている皆さんはご自身の環境にあわせて読み替えてください。)

ちなみに、最初 /dev/sdb1 とかのパーティション?を指定してしまってエラーになってしまいました。よく考えたら当たり前なのかもしれませんが・・・。
(おさがりだったので事前になんらかのファイルシステムでフォーマットされていたのかもしれません)



次にこのディスクを単体でマウントします。
このあたりまでは旧来のファイルシステムと同じ感覚でやってたのですが問題なくできてました。

$ mkdir /mnt/btrfs_test
$ sudo mount /dev/sdb /mnt/btrfs_test

/mnt/btrfs_test はマウントポイントですね。
もしファイルシステムのタイプがどうのこうのというエラーになったら -t btrfs をつけると良いと思います。

これでもう /mnt/btrfs_test 以下には好き放題にファイルを作ったりできちゃうのですが、便利に使うためにもうあといくつか作業をします。



このままでは、PC を再起動するたびにマウントしなおさないといけなくなるので、/etc/fstab に以下の内容を書いておきましょう。

/dev/sdb    /mnt/btrfs_test    btrfs  noatime,nodiratime  0  0

/dev/sdb は最初に初期化したデバイスファイル名なのでみなさんの環境にあわせて変えてください。
/mnt/btrfs_test はマウントポイントです。
つぎの btrfs はファイルシステムのタイプで、
その次の noatime,nodiratime はパフォーマンスがよくなる(ファイルやディレクトリの最終アクセス日時をいちいち更新するのをやめる)ということです。これらのオプションはつけても付けなくても良いと思います。




さらに、サブボリュームと呼ばれるものを作っておくと、そのサブボリューム単位でスナップショットをとったりすることができて便利になるようです。

$ cd /mnt/btrfs_test
$ sudo btrfs subvolume create <subvolume name>


マウントするときは、このサブボリュームの単位でマウントすることもできるようです。




しばらくこの状態で使っていたら、もう一台 1TB HDD のおさがりをもらいました。
いったん PC をシャットダウンしてその HDD を接続したあと PC を起動し、/dev/sdc が認識されていることを確認しました。

この /dev/sdc も btrfs でフォーマットしました。

これを単体でマウントして別々のディスクとして扱うのではせっかく btrfs にした意味がないので、既存の /mnt/btrfs_test の容量を増やすようにしたいと思います。

それには、以下のコマンドでファイルシステムにデバイスを追加します。

$ sudo btrfs device add /dev/sdc /mnt/btrfs_test

これだけで完了です。簡単ですね。

ただ、この状態では、古い方(/dev/sdb)の 1TB のディスクにばかりデータが書きこまれていて、新しい方(/dev/sdc)にはまったくデータが書きこまれていないというアンバランスな状態となっていますので、これをバランスさせます。

$ sudo btrfs filesystem balance /mnt/btrfs_test

このコマンドは実行にかなり時間がかかります。

このコマンドが完了してから df コマンドを実行すると、無事 /mnt/btrfs_test の容量が約 2TB になっていることが確認できました。


なお、デバイスを追加しても、fstab は書き換えなくても大丈夫なようです。ファイルシステムに追加されたデバイスのうちどれか一つを指定してマウントすると、すべてのデバイスがまとめて使用可能になるようです。





以上、僕が知りたかった情報(なぜサブボリュームを作るのか、等の理由も含めて)があまりまとめられていなかったのでまとめてみました。

間違いの指摘やアドバイス等、よろしくおねがいします。

Ruby で特定のパターンが出現するまで簡単にファイルを読み飛ばす方法

テキストファイルの処理をしてると、たまに表題のようなことをやりたくなりますね。

ヘッダーの1行だけ読み飛ばすとか固定行数読み飛ばすだけならその行数の分だけ gets() を呼べばいいのですが、何行目に現れるかわからない特定のパターンまで読み飛ばすというのは、C 言語脳な僕には gets() して目的のパターンかどうか比較してそうでなければ次の行・・・みたいなループを書いてしまいがちです。

Ruby 脳的にはどうするのがいいかなと思っていたのですが、gets() の rs 引数としてその特定のパターンを渡せばよいようです。

すなわち、

aaaaa
bb
ccccc
ddd
eeeeeee
fff
<<<DATA
data 1
data 2
data 3
  :

という感じのファイルがあったとして、<<

open('data.txt') do |f|
  f.gets("\n<<<DATA\n")
     :
  # 本来の目的の処理
end

と1行で読み飛ばせてしまうことがわかりました。

"\n<<<DATA\n" を行の区切りとして、そこまでを一行として読み取ってしまうという荒業ですね。(そうでもない?)

前後の \n によって、その文字列だけからなる行があるということを意味しています。

逆に特定のパターンが行の途中に現れるとかだとすると \n を除かないといけません。
ただ、後ろの \n が無いと、本来の処理に入ってから一回だけゴミが渡されてきちゃうような気がしますので要注意かも。といっても gets() (引数なし)をもう一回呼べばいいだけですかね。

パターンとして正規表現が使えたら最強な気もしますが、rs のデフォルトが $/ ということはそれはできないのかな?


多分、年に2回くらい使うので忘れないようにメモ。

ssh サーバに公開鍵をワンライナーで登録する方法

2014.05.09 追記

$ ssh-copy-id user@hostname

でいいかも。
(公開鍵ファイルを指定したい場合は -i オプションを使用する)





$ ssh user@hostname "echo `cat ~/.ssh/id_rsa.pub` >> ~/.ssh/authorized_keys"

以上。
たまにやりたくなるんだけどいつも忘れるのでメモ。

`〜` はローカル側のシェルで置き換えられてから ssh コマンドが実行され、echo 〜 はリモートサーバ上で実行される。

ちなみに bash の man の EXPANSION の項によると、

  1. ワード分割
  2. ブレース展開(a{b, c, d}e を abe, ace, ade に分割)
  3. チルダ展開(~ をホームディレクトリなどに展開)
  4. 以下の展開が同時に行われる(左から右の順で評価される)
    1. パラメータ、変数および算術展開(${〜} や $((〜)) を展開)
    2. プロセス置換(<(〜) や >(〜) を置換。名前付きパイプ(FIFO)をサポートしている環境のみ)
    3. コマンド置換($(〜) や `〜` を置換)
  5. ワード分割(ここまでの展開で生成されたワードに基づいて再度分割)
  6. パス名展開(* や ? や [〜] を展開)

の順で処理されてから実行されるようです。

Java とか Android (DEX) の MUTF-8 (Modified UTF-8) って何者よ?っていう話

Android の APK の DEX をゴニョゴニョしてたら、DEX の string 領域に格納されている文字列は実は UTF-8 じゃなくてちょっと modify された MUTF-8 (Modified UTF-8) だということが判明して軽くショックを受けています。

Wikipedia の UTF-8 の項によりますと、標準の UTF-8 から以下の 2 つの変更点があるようです。

後者に関しては端的にいうと CESU-8 (Compatibility Encoding Scheme for UTF-16: 8-Bit) というエンコード方法に則っているということのようです。

Wikipedia のページにも例がありますが、U+10400 というコードポイントを普通に UTF-8 でエンコーディングしたら 0xF0, 0x90, 0x90, 0x80 という 4 バイトのバイト列になるのですが、CESU-8 だと 0xED, 0xA0, 0x81, 0xED, 0xB0, 0x80 という 6 バイトのバイト列になります。

これは U+10400 を UTF-16 でエンコーディングすると 0xD801, 0xDC00 というサロゲートペアになるのですが、それぞれ、0xD801 を UTF-8 のようにエンコーディングすると 0xED, 0xA0, 0x81 となり、0xDC00 を UTF-8 のようにエンコーディングすると 0xED, 0xB0, 0x80 となるためなんですね。

これら 2 つのルールを整理しますと、以下の表のようになります。

Unicode コードポイント U+0000 U+0001 〜 U+007F U+0080 〜 U+07FF U+0800 〜 U+FFFF U+10000 〜 U+10FFFF
通常の UTF-8 0x00 0x01 〜 0x7F 0xC4,0x80 〜 0xDF,0xBF 0xE0,0xA0,0x80 〜 0xEF,0xBF,0xBF 0xF0,0x90,0x80,0x80 〜 0xF0,0x90,0xBF,0xBF
UTF-16F 0x0000 0x0001 〜 0x007F 0x0080 〜 0x7FFF 0x0800 〜 0xFFFF 0xD800,0xDC00 〜 0xDBFF,0xDFFF
Modified UTF-8 0xC0,0x80 0x01 〜 0x7F 0xC4,0x80 〜 0xDF,0xBF 0xE0,0xA0,0x80 〜 0xEF,0xBF,0xBF 0xED,0xA0,0x80,0xED,0xB0,0x80 〜 0xED,0xAF,0xBF,0xED,0xBF,0xBF


ちなみに、MUTF-8 を UTF-16 に戻したり、逆に UTF-16 を MUTF-8 に変換したりするコードは Android のソースの
dalvik/dx/src/com/android/dx/rop/cst/CstString.java
あたりにあります。
(関数名 utf8BytesToString() や stringToUtf8Bytes() が該当します)


その他、参考 URL
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp16542

HTML5/JavaScript/CSS3 でクロスプラットフォームなデスクトップ GUI アプリを作れるフレームワークの決定版を見つけた(かもしれない)件

[追記 2015/05/19]
2015年時点では HTML5/JavaScript/CSS でデスクトップ GUI アプリを作るなら、Electron 一択でしょうね。electron.atom.io

[追記ここまで]


私はデスクトップアプリケーション開発歴はすでに20年近い老人ですが、数年前から「HTML5 でデスクトップ GUI アプリを開発するのが今後主流になるはず」と言い続けてきました。

最近になってやっと、その説をサポートしてくれてかつ人に紹介しても恥ずかしくなさそうなフレームワークに出会えたので(それも一気に 2 つも)、紹介したいと思います。


ちなみに、私のデスクトップアプリ開発に使ってきたフレームワークの遍歴は、以下のような感じです。(抜けてるのもあるかも)

他にも、大学の計算機の授業の課題で SunOS の上で生の Motif を書いたりしたし、趣味でいろんなフレームワークをつまみ食いしたりしてチュートリアル程度はやったというのを含めるとこのリストは倍くらいになるかもしれない。

で、一時期 Web アプリやモバイルアプリの開発なんかもやってみて思ったのが、結局どのフレームワークでも、コントロールやウィジェットと呼ばれる GUI 部品を座標とか大きさを指定したりレイアウトマネージャー的なものにそのへんを任せたりしつつ配置して、それぞれの部品のアクションに応じてイベントハンドラ書いたり、MVC モデルとか使ってデータが更新されたら見た目も更新する(もしくはその逆)みたいなことをしたり、結局はどれもこれも似たようなことやってるだけだなと。なのに、新しい環境が出てきたら毎回毎回新しい言葉を覚えて新しい習慣を身につけないといけないと。
WPF やってるくらいのころに、「もうこれ HTML でいいじゃん」とマイクロソフトを呪ったわけです。なんでまた新しいマークアップとかバインディングとか覚えないといけないのと。

たぶんそれが 2006〜2007 年くらい。

で、新しもの好きがたたって(?)一時期 Titanium Desktop とかに可能性を感じてみちゃったりしたわけです(結局 Appcelerator は Titanium Desktop を手放してオープンソース化されて Tide SDK ?とかになって細々とやってるのかな)。

AppJS っていうのを見つけたりしてこれもいいかもと思ったんだけど、実際使ってみるとどうも思ったとおり動いてくれない(Windows 64bit 環境だと起動もせずにクラッシュした。そのうち直るかもしれないけど)し、ドキュメントとかも圧倒的に足りてない感じ。→ 今は deskshell っていうプロジェクトに引き継がれているようですが、どうなることやら。

最近は Chrome App がいい感じかな〜とも思ったけど、お手軽さという意味ではいいんだけどやっぱりブラウザに縛られるというか普通にローカルのファイルを見に行けないとかそういう息苦しさみたいなものはある。作れるアプリが限定されちゃうというか。必要なデータは全部 Web からかき集めてきて、保存するときもクラウド、みたいな Web ネイティブなイマドキのアプリにはいいのかもしれない。(実際、2 つくらい自分用の実用的な小さなアプリを Chrome App で作ってみた)


前置きが長くなったけど、そんな中で見つけたのが node-webkitQt

node-webkit

node-webkit は、数ある「WebKit と LL を組み合わせて見ました」系のフレームワークとは一線を画す感じで、ちょっと使ってみた感じでも商用アプリを作るのに耐える品質を備えているんじゃないかと思ったフレームワーク。開発も活発に続いている。ドキュメント等、情報も他のものに比べると十分そろっていると思う。(少なくとも、今までアプリを作ってて困ったことがあってぐぐったら全部答えが見つかっている)

少しだけ特徴をあげてみると、

  • 作ったアプリをバイナリ単体で配布できる(Windows なら単一の .exe ファイルにできるし、Mac ならパッケージを作れる。Linux でも 1 つの実行ファイルにして配布できる)
  • node.js で DOM をいじれる

→ これ結構気持ちのいいパラダイムシフト。サーバサイドの人もクライアントサイドの人も到達したことのない境地のはず。「サーバサイドとクライアントサイドの言語が統一できますよ」っていうの(一瞬うれしそうだけど全然嬉しくないやつ)のレベルじゃない。たとえば、AngularJS のコントローラの中で SQLite で直にファイルからデータを読みだしたりできるんだぜ?
CoffeeScript とか LESS とかソレ系のやつを grunt で毎回コンパイルしたりしなくてよい。GUI アプリとして実行される時にコンパイルすれば良いから。で、シングルページアプリケーションとして動かして DOM をグリグリいじって画面の更新をするようにすれば再読み込みが発生しないのでパフォーマンスにもインパクト小(起動時に一回だけコンパイルされるだけ)。どうしてもそれも許せないなら普通に事前に JS や CSS へとコンパイルしてもいい。

→ パフォーマンスは逆に悪化するらしいが、秘密にしたいコードを(若干ではあるが)隠せる。

などなど。
node-webkit を使って、これも 2 つくらいアプリを書き始めてみたところ。

Qt

Qt なんて、見つけたというか温故知新というか僕が今まで気づいてなかっただけで、C++ のごっつい旧世代のフレームワークくらいにしか思ってなかったんだけど、実は Webkit ベースで HTML5 アプリを作れて C++ の世界(QObject)とのインタラクションが快適そうなので急浮上してきた。

実際ちょっと使ってみたら、Qt って名前の通り結構キュートなやつなのな。クラスライブラリの設計とかもちゃんとモダンな標準に従っててエレガントな感じがしてさわり心地がいい。C++er としてはホント今まで気づいてあげられなくてごめんよという感じ。
node-webkit ほどの気持ちよさは無いけど、パフォーマンスを極限まで追求したいとかどうしてもシステムコール呼びたいとか、ポインタが無いと生きていけないとかそんな下寄りに行きたい、でもイマドキっぽいかっこいい GUI も欲しいとかいうようなときは(どんなときだよ)、今後は僕は Qt を選ぶと思う。(node-webkit + native extension に行っちゃうかもしれないけど)

一つ実験的に規模大きめの GUI アプリを書き始めてみた。

まとめ

Web/モバイル全盛のこの時代、デスクトップアプリ自体がオワコンっていう話もあるのかもしれないけど、たぶん HTML5 ベースのデスクトップアプリによって一回揺り戻しが来るんじゃないかな〜なんて考えています。

久しぶりにワクワクしながら GUI アプリを書いている今日このごろです。

chef で remote_directory リソースで一気にファイルをコピーしようとしたら空ディレクトリがコピーされなくて困った件(解決策もあるよ)

仕事では vagrant + chef を使って Hermetic なテスト環境を誰でも簡単に作れるようにしようという取り組みをしています。

モバイルアプリからアクセスするバックエンドのサーバは、現時点では本番環境かテスト環境かというくらいしかないのですが、これを vagrant と chef で誰でもローカルの仮想マシン上にセットアップできるようにしちゃおうという目論見です。

バックエンドサーバのコードは自社製のレガシーなものがすでにありますので、まずはそれをデプロイしたいなと。
chef のリポジトリの site-cookbooks/<cookbook-name>/files/default/ あたりにそのバックエンドサーバの実行に必要なファイル一式を用意しておいて、まるっと仮想マシンにコピーしたいわけです。

で、chef のリソースについてのドキュメントなんかを読むと、どうやら remote_directory というリソースを使えば cookbook に入れておいたファイルたちをディレクトリごとまるっとコピーしてくれるようだということがわかります。

そこで早速使ってみたのですが、一つ問題に気づいてしまいました。

空っぽのディレクトリが仮想マシン側の環境にコピーされていないのです。

ログを出すためのディレクトリとか、ユーザからのアップロードを受け付けるためのディレクトリだとかそんな感じのディレクトリの一つや二つ、ありますよね?
そういう空のディレクトリが cookbook の files の下にあっても、仮想マシン側にはそれがコピー(作成)されないのです。

一つや二つなら、実行時にどうせ作られるし別に気にしないのですが、今回いじってるサーバはちょっとわけあって100個くらいそういう空のディレクトリがあります。
しかも、本番環境やテスト環境と差分がないことを diff とったりして確認したいので、100個も差分があると本当の差分が埋もれてしまって困ることになります。

で、解決策がここにありました。
https://github.com/higanworks-cookbooks/mongodb-10gen/issues/3

やはり同じ事で困っている人はいるみたいです。


解決策を大雑把に説明すると、コピー元の cookbook の files の下の空ディレクトリになんでもいいからダミーの空ファイルを入れておけということのようです。

私の場合は

find ${COOKBOOK_FILES_DEFAULT_DIR} -type d -empty -exec touch {}/delete.me \;

という感じで一括して delete.me という名前のファイルを空ディレクトリの中に作成しました。

で、レシピには、

execute 'delete delete.me files' do
  command "find #{dst_dir} -name 'delete.me' -exec rm {} \\;"             
end

こんな感じのコードを書いておくと knife solo cook したときに delete.me が消えてなくなります。

シェルスクリプトの中でコマンドが存在するかどうかを確かめる方法

stackoverflow に答えとともに良い説明があった。
http://stackoverflow.com/a/677212/2122085

#!/bin/sh なスクリプトの場合(bash ではなく sh を使っている場合)は

\command -v foo >/dev/null 2>&1 || { echo >&2 "'foo' is required.  Aborting."; exit 1; }

で OK。

こういう場合、よく which を使う(というか僕はいままで which を使っていた)のだけど、それだとどうもコマンドが見つからなかった時に 0(正常終了)を返してくる環境があるらしく、また which は外部コマンドなので多少オーバーヘッドがあったり、ディストリビューションによっては which をカスタマイズしてパッケージマネージャと連携させていたりするらしいのでヘビーデューティなスクリプトだとパフォーマンスに多少影響を与えることになるのかもしれない。

一応上記コマンドの解説。

\command -v は sh のビルトインで、引数で指定されたコマンド(外部コマンド、ビルトインコマンド、エイリアスを含む)を実行はせずに、外部コマンドならそのコマンドの絶対パス、ビルトインコマンドならコマンド名、エイリアスならエイリアスの展開、をそれぞれ表示してくれる。
(stackoverflow の回答では先頭に \ をつけていないけど、念のためつけておくことにした。http://bearmini.hatenablog.com/entry/2013/04/13/000055 参照。)

foo は探したいコマンド。

>/dev/null 2>&1 は command -v の出力を(エラー出力も含めて)捨てている。

|| { 〜 } の部分は、コマンドが見つからなかった時に command ビルトインの終了コードが 0 以外になるので実行される部分。上記の例ではエラーメッセージを表示して exit 1 している。



(sh ではなく)#!/bin/bash を使用している場合は command ビルトインの代わりに type もしくは hash ビルトインが使える。

hash ビルトインを使うと、コマンドをサーチしてその場所がハッシュされて残るので、実際にそのコマンドを実行するときのサーチが高速になるとのこと。ただし外部コマンドを探すときにしか使えず、ビルトインコマンドを探すことができないという欠点がある。

type ビルトインを使うと、2回目以降のサーチが速くなったりはしないがビルトインコマンドも探すことができる。command ビルトインとの違いはよくわからないけど、man を読んだ限りでは、type だと tracked alias というものにも対応しているのかな?ただ、tracked alias の説明をググったりして探してみても ksh というシェルの機能のようで bash では使えなさそう。command -v より type のほうがキータイプ数(ファイルに保存される文字数)が少なくなるというメリットがあるのかな?
上記 stackoverflow の回答では bash のときは hash か type を使えと書いてあるけど command -v ではいけない理由までは書いてないな。

なんかモヤモヤしたままこの記事は終了^^;

bash スクリプトの中でそのスクリプト自身が置かれているディレクトリを絶対パスで取得する方法

[2017.04.04 update]
shellcheck でエラーが出ないように修正
[/2017.04.04 update]

イディオム的な。

BASE_DIR="$( cd "$( dirname "$0" )" || exit; pwd )"

いつも忘れるのでメモ。

GotW #6a: 正しい const 第1部(勝手訳)

GotW #6a の翻訳です。

例によって原文著者(Herb Sutter 氏)の許可は得ていませんし、私の英訳がヒドいクオリティである(用語の統一がとれていないとか、誤訳が含まれているとか)かもしれませんのでそこのところはご理解いただければと思います


原文:http://herbsutter.com/2013/05/24/gotw-6a-const-correctness-part-1-3/

const and mutable have been in C++ for many years. How well do you know what they mean today?

const と mutable は長年にわたって C++ に存在しています。現在それらがどういう意味を持つか、あなたはどのくらい知っていますか?

Problem 問題

JG Question 見習いグルへの問題

1. What is a “shared variable”?

1. "共有変数" とは何か?

Guru Questions グルへの問題

2. What do const and mutable mean on shared variables?

2. 共有変数に対する const と mutable は何を意味するか?

3.How are const and mutable different in C++98 and C++11?

3. const と mutable は C++98 と C++11 においてどのように異なるか?

Solution 解答

1. What is a “shared variable”?

1. "共有変数" とは何か?


A “shared variable” is one that could be accessed from more than one thread at the same time.

"共有変数" は複数のスレッドから同時にアクセスできる変数のことです。


This concept is important in the C++ memory model. For example, the C++ memory model (the core of which is described in ISO C++ §1.10) prohibits the invention of a write to a “potentially shared memory location” that would not have been written to in a sequentially consistent execution of the program, and the C++ standard library refers to this section when it prohibits “modify[ing] objects accessible by [other] threads” through a const function, as we will see in #2.

このコンセプトは C++ メモリモデルにおいて重要です。たとえば、C++ メモリモデル(核となる部分は ISO C++ §1.10 に記述されています)は”潜在的に共有されるメモリ位置" への書き込みを禁じていて、プログラムが正しく実行されている限りにおいてはそのような場所に書き込まれることはありません。また、C++ 標準ライブラリが次の 2. でこれから見るように const 関数によって "[他の] スレッドからアクセス可能なオブジェクトの変更" を禁じているのは、このセクションを参照しているためです。

2. What do const and mutable mean on shared variables?

2. 共有変数に対する const と mutable は何を意味するか?

Starting with C++11, const on a variable that is possibly shared means “read-only or as good as read-only” for the purposes of concurrency. Concurrent const operations on the same object are required to be safe without the calling code doing external synchronization.

C++11 の場合から見て行きましょう。共有される可能性のある変数に対する const は、並列実行の目的のために "読み取り専用 もしくは 読み取り専用と同等" を意味します。同じオブジェクトに対する並列 const 操作は外部的に同期をするためのコードの呼び出しなしで安全であるために必要とされます。

If you are implementing a type, unless you know objects of the type can never be shared (which is generally impossible), this means that each of your const member functions must be either:

あなたが何かの型を実装しようとしているなら、その型のオブジェクトが絶対に共有されることがないとわかっている場合(そんなことは普通ありませんが)を除いて、すべての const メンバ関数は以下のいずれかである必要があることを意味します:

  • truly physically/bitwise const with respect to this object, meaning that they perform no writes to the object’s data; or else
  • internally synchronized so that if it does perform any actual writes to the object’s data, that data is correctly protected with a mutex or equivalent (or if appropriate are atomic<>) so that any possible concurrent const accesses by multiple callers can’t tell the difference.
  • このオブジェクトに関して、真に物理的にビット単位で const である。すなわち、そのオブジェクトのデータに対して書き込みが行われない;もしくは、
  • 内部的に同期しているので実際にはそのオブジェクトのデータに何か書き込んでいるが、そのデータは mutex もしくは同等のもの(もしくは atomic<> が適切ならそれ)を用いて正しく保護されているので、複数の呼び出し元からの何らかの並列な const アクセスにはそれがわからないようになっている。

Types that do not respect this cannot be used with the standard library, which requires that:

これを守らない型は、標準ライブラリと組み合わせて使うことができません。標準ライブラリは以下のことを要求しています:

“… to prevent data races (1.10). … [a] C++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const arguments, including this.”—ISO C++ §17.6.5.9

"... データの競合 (1.10) を防ぐため ... [a] C++ 標準ライブラリ関数は、関数の非 const な引数(this を含む)によって直接または間接的にアクセスされる以外は、直接または間接的に現在のスレッド以外のスレッドからアクセスされるオブジェクト(1.10) を変更してはならない。- ISO C++ §17.6.5.9

Similarly, writing mutable on a member variable means what it has always meant: The variable is “writable but logically const.” Note what this implies:

同様に、メンバ変数に mutable と書くことはすでに述べたような意味を持ちます:その変数は "書き込み可能だが論理的には const" です。これが意味するところは、

  • The “logically const” part now means “can be used safely by multiple concurrent const operations.”
  • The “mutable” and “writable” part further means that some const operations may actually be writers of the shared variable, which means it’s inherently got to be correct to read and write concurrently, so it should be protected with a mutex or similar, or made atomic<>.
  • "論理的に const" の部分は "複数の並列 const 操作によって安全に使うことができる" ということを意味します。
  • "mutable" と "書き込み可能" の部分は、const 操作 によって実際には共有変数に書き込むことがあるかもしれないということを意味し、read と write が同時に行われたとしても本質的に正しくなければならないということであり、mutex もしくは同等のもの、もしくは atomic<> にすることによって保護されるべきであるということです。


In general, remember:

一般的には、以下のルールを覚えてください:

Guideline: Remember the “M&M rule”: For a member variable, mutable and mutex (or atomic) go together.

ガイドライン:"M&M ルール" を覚えましょう:メンバ変数に対して、mutable と mutex (もしくは atomic)はいつも一緒に使います。


This applies in both directions, to wit:

これは両方の面から適用されます。すなわち:

(1) For a member variable, mutable implies mutex (or equivalent): A mutable member variable is presumed to be a mutable shared variable and so must be synchronized internally—protected with a mutex, made atomic, or similar.

(1) メンバ変数に対して、mutable は mutex(もしくは同等のもの)を示唆します:mutable なメンバ変数は mutable な共有変数であると推測されるので、内部的に同期されなければなりません。すなわち mutex を使うかもしくは atomic にするかもしくは同等の方法で保護されなければなりません。

(2) For a member variable, mutex (or similar synchronization type) implies mutable: A member variable that is itself of a synchronization type, such as a mutex or a condition variable, naturally wants to be mutable, because you will want to use it in a non-const way (e.g., take a std::lock_guard) inside concurrent const member functions.

(2) メンバ変数に対して、mutex(もしくは同等の同期型)は mutable を示唆します:mutex や条件変数のような同期型のメンバ変数は、必然的に mutable になるはずです。非 const な方法(たとえば std::lock_guard を取るとか)で並列 const メンバ関数の中から使われるからです。


We’ll see an example of (2) in Part 2, GotW #6b.

(2) の例は第2部、GotW #6b で見て行きましょう。

3. How are const and mutable different in C++98 and C++11?

3. const と mutable は C++98 と C++11 においてどのように異なるか?

First, let’s be clear: C++98 single-threaded code still works. C++11 has excellent C++98 compatibility, and even though the meaning of const has evolved, C++98 single-threaded code that uses the old “logically const” meaning of const is still valid.

まず一つ明確にしておきましょう:C++98 のシングルスレッドのコードは今でも動きます。C++11 は C++98 との素晴らしい互換性を持っていて、const の意味が改良されたにもかかわらず、const をその古い "論理的に const" の意味で使っている C++98 のシングルスレッドのコードは今でも有効です。

With C++98, we taught a generation of C++ developers that “const means logically const, not physically/bitwise const.” That is, in C++98 we taught that const meant only that the observable state of the object (say, via its non-private member functions) should not change as far as the caller could tell, but its internal bits might change in order to update counters and instrumentation and other data not accessible via the type’s public or protected interface.

C++98 では、私たちは C++ 開発者達に "const というのは論理的に const であって物理的/ビット単位で const ということではない" と教えました。すなわち、C++98 においては、cost はそのオブジェクトの観測可能な状態(つまり、private でないメンバ関数を介して、ということですが)が呼び出し元にわかる範囲では変わってはいけないが、内部のビットはカウンタや計測値を更新したり、public もしくは protected なインターフェースを介してアクセスされることのないようなデータは変化しても良いと教えました。

That definition is not sufficient for concurrency. With C++11 and onward, which now includes a concurrency memory model and thread safety specification for the standard library, this is now much simpler: const now really does mean “read-only, or safe to read concurrently”—either truly physically/bitwise const, or internally synchronized so that any actual writes are synchronized with any possible concurrent const accesses so the callers can’t tell the difference.

この定義は並列性のためには不十分です。C++ およびそれ以降では、標準ライブラリのための並列性メモリモデルとスレッド安全性仕様が含まれます。これはよりシンプルです:const は "読み取り専用、もしくは並列読み取りに対し安全" という意味を持つようになりました。これは、真に物理的にビット単位で const であるか、実際には書き込みが同期されていても並列 const アクセス時に呼び出し元に違いがわからないようにするために内部的に同期するかのどちらかです。

Although existing C++98-era types still work just fine in C++98-era single-threaded code for compatibility, those types and any new ones you write today should obey the new stricter requirement if they could be used on multiple threads. The good news is that most existing types already followed that rule, and code that relies on casting away const and/or using mutable data members in single-threaded code has already been generally questionable and relatively rare.

既存の C++98 時代の型は互換性のために今でもちゃんと C++98 時代のシングルスレッドコードで動きます。そのような型も、あなたが今日以降書く新しい型も、もしマルチスレッドで使われるのであれば、新しい厳格な方の要求に従うべきです。良いニュースはほとんどの既存の型は実はそのルールにすでに従っているということです。また、シングルスレッドのコードにおいて、キャストによって cosnt を外してしまうことや mutable なデータメンバを使うことに依存しているようなコードは一般的にはいかがわしいものとされてきましたし、相対的にレアなものです。

Summary まとめ

Don’t shoot yourself (or your fellow programmers) in the foot. Write const-correct code.

自分自身の足を撃ちぬかないでください(もしくは同僚プログラマの足を)。正しい const のコードを書いてください。

Using const consistently is simply necessary for correctly-synchronized code. That by itself is ample reason to be consistently const-correct, but there’s more: It lets you document interfaces and invariants far more effectively than any mere /* I promise not to change this */ comment can accomplish. It’s a powerful part of “design by contract.” It helps the compiler to stop you from accidentally writing bad code. It can even help the compiler generate tighter, faster, smaller code. That being the case, there’s no reason why you shouldn’t use it as much as possible, and every reason why you should.

一貫して const を使うことは正しく同期されるコードのために必要です。それだけでも、一貫して "正しい const" であるべき理由として十分ですが、理由はほかにもあります:正しい const は、インターフェースと不変性について /* これは変更しないよ。約束します! */ なんて書くよりもずっと効率的にドキュメンテーションすることにもなります。これは ”契約によるデザイン (design by contract)" のパワフルな部分です。

Remember that the correct use of mutable is a key part of const-correctness. If your class contains a member that could change even for const objects and operations, make that member mutable and protect it with a mutex or make it atomic. That way, you will be able to write your class’ const member functions easily and correctly, and users of your class will be able to correctly create and use const and non-const objects of your class’ type.

mutable を正しく使うことが "正しい const" のキーになることを覚えておいてください。もしあなたのクラスが const オブジェクトに対する const 操作であっても変更されるようなメンバを持っているなら、そのメンバを mutable にしてそれを mutex で守るか atomic にしてください。そうすると、あなたのクラスの const メンバ関数は簡単に正しく書くことができるようになりますし、あなたのクラスを使う人もあなたのクラス型の const もしくは 非 const オブジェクトを正しく生成して使うことができるようになります。

It’s true that not all commercial libraries’ interfaces are const-correct. That isn’t an excuse for you to write const-incorrect code, though. It is, however, one of the few good excuses to write const_cast, plus a detailed comment nearby grumbling about the library vendor’s laziness and how you’re looking for a replacement product.

すべての商用ライブラリのインターフェースが "正しい const" ではないことは確かです。しかしそれはあなたが "正しくない const" のコードを書くための言い訳にはなりません。ただし、それは const_cast を書くための、そしてそのライブラリのベンダの怠慢やあなたが代わりになる製品を探していることについて愚痴をこぼすための詳細なコメントをそのライブラリのコードの近くに書くための言い訳として許される、数少ないものの一つです。

Acknowledgments 謝辞

Thanks in particular to the following for their feedback to improve this article: mttpd, jlehrer, Chris Vine.

この記事をより良くするための以下の各位からのフィードバックに対し、特に感謝する:mttpd, jlehrer, Chris Vine.

Vagrant で作成した仮想マシンを、ホスト起動時に一緒に自動的に起動する方法(Ubuntu 12.04)

Ubuntu 12.04 の場合、/etc/rc.local あたりに以下のように書いておきます。
(他のバージョンの Ubuntu や、他のディストリビューションでもコマンド自体は同じで大丈夫でしょう。このコマンドを書く場所がちょっと違うかもしれませんが、そのシステムごとに起動時に自動実行されるスクリプトがあるはずですのでそこに書きましょう)

sudo -u $user VBoxManage startvm $vm --type headless

$user は VM を作成した(その VM を管理している)ユーザのユーザ名です。
$vm は VM の名前です。あなたの VM の名前に置き換えてください。
VM の名前がわからないという場合は VBoxManage list vms というコマンドを実行するとたぶんわかります。