2013年12月アーカイブ

screencaptureコマンド


screencapture foo.png

ファイル名を引数に指定すると、そのファイル名でスクリーンキャプチャがカレントディレクトリに生成される

-t pdf

のようにフォーマット指定が可能。省略の場合 png

-x

サウンドを再生しない。"パシャ!" ってやつです。


screencapture -R 117,226,100,100

ピクセル範囲指定<x,y,w,h>。

ファイル名 117,226,100,100 のようなファイルがカレントディレクトリに生成される(ファイル名指定との併用はできない模様)。Retinaディスプレイの場合、この指定では実際は200ピクセル四方となる模様。

sipsコマンド

画像の情報取得、リサイズ、加工など。

sips --resampleWidth 400 from.png --out to.png
幅400pxに拡大(リサイズ)
sips --resampleHeightWidthMax 400 from.png --out to.png

縦横比を変更せず、最大ピクセルを400pxとして拡大(リサイズ)

sips --resampleHeightWidth 400 400 from.png --out to.png

縦横を指定して拡大(変形)

sips -s format jpeg  from.png --out to.jpg

フォーマット変換。品質指定も可(例:-s formatOptions low)

mdfindコマンド

スポットライトのコマンドライン版。高速にファイル検索が可能。

mdfind foo

fooを含むファイルの検索。

mdfind -name foo

ファイル名に「foo」を含むファイルの検索。

mdfind -onlyin /Applications/ 'kMDItemContentTypeTree=="com.apple.application"

アプリケーションディレクトリ以下の種類が「アプリケーション」のファイルをリストアップ。

textutilコマンド

テキスト等のファイルフォーマットの変換など。

textutil -convert html foo.docx -output foo.html

foo.docx(Wordで作成したOpenXML形式のファイル)をhtmlファイルにコンバートする。

qlmanageコマンド

クイックルックのコマンドライン版(本来はデバッグ用ツール)

qlmanage -p foo.png

ファイル名を引数指定するとクイックルックを表示する。本来はXcode等での開発時のデバッグ用ツールのようで、ウィンドウタイトルには[DEBUG]が追加され、実行結果にはデバッグ結果が表示される。

1秒毎に進行して10段階(秒)で終了する処理の進捗をプログレスバーでユーザーにフィードバックする時の話しです。 0から10段階に設定して、1秒毎に1(10%)ずつ進めて行き、10に到達した瞬間に非表示にする(処理終了)という実装をすると、何か違和感がないですか? (以下の動画)

プログラマ的には素直な処理の実装なのですが、以下の2点が違和感につながっているように思います。

  • スタート時、バーが0の時、処理が止まっているように見える。
  • 終了時、9段階から10段階に到達したとき、10段階に到達した画面が見えずに(一瞬で非表示になるため)、違和感が残る。

そこで、以下のように改良します (以下の動画)。

  • 敢えて10段階とせずに、9段階とする。
  • 0段階の時と9段階の時に散髪屋状態(barbar pole)とする
  • 0段階はあえて見せずに、1段階から見せる

最後の10段階をもうちょっとちゃんと見せたほうが完了した感が出るとか、改良点はあると思いますが、GUIをプログラミングする時に、単に処理の都合で安易に実装してしまわずに、例えば処理開始時にバーを1段階進め、最後の処理をbarbar poleにする、そのために敢えて10段階を9段階とする、などの工夫がUXを良くしていくのだろうな、等と考えた年の瀬でした。

おそらく今年最後のブログ記事になるかと思います。みなさま良いお年をお迎えください。そして、来年も何卒宜しくお願いします。

追記

進捗もへったくれもなく、かかる時間を予測してとにかく一定スピードで進めちゃう、みたいな考え方もあるでしょうね。もしくは済んでない(非同期で引き続き実行中な)のにちょっと前には終ったように見せるとか。ウェブアプリとか。失敗したら後で知らせたらいいや、みたいな。

進捗もへったくれも、というあたり、それって正しいプログラミングではないやろ、という意見もあるだろうけど、こっちのほうが体験的に快適という考え方もあるのだろうね。

この記事は、Movable Type Advent Calendar 2013の最終日の記事です。

イントロダクション 再構築キュー経由の再構築を並列処理でどこまで高速化できるか

