ホーム

情報と音楽

新年のごあいさつ (おそい)

  • 投稿者: labocho
  • 2012年1月26日 9:51 PM
  • 未分類

もう来週は 2 月ですが、あけましておめでとうございます。

昨年は転職したのが一番おおきなイベントでした。人並みに働くのは体力的にしんどいですが、まあ、好きなことを仕事にできてるので、幸せなほうでしょう。

さて、昨年に掲げた目標をみてみましょう。

  • Web サービス作る
    夏くらいには 8 割方できてたんだけどほったらかし・・・。仕事がプログラミングだと、個人的なプログラミングはなかなか進まない。
  • 身体を動かす趣味をつくる
  • なにか習い事始める
    この 2 つについては、4 月からフェンシングを始めたので、目標達成。と思ってたんだけど、ここのところ全然行けてないので、今後はどうだろ。

ということで、いまいちな感じ。

では、今年の目標。

  • Web サービスつくる
  • もう少し文章書く
  • 無理しない

今年もよろしくお願いします。

 

Rails に XML をボディとするリクエストを JavaScript で送る

Rails における XML でのリクエスト

Rails に、Content-Type: application/xml で、ボディが XML のリクエストを送ると、コントローラ中では params に展開される。

# リクエスト # ヘッダはいろいろ省略してます POST /entries HTTP/1.1 Content-Type: application/xml <?xml version="1.0" encoding="UTF-8"?> <entry> <body>New blog entry</body> </entry> # EntriesController def create p params # => {"entry" => {"body" => "New blog entry"}, ... ...

これは主に ActiveResource のための仕様だろうが、XML によるレコードのエクスポートとインポートを行う目的で、同じインターフェイスを HTML から使いたいと考えた。

JavaScript によるリクエスト

HTML の form で Content-Type を application/xml にすることはできない (よね?) ので、jQuery を使って JavaScript で送る。

// url に URL 文字列、 // xml に XML 文字列が格納されているものとする。 $.ajax({ type: "POST", url: url, dataType: "xml", // Accept ヘッダをセットする。レスポンスを XML で受けとるなら必要。なくてもよい。 contentType: "application/xml", // Content-Type を XML にする data: xml, success: function(res, type) { alert(res); }, error: function(req, message, error){ alert(error); }, });

しかし、HTTP メソッドが GET 以外の場合、リクエストに含まれる authenticity_token をチェックし、無いか session[:authenticity_token] と一致しないと、session が空になってしまう (※)。

これは具合が悪いので authenticity_token を送信する方法を考える。

※ ApplicationController などで protect_from_forgery メソッドが呼ばれている場合。普通呼ばれてます。

CSRF プロテクショントークンを送る

form_for で作ったフォームには authenticity_token が hidden フィールドで格納されているので、そのまま submit すればよい。また、Ajax 通信でも、JSON で送るなら、送信するオブジェクトに authenticity_token プロパティを付与すればよい。この場合 authenticity_token は meta タグから取得する。

<!-- 最近の Rails (3 以降?) なら application.html.erb の head 要素にこんな記述があるはず --> <%= csrf_meta_tag %> <!-- これにより下記のような meta 要素が生成される --> <meta content="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" name="csrf-token"> // jQuery でこれを取得する var csrf_token = $("meta[name=csrf-token]").attr("content");

しかし、XML はルート要素が 1 つと決められているし、ルート要素は params の 1 要素に納められてしまうため、リクエストボディに authenticity_token を含めることはできない。

そこで、authenticity_token をチェックしているコードをみてみる。

# actionpack/lib/action_controller/metal/request_forgery_protection.rb def verified_request? !protect_against_forgery? || request.get? || form_authenticity_token == params[request_forgery_protection_token] || form_authenticity_token == request.headers['X-CSRF-Token'] end

どうやら X-CSRF-Token ヘッダにトークンを書いてもいいらしい。

jQuery.ajax は beforeSend オプションで、XMLHttpRequest オブジェクトを変更できるので、XMLHttpRequest.setRequestHeader() を使って X-CSRF-Token ヘッダを追加する。

