Hatena::ブログ(Diary)

きりかノート 2冊め

2014-10-28

[][]MacPortsのport:ruby21, ruby20, ruby19を更新(セキュリティ修正あり)

あたらしいバージョンがリリースされていたので対応しました。

  • port:ruby21: 2.1.4
  • port:ruby20: 2.0.0-p594
  • port:ruby19: 1.9.4-p550

今回のリリースはセキュリティ修正を含みます。詳細は公式の情報をごらんください。

また、今回のリリースからPOODLE対応として安全でないとわかっているSSL/TLSオプションが無効になっています。こちらも公式ページに説明があります。

MacPortsのrubyとしては、この変更を取り消すvariantは用意しません。


OS X 10.7と10.8でコンパイルが終了しない対策

buildbotの進捗をながめてたら、10.7と10.8のビルドタイムアウトで失敗していた。手元の10.7環境で試してみたところ、minirubyでrbconfig.rbを生成するところで止まってることが確認できた。どうもminirubyがおかしいみたい。`./miniruby sample/test.rb`を実行してみてもうんともすんとも言わない。

このレベルで動かないのはconfig.hがおかしいことが多いので、正常に動作した10.9環境と比べてみる。

   % diff -u config.h-10.9 .ext/include/x86_64-darwin11.0/ruby/config.h
   --- config.h-10.9	2014-10-28 02:38:10.000000000 +0900
   +++ .ext/include/x86_64-darwin11.0/ruby/config.h	2014-10-28 22:09:09.000000000 +0900
   @@ -272,7 +272,6 @@
    #define HAVE_UTIMES 1
    #define HAVE_WAIT4 1
    #define HAVE_WAITPID 1
   -#define HAVE_BUILTIN___BUILTIN_BSWAP16 1
    #define HAVE_BUILTIN___BUILTIN_BSWAP32 1
    #define HAVE_BUILTIN___BUILTIN_BSWAP64 1
    #define HAVE_BUILTIN___BUILTIN_CLZ 1
   @@ -316,9 +315,9 @@
    #define DLEXT_MAXLEN 7
    #define DLEXT ".bundle"
    #define LIBDIR_BASENAME "lib"
   -#define RUBY_SETJMP(env) _setjmp((env))
   -#define RUBY_LONGJMP(env,val) _longjmp((env),val)
   +#define RUBY_SETJMP(env) __builtin_setjmp((void **)(env))
   +#define RUBY_LONGJMP(env,val) __builtin_longjmp((void **)(env),val)
    #define RUBY_JMP_BUF jmp_buf
    #define HAVE_PTHREAD_H 1
   -#define RUBY_PLATFORM "x86_64-darwin13.0"
   +#define RUBY_PLATFORM "x86_64-darwin11.0"
    #endif /* INCLUDE_RUBY_CONFIG_H */

まー、RUBY_SETJMP()やRUBY_LONGJMP()あたりがあやしいよね。configureのオプションで--with-setjmp-type=_setjmpとして強制的に指定してやればminirubyは動くようになって解消した。とりあえず、MacPortsのPortfileにはこれを入れて対処することに。

抜本的な対応は、rubyのupstreamのほうでどうにかしよう。

(10/29 追記)trunkに修正が入り、この問題は解消しました。はやすぎる!

2014-10-26

[][]忘れがち、OS Xの標準のファイルシステムは大文字小文字を区別しない