PowerCMS 4のリリースから自分の中では今後は再構築キューをデフォルト、推奨としていく方針なのですが、実際にキューに設定すると画面上再構築処理は数秒とか数分で返ってきます(体感的に速くなったように感じます)。でも実際はサーバー側のプロセスが1ファイルずつ再構築しているわけで、すべてが反映(再構築)されるまでにはそれなりに時間がかかります。

再構築キューのしくみ

実測した環境では、700のキューが予約されているケースで2分半程度かかっていました。

そこで、サーバー負荷はこの際気にせずに、どのくらいの速度で再構築ができるものか、スクリプトを書いてみました。


cd path/to/mt; perl tools/speed-rebuild --per_proc 175 --max_proc 4

この場合、1プロセス175ファイル、プロセスの最大数4という感じになります。このパラメタを調整することで、スレッド数、スレッドあたりの再構築単位を指定できるというものです。指定した数値で一度に再構築キューが消化できなかった場合、プロセス終了後にmax_procを最大数として新たなスレッドが再構築処理を継続します。


perl tools/speed-rebuild --per_proc 700 --max_proc 1  - 2′01″
perl tools/speed-rebuild --per_proc 350 --max_proc 2 - 1′23″
perl tools/speed-rebuild --per_proc 175 --max_proc 4 - 1′00″ 
perl tools/speed-rebuild --per_proc 88 --max_proc 8  - 55″
perl tools/speed-rebuild --per_proc 44 --max_proc 16 - 56″(遅くなった,もしくは変化は誤差の範囲)
perl tools/speed-rebuild --per_proc 22 --max_proc 32 -  (正常終了せず)

アクティビティモニタの状態
まぁ、いくらなんでもこれはやり過ぎですね...

ということで、並列処理数は3-5プロセスくらいが最も効率的という結果になりました。これ以上増やしてもリソース使い果たすだけで正常処理できなきゃ意味がないし。あ、もちろんこのスクリプト自体が再構築処理投げっぱなしの使い捨てスクリプトだし、様々な面でマシンスペックによってはもっといけるかもしれんものなので(もちろんその逆のケースもある)、その点は宜しくお願い。もちろんこれは力技なので、テンプレートの最適化やキャッシュ利用などによる効果は別途見込めます。テンプレート次第でさらに半分、もっと短縮も夢ではありません。

尚、現在のMT標準の MT::Worker::Publish (再構築キュー)はこのスクリプトとは逆に、負荷が一定上がらないように工夫されています。

さて、ただ単純に複数スレッドで並列処理すれば速くなるか? 決して単純に速くなるわけでもないということがお分かりになったと思います。そこで、ここから本題。

Web Accessibility Advent Calendar 2013の21番目の記事です(今年は3つ4つもAdvent Calendarに登録してしまった...)。

のっけからいきなり言い訳がましくて恐縮ですが、僕はここで取り上げるような新しい技術やアイデアは素晴らしいと思います。素晴らしいと思うだけに、このような新技術やアイデアを実現する人、あるいは利用する人に少しだけ考えて欲しいと思い、この記事を書きます。

新しい画像認証 - Copy

1つめ。画像認証の代わりになる「Capy」というサービス。知ったのは以下のニュース。提供元のサイトはこちら(Capy - 低コストで導入も簡単な不正ログイン対策)

ひとことでいえばジグゾーパズルの1ピースをドラッグしてはめ込むことで人間が認証しているということを判別するようなしくみです。

Copy の画面キャプチャ。メールアドレスとパスワードに加え、ジグゾーパズルのピースをはめるようになっている。

そもそも「画像認証」自体のアクセシビリティがどうなの? という話しもありますが(最近は音声再生ボタンがついているものも増えましたね)、この技術も同じく例えばスクリーンリーダーだったらどうするとか、そもそもこの画像のALTをどうするのかといった問題があると思うのです。以下のページはテキストタイプのデモですが、こういうJavaScript不使用タイプを用意しているあたり、古いブラウザのことや携帯電話なども考慮している姿勢が伺われます。だからこそ、画像のALT属性自体がないのが少し残念だし、代替手段でもユニークなアイデアを示せなかったのかな、と思います。

<img src="https://www.capy.me/gimpy/get_image/?captcha_key=GIMPY_DYHMCon5dyigDx99vbK1iEQLYm5cTT">

