2008-09-02
目次
りんご味Ruby 第31回 藤本 尚邦
今回は、前回作成したHTTP POSTのためのリクエストヘッダとボディを使ってpost_textを完成させます。
■ post_textの実装 (rest-open-uri)
Yahoo!翻訳のトップページを取得(open_top_page)するためのHTTP GETには、Ruby 1.8.6に添付されているopen-uriライブラリを使用しました。open-uriはどうやらHTTP GETのみのサポートのようなので、(HTTP GETではなく)HTTPPOSTする必要があるpost_textの実装には使うことができません。
open-uriよりも低レベルのHTTPプロトコルライブラリであるnet/httpを使って実装しても大した手間ではないのですが、できることならopen-uriのような手軽な使い勝手でHTTP POSTも扱いたいですね。以前、「Restful Webサービス」という本を眺めていたときに、open-uriのインターフェースを拡張してPOSTやその他のHTTPメソッドを扱えるようにしたrest-open-uriというライブラリを見つけたので、それを使って実装することにします。rest-open-uriはgemコマンドを使ってインストールできます:
$ sudo gem install rest-open-uri
では、rest-open-uriを使ってpost_textを完成させましょう:
require 'rubygems'
require 'rest-open-uri'
(中略)
def post_text(mode, text)
params = {
:eid => _eid_(mode), # 変換モード(_eid_で正規化)
:text => text, # 翻訳したいテキスト
:key => @key, # HTTPレスポンスから取得した値
:time => @time, # HTTPレスポンスから取得した値
:both => "TH" # (謎のパラメータ、おまじない)
}
body = params.map{ |key, val|
"#{key}=#{CGI.escape(val.to_s)}" }.join('&')
request = HTTP_REQUEST_HEADER.merge(
"Content-Type" => "application/x-www-form-urlencoded")
request[:method] = :post # HTTPメソッドをPOSTに指定
request[:body] = body # HTTPリクエストのボディをセット
open(URL, request) { |io| io.read }
end
前半のPOST用のデータを作っている部分は前回作成したコードです。open-uriでは、openメソッドの2番目以降の引数として、リクエストヘッダに相当するHashオブジェクトを渡す仕様になっていますが、rest-open-uriは、このHashオブジェクトに、HTTPリクエストのメソッド(GET、POSTなど)やボディなどを追加指定できるように拡張されています。
さて、ずいぶんと回り道をしましたが、ようやくpost_textが完成しました。テストしてみましょう:
$ ruby test-yahoo-honyaku.rb
(中略)
1) Error:
test_s_translate(TestYahooHonyaku):
NotImplementedError: まだ実装してねぇ、誰か書いてくれ!
./yahoo-honyaku.rb:73:in `parse_result'
./yahoo-honyaku.rb:14:in `translate'
./yahoo-honyaku.rb:8:in `translate'
test-yahoo-honyaku.rb:19:in `test_s_translate'
これでYahooHonyakuをすべて実装したような気になっていましたが、まだparse_result を実装していませんでした。ささっと実装してしまいましょう。
■ parse_resultの実装
parse_resultの役割は、post_textのレスポンスをパースして翻訳されたテキストを取り出して返すことです。これは実際のところ、open_top_pageの実装(第28回)のときに作ったparse_form!でほとんどできあがっています。ということで、共通部分を整理しつつparse_resultを作ります:
def parse_html!(html)
doc = Hpricot(html)
@form = doc.search("form[@name=textFormEntry]")[0]
@key = @form.search("input[@name=key]")[0]["value"]
@time = @form.search("input[@name=time]")[0]["value"]
if @form.nil? or @key.nil? or @time.nil?
raise "Yahoo翻訳の返すHTMLのパースに失敗しました"
end
# 翻訳されたテキストを返す
@form.search("textarea[@name=trn_text]").text
end
alias parse_result parse_html!
alias parse_form! parse_html!
parse_form! の実装の最後の部分に、HTTPレスポンスから翻訳されたテキストの入っているtextareaを取り出してそれを返すコードを追加して、parse_html!というメソッド名に変更しました。このparse_html!メソッドは、そのまま、parse_form!としてもparse_resultとしても使うことができます。
alias というのは、メソッドに別名をつけるための構文です。上記のコードでは、parse_html!メソッドに、parse_resultという別名とparse_form!別名をつけていることになります。
(余談) ずっと前(第5回)に、Rubyでの代入構文は「オブジェクトに名前を付ける」というような意味になる、というようなことを書きました。メソッドを定義するための構文defや、メソッドに別名をつけるための構文aliasも「メソッドに名前をつけること」と考えてもいいかもしれません。
さて、parse_resultができたところでテストしてみましょう:
$ ruby test-yahoo-honyaku.rb
(中略)
2 tests, 4 assertions, 0 failures, 0 errors
なんとテストを通ってしまいました! irbでも試してみましょう。
$ irb -r yahoo-honyaku --simple-prompt
>> y = YahooHonyaku.new
=> #
だいじょうぶそうですね。:jc,:cjで日中・中日、:jk,:kjで日韓・韓日の翻訳も可能です。
ということで、ようやくですが、YahooHonyakuライブラリとして機能するようになりました。次回からは、これを使ってコマンドやCocoaアプリケーションを作っていく予定です。
== YahooHonyakuのライブラリとテストプログラムのソース
以下のURLに、今回完成したYahooHonyakuのライブラリとテストプログラムのソースを置いてありますのでご覧ください。
http://www.mosa.gr.jp/?p=2096
このURLからringoajiruby31.zipをダウンロードしてください。解凍するとringoajiruby31フォルダ内に二つのファイルがあります。
ライブラリ(yahoo-honyaku.rb)
ringoajiruby31/yahoo-honyaku.rb
テストプログラム(test-yahoo-honyaku.rb)
ringoajiruby31/test-yahoo-honyaku.rb
藤本裕之のプログラミング夜話 #144
あっと言う間にオリンピックが終わり、前回原稿で振った話が宙に浮いた状態になってしまったが、要は「北京オリンピックを契機にハイビジョンテレビを買うヒト」と「北京オリンピックを契機にダビング10機能のついた録画機器を買うヒト」の比率ってのは有意に違うでしょ、ということである。
作って売る側は「オリンピックですオリンピック、4年に1回ですよダンナ、北島選手は金メダル確実だし(そうでした)、星野ジャパンだってやるでしょう(やりませんでしたけどね)。その記念すべき瞬間をハイビジョンで残せるんです、しかもダビング10! 今まで1回ムーブできるだけだったのが、9回もコピープラス1回ムーブできるんです!」と言えばみんな飛びつくと思ったの
か知らんが(だからオリンピックに間に合うように話をつけたんでしょ?)、そもそもそういうニーズ自体そう大きくないんとちゃうの?
そんで、オレ、パソコンのアプリケーション・ソフトもここ数年(ようやく話がここに戻ってきましたよ)、この「ダビング10機能搭載機器」みたいに、なんつか「作る側が製品に対するニーズを過剰に見積もっている」ようなモノばかりに見えるのである。
思えば20数年前のパソコン黎明期(異論もあろうが一応1983年からの16ビットマシン出現以降をこう呼ぶ。それ以前は先史時代)。ふとした弾みで(弾みってこたぁないけどね)パソコンを買ったヒトビト、なかでも仕事半分のオレ達と違って完全に趣味でパソコンを買ってしまったヒトビトは、周囲のヒトから発せられる「そんな高いものを買っていったい何の役に立つの?」という
質問への答えをそれこそ必死に探していたもんである。
いわく「字が下手だからワープロを使いたい」「データベースで蔵書を整理する」「MIDIを使って音楽をやる」……その他モロモロ、まぁはっきり言ってその答えに相手が納得するなんてシーンは見かけたことがなかった。口先だけであっても「すごいですね」と感心してもらえればいいほうで、たいがいのばあいは「へぇえ」とか間抜けな声と、昨今の言葉で言えば「ビミョー」な視線をあびせられるのがオチだった。
考えてみればあれ、ヘンな話でね。趣味のために買うゴルフセットや釣り道具、楽器でもファッションでも鉄道模型でも趣味で買ってる以上、「それが何の役に立つ」みたいな話は(たとえばゴルフセットがビジネスにおける接待の役に立ったとしても、だ)下品だからみんなしないのだ。
なのに趣味でパソコンを買ったヒトだけは、なんか脅迫されてるみたいにそれが「いかに役に立つか」を説明しなければならなかった。場合によってはプロであっても、家にパソコンを買う時にはなにか家族に言い訳をしたりしたかもしれない。思い当たるヒト、いるでしょ?
で、ダビング10は知らず、パソコンのアプリケーション・ソフトを企画・制作するヒトの、ニーズを過剰に見積もってしまうという傾向(性向?)には、どっかそういう過去も少しは関係しているような気がするのだよね。以下のような思考回路が働くわけ。
(1)パソコンで☆▲◎をするのは(できないわけぢゃないけど)結構面倒くさい。
(2)このソフトを使えばその面倒くささを大幅に軽減できる。
(3)だからこれを売り出せば☆▲◎をするヒトはみんな買うはずだ。
でもこれ、見方を変えると「パソコンは役に立たなくちゃいけない」と思い込んでるヒトならではの発想とも言えるのだ。
そもそもそういうヒトだから「パソコンで☆▲◎をしよう」なんて思うんぢゃないか? 普通のヒトは☆▲◎をするのにパソコンを使わないかも。もしかしたら普通のヒトは☆▲◎自体をしないかもしれない。☆▲◎をするヒトはみんな買うかも知れないが(それも怪しいが)、そうだとしても総数がそれほど多くないのでは?
ウチの電子レンジにはオーブン機能がついている。だからやろうと思えばオーブン料理ができるのだがやったことはない。その理由の一つは誰にも「この電子レンジ、こんなに便利なんだよ。ほらオーブン料理もできるしさ」と説明する必要がないからで、今はパソコンを持ってるヒトもたぶんそうなのだ。プロのオレ達は「パソコンが役に立つ」ことに拘りすぎている……のかも知れない、と。
(以下次回 2008_08_30)
高橋真人の「プログラミング指南」第142回
〜XcodeによるPowerPlant X入門(31)〜
こんにちは、高橋真人です。
早速続きに入ります。
さて、DoWindowDeactivated()というメンバ関数では、Viewを作った時に付け加えてあったアタッチメントを外す処理を行っています。
最初に対象となるViewを検索します。
さて、DoWindowDeactivate()には、引数としてウインドウが渡されてきています。ここで渡されているウインドウはOSネイティブのWindowRefであって、PPx::Windowではありません。
もっとも、この関数はMyWindowクラス(PPx::Windowを継承している)のメンバ関数ですから、あえてWindowRefを引数に加える必要はないのではないかと思わないでもありません。もし、今処理している関数の中でPPx::Windowオ
ブジェクトが内部に保持しているWindowRefが必要なら、GetSysWindow()という関数ですぐに取り出すことができますので。
それでもPPxでは、今までずっと説明してきたように、Carbon上で発生する様々なイベントをPPx::EventDoerを継承の大元とする様々なクラスで処理する構成になっているため、これらの処理を同一のパターンで処理するようになっているのです。よって、このメンバ関数では引数になくても何ら困らないWindowRefも、発生したイベントの中に要素として入っているので、一律に取
り出して列挙しているということなのです。
ところで、今回のようにPPx::Windowのメンバ関数ではなく、任意の場所においてWindowRefがあったときに、それをPPx::Windowに変換するにはどうしたらよいでしょうか? その場合には、
// inWindowはWindowRefの変数
PPx::Window window = PPx::Window::GetWindowObject(inWindow);
というように行います。過去に連載の113、116回目あたりで触れていますので、参考にしてみてください。
ちなみに、このようにしてPPx::Windowに変換できるWindowRefは、あらかじめPPxのオブジェクトとして作られたウインドウに属しているものであることが前提です。PPx::Windowによらない、単に自分で::CreateNewWindow()を呼び出して作ったウインドウを変換しようとしても失敗します。
本題に戻ります。PPx::WindowのGetWindowContentView()という関数により、ウインドウの保持するView群のルートのViewを得ます。これはHIViewで言うところのroot viewに該当します。つまり、::HIViewGetRoot()と同等の処理をしていると考えるのが妥当です。
ちなみに、オリジナルのPowerPlantでは“ウインドウもビューの一種である”という考え方で、LWindowはLViewのサブクラスになっていました。PPxではそうではありませんから、PPの経験のある方はこの点を頭に置いておきましょう。
さて、ContentView(トップビュー)を得たら、次にアタッチメントの付加されているViewを探します。そのためには、ContentViewでFindViewByID()という関数を呼びだします。勘違いされるかもしれませんが、ContentViewが特殊なViewなわけではありません。他のViewと同じくPPx::Viewの普通のインスタンスです。ただ、ウインドウ上のView階層を構成するツリー構造のいちばんトップ(根のところ)にいるために、“唯一の、親を持たないView”であるのが特徴と言えば特徴です。
Viewの検索はトップビューに対してしか行えないわけではありません。どのViewに対してもFindViewByID()は呼び出せますが、検索の対象がそのViewと、そのView以下(子や孫やその先)の階層が検索の対象となる仕組みです。
ここでちょっと話が外れますが、階層構造について慣れていない方がおいでかもしれませんので少し触れておきます。
今、親とか子とか、根などという言葉が出てきました。これらはすべてツリー構造、つまり木のように幹から枝が分かれていくというデータ構造の一種を指しています。「木」と言うと、“一般的な木”を思い浮かべる人がほとんどとは思うものの、中にはモミの木(クリスマスツリーに使われるヤツです)などを思い浮かべたりしてかえって混乱する人も出てくるといけないので
(笑)、家系図のような階層構造と言っておきます。(この方が誤解する人は少ないでしょう)
いずれにせよ、一つの基から段階的に複数に分かれていくような構造(データの整理の仕方)を“ツリー構造”とプログラミングの世界では呼ぶわけです。もちろんプログラミングに特有の考え方というわけではなく、家系図にも見られるように世間一般で普通に使われる考え方です。
昔は、ツリー構造と言うと、アルゴリズムのためのデータ構造がまず頭に浮かんだものですが、最近では、XMLとかオブジェクト指向の継承など、ツリー構造で表現されるものはいくらでも見つかります。Macユーザーの皆さんにとっては、ファインダのファイル階層こそがいちばん身近なツリー構造と言えるでしょうか。
というわけで、PPxにおいても至るところでツリー構造の考え方が出てきます。一口に親とか子とかいっても、真っ先に自分の頭に浮かんだものだと短絡するのではなく、“どの”ツリー構造のことを言っているのかをちょっとだけ意識しておく必要があるかもしれません。
ところで、ツリー構造と呼ぶことから、当然“木”をイメージして考える人もいるわけですが、幹から枝に進むことを“上る”というのか“下る”というのかが時々議論になります。リアルな木では、幹もしくは根は下側にありますから、枝に進む場合には当然“上る”になるわけです。
ですが多くの人(と思うのは私がこっちだから?)は、ルート(根)が上で、下に向かって枝分かれていくイメージを持っているため、枝に進むことを“下る”と表現します。
要は話がきちんと通じればよいだけですが、世の中にはこのような人もいるのだということを知らずに自分の“常識”だけでやり取りをしていると、とんだ誤解を招いてしまう恐れもありますので注意しましょう。
ちょっと余談が長引きました。続きは次回にお話しします。
書籍紹介 Cocoa勉強会会誌 Cocoa Life Vol.4
解説担当:高橋政明
Cocoa勉強会の会誌Cocoa Life Vol.4が発売されました。墨一色ながら120ページを超えるボリュームです。
webで様々な開発情報が得られますが、いざ参照しようとするとアクセスできなかったりもしばしばです。その点書籍などで手元に情報を確保することは現在でも重要です(プログラミングテクニックの一つと言えるかも知れません)。変化の激しい技術情報を日本語で読む事ができるのも助かります。
下記webで目次と各記事の最初のページが載ったPDFファイルをダウンロードする事ができます。八名の共著による多彩な内容です。各記事の内容をざっとご紹介しましょう。
◆QuickLookプラグインの作り方
LeopardのQuickLookに対応するためのプラグインを作るために必要な情報が
まとめられています。
◆Leopard NSMenu差分
これまでCocoaでは作れなかった種類のメニューを作る方法と、10.4と10.5
のメニューの違いが詳しくまとめられています。
◆PDF Kit入門 – Leopard変更点
PDF KitのLeopardでの変更点と以前のバージョンで散見された問題が改善さ
れた部分などがまとめられています。
◆インラインの文字入力
NSTextInputプロトコルの実例が解説されています。
◆DiskImageへSLAを追加する
ディスクイメージファイルをFinderにマウントする前にソフトウェアライセ
ンス契約を表示する方法(その表示を日本語などにローカライズするやり方
を含む)が具体的に紹介されています。
◆多言語対応のReadMeファイル
ReadMeファイルを他言語対応とする独自の方法が紹介されています。
◆Uncrustifyでコード整形
Objective-Cに対応したソースコード整形ツールの紹介記事です。
◆識別情報の変換
文字エンコードとデータタイプを識別する識別情報をCocoaで取り扱う方法
を具体的に紹介しています。
◆カスタムシートとModality
重要なモーダルなインターフェースについて、シートを中心にサンプルプロ
グラム付きで詳しく解説されています。
◆PaSoRi x Mac 応用編
FeliCa用カードリーダ/ライタをMac OSで無料で使えるPasoriKitについて
紹介されています。EdyやSuicaデータの情報もあります。
◆DTrace:はじめの一歩
開発ツールのInstrumentsでもつかわれている、DTraceについての紹介記事
です。
◆HID Manager API
USBのHIDをアプリケーションで直接扱うサンプルプログラムが解説されてい
ます。
◆Quartzでのインデックス画像の取り扱い
10.4以降でQuickDraw APIを使わずにインデックスカラー画像を編集する方
法が解説されています。
◆アニメーションGIFの作り方
Mac OS XでGIFアニメーションを作り保存する方法がファイルのデータ構造
とサンプルプログラムとともに解説されています。
◆CGS プライベート関数の利用
非公開プライベート関数をアプリケーションから利用しFinderなどで使われ
ているトランジションを利用する方法が紹介されています。
Cocoa Lifeは下記webページから購入申し込みできます。
バックナンバーの情報はこちらにあります。
http://www.cocoa-study.com/book/
▼Cocoa勉強会会誌のweb (サンプルページのpdfあり)
http://www.cocoa-study.com/book/book4.shtml
◇MOSAからのお知らせと編集後記は割愛します◇