ちょっと前にMacPortsのチケットで問い合わせがきてた(#45257 (ruby20: warnings from library files that differ only by case of filename) – MacPorts)ものについて、慣れてるとすぐあたりがつくんだけど、気付かないとだいぶイミフなのでメモ残しとこう。

これはMacPorts固有の現象でもないので、10.9 Mevericksに添付のrubyで試してみよう。

   % irb -w --simple-prompt
   >> RUBY_VERSION
   => "2.0.0"
   >> require 'Digest'
   => true
   >> Digest::MD5.digest("!")
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/digest.rb:4: warning: method redefined; discarding old const_missing
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/Digest.rb:4: warning: previous definition of const_missing was here
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/digest.rb:28: warning: method redefined; discarding old file
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/Digest.rb:28: warning: previous definition of file was here
     :

定数が上書きされてるよ!という警告がでてきてしまう。これはなぜ?という話。もちろん実際にはファイルは小文字の名前の"digest.rb"しかない。

requireされたファイルを見てみると、確かに"digest.rb"と"Digest.rb"のふたつの名前が読み込まれている。これは実際には同じファイルだ。

   >> $LOADED_FEATURES.grep(/digest/i)
   => ["/System/Library/.../lib/ruby/2.0.0/universal-darwin13/digest.bundle",
       "/System/Library/Frameworks/.../lib/ruby/2.0.0/Digest.rb", # *D*igest
       "/System/Library/Frameworks/.../lib/ruby/2.0.0/digest.rb", # *d*igest
       "/System/Library/.../lib/ruby/2.0.0/universal-darwin13/digest/md5.bundle"]

原因はOS Xの標準のファイルシステム、HFS+がファイル名の大文字小文字を区別しないことだ。

1. require "Digest" → $LOAD_PATHから"Digest.(rb|bundle)"を探すと(詳細はるりまのKernel#require参照)、ファイルシステムは大文字小文字を区別しないので「"Digest.rb"があるよ」と答える → digest.rbが読み込まれ、"Digest.rb"として$LOADED_FEATURESに記録される。

2. Digest::MD5したとき、const_missingの処理の中で`require "digest"`される。"digest.rb"はまだ$LOADED_FEATURESの中にはないので、同じ"digest.rb"が読み込まれる。

という流れみたい。今回は警告メッセージ出すようにしてたから気付けたけれど、ファイル名の大文字小文字がちがってても動いてしまうので、そのまま他の環境に持っていくと動かない。ということもあるので注意。

Mac用のアプリでもこのへんわりとぐだぐだで、ファイルシステムを大文字小文字区別するHFSXに変えると動かないものがあるというのは時々聞く話。でも個人的にはそろそろ標準をHFSXにしてほしいなあと思う。

2014-10-13

[]RubyCocoa with Ruby-1.8 on Yosemite

ちょっとまだruby 2.0対応版に問題があるようなので、とりあえず用意しました。Yosemite GM3上で簡単に動作確認済みです。

配布物は次の2つです。

  • Ruby-1.8-for-RubyCocoa.pkg: ruby本体。rubygemsとtest-unit入り。
  • RubyCocoa-1.2.0-OSX10.10-Ruby1.8.dmg: RubyCocoa。libruby.aに静的リンク済み。

ruby-1.8.7-p374とRubyCocoaのインストーラは別々です。rubyは--disable-sharedしてつくったので、組み込みライブラリCocoaだけで構成されたアプリであれば、ruby本体は不要です。

標準添付ライブラリや他のgem・ライブラリを使用している場合(ようするにアプリのコード以外にrequireしている場合)は、アプリケーション単体で配布するにはRubyCocoa添付のstandaloneify.rbを利用して、アプリケーションバンドルに必要なファイルをアプリケーションに含める必要があります。

 % ruby standaloneify.rb -f -d YourApp.app /path/to/build-dir/YourApp.app

なにかあればお知らせください。

2014-08-01

[][]ruby-2.1.2のlibffi-3.1対応

チケットが来てたので対応しました。

内容についてはrubyのissie#9897にあるとおりです。

いちお簡単に説明すると、ビルド時にマクロとしてRUBY_LIBFFI_MODVERSIONという値を定義しているのですが、従来の"3.0.13"のような数字3つのバージョンから"3.1"という数字2の形式に変わったため、その値に入れるバージョンの加工に失敗してfiddleがコンパイルされないという状況になっていました。

trunkやruby_2_1ブランチでは修正済みだったので、その変更を適用しました。ruby-2.0ではRUBY_LIBFFI_MODVERSIONを使っていないためこの問題はありません。

また、別件で新しいXcodeでdlモジュールがインストールされないという問題があったので合わせて対応しています。

port:ruby21でfiddleが使えないなどの状況が起きた場合は、port upgrade ruby21で解消すると思います。

2014-07-27

[] RubyCocoa 1.2.0 リリース!

しました。ついにRuby 2.0以降に対応しました!(1.9は対応しません)

ちょっとパッケージング失敗したので、日本時間で今日の14:30以前にダウンロードした人は取り直したほうがよいかもです。

変更点をNEWS.jaから抜き出し。ruby-2.0対応したのが中心で、他は特にありません。

   == 1.1.0から1.2.0の変更点: 2014-07-27

   === 改良

     * ruby-2.0に対応しました。おおむねruby-1.8と同様に動作します。
       * RubyCocoaのインストーラはruby-1.8用と2.0用で別々のファイルとして
         リリースされます。RubyCocoaアプリケーションをOS X 10.9添付のruby-2.0で
         動作させてみたいときは、RubyCocoa.frameworkを入れ替えてください。
     * 存在しないメソッドが呼び出されたときの例外をNoMethodErrorに変更しました。
       (以前はOSX::OCMessageSendExceptionでした。)

   === 廃止された機能

     * CocoaClass#objc_export()は廃止されました。objc_method()を使ってください。
     * OSX::NSObject#ocm_responds?()は廃止される予定です。ocm_respond_to?()を使ってください。
     * OSX::NSData#dataWithRubyString()およびOSX::NSMutableData#dataWithRubyString()は
       廃止される予定です。[NSString dataUsingEncoding:]を使ってください。

   === 修正

     * Yosemite DP上でのビルドエラーを修正しました。

   === RubyCocoaをRuby-2.0上で使う際の注意

     * ruby-2.xの文字列はエンコーディングを保持するようになります。詳しくは
       https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/MigrationIssuesFrom18 や
       http://magazine.rubyist.net/?0025-Ruby19_m17n をごらんください。
     * (frameworkでない)bundleやdylibのObjective-CのクラスをRubyのコードで
       拡張したいときは、OSX.ns_importを書くようにしてください。

           require 'path/to/your_bundle.bundle'
           OSX.ns_import :YourClass
           module OSX
             class YourClass
               : # extend class in Ruby code
             end
           end

RubyCocoa.frameworkが、ruby-1.8用とruby-2.0用が存在することになるので、Finderに表示するようにしてみた。

f:id:kimuraw:20140727175259p:image


今後の予定

このくらいですかねえ。

最後のはまだアタリもつけてないけど、簡単にできるとよいなあ。

2014-07-26

[] RubyCocoa 今週のコミット ..2014-07-26 10.6/10.7での初期化エラーを修正

細かいとこではドキュメント更新したり、コンパイル時の警告つぶしたりしてた。

大きい作業としては、Snow LeopardやLion環境では"trunkでrequire 'osx/cocoa'しただけで落ちる"という致命的な問題があってその対応をしていた。

エラーメッセージはこんなの。

   "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby" -I../e
   xt/rubycocoa -I../lib testall.rb
   2014-07-25 05:48:43.038 ruby[4778:60f] *** NSInvocation: warning: object 0x7
   fff708db850 of class 'Object' does not implement methodSignatureForSelector:
    -- trouble ahead
   2014-07-25 05:48:43.041 ruby[4778:60f] *** NSInvocation: warning: object 0x7
   fff708db850 of class 'Object' does not implement doesNotRecognizeSelector: -
   - abort
   test failed

ようするに(Objective-Cの)Objectクラスを処理しようとしてエラーになってるわけだ。


Objective-Cのクラスの話

前提として説明すると、Objective-CのランタイムにあるすべてのクラスがCocoaのクラスというわけではない。Cocoaでは、NSObjectとNSProxyの2つのルートクラスがあり、ほとんどはNSObjectの派生クラスとしてFoundation等のフレームワークは構成されている。

で、それらとは別系統のクラスもあって、たぶんObjective-C組み込みと思われる"Object"クラスなんてのもある。

   // OS XのObjective-Cのクラス階層
   + NSObject
     + NSArray
     | + NSMutableArray
     + NSResponder
       + NSView
         + NSText
         | + NSTextView
         + NSTableView
   + NSProxy
   + Object # <= NOT a Cocoa class

ちなみに、今までほとんど表にでてこなかったObjectクラスなんだけど、SwiftのクラスはこのObjectクラスの派生クラスになってるという話もあるみたいね。

話を戻そう。(最近の)RubyCocoaでは、この「Cocoaのクラスかどうか」を

  • 自クラスまたはその親のクラスがNSObjectプロトコルに適合しているかどうか

で判定している。実装はこんな感じ。

   // framework/src/objc/mdl_osxobjc.m
   /*
    * Detects Cocoa Objective-C class or not with protocol "NSObject".
    * - NSObject => YES
    * - NSProxy  => YES
    * - Object   => NO
    */
   static BOOL
   class_is_cocoa_class_p(Class klass) {
     Protocol *proto = objc_getProtocol("NSObject");
     Class klass_sup = klass;
     while (klass_sup) {
       if (class_conformsToProtocol(klass_sup, proto)) {
         return YES;
       }
       klass_sup = class_getSuperclass(klass_sup);
     }
     return NO;
   }

で、これを利用してCocoaのクラスではないクラスはRubyCocoa的には存在しないものとして処理している。


今回のエラーの話

RubyCocoaでは、できるだけObjective-Cのクラス階層をRuby側でも再現するために、あるクラスがRuby側に現れたとき、そのスーパークラスもRuby側に呼び出すようにしている。今回はその機能でひっかかるとこができてた。

RubyCocoaの初期化時にOSX.ns_import_allでぜんぶのクラスをRuby側に持ってくるようにしているんだけど、そのとき処理対象となるProtocolクラスのスーパークラスがSnow Leopard環境などではObjectになってる。でObjectクラスをRuby側で扱おうとしてもCocoaなクラスじゃないのでRubyCocoaを通した操作ができない。でエラーになるというわけ。

RuntimeBrowserで実装を見てみると、ProtocolクラスのスーパークラスがMavericksではNSObjectに、Snow LeopardではObjectになっていることがわかる。

   // OSX 10.9 Mavericks
   @interface Protocol : NSObject  {

   // OSX 10.6 Snow Leopard
   @interface Protocol : Object <NSObject>

f:id:kimuraw:20140726123232p:image

f:id:kimuraw:20140726123233p:image

これを解消するためには、OSX::Protocol.oc_superclassがnilを返す(スーパークラスなし)ようにすればよい。つまり、Objective-Cのメソッド呼び出しの結果がClassで、そのクラスがCocoaのクラスじゃないときにはnilを返すように変更することになる。

関連するコミット。

  • Cocoaのクラスかどうかの判定基準をisKindOfClass:でなく、NSObjectプロトコルに適合しているかどうかに変更。10.8以前では+[NSProxy isKindOfClass:]を呼び出すとエラーになるため。(r2618)
  • Cocoaのクラスかどうかの判定を関数class_is_cocoa_class_p()に切り出し。(r2620, r2622)
  • メソッドの返り値がクラスで非Cocoaのクラスのときnilを返すようにする。(r2626)

これでOS X 10.6 - 10.9の環境でtrunkのテストがぜんぶ通るようになった。

2014-07-21

[] RubyCocoa 今日のコミット 2014-07-21 NSData.dataWithRubyString()をdeprecatedに

いちおRC出したのでそんなにいじるつもりはないので、yardのドキュメントをメンテしたり。

便利メソッドとしてOSX::NSData.dataWithRubyString(str)というメソッドが昔からあるんだけど、使い道があんまりないなーと思った上に、そもそもエンコーディングなしにバイト取るのもどうなんだろ?と思ったのでdeprecatedにした。NSMutableDataのメソッドも同様。

  • yardで@deprecatedを指定。NEWSにも書いた。実行時にはwarnする。(r2611)
  • テストで使ってるとこを必要な箇所を除きNSString#dataUsingEncoding()に直した。(r2612)
  • NSData#lengthのテストに非asciiなデータも足しておいた。(r2613)

たぶん誰も使ってないと思うので、1.2の次の次くらいのリリースで削除します。

2014-07-20

[] RubyCocoa 今週のコミット ..2014-07-20 サンプルアプリの動作確認

sample/以下にあるアプリの一覧をつくって、ひたすら確認して直してた。

  • もともとおかしかったぽい
    • make系のプロジェクトで-framework AppKitが足りない。
    • import <AppKit/NSApplication.h>足しておいた。
  • ruby-2.0によるもの
    • ruby-2.0でSyntax Errorになるものを直した。

他のアプリのプラグインとかは確認するのが大変なのでコンパイルできるとこまでしか確認していないです。

[] RubyCocoa 1.2.0 RC (Ruby-2.0対応版)を公開

しました。いきなりリリースしてもよかったんだけど、自分だけの確認では不安だったので。

動作確認用なのでOS X 10.9用のみです。なにかあればお知らせください。ヤバそうな問題が報告されなければ次の週末あたりにリリースします。

これまで試してきた印象では、RubyCocoaによる問題よりもrubyが1.8から2.0になった部分のほうが影響が大きいんじゃないかと思います。String#each → #each_lineとかそういうの。

2014-07-16

WebVTTファイルを利用して動画に字幕を付ける

小ネタ。自分用のメモです。

WWDCのtranscriptをテキスト化しているasciiwwdcリポジトリwwdc-session-transcriptsをながめてて、拡張子".vtt"てなんじゃろと思って調べてみたところ、WebVTTという規格のテキストであることがわかった。

テキストはこんな感じで、字幕のテキストの他に表示する時間や表示する形式が書かれている。シンプルな構造だね。

   WEBVTT
   X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000

   00:00:13.236 --> 00:00:14.526 A:middle
   &gt;&gt; My name is Olivier Bonnet.

   00:00:14.526 --> 00:00:18.266 A:middle
   I'm the engineering manager for
   the CloudKit on the client side.

動画と組み合わせて字幕を表示させるには、html中のtrack要素で書いてやればよい。

   <video controls autobuffer autoplay loop id="wwdcvideo" width="100%">
       <source src="./2014/408_sd_swift_playgrounds.mov" type="video/quicktime" />
       <track kind="captions" src="./2014/408.vtt" type="text/vtt" srclang="en"
              label="English Subtitles" default />
   </video>

ちなみに2014年のWWDCの動画には最初から字幕データが入っているので、こんなことしなくても字幕付く。てゆか二重に表示される。

いやさ、Safariでそのまま見てると最大化しないと字幕のオプションでてこないから、気付かなかったんですよ!

2014-07-14

[] RubyCocoa 今日のコミット 2014-07-14 インストーラ作成スクリプトの調整

10.9 Mervericks用はruby-1.8とruby-2.0の両方がOSに付いてるので、それぞれ用のRubyCocoa.frameworkのインストーラをリリースする予定。なのでそのあたりの調整あれこれ。

  • リリースファイルの名前を自由に指定できるように。 (r2587)
  • パッケージ作成時の設定ファイルをコマンドラインから渡せるように。 (r2588)
  • 10.9+ruby2.0用の設定ファイルを追加。(r2589)

今は自動的に"RubyCocoa-1.1.0-OSX10.9.dmg"などの名前を生成しているけれど、任意の名前も指定できるように。単にRubyのバージョンを足して、

  • RubyCocoa-1.2.0-OSX10.9-Ruby1.8.dmg
  • RubyCocoa-1.2.0-OSX10.9-Ruby2.0.dmg

になる予定。

パッケージ作成時の設定ファイルをpackage/config/以下におくようにして、`ruby install.rb package`で該当OSバージョンのファイルを使うんだけど、OSのバージョンが同じなので実行時のコマンドラインオプションで選べるようにした。

   % ls -1 package/config/
   10.4
   10.5
   10.6
   10.7
   10.8
   10.9
   10.9-ruby2.0 # <= NEW!

エンコーディングの件はまだちょっと悩み中。現在の案だとどうせ直すことになりそうだし、UTF-8使えれば現在の1.8レベルの利用は問題ないはずなので、次の次のバージョン(1.3?)に送っちゃおうかなあ、、とひよっている。今週末までの進行具合で判断しますです。

2014-07-10

[] RubyCocoa 今日のコミット 2014-07-10 ruby-2.xでThreadがおかしい?件に対応

だいたいruby-2.x対応できたので、samples/以下にあるアプリを動かしたりして動作確認してる。で、どうもrubyのThreadを使ったコードがうまく動かなくって、スレッドが切り替わらなかったりするのを調べてたんだけれどようやくわかった。

  • Thread.passがひつよう。(r2584)

RubyCocoa本体側を疑ってコード追っかけてたからぜんぜん気付かなかったぜい。


1.2.0リリースまでの残作業

今回は一度RC出す予定です。

2014-07-09

[]port:pecoを0.2.0に更新

しました。

先日MacPorts公式にport:pecoを登録してから気付いたんだけど、peco-0.1.12とMacPortsのportコマンドとの組み合わせで、どうも動作がおかしい。portの出力をpecoに渡すとそのまま固まってしまう(killしないと終了できない)。0.1.11以前は問題なかった。

pecoの変更を追っかけてみると、0.1.11と0.1.12で入力バッファの処理が変更されていて、どうもそのへんじゃないかと思ってレポートしたりして、報告した問題は解消されたんだけど、portだけまだおかしい。これはたぶんportが悪いんだと思う。

仕方ないので、パイプでつながないようにすることにした>"pbcopy; pbpaste"のあたり。

   % sudo port selfupdate
   % sudo port upgrade $(port outdated | pbcopy; pbpaste | peco | cut -f1 -d\ )

これで更新したいのを選ぶとupgradeされる。地味に便利。

2014-07-04

[] RubyCocoa 今週のコミット ..2014-07-03 standaloneify.rbのruby-2.x対応

1週間以上前にテスト全部とおるようになったんだけど、実際にアプリ試してみるとダメなところあったりで対処中。今はstandaloneify.rbを対応してるとこ。

  • ruby-2.xで"$0 not initialized"を修正。(r2581)
  • ruby-2.xでクラッシュするのを修正。(r2582)

簡単に説明。

rubyで実行中に$0の値を設定すると、プロセスの表示名(なんていうんだ?)を変更することができる。これを利用してstandaloneify.rbを実行中にターゲットのアプリのパスを$0に設定して、NSBundle.mainBundleがアプリになるようにしてたりする。これがruby-2.x上では"$0 not initialized"とエラーになってしまうようになった。

これはruby-2.0以降では実行しているプロセスがrubyコマンドのとき(正確にはruby_sysinit()されたとき)のみ、$0への代入を許可しているため。対応としては

  • $0へ代入しない。
  • ruby_sysinit()で初期化するようにする。

あたりなんだけど、とりあえず前者から試してみて対応できたのでそのようにした。CocoaではNSProcessInfoでrubyの$0と同様に実行中のプロセスの$0を変更できるのでそれを利用した。

次にクラッシュの件。standaloneify時のアプリで文字列Stringのインスタンスを生成すると落ちるというもので、これは数日調べてもぜんぜんわからなかった。なんだけど、ruby_run_node()での実行が終わったあとに操作してるのが問題ぽくて、そもそもstandaloneify時には必要ない処理だったのでクラッシュする箇所に到達する前にexit()するようにしたら直った。気付けば簡単なことなんだけど、これは苦戦した。。

あと残ってるのはどうもThreadの動作があやしくて、サンプルのSimpleAppからしてスレッド使ったとこがちゃんと動かない。たぶんこれ直したらリリースできると思う。

[] pecoのPortfileを本家に投入した

先日の”pecoのPortfileを書いてみた”から、納得いくカタチまで改善できたので、本家にコミットした。

   % port info peco
   peco @0.1.12 (sysutils)

   Description:          peco can be a great tool to filter stuff like logs,
                         process stats, find files, because unlike grep,
                         you can type as you think and look through the
                         current results.
   Homepage:             http://peco.github.io

   Build Dependencies:   go
   Platforms:            darwin
   License:              MIT
   Maintainers:          kimuraw@..., openmaintainer@...

これでMacPortsユーザも`port install peco`だけで使えるようになります。buildbotも正常に終了しているので、ふつーはport:goのインストールは不要です。

改善したところ。

  • 依存コードのgo-flagsなどもバージョン/リビジョンを指定して、tarballを取ってくるように。
  • peco本体と依存コードのブロックを分けるようにした。
  • checksumsの書式をきれいに。
  • コメントで補足書いた。
    • 依存コードのバージョン上げたらportのrevisionも上げてね。
    • port extract後のファイル構成。work/以下にgopathをつくって集める。

だいたいこのあたりはghqのPortfileも書きながら整理してたとこ。ghqのほうは、依存してるgoauth2google code上にあるMercurialリポジトリで、tarballとってくる方法がわからなくて保留中。別にhgコマンドで取ってくるのでもかまわないんだけど、ミラーの関係などでMacPorts的にはできればtarballやzipにしたいところ。

(2014-07-05追記:ソースツリーながめてたらふつーに"Download"のリンクがあった…。見落としてたよ、すまぬ。>google code)

github上にgoauth2のミラーがあればそっち使うんだけど、いくつか見た感じではforkで手が入ってるみたいなのでそれは使えないなあと。

ふだんだったら自分用につくって終わりなんだけれど今回本家にまで入れたのは、このあたりのツールは常識レベルになりそうな気配だったので可能ならMacPortsでも提供したいと思ったから。今どきはhomebrew使う人が多いだろうけれど、選択肢はあって悪いものじゃないしね。

2014-06-22

[][]第66回 Cocoa勉強会に行ってきた(6/14)

会場はいつもの新宿伊藤ビルの貸し会議室

以下発表など。内容的なことは勉強会のサイトのほうにレポートを書いたので、こちらは感想とか主観メインで。


発表「LightBlue Bean」(gadget)

BLE(Bluetooth Low Energy)で接続できる、いろんなセンサーついてる、Arduinoなどのフリスクサイズのデバイス。きょうびこの手のってすげえ小さくなってるよねえ。

当初の予定よりすごい遅れて勉強会の当日にSDKが公開されたんだけど、Objective-CAPIになってちょっとおどろき。Cの関数だけ並んでると思ってたよ。

あとで開発会社のWebサイト見たら、開発かかわってたらしいpopSLATEのAPIのとこも"Coming soon!"て書かれててちょっと笑ってしまった。


発表「iOSアプリ署名」(iOS)

アプリのビルドと署名の分割について。去年の12月の続き。

iOSアプリぜんぜんやってないから理屈で考えつつ聞いてた。ふだんXcodeいっぱつでできるのは簡単で良いけど、逆に隠蔽されてて融通きかないところもあるよね。


発表「OS Xの画面開発」(Mac)

storyboardの話。既存のアプリでViewControllerに手を入れまくってるから、いまさらレスポンダーチェーンに入れられても困る、という参加者の意見にもなるほど。まあでも新規アプリでしか使わんよね。


発表「irMagician」(gadget)

MacやPCなど別機器からの指示を受けてIRリモコンになるirMagicianの話。

発表者の他のユーザからオプションパーツのリクエストが出たりと、「開発してるなあ」と本質的でないとこで感心してしまったり。


発表「Swift」(swift)

Appleの新言語、swiftについて。発表者が自分用にplaygroundで試しつつ作ったという、大ボリュームのスライドを見ながらみんなであれこれ。

C++からObjcive-Cに来た人と、Rubyから来た自分でけっこう感じ方がちがうなあと思った。自分としては「実行速度を言語でとりにきたか」というのが第一印象。WWDCのちょっと前にrustについてちょっと調べてたのもあるけれど。


次回の予定

8/2に開催予定です。

[] RubyCocoa 文字列エンコーディング (続き)

先週の続き。

  • if/switchによる変換を、st_tableの変換表に。→実装した。
  • 名前によるエンコーディング変換表の自動作成。→うまくいかなかった。
  • 変換できないエンコーディング。→可能ならUTF-8に。

試しながら考えたや課題など。


st_tableによる変換表

Rubyのencoding indexとCFStringEncodingはどちもintなので特に問題なく。

これは「同じエンコーディングは同じ符号化(バイト列)」であることを前提にしてるので、RubyのUTF-8-MacをUTF-8にしてからCFStringに渡す、ということはできない。これを実現したい場合、入力エンコーディングに対して

  • 変換の要否、その方法
  • 変換先のエンコーディング

といった情報をHashなどで持たせるような変換表にする必要があるだろう。このようにするべきかどうかは結論がでてない。

また、Rubyのエンコーディングは拡張ライブラリ(?)になっていて必要なときに読み込みするようになっているので、最低限の変換表(ASCII-8BIT, UTF-8)だけ初期登録しておいて、あとは実行時に追加していくのが良いと思う。(そうしないとindexがわかっていても、エンコーディング本体がロードされてなくて妙な動作をしたりする。)ただこの「実行時に追加」をどうするのかが考えどころ。

名前(char *)の変換表を内部的に持つあたりかなあ。ということで次へ。


名前によるエンコーディング変換

RubyもCFStringも「エンコーディングの名前」を持っているので、これを使えばよいのでは?と試してみた。

CFStringEncodingで使えそうなのは、

  • IANA charset名 (CFStringConvertEncodingToIANACharSetName)
  • Windowsコードページ (CFStringConvertEncodingToWindowsCodepage)

あたり。IANAでない名前を取ることはできる(CFStringGetNameOfEncoding)けれど、名前から引くことはできないので除外。

RubyのEncodingで使えそうなのは

  • 名前 (Encoding#name)

あたり。RubyのEncodingは名前を複数持てるんだけど、Rubyのメソッドを通さないと拡張ライブラリからはひとつめ名称にしかアクセスできないっぽい。

で、とりあえずIANA charset名と名前で引けたものは自動的に変換テーブルに登録していくってのをやってみたんだけどうまくいかない。UTF-16がどうもうまくない。

NSString|CFStringは、Rubyの文字列とちがってある文字列を特定のエンコーディングとして認識しているのではなく、Cのバイト列との相互変換のときにエンコーディングを都度指定するようになっている。NSStringのインスタンスに対しては

  • fastestEncoding: バイト列にするときに時間がかからないもの。
  • smallestEncoding: バイト列にしたときそのサイズが小さいもの。
  • canBeConvertedToEncoding: 情報のロスなしに指定のエンコーディングに変換可能か。

などを問い合わせることができる。

この「エンコーディングそのものを持ってない。目的に応じて使えるエンコーディングを問い合わせることができる」てのがくせ者で、UTF-8で生成した文字列が、fastestEncodingでは(BEでもLEでもない)UTF-16を返すということがある。するとRuby側からUTF-8で渡した文字列がObjCから帰ってくるときにUTF-16になってしまう。これはNSString|CFStringの仕様的にどうにもならんのだけど気持ち悪い。

きょうびUTF-8がほとんどだと思うので、CFString(UTF-16)→Ruby Stringの場合はUTF-8に変換しちゃうほうがよいかもしれない。


変換できないエンコーディング

とりあえずUTF-8試してだめならバイト列という対応。internalやexternalというものがRubyにはあるので、それ使うほうがいいんじゃ?とも思ったけど、そのエンコーディングが変換可能なものかは実行時にならないとわからないのであまり良くないかなあと。

だいぶ(元の意味でも誤用の意味でも)煮詰まってきたので、ちょっと置いて今週は別の作業するつもり。

2014-06-21

[] pecoのPortfileを書いてみた

さいきんちらほら見かけた、絞り込み選択インターフェイスのコマンドpecoが気になったので試してみた。golangで書かれているので、goでビルドしてやる必要がある。

自分はMacPortsユーザなので、こういう状況になると「とりあえずPortfile書くか」というのがアプローチになるんだけれど、goの作法とかは全然わからない。ありがたいことに本家でhomebrew用のformulaが公開されてるので、それを参考にすればよい。

これでport install pecoで使える(注:本家にはコミットしていません)。標準出力が使えるってのが思ってた以上に強力で、どこでも差し込めるからあれこれ試しててけっこう楽しい。

で、Portfile書きながら、MacPortsとgolang製ツールの相性とかをぼんやりと考えていた。


○良いところ

buildbotが各OSバージョン用のバイナリ作ってくれるので、port:go入れなくてもインストールできる。今回なら${prefix}/bin/pecoだけ取ってくることになる。

また、goのことを知らなくてもインストールできる。ただこれは他のパッケージ管理ツールでも同様。

ちなみにpecoのissueながめてたところ、issue83に「drone.io使えばバイナリ自動ビルドできるよ」的なことが書いてあるので、そもそもそれ使えばよい話かも。


×良くなさそうなところ

今回は`go get`で逃げてるけれども、MacPorts的にはバージョンやタグを指定して、ライブラリ特定のリビジョンをdistfileとして取ってくるようにしたいところ。チェックサムの検証もできるし。

MacPorts自体はdistfilesにtagをつけることで、各distnameをそれぞれのmaster_siteから取ってくる機能があるので実現可能だと思う。

ただgithubのdownloadsがくれる.tar.gzなどはディレクトリにコミットidが入ってたりと使いづらい。それをPortGroup githubが解消してくれるんだけど、複数ファイルには対応してないっぽい。けっこう手を入れないと対応は難しそう。

Portfile書くにあたって、port:goが依存関係に入ってる公式portを検索してみたら、今朝時点ではport:codesearchひとつしかなかった。。

とくに結論とかはありません。