例えば、誰もが知っている、わかるであろう質問をクイズで音声で出題して、回答を入力するとかのアイデアはいかがでしょう? 簡単な算数とか常識問題とか。もちろん既存の音声ボタンを代替手段として付けてもいいと思いますし。

ひとつ大切なことは、アクセシビリティというと、すぐにスクリーンリーダーや音声ブラウザのことを想像する人が一定いるように思いますが、このようなドラッグ&ドロップでの細かいマウス(今やマウスとは限りませんが)前提の動作というのは、肢体不自由のユーザーにもバリアになります。これ、技術的なチャレンジという点でいえば視覚障害者対応ということ以外にキーボード操作(←→↑↓)で動かしてはめ込めると素敵じゃないかな(面倒ではありますが)。

これに限らないですけど、逆の意味で例えば電話の音声案内限定のやつとか、そういうのも考慮が必要ですね。

新しい電子チケット - ColorSync

2つめ。Peatix の全く新しい電子チケット方式「ColorSync」(以下の記事より引用)。

動画を貼っておきます。

素晴らしいアイデアだと思います。そう、思うんですが色によっては識別できない人がいる可能性があるということも考えると、数字を併記するとか(記号が良いかな...どっちにしても色+形で識別できるようにしたいところ)、そういう実装も考えてみて欲しいとも思います。人によると思いますが、多分、この動画を見る限りは識別できるんじゃないだろうかと想像しますけど、これを使う前提のバイトの面接とかだと、自分が色の識別が他人と違うと認識している人は尻込みしてしまうかもしれないですし。

あと、これも見落としがちなのが以下の話し。いわゆるポケモン・ショックですね。

光過敏性発作の疾患のある利用者は、閃光を放つ視覚的なコンテンツによって発作を引き起こす恐れがある。ほとんどの利用者は、発作が起こすまでは自分がこの疾患を持っていることに気づいていない。

JR東日本の静止画の配信

3つめ。これは、技術的に新しいというわけではないけれど、アイデアの勝利。でも、これやるなら、音も拾って配信しよう。写真は現在の技術では読み上げられない。時間が解決するとは思うけど。写真中の文字、そのうち読めるようになるだろうけど(OCR技術が進化するだろうけど)。

まとめます。

繰り返しになって恐縮ですが、新しい技術やアイデアを形にすることは素晴らしいことだし、僕はこれらの技術やサービスを批判するつもりは全くありません。1つめの話なんかはサービスに導入する側が配慮すればそれで済む、という考えもありますし。

それでも、こういった技術を実装するエンジニアやそれ以外の人の中にこういったことについて問題提起できる人がいて(既に配慮されているのかもしれません)、その課題をクリアする手段を提供できるならば、そのサービスがより多くの人に利用できるという点において、よりいっそう素晴らしいものになっていくのだと思います。

デバイスが多様化する現代だからこそ、新しいアイデアがどんどん生まれてくる。わくわくする時代。だからこそ、そこで今一度、アクセシビリティについて考えてみましょう。

この記事はPerl Advent Calendarの19番目のエントリーです。

Net::Azure::StorageClient モジュールを作ってCPANデビューしました。

11月に Net::Azure::StorageClient というモジュールを作って、CPANデビューしました。Azureの Advent Calendar でこのモジュールの紹介をしようと思っていたのですが、Mac用クライアントを作ったのでそっちの話題にしてしまったので、こっち(どっちだ)に書こうかと。

モジュールの利用方法

use Net::Azure::StorageClient::Blob;
my $blobService = Net::Azure::StorageClient::Blob->new(
                                    account_name => $you_account_name,
                                    primary_access_key => $your_primary_access_key,
                                    container_name => $container_name, );
my $path = 'path/to/blob';
my $res = $blobService->get_blob( $path );

戻り値は HTTP::Response object(s)です。 詳細はドキュメントを見ていただくとして、Azure Blob APIにある一通りの機能は実装してあります。それ以外にいくつか便利なものが。例えばダウンドードはこんな感じで

my $res = $blobService->download( $container . '/' . $path, $local_path, $params );

アップロードは以下のようになります。

my $res = $blobService->upload( $container . '/' . $path, $local_path, $params );

download/upload は実はフォルダ指定にも対応しています。downloadは、コンテナ指定もできます。

マルチスレッドによる高速ダウンロード/アップロード