var csrf_token = $("meta[name=csrf-token]").attr("content"); $.ajax({ type: "POST", url: url, dataType: "xml", // Accept contentType: "application/xml", beforeSend: function(xhr) { // X-CSRF-Token ヘッダのセット xhr.setRequestHeader("X-CSRF-Token", csrf_token) }, data: xml, success: function(res, type) { alert(res); }, error: function(req, message, error){ alert(error); }, });

これで OK。

Processing 環境の比較

このところ、花火シミュレートアプリ HANABICS (Chrome で見てね) というのを開発している (仕事じゃないよ)。

Processing というフレームワークで動かしてるんだけど、開発の過程でいろいろな環境を渡り歩いたので、それぞれの特徴についてまとめてみる。

続きを読む

RubyKaigi 2011 メモ (2 日目)

RubyKaigi 2011 のメモ、2 日目です。rubykaigi.org に録画があることに気づいたので、リンクをつけてます。

続きを読む

RubyKaigi 2011 メモ (1 日目)

7 月 16 日から 18 日まで開催された RubyKaigi 2011 に参加してきました。非常に楽しく、ためになる 3 日間でした。

セッションをきいている間、メモをとっていたので (多少整形して) 公開します。

理解できていない部分、誤って理解している部分、抜けている部分など多々あるので、備忘録としての役割が主です。これを読んで気になる部分があれば、他のレポート (RubyKaigi2011 スペシャルレポートとか) を読むなり、ust みるなり、登壇者が発信してる情報をさがすと良いと思います。

続きを読む

Mac の特殊キー記号の由来

Mac では、特殊キー (修飾キー) を記号で表現することがよくある。下記がその一覧。

記号キーコードポイントUnicode での文字名
commandU+2318PLACE OF INTEREST SIGN
controlU+2303UP ARROWHEAD
option / altU+2325OPTION KEY
shiftU+21E7UPWARDS WHITE ARROW
enterU+2324UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS
escape / escU+238BBROKEN CIRCLE WITH NORTHWEST ARROW
homeU+2196NORTH WEST ARROW
endU+2198SOUTH EAST ARROW
returnU+21A9LEFTWARDS ARROW WITH HOOK
U+2191UPWARDS ARROW
U+2193DOWNWARDS ARROW
U+2190LEFTWARDS ARROW
U+2192RIGHTWARDS ARROW
deleteU+232BERASE TO THE LEFT
forward deleteU+2326ERASE TO THE RIGHT

command は使用頻度高いし、キーに印字してあるからすぐ覚えたんだけど、control や option は、印字してないし (MacBook Pro 2010-2011)、使用頻度同じくらいだしでよく間違える。

そこで、友達から、記号の意味がわかれば覚えるんじゃないか、といわれ、なるほどと思って調べてみた & 推測してみた。

資料はおもに日本語版および英語版の Wikipedia なので、悪しからず。

(command)

command キーを示す については、Wikipedia に詳しい記述がある

初代Mac開発メンバーであったスーザン・ケアが、北欧の史跡などを示す交通標識に使われる マークを記号辞典で見つけ、採用したといわれている。開発段階ではアップルマークが使われていたが、コマンドキー表示としてアップルマークが連なるメニューを見たスティーブ・ジョブズが自社ロゴを濫用していると感じ、別のマークにするよう指示した。

コマンドキー – Wikipedia

記号自体については Saint John’s Arms に詳しく、北欧で5-7世紀頃に使われていた記号だそうだ。Saint John’s Arms のほか Saint Hannes Cross などと呼ばれており (ただし、紀元前の木製スキーにも描かれているためキリスト教起源ではないとされる)、フィンランドでは、魔除けとして家の壁にペイントしたりするそうだ。

(control)

そもそも control キーは下記のような役割をもつ。

テレタイプ端末、及び初期のコンピューターキーボードでは、コントロールキーを押しながら他のキーを押すと、生成されるASCIIの下位5ビット以外がゼロとなった。これによりユーザーはASCIIの非表示文字である最初の32文字 (0×00 – 0x1f) を生成、入力できる。

コントロールキー – Wikipedia

たとえば、J (0x4A, 1001010b) を control とともに押下することで、改行 (0x0A, 0001010b) を得られる。制御文字 = Control character を入力するためのキーなので control キーというわけだ。

上記の例で、改行文字を ^J と書く記法があり (Caret notation, ASCII も参照)、この事で control を ^ で表すことになったらしい。そもそもなぜ ^ が使われたかはわからなかったが、この記法は Mac に限らない、一般的な記法らしい。

ただし、Unicode では、ASCII に含まれる ^ (U+005E, caret) と、Mac で control を示す (U+2303, up arrowhead) を区別している。

(option)

option キーを示す については、Wikipedia に記述がない。Google で調べてみたら、Quora にそのものずばりの質問があった。

Computer Keyboards: What is the origin of the Mac’s “option key” symbol ()? – Quora

その回答として、一番支持されてたものがこちら (抜粋)。

It was clearly inspired by the electrical symbol for an SPDT switch:

この回路図の左側から流れる電流を、スイッチによって、右上に流すか、左下に流すか選択できる。通常の動作を別のものに切り替えるという事で option や alternate (alt) を示すのだろう。

(shift)

まずはシフトキーの由来。

シフトキーの名称は、英文タイプライターが由来である。当初は刻印用の文字盤が水平に置かれて、下からの打鍵圧力により打刻される(アップストライク方式)構造だったが、その文字盤をシフトキーで「シフト(shift,ずらす)」という構造になっていた。

シフトキー – Wikipedia

shift は移す、替えるという意味で必ずしも上向きではない。上向きの矢印になったのは、下記の経緯によるのではないか。

のちにタイプライターは文字盤を手前側に置かれ、前からの打鍵圧力によって打刻される(フロントストライク方式)構造へと移り変わった。その文字盤は「ずらす」のではなく「リフト(lift,持ち上げる)」されるが、呼称は変わることなく「シフト」と呼ばれ続けた。

シフトキー – Wikipedia

(enter)

上の破線で部屋の入り口を、下の折れ線でその部屋に入る (enter) ことを示していると考えられる。

(escape)

○で示した領域から、逃げ出す (escape) 様を矢印で示していると考えられる。

(page down) / (page up)

省略を示す二本線をともなう矢印だろうか。

(home) / (end)

欧文の文書における、文の始め = 一番上の行の一番左、文の終わり = 一番下の行の一番右、を示していると考えられる。

(return) / ↑↓←→ / (delete) / (forward delete)

このあたりは明確ですよね。

ちなみに

上記の記号を使うときは、フォントは Lucida Grande にしとくといい感じですよ。

Picup を利用して Rails アプリに iPhone / iPad から画像をアップロードする

ご存じ iPhone / iPad のブラウザである Mobile Safari は、HTML5 の機能を多数実装してるわりに、<input type=”file” /> を使ったファイルのアップロードができない。

もちろん専用のネイティブアプリを作成すれば可能だけど、まあ、ほとんどの場合めんどくさいよね。

そこで、多少ユーザを選ぶけど、便利そうなのが William Lindmeier 氏制作の iOS アプリ Picup である。

ここでは、Picup の仕組みと、Rails アプリでの実装例を紹介する。

Picup の仕組み

iOS や MacOS (X?) では、URL スキームにアプリケーションを関連づけられる。Picup の場合 fileupload:// に続けて、アプリに渡したいパラメータをつけて Safari 等で開けば、Picup にパラメータが渡され起動する。

サーバ側では、Picup の Web サイトで配布しているスクリプト (picup.js) を利用して、<input type=”file” /> を、fileupload://… を開くボタンに書き換える (別にこのスクリプトを使わなくても fileupload://… へのリンクを自前で作ってもいい)。

このボタンがクリックされると、POST 先の URL (postURL)、フィールド名 (postImageParam) などのパラメータを渡して Picup が起動される。そして、Picup 上で、ユーザーが、カメラで撮影するか既存の写真を選択し、Done をタップすると、さきほど渡されたパラメータをもとに POST してくれる。

さらに、callbackURL を指定すると、POST 後に任意の URL を Safari で開くこともできる。その際に # 以降にいくつかパラメータが渡されるので、それを利用して、ユーザーを誘導することもできる。

Rails での作例

以下では、Ruby 1.9.2 + Rails 3.0.7 + carrierwave で Picup による写真のアップロードに対応した Rails アプリを作る。

とりあえず初期設定。

$ rails new picup_demo -d mysql -J # Gemfile - gem 'mysql2' + gem 'mysql2', '0.2.7' + gem 'carrierwave' + gem 'jquery-rails' $ bundle $ rails g jquery:install

jquery や後述の picup.js をロードするようにする。

# app/views/layouts/application.html.erb - <%= javascript_include_tag :defaults %> + <%= javascript_include_tag :all %>

写真のモデル・コントローラ・ビューを scaffold でつくる。

$ rails g scaffold photo file:string $ rake db:create $ rake db:migrate

アップローダをつくり、photos.file に設定する。

$ rails g uploader photo # app/models/photo.rb class Photo < ActiveRecord::Base + mount_uploader :file, PhotoUploader end

フォームのフィールドを、type=”file” にする。show で写真を表示する。

# app/views/photos/_form.html.erb - <%= form_for(@photo) do |f| %> + <%= form_for(@photo, html: {multipart: true}) do |f| %> - <%= f.text_field :file %> + <%= f.file_field :file %> # app/views/photos/show.html/erb - <%= @photo.file %> + <%= image_tag(@photo.file.url) %>

この時点で PC の Web ブラウザからアップロードできるか確認しておくとよい。

$ rails s # http://localhost:3000/photos/new へ Web ブラウザでアクセス

Picup のヘルパースクリプトを導入。http://picupapp.com/picup.js.zip をダウンロード、展開し、picup.js を public/javascripts 下に移動する。

type=”file” のフィールドを Picup を開くボタンに置き換える。

# app/views/photos/_form.html.erb <script type="text/javascript" charset="utf-8"> $(function(){ window.name = "Picup_demo_new_photo"; // アップロード後表示されるページから遷移するためにウィンドウ名をつけておく Picup.convertFileInput( "photo_file", // <input type="file" /> の ID { 'referrername': escape('Picup Demo'), // Picup に表示されるアプリケーション名 'purpose': escape('Upload A Photo'), //Picup に表示されるメッセージ 'postImageParam': 'photo_file', // フィールド名、この場合、rails では params[:photo_file] でアクセスできる。 'postURL': 'http://192.168.1.10:3000/photos.json', // post先 'callbackURL': 'http://192.168.1.10:3000/uploaded' // アップロード後に開く URL } ); }); </script> # app/controllers/photos_controller.rb def create - @photo = Photo.new(params[:photo]) + @photo = Photo.new(file: params[:photo_file])

IPアドレスは適当に書き換えて。 ここまででとりあえずアップロードはできる。 (アップロード後表示されるページは RoutingError になっちゃうけど、/photos を見ると、正しくアップロードできているのが確認できる)

アップロード後、アップロードされた写真のページへ遷移させたいので、create のレスポンスに、そのページの URL を含ませる。

# app/controllers/photos_controller.rb format.html { redirect_to(@photo, :notice => 'Photo was successfully created.') } format.xml { render :xml => @photo, :status => :created, :location => @photo } + format.json { + imgur_like_response = { + rsp: { + stat: "ok", + image: { + original_image: photo_url(@photo) + } + } + } + render :json => imgur_like_response + }

{rsp: …} となっているハッシュは、imgur に画像をアップロードした際のレスポンスを模したものである。いままで触れなかったが、Picup は postURL の指定がない場合、imgur.com に画像をアップロードする。その際、レスポンスに含まれる original_image の値は、アップロード後開かれる URL の # 以降に remoteImageURL=… の形で渡される (imgur.com からのレスポンスでは他にもいろいろな情報が付与されているが、無視されている)。

# public/uploaded.html <!DOCTYPE html> <html> <head> <title>Picup Demo</title> <script> <!-- var redirect = function() { var keys_values = window.location.hash.substring(1).split("&"); var params = {}; for(var i = 0; i < keys_values.length; i += 1){ var key_value = keys_values[i].split("="); params[key_value[0]] = key_value[1]; } if (params.remoteImageURL) { window.open(unescape(params.remoteImageURL), 'Picup_demo_new_photo'); window.close(); } }; redirect(); //--> </script> </head> <body> <h1>アップロード完了</h1> <a href="javascript:redirect();">自動的に移動しない場合はここをタップしてください。</a> </body> </html>

これが、アップロード後開かれるページである。URL の # 以降の remoteImageURL=… の値を読み出し、もともとフォームを表示していたタブ (Picup_demo_new_photo) で開き、このページ自身は閉じるようにしている。いちおうこれで、PC のブラウザからアップロードした際と似た挙動を実現できる。

なお、<input type=”file” /> の置き換えを、UA が Mobile Safari であることを確認した上で (Apple 公式の DetectingWebKit を使えば簡単) 行えば、PC のブラウザでも Mobile Safari でもほぼ同じように使える。

気になるところ

先述のとおり Picup.convertFileInput には postImageParam オプションで、送信されるファイルのフィールド名を指定できる。ここは、Rails の規約に従って photo[file] としたいところだが、実際に試してみると、Rails にはフィールド名が photo%5bfile%5d として渡されてしまい、params[:photo][:file] のようなかたちではアクセスできない。無用なエスケープがされちゃってるんですね。ちょっと残念。

あと、POST のレスポンスをもうすこし利用できるとうれしい。imgur のレスポンスに特化してるのがもったいない。

iBooks で日本語の辞書を引くように EPUB ファイルを変換するスクリプト

iPhone / iPad などの iBooks で、EPUB ファイルを読むとき、文字列を選択して辞書を引ける。ただ、ここで引ける辞書は (なぜか) EPUB の言語に依存するので、英語の本で辞書を引くと、英英辞書を引くことになる。

英和辞書を引くためには、EPUB 内のファイルを編集し、言語を日本語 (ja) にする必要がある。この手順は下記ページに詳しい。

ただ、この手順、結構めんどくさいので Ruby でスクリプト書いた。

Ruby (1.8.7 か 1.9.2) と RubyGems (1.8 の場合) があるなら、

gem install zipruby

で、必要な gem を導入して、上記スクリプトをダウンロード。スクリプトのあるディレクトリで、

ruby change_lang_of_epub.rb (変換したい EPUB ファイル)

とすれば、(元のファイル名).ja.epub というファイルが生成されます。

ruby change_lang_of_epub.rb (変換したい EPUB ファイル) (言語コード)

とすれば、日本語 (ja) 以外の言語コードも指定できます。

Ruby はこの手のスクリプトがさくっと書けてよかですね。

無限大を含む Date の Range で include? (include_with_range?) に失敗する

Ruby + ActiveSupport で、ある期間と別の期間との関係を調べるメソッドを書いてたところ、期間に無限大を含む場合に失敗した。

# ruby 1.8.7 require "date" require "rubygems" require "active_support" (Date.today..(1.0 / 0)).include?(Date.today..Date.tomorrow) # true これは問題ないが、逆にすると... (Date.today..Date.tomorrow).include?(Date.today..(1.0 / 0)) # NoMethodError: undefined method `<=' for nil:NilClass

ActiveSupport のコードを追ってみると、原因は Float <=> Date で nil が返ってしまう点にあるらしい。

Date.today <=> 1.0 # 1 1.0 <=> Date.today # nil

Date が演算子の左側にある場合、Date#<=> が呼ばれる。実装は下記。

# File lib/date.rb, line 1267 def <=> (other) case other when Numeric; return @ajd <=> other when Date; return @ajd <=> other.ajd end nil end

演算子の右側が Numeric なら、@ajd と比較している。@ajd は、紀元前4713年1月1日からの日数を示す数値。数値なので Float と比較できる。

いっぽう、Float が演算子の左側にある場合は、Float#<=> が呼ばれるため、Date をどう扱っていいかわからず、比較できない。

そこで Date#coerce を実装した。

require "date" class Date def coerce(other) return [other, @ajd] if other.is_a? Numeric nil end end

Numeric は、比較対象と型が異なる場合、比較対象の coerce メソッドを (あれば) 呼び出して、型を合わせてから比較する。これにより、@ajd を使って比較できるようにする。
これで演算子の左側が Float でも比較できるようになり、include? や overlaps? も動く。

1.0 <=> Date.today # -1 (Date.today..Date.tomorrow).include?(Date.today..(1.0 / 0)) # false

また、始点に Float を、終点に Date を持つ Range も作成できる。

(-(1.0 / 0)..Date.today) # 無限遠の過去から今日までの Range

include? や overlaps? 含め、おおむね期待どおりに動くが、この場合、Date の範囲でなく Float の範囲になってしまうので、Enumerable にならないなどの制限がある。

しかし coerce なんて、ごく最近、プログラミング言語 Ruby 読むまで知らなかった。記述細かいなあと思ってたけど、役に立つもんですね。

転職しました

  • 投稿者: labocho
  • 2011年3月31日 9:42 PM
  • 未分類

以下、私的な内容です。

年始のご挨拶 でも、ちらっと書いていますが、2011 年 3 月31 日付で、三重大学附属図書館を退職し、同 4 月 1 日より、Web アプリケーション開発を主たる事業とする会社に就職しました。

三重大学附属図書館には、4 年もの間お世話になり、いろいろな人と出会い、いろいろな仕事をやらせていただきました。月並みですが、この 4 年間がなければ、今の私はなかったと思います。

同僚のみんなと毎日会えなくなるのは、ほんとにさみしいです。こんな気持ちは大学の卒業式以来です。

また、ネットを通じて、素敵なライブラリアンの皆さんを知ることができたのも幸せでした。ライブラリアンっておもしろいひと多いよね (観測範囲狭いけど)。

今後、図書館との関わりがどうなっていくのか、まだわかりませんが、なんだかんだでゆるいつながりがあるので、ときどきは図書館と関わっていくんじゃないかと予想しています。

みなさん、ありがとうございました。そして、これからもよろしく。

ホーム

検索
フィード
メタ情報

ページの上部に戻る