RubyのAPI WrapperのGemをRubyMotionのGemに書き換えてみた

公開が遅くなりましたが、、RubyMotion Advent Calendar 2013の14日目の記事です。

RubyMotionの初心者の僕が、ごく一般的なHTTPのAPI WrapperのRubyGemをなんとかしてRubyMotionのGemに書き換えたという話を書きたいと思います。
(なのでツッコミどころ満載だと思いますのでご指摘ございましたらよろしくお願いいたします。＞＜)

今回書き換えた対象の Gem は翻訳クラウドソーシングサービス Gengo のAPIをの Wrapper を提供しているこちらのクライアントを使用しました。

https://github.com/gengo/gengo-ruby/

#RubyMotion gemの雛形作成

RubyMotionのcreateコマンドからgem作成用のtemplateを指定して作成することができます。

```ruby
motion create template=gem gengo-motion
```

## lib/projectディレクトリ配下にソースを移動

RubyMotionのgemはデフォルトでlib/project配下のrbファイルを読み込むようなので、ソースをとりあえずまるっと移動します。

```ruby:ib/project/gengo-motion.rb
lib_dir_path = File.dirname(File.expand_path(__FILE__))
Motion::Project::App.setup do |app|
  app.files.unshift(Dir.glob(File.join(lib_dir_path, "project/**/*.rb")))
end
```

# 必要なライブラリの書き換え

有名な話ですが、RubyMotionはrequreが使えないので、Rubyの多くのライブラリが使えません。これは大変です。でも一つ一つRubyMotionで使えるライブラリに置き換えていきたいと思います。

## ‘openssl’の書き換え

OpenSSLライブラリが使えないのでhmacの暗号化を行うために、CocoaPodsで公開されているIGDigestというライブラリを代用しました。

https://github.com/siuying/IGDigest

cocoapodsのライブラリを使用するには、gemspecファイルに以下を記述し、

```gemspec
spec.add_dependency 'motion-cocoapods', '~> 1.4.0'
spec.add_dependency 'cocoapods'
```

Rakefile内で以下のように宣言します。

```ruby
Motion::Project::App.setup do |app|
  # Use `rake config' to see complete project settings.
  app.name = 'gengo-motion'

  app.pods do
    pod 'IGDigest'
  end

  app.frameworks << 'Security'
end
```

こんな感じで書き換えができます。

```ruby
# Creates an HMAC::SHA1 signature, signing the timestamp with the private key.
def signature_of(ts)
  # OpenSSL::HMAC.hexdigest 'sha1', @opts[:private_key], ts
  ts.SHA1HMACWithKey(@opts[:private_key])
end
```

## ‘net/http’の書き換え

HTTPのWrapperはbubble-wrapなどの便利ライブラリがRubyMotion用に公開されていますが、headerなどをゴニョゴニョやるにはNSURLRequestを直接呼び出す方が都合が良さそうなので、naoya_itoさんのHBFav2のソースを<del>パクって</del>参考にさせていただいて書き換えました。

https://github.com/toshipon/gengo-motion/blob/master/lib/project/gengo-ruby/http_client.rb#L11

```ruby
# http = Net::HTTP.start(@api_host, 80)
# resp = http.request(req)
request = NSURLRequest.alloc.initWithURL(url.nsurl, cachePolicy:@cache_policy, timeoutInterval:@timeout)
```


## ‘cgi’の書き換え

url escape処理はsugarcubeのNSString拡張を用いて書き換えました。
sugarcubeはいろんな便利ライブラリが詰まっていてRubyMotionでの開発で重宝しそうです。

https://github.com/rubymotion/sugarcube

sugarcubeのstring拡張を使用するにはgemspecファイルに以下を記述し


```ruby
spec.add_dependency 'sugarcube'
```
Rakefileに以下を記述しました。

```ruby
require 'sugarcube-attributedstring'
```
こんか感じで書き換え可能です。

```ruby
# Use CGI escape to escape a string
def urlencode(string)
  # CGI::escape(string)
  string.escape_url
end
```

# specの記述方法変更

RubyのspecにはあるけどRubyMotionのspecにはないメソッドがいくつかあったのでそれを書き換えました。

should_notとraise_errorは使えなかったので以下のように、

```ruby
it "should be successful" do
  lambda do
    @gengo_client.getAccountBalance
  # end.should_not raise_error
  end.should.not == :error
end
```
be_an_instance_ofは使えなかったので、class.shouldに書き換えて検証してます。

```ruby
it "should have a credits field as a string" do
  credits = @useful_response_body['credits']
  # credits.should be_an_instance_of(String)
  credits.class.should == String
end
```

# gemの公開

最後にgemの公開方法ですが、通常のRuby Gemと同じです。

```shell
gem build gengo-motion.gemspec
gem push gengo-motion-1.0.gem
```
 
作成したRubyMotionのgemのソースはこちらになります。

https://github.com/toshipon/gengo-motion
※ まだ開発途中で、一部のAPIが動かなかったり、specを完全に移行できていません。もし興味がありましたら是非forkお待ちしております！

# 参考にさせていただいたサイト
https://github.com/naoya/HBFav2