Threadが利用可能な時、ディレクトリを指定するときに、$params に { use_thread => 10 } を与えるとマルチスレッド(スレッド数の上限が10)で高速に処理を実行できます。

Windows Azure Blob APIのいくつかのTips

せっかくなので、ハマったこととか、ドキュメントがなくて悩んだことなどを。何せ、書籍も古いものしかないので(買ったけど)。

ディレクトリの扱い

ディレクトリ以下のBlob一覧を得るには、リクエストに prefix=パスの開始文字 を追加します(厳密にはディレクトリという概念はないのですが、例えばパスに / のような文字列を指定して擬似的にディレクトリのように扱うことができます)。

my $res = $blobService->list_blobs( $container_name, { options => 'prefix=directory_name/' } );

この時、ディレクトリ直下のアイテムのみを得るには(そうでないと、大量のコンテンツを含む上位ディレクトリほど処理が重くなる)、delimiterオプションを付与します(大量のコンテンツのある上位ディレクトリの表示にCloudXplorerとかめっちゃ速くてどうやってんだろ、これみたいなことで英文の技術ブログなんか読みあさって試行錯誤して発見したのでした...)。

my $res = $blobService->list_blobs( $container_name, { options => 'delimiter=/&prefix=directory_name/' } );

5000件を超えるBlobのリスト取得

my $res = $blobService->list_blobs( $container_name );

とすると、コンテナ以下のBlobの一覧を取得しますが、5000件の制限があります。5000件を超える場合、取得したXMLに NextMarker という要素があるので、この値を marker パラメタに渡してやります。

my $res = $blobService->list_blobs( $container_name, { options => 'marker=' . $marker } );

この時、$NextMarker をURLエンコードしてやらないといけません。というか、エンコードしないとあかん文字列がAPIから返ってくるのでした。

