Ruby の http ライブラリの通信を表示する http-dump を作った

f:id:secondlife:20140110170809p:plain

 

Ruby 上で http を叩いた通信見たい時に、毎回同じ事をやってるので抽象化して http-dump というライブラリを作った。

$ gem install http-dump
require 'net/http'
require 'uri'
require 'http-dump'

HTTPDump.dump {
    Net::HTTP.get(URI('http://example.com'))
}

と http でやりとりしてるコードを block で囲むと、以下のように出力される。

> GET http://example.com/ with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Host'=>'example.com', 'User-Agent'=>'Ruby'}
< 200 OK
< Accept-Ranges: bytes
< Cache-Control: max-age=604800
< Content-Type: text/html
< Date: Fri, 03 Jan 2014 13:42:51 GMT
< Etag: "359670651"
< Expires: Fri, 10 Jan 2014 13:42:51 GMT
< Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
< Server: ECS (sjc/4FB4)
< X-Cache: HIT
< X-Ec-Custom-Error: 1
< Content-Length: 1270
<
<!doctype html>
<html>
<head>
  <title>Example Domain</title>
... more ...

enable! / disable! で全体的に有効・無効を切り替えられる。

require 'open-uri'
require 'http-dump'

HTTPDump.enable!
open('http://example.com').read
HTTPDump.disable!

Rails からなら

group :development do
  gem 'http-dump', require: ENV['HTTP_DUMP_ENABLE'] ? 'http-dump/enable' : 'http-dump'
end

を Gemfile に追加。

HTTP_DUMP_ENABLE=1 bundle exec rails s

で Rails アプリ内部から叩いている http のやりとりを表示、とかに使える。

サポートしてる http のライブラリは net/http ベースの物からその他 WebMock で使える物すべて。http-dump の内部実装は全くたいしたことはやって無くて、WebMock の機能にのってるだけです。

どうぞご利用下さい。

Rubyistokei for iOS を RubyMotion で作った話

この投稿は RubyMotion Advent Calendar 2013 の23日目の記事です。

最近 iPhone に買い換えて、初めて iPhone をメイン端末にしてみたので iOS アプリを何か作ってみよう、と思い最初は無難に Xcode + Objective-C で書いていたんだけど、そういえば RubyMotion でも iOS アプリ作れるんだっけ、どんな感じなんだろうと思って Rubyist がみんな大好き*1 Rubyistokei の iOS 版を作ってみた。

Rubyistokei for iOS

Rubyistokei は

  • 画像の表示
  • ネットワークでのデータ取得
    • github 上に表示元のメタデータが上がってるため、それを取得し利用する
  • レイアウトの構築
  • タイマーの利用
    • 時計なんで

あたりの実装が必要で、最初の題材としては簡単すぎずも無く、難しすぎずも無くちょうど良い感じでした。

というわけで作ってみたんだけど、コードはほぼ app_delegate.rb に。ネットワークやりとりして Rubyist オブジェクトを返す実装のみ rubyist.rb へ。本当はもっときれいな抽象化と、適切なファイル分離を行うんだろうけど、RubyMotion 自体はもちろん、Cocoa フレームワークや UIKit も理解してないため、1ファイルで試行錯誤できた方が楽だったので、ほぼ1ファイルで実装。きれいな実装では無いので、参考にはあんまりならないと思います。

また SugarCube 等の RubyMotion で Ruby らしく書けるライブラリは、理解が薄い時から高レベルのラッパーを使ってしまうと、挙動の理解ができなくなってしまうので、意図的に使わずに。使ったのは BubbleWrap の HTTP と String#to_color ぐらいかな。

AppStore に申請してリリース

作ったからには AppStore に申請してリリースする気満々だったんだけど、レビューで落とされたヨ…。理由は、シンプルすぎる時計アプリだから、もっとユーザ価値を考えて!とのことでした。まわりの iOS 開発者に聞いてみたところ、これぐらいのアプリでも落とされたりすることもあるんだね、とのことだったので、運が良ければ通るし、運が悪ければ落とされる感でした。

RubyMotion で開発してみて

開発してみて、意外とつまずくところが少なかったなぁ、という印象。RubyMotion だからハマった、というところはほぼ無くて、だいたい自分が理解してない iOS フレームワークの部分だった。

RubyMotion JP など日本語のチュートリアルドキュメントも充実してて、日本語化してくださった皆さんには感謝です。

特に Objective-C の表現をどう Ruby で現してるか、などランタイムのことが書いてある RubyMotion Runtime Guide(日本語訳) が興味深かったですね。

*1:個人の見解です

GlitchKit - iOS でカジュアルにグリッチできるライブラリ

本日、社内外の iOS/Android 向け Tips 共有会、#potatotips 第二回 で、「XXXKit -それははしかのような物-」という内容を発表した。

最近 iOS (Objective-C) を今更ながらに学び始めたんだけど、新しい事を学んで今まで知らなかった/興味深いパラダイムがあると、それにどっぷりつかりがちで、それを プログラマにおけるはしか 、と言ったりする。

その中でかじってすぐに興味深いと感じたのは Objective-C の"カテゴリ"で。これはヘッダを import するだけ(実際は import するしない関わらずリンクされた時)で、様々なオブジェクトのクラスの挙動を拡張できる。Ruby における mixin + refinements のような物だし、Perl でも use して特定のオブジェクトの挙動を変えることが出来るが、Objective-C を学ぶまで、このようなことができることを知らなかった。

またこの "カテゴリ" と組み合わせて、標準のオブジェクトや UIKit といったフレームワークを拡張することができる XXXKit という語尾に Kit をつけたライブラリがある。たとえば EnumeratorKit なんかは、NSArray や NSDictionary で、Ruby の Enumerator 的なコードを書くことができるようになる。もちろんこれらは意図しない動作を引き起こす可能性もあるため、多用すると危険なのだが、そこは便利さとトレードオフなので、どうしてもオレオレ XXXKit を作りたくなる衝動がでてくる。

そのため、"カテゴリ" と "XXXKit" は Objective-C におけるはしかのようなものだなぁ、と感じた。と言うわけでカテゴリ使って Glitch する XXXKit を作ってみた。

Podfile に追加する

pod 'GlitchKit'

 

before glitch

UIImageView -glitch でグリッチ

#import "GlitchKit.h"

// glitch!
[uiImageView glitch];

   after glitch

簡単便利

UIImageView -glitchWithBlock: でグリッチ

好きなようにグリッチさせる

// apply custom glitch
[uiImageView glitchWithBlock:^int(int byte, int index, uint length, Byte *bytes) {
  return (byte == 42 && arc4random() % 3 == 1) ? 0 : byte;
}];

 

after glitch3

簡単便利

他にもUIImage クラスで以下が使えるようになる。

  • (UIImage *)glitch;
  • (UIImage )glitchWithBlock: (int (^)(int byte, int index, uint length, Byte bytes)) block;
  • (NSData *)glitchData;
  • (NSData )glitchDataWithBlock: (int (^)(int byte, int index, uint length, Byte bytes)) block;

どうぞカジュアルにごりようください。