アドベントカレンダーを電子書籍で読めるサービスを作った

f:id:secondlife:20140111143236j:plain

 

QiitaAdventarATND のアドベントカレンダーがオフラインの電子書籍で読みたい、と思ったので作った。例えば寿司アドベントカレンダーなら、URLを入れて変換すると、readlistsを裏側で叩いて、こんな感じに生成される。

生成後は readlists の機能を使って、iPhone や iPad に送ったり、dropbox に epub を保存したり、その他いろいろな方法で、様々なデバイスで読むことが出来る(※なお readlists の kindle に送る、は一部文字がおかしくなるのでオススメしない)。また Qiita のアドベントカレンダーは、HTML の要素の関係で必要の無い要素も混じってしまっていて、ちょっとごちゃっとしてしまっているが、これは Qiita チームが HTML の構造を綺麗にしてくれれば解決するので勝手に期待!!1

どうぞご利用下さい。なおこのサービスのソースコードはこちら。

サービスの裏側のこと

当初、readlists-anonymous というライブラリを作っていて、これを公開すればいいや、と思ってたのだけど、CUI じゃほぼ誰も使わなさそうなので Web サービス化した。

作ってみたものの飽きそうなWebアプリはherokuで動かしておく - はこべブログ ♨ でも書かれてるとおり、自分の VPS や自宅サーバに作ると何かのタイミングで動かなくなる未来が見えていたのと、最近の heroku 事情はどうなんだろうと使ってみたかったので、と思って heroku でホスティング。

このサービスは裏で readlists を http 叩いていてネットワークIO待ちが発生し、トータルの処理時間に数十秒かかるんだけど、いちいち worker 化するのもめんどうだよなぁ、と思っていたところ、Web サーバに Thin 使って EventMachine 使えるようにしておくと、EM::defer 使ったバックグランド処理が楽に書ける とのことなのでソレで*1。データは消えても問題ないので、memcached(heroku だと今は MemCachier) plugin に進捗の状態なども入れて管理。簡単ワイワイ

また heroku でどうやれば良いんだろう、という問題解決がオフィシャルサイトのドキュメントにかなり載っているため、ググって stackoverflow 見るより、オフィシャルを見た方が素早く解決して素晴らしい感じ。その他も heroku でハマることは一つも無く、サクサク作って行けた。しかも0円、無料です。

Web のデザイン周りは、Twitter Bootstrap, Bootswatch, Font Awesome とそれを CDN でホスティングしてくれる Bootstrap CDN で。favicon も無いと寂しいので、Icon Generator でとりあえず感あふれる favicon を作った。デザインの抽象化・再利用のエコシステムもできあがっていて、大変便利な時代が来てることは知っていたけど、いざ自分が使ってみると便利さが実感できた。

readlists-anonymous のこと

サービスの裏側で使ってる readlists-anonymous はコマンドラインのツールもついているので、

$ gem install readlists-anonymous
$ readlists-anonymous -t example-title http://example.com/ http://test.example.com/
* Created anynymous readlists
share-url: http://readlists.com/8ddbbc9e/
public-edit-url: http://readlists.com/8ddbbc9e2a52458ea0104afed343cb81/
Add http://example.com/
Add http://test.example.com/
...

みたいに、CUI から自分の好きな URL を readlists に登録して使うことも出来る。どうぞご利用下さい。

*1:この方法だと Web サーバの再起動時に処理が止まってしまうので、実行中断時の処理をキチンと入れないとなんだけど入れて無い

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:個人の見解です