my @responses;
my $res = $blobService->list_blobs( $container_name );
push ( @responses, $res );
my $xml = XML::Simple->new;
my $data = $res->content;
my $list = $xml->XMLin( $data );
$marker = $list->{ NextMarker };
$marker = undef if ( ( ref $marker ) eq 'HASH' );
while ( $marker ) {
    $marker =~ s!([^a-zA-Z0-9_.~-])!uc sprintf "%%%02x", ord($1)!eg;
    $res = $blobService->list_blobs( $container_name, { options => 'marker=' . $marker } );
...

Net::Azure::StrageClient::Blobのlist_blobsでは、この辺りの処理は自動的にやってくれます。 冒頭に「HTTP::Response object(s)です。」と書きましたが、(s)というのは、list_blobs等の場合は自動的に再帰的にリクエストを送って HTTP::Response object の配列を返すようにしているからです。

といった感じで、これ、PerlからAzureのBlobを扱うのに便利なモジュールですよ。

この記事は Windows Azure Advent Calendar 2013 の17日目の記事です。

AZBlobClient(Mac OS 用Windows Azure Blobクライアント)の画面

当初「PerlモジュールNet::Azure::StorageClientについて」の記事を書こうと思っていたのですが、気が変わったというか、こっちのほうがトピックスとしてはおもしろいと思うので、すいませんが勝手に変えますm(_ _)m

ちなみに、Perlモジュール Net::Azure::StorageClientはこちら。 GItHubのリポジトリのほうが少し更新は早いかもしれません。

それでも? 一応ふれておきますね。

Perlモジュール Net::Azure::StorageClientについて


use Net::Azure::StorageClient::Blob;
my $blobService = Net::Azure::StorageClient::Blob->new(
                                    account_name => $you_account_name,
                                    primary_access_key => $your_primary_access_key,
                                    container_name => $container_name, );
my $path = 'path/to/blob';
my $res = $blobService->get_blob( $path );
  

返り値は HTTP::Response object(s)です。container_nameは省略可能、その場合、コンテナのパスからblobパスを結合して、container_name/path/to/blob のようにして渡せばあとはよしなにしてくれます。

こちらのページのドキュメントを見ていただければわかると思いますが、Blobについては基本的に一通りのAPIを呼び出せるようになっています。もちろん、アップロードやリストの取得等も簡単です。

Tableやキューについても基本は同じだと思うのですが、個人的にBlobストレージ以外を扱う機会がなかったのでBlobオンリーになっています。機会があればテーブル、キューに対応したモジュールも書けたらと思っています。

ちょっと面白いのはマルチスレッドに対応していて、examples/blobsync.pl のサンプルを使うと以下のような感じでローカルのディレクトリとBlobを高速に同期できる点です。

/usr/bin/perl examples/blobsync.pl --account your_account --accesskey you_primary_access_key --direction upload --path container_name/directory_name --directory /path/to/local/directory --use_thread 10

--direction download とすれば逆方向の同期も可能。AZCopyはMacでは使えないですし、もちろん CloudXplorer もMacでは使えないため、毎回 VMWareで Windowsを立ち上げて作業していたのですが、あまりに面倒だし、個人的には Movable Type を仕事で使うことが多いのに PHP のSDKはあるけどPerl SDKはないし... というので書いた次第。サンプル等を色々書くつもりだったのですが、それはまたいずれ。

ちなみに、以下のページ「COMPLETED」になっていますね。早くPerlも正式サポートされて欲しいものです。

Mac OS X用のBlobストレージクライアントソフトを作ってみたお話

ようやくここから今回の本題に入るのですが、Perlモジュール作ったことでコマンドラインからBlobの読み書きができるようにはなった。とはいえ、コマンドラインツールです。サイトのメンテナンスをする人、例えばFTPクライアントでファイル転送することはできる、くらいのスキルの人(つまり、一般的なWeb制作者(not 開発者))がコマンドライアンから作業って敷居が高いではないですか。で、ふと思い立ってMac OS X用のBlobストレージクライアントソフトを作ってみようと思ったのでした。

百聞は一見に如かず、まずは動画を。

できること

  • マルチアカウント対応
  • コンテナの作成
  • フォルダの作成
  • ファイル/フォルダのアップロード(ドラッグ&ドロップ)
  • ファイル/フォルダのダウンロード(ドラッグ&ドロップ)
  • コンテナのACL(アクセス権)の設定
  • コンテナ/Blobのメタデータの確認、編集、追加、削除
  • Blobの直接編集
  • Blobのクイックルック
  • コンテクストメニュー対応(コントロール+クリック又は右クリック)

使い方

  • 「設定」タブをクリックして、Blobストレージのアカウントとプライマリアクセスキーを入力、保存
  • 「ブラウザ」タブをクリックして「コンテナの一覧」ボタンをクリック
  • あとは、普通? のFTPクライアントのようにダブルクリックでコンテナ、フォルダを開く、ドラッグ&ドロップでファイルのアップロード、ダウンロードなどの操作が行えます。
  • .. で 一つ上の階層への移動、 . でリロード
  • キーボードショートカット対応(←(ひとつ戻る) →(ひとつ進む)、I (情報を見る)、O(開く)、等)
  • クイックルック(スペースキーまたはコマンド+Y)

動画をご覧いただいてわかる通り、そこそこのスピードは出ていると思います。

ソフトウェアのダウンロード(このソフトウェアはβ版です)

現在App Storeに登録すべく、Apple Developer Programへの登録申請を行おうとしたのですが、DUNS 情報の修正のところで時間がかかっているため(2週間くらいかかるようです)、未登録、サンドボックス化がまだなので、野良? アプリ段階ですが(最初の起動時には右クリック(コントロール+クリックから起動する必要があります))、一応置いておきます。ご利用は自己責任でお願いします。

ちなみに、Blobへのアップロード、コンテナ作成、コンテナのアクセス権設定などはすべてこのソフト自身でやりました。

と、いうことでPerlモジュールの話し改め Mac OS X用のAzure Blobクライアントソフトの紹介になりましたが、このソフトの処理部分は実はこのPerlモジュールが使われています。XojoでGUIを被せただけで、実際のAPIを利用したアクセスはPerlが担っています。興味のある方は以下のエントリーもどうぞ。

追記 : 動かなかった(エラー)という方がいたので、エラーについてある程度の詳細が出るようにしたバージョンに差し替えました。宜しければフィードバックいただけると幸いです。junnama[at].alfasado.jp

Xojoネタを続けます。備忘録、忘れていたことの覚え書き、何でもいいや。

動的なメニュー、例えばスタイル付きテキストエディタやワープロのフォントメニューの例とかで、Tutorial & Developer's Guideに書いてあるんだけど(REALBasic3のを引っ張りだしてきたのだ)、肝心のメニューハンドラのコードが書いてない。メニューアイテムを配列にするには indexに 0 を指定する(以下のキャプチャのように)

メニューエディタ(メニューアイテムを配列に指定)

動的にメニューを追加するには、例えば以下のように。


Dim m As MenuItem
m = new MenuWindowProperties
m.Text = Foo
m.Tag = Bar
m.Visible = True
m.Enabled = True

で、具体的にメニューハンドラを書こうとして...

メニューハンドラの入力画面

普通は書いてあるじゃん。以下のような感じで...

コードエディタに引数と返り値の型が記述してある

答え : indexに選択されたメニューのindex(Integer)が入っているのでした。


MenuWindowProperties(index As Integer) As Boolean

と、なるべきだな。昔のコード引っ張りだして見つけたから良いようなものの...

引き続きXojo(とMacOS)ネタ。

要するに、こういうことをやりたいとき、Dropされたアイテムのパスを得られないとどうしようもないのですが、DragItem.Destinationというプロパティでこれが実現できる、とあります(サポートに教えてもらった)。但しこれはMac OS限定ということでWindows、Linuxではダメらしい。今回はMac OS限定の開発なので、これでできると思いきや、Carbonでは動くがCocoaではこの値がとれない(現段階でサポートに確認中)。で、このためだけにCarbonにするのも悔しかったので、どうにかやってみようと。

アプリのリストボックスからアイテムをドラッグ&ドロップしたい

アプローチその1. エイリアスを作ってTimerで監視

MakeAliasというAppleScriptを作ってテンポラリ領域に作ったファイルのエイリアスを作り、Timerを使ってドラッグされた先のパスを見る。


on run (theOriginal)
    set theOriginal to POSIX file theOriginal
    set theOriginal to alias theOriginal
    tell application "Finder"
        set theFolder to folder of theOriginal
        make new alias file at theFolder to theOriginal returning theResult
        set theResult to theResult as string
    end tell
    --set theResult to POSIX path of theResult
    return theResult
end run

オリジナルのアイテムのパスを得るためにResolveAliasというAppleScriptを作る。

on run (theOriginal)
    set theOriginal to alias theOriginal
    tell application "Finder"
        set theResult to (original item of theOriginal) as alias
    end tell
    set theResult to POSIX path of theResult
    return theResult
end run

結論から言うと、これはNG。またもやCarbonで動くがCocoaでアウトなのでした。DragItem.FolderItemがMoveではなくCopyになってしまう。なので、オリジナルのパスはテンポラリ領域のファイルとなる(ただ、せっかくやったのでこうやって書いておくのだ。きっとどこかで誰かが、あるいは自分の役に立つので)。POSIX path というのが使えるのを学びましたよ(PathをUnixタイプのNative Pathに変換してくれる)。

アプローチその2. Spotlightを使ってTimerで監視

こちらは上手く行きました。ちょっとだけタイムラグが出るのが玉にきずですが。

Dim command As String = "mdfind -name " + DraggingItem
Dim Sh As New Shell
Sh.Execute( command )
Dim Res As String = Sh.ReadAll

要するに、存在しないファイル名(乱数から生成したMD5ハッシュ値とタイムスタンプとかから組み立てたファイル名)でテンポラリファイルを作り、不可視にしてDragさせる。同時にTimerを走らせる。If System.MouseDown = False Then (マウスが押されていない状態になった時)に上記を実行する(mdfindというコマンドがあって、こいつは Spotlight のコマンドラインツールなのです。

多少のタイムラグが出るものの、これでドラッグされた不可視アイテムのパスが得られるので、その親(フォルダ)に対して選択されたアイテムをダウンロードさせる、という方法。存在しないファイル名として作ったファイル名が本当に存在しないかどうかも同じコマンドで得られるので。

ただ、やっぱりちゃんと DragItem.Destination なりでサポートして欲しいと思ったのでした。とりあえずCocoa化はできた。Carbonはやっぱり速度とかLook & Feelが美しくないので、やっぱり作るならCocoaで作りたいよね。

先月目出たくCPANデビューを果たしたり色々あったのですが、ご無沙汰でブログ書けてませんでした...

メモも兼ねて。久しぶり、そう、もう10年近く振りになるのか、デスクトップアプリを作ってみたくなったので、Xojoを落として使ってみました。以前はREALBasic(それより前はCross Basic)、その後REAL Studioと改名され、現在はXojo(ソージョーと呼ぶらしい)。

その? CPANに上げたPerlモジュールを社員に使わせたいんだけど、黒い画面が苦手な女の子(すでに子、じゃないけど)だったら? やっぱりGUIのアプリが欲しくなるよね。作れるかな? というのがきっかけでした。Xojo にはShellというクラスがあって、Mac/Windows/Linuxともにシェルコマンドが叩けるというので、Perlでスクリプトを書いてそれを叩けば(結果をうけとれれば)作れるんじゃね? と思って書いたらちゃんと動きました。MacOSのアプリケーションの実体は「フォルダ」なので、アプリケーションパッケージ内にPerlモジュールをコピーしてしまえば配布する時はそのままでいいので。

アプリのスクリーンショット

作成したのはWindows Azure のBlobストレージのクライアントアプリ。ファイルやフォルダをドラッグ&ドロップでアップロード、ダウンロードできたり。Azure BlobのAPIはXMLを返すのだけど、XojoではXMLの処理ができるのでAPIからの値の受け渡しのみPerlでやればあとはXojo側で実装できます。1日程あれば基本的な動作確認ができることろまで作れる(その後が色々大変なのではあるけれども)。


  CONST DEBUG_PATH = "/Users/alfasado/Desktop/MyApp"
  Dim App as new Application
  Dim SelfPath As FolderItem
  Dim Debug As Boolean
  SelfPath = App.ExecutableFile // 実行している自身のパスを得る
  if CountFields( SelfPath.Name, "." ) = 2 And NthField( SelfPath.Name, ".", 2 ) = "debug" Then
    Debug =True // デバッグ時にはモジュールのパスを指定
  End If
  Dim Path As String
  if Debug = True Then
    Path = DEBUG_PATH
  Else
    Dim Name As String = SelfPath.Name + ".app"
    SelfPath = GetFolderItem( SelfPath.NativePath ).parent
    SelfPath = SelfPath.Child( Name )
    SelfPath = GetFolderItem( SelfPath.NativePath )
    Path = SelfPath.ShellPath // スペース等をバックスラッシュでエスケープしたパスが返る
    MsgBox( Path )
    // /Users/alfasado/Desktop/MyApp/\:Users\:alfasado\:Desktop\:MyApp\:My\ Application.app
    Path = NthField( Path, "\:", 1 ) + Name + "/Contents/MacOS"
  End If
  Dim Cmd As String = "cd " + Path + "; perl src/app.pl"
  Dim Sh As New Shell
  Sh.Execute( Cmd )
  MsgBox( Sh.Result )
  // app.plで printした結果が取得できる

あとは、ビルドしたあとで、パッケージにモジュールをコピーすればOK。

cd /Users/alfasado/Desktop/MyApp/Builds\ -\ AZBlobClient0.5.carbon.Xojo_binary_project/Mac\ OS\ X\ \(Intel\)/AZBlobClient.app/Contents/MacOS/
cp /Users/alfasado/Desktop/MyApp/lib.zip lib.zip
cp /Users/alfasado/Desktop/MyApp/src.zip src.zip
unzip lib.zip
unzip src.zip
rm lib.zip
rm src.zip

MacOSにはPerlとか標準で入っているから、普段軽量プログラミング言語を使っていてデスクトップツールを作りたい人なんかにXojoいいかも。REAL Studio一時不安定なイメージを持っていたけど、1週間程使い込んだ印象では安定して動きます。ライセンス購入したら(デスクトップライセンスを購入したよ)日本語のサポートも受けられますよ。

追記。こんな感じのパスになるのは、


    // /Users/alfasado/Desktop/MyApp/\:Users\:alfasado\:Desktop\:MyApp\:My\ Application.app

GetFolderItemの引数がまずかったせいらしい。FolderItem.PathTypeAbsolute(0), FolderItem.PathTypeShell(1), FolderItem.PathTypeURL(2), FolderItem.PathTypeNative(3) という定数があって、2つめの引数に指定するときれいに取れる。この場合は、3(FolderItem.PathTypeNative)を指定。


GetFolderItem( SelfPath.NativePath, 3, )

Facebook

Twitter

このアーカイブについて

このページには、2013年12月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2013年9月です。

次のアーカイブは2014年1月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Powered by Movable Type 6.2.6