weather_hacker.gem: Rubyで天気予報調べるやつ作った



WeatherHacker - Hacking to the Weather
郵便番号から今日〜明後日の天気予報を調べられる。

Background

ここ最近、毎日家を出る前にiPhoneの天気予報アプリを見ていたけど、見やすくないし、結局見逃して急に夜寒かったり雨降ってきたりするので、もっとデザインの良い天気予報サイトを作ろうと思った。それで、天気予報取得用のライブラリを探したけど、日本向けのは良いのがなかったので自分で作ってGemにした。

API

最終的にはLivedoorのAPIを利用させてもらうことにした。天気予報の取得元として候補に入れてたのはGoogle・Yahoo・Livedoorの3つだったけど、正直1番難しいのは位置情報検索部分で、Googleは英語で市名や県名を与える必要があるし、Yahooは明日までのデータしか取れなさそうで、結局ドキュメントのわりとまともなLivedoorのものにした。作ってから気付いたのだけど、LivedoorAPIは気温を空のまま返す確率が高くて、気温が取れないことが多いのと、更新頻度がそんなに高くないのが、結構困るかもしれない。とりあえず2日後のデータまでは取れるので、毎日取得して2日の間に気温が更新されてればラッキーという雰囲気。

あと郵便番号から地名を検索するために、郵便番号データのダウンロード - zipcloudAPIを利用させて頂いた。日本郵便の提供している郵便番号と地名の対応データを持っていて、郵便番号で問い合わせるとXMLで地名を返してくれて、素晴らしい。一方LivedoorAPIの方では、市名とcity idの対応表APIと、city idで各地の天気予報を返すAPIを持っているので、まず対応表をもらってきてから、郵便番号で地名を取得して、近い地点のcity idがないか泣きながら探してから、ようやく天気予報APIを叩く。叩く。...という実情を隠蔽して簡単に機能を提供できたのでわりと良い感じのものができたと思う。

Gem

@sora_hに教えてもらいながら、Bundler(RubyのGem管理用ライブラリ)でGemをつくった。かなり前にJewelerというので1度作った気がするけど、ほとんど覚えてなかった。Bundlerで作ってみたらこんな感じで超簡単にGem作れたので、便利なものはどんどん公開していこうという気持ちになる。

$ bundle gem weather_hacker
$ cd weather_hacker
$ mkdir lib
$ vim lib/weather_hacker.rb
$ cat lib/weather_hacker.rb

module WeatherHacker
end

$ vim weather_hacker.gemspec
$ git add .
$ git commit -m "Update weather_hacker.gemspec"
$ rake build
$ rake install
$ rake release

Travis CI


Travis CIを初めて利用してみた。導入に40分ぐらい掛かると思っていたけど、5分ぐらいで出来た。
このアイコンが赤く染まっているときは、テストが落ちてる。

  1. Travis CIにGitHubユーザでログインする
  2. GitHub上の自分のレポジトリが表示されるのでTravisCIを使いたいものを選ぶ
  3. .travis.ymlにRubyのバージョンの設定を書く (任意)
  4. bundle exec rakeでテストが実行されるようにRakefileを書換える
  5. git pushする
  6. Travis CI上で確認する
  7. GitHubのREADMEにCI結果のアイコンとか貼っちゃう
  8. おしまい!

travis.yml

# .travis.yml
language: ruby
rvm:
  - 1.9.2
  - 1.9.3

Rakefile (何かの雛形で生成されたやつを拾ってきた)

#!/usr/bin/env rake

require "bundler/gem_tasks"
require "bundler"

begin
  Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
  $stderr.puts e.message
  $stderr.puts "Run `bundle install` to install missing gems"
  exit e.status_code
end

require "rspec/core"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task :default => :spec