おんがえしの blog

作ったプログラムと調べた技術情報

ソースコードを読んでみた - bgm.rb

ターミナルから簡単に曲を聞けるbgm.rbというのを作った - hitode909の日記

Rubyのgemのソースコードを効率的に読む方法を使ってbgm.rbのコードをざっと読んでみました。bundlerは実行環境なのでちょっとずつ挙動を変えながらコードを読めるのがよいです。2015年で今更だけどbundler本当に便利だ・・。

bundle exec -- ruby bgm.rb "椎名林檎"

しながらコード読みました。

f:id:tuto0621:20150130231222p:plain

bgm.rb

bgm.rb

本体です。BGMクラスの定義が上部にBGMクラスのインスタンスを使うメイン処理が下部にあります。

BGMクラスは大きく分けて

  • キーワードにマッチする楽曲データを取得
  • 楽曲データから音楽ファイル(m4a)のURLを取得、ダウンロード
  • ダウンロードした音楽ファイルを再生(デフォルトはafplay)

OSXってafplayっていうコマンドで音楽再生出来るのですね。

  def play(item)
    file = download(item)

    command = "#{@player || 'afplay'} #{file.path}"

    if @rate
      command += " --rate #{ @rate } "
    end

    if async?
      command += " &"
    end

    system command
  rescue Interrupt
    nil
  end

楽曲データの取得は'itunes-search-api'というGemに任せているようなのでそちらも読んでみます。

class BGM
  def each(term)
    tracks = ITunesSearchAPI.search(term: term, country: "JP", media: "music", limit: async? ? 10 : 200)
    tracks.shuffle! if @shuffle
    tracks.each{|track|
      yield lookup track
    }
  end
  .
  .

itunes-search-api gem

rlivsey/itunes-search-api

HTTPartyというgemを使ってAPIを定義しているようです。おそらくgetベースの特定のURLを叩くとjsonが返ってくるAPIのようです。

require 'httparty'

class ITunesSearchAPI
  include HTTParty
  base_uri 'http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa'
  format :json

  class << self
    def search(query={})
      get("/wsSearch", :query => query)["results"]
    end

    def lookup(query={})
      if results = get("/wsLookup", :query => query)["results"]
        results[0]
      end
    end
  end
end

README.rdocを読んでみるとiTunes APIのドキュメントへのリンクがありました。

= ITunesSearchAPI

Ruby interface to the ITunes Search API

http://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html

得られた知見

  • iTunesの楽曲データを取得したい時はitunes-search-api gemを使う
  • ダウンロードした音楽データの再生にはOSXだとafplay
  • HTTPartyというgemを使うとAPIのラッパークラスを簡単に書ける

Rubyのgemのソースコードを効率的に読む方法

いきなり読み始めてもよいのですが、事前に軽く準備しておくと読みやすくなります。

  • 読みたいソースコードをダウンロード
  • bundle install --path vendor/bundle
  • 検索用のインデックスを貼る
  • 読む

bgm.rbを例に説明します。

読みたいソースコードをダウンロード

hitode909/bgm

$ git clone git@github.com:hitode909/bgm.git
$ cd bgm

bundle install --path vendor/bundle

$ bundle install --path vendor/bundle
.
.
Installing json 1.8.2
Installing multi_xml 0.5.5
Installing httparty 0.13.3
Installing itunes-search-api 0.1.0
Using bundler 1.7.12
Your bundle is complete!
It was installed into ./vendor/bundle
Post-install message from httparty:
When you HTTParty, you must party hard!

これでvendor/bundle以下にgemのソースコードがインストールされます。

書き換えやすくするためにgitにもコミットしておきます。人のコードなのでアクセス権も無いはずなので間違えてpushすることもないはず。(身内のコードだとあるかもしれないので注意。その場合はブランチ切りましょう)

$ git add .
$ git commit -m "Add vendor/bundle"

検索用のインデックスを貼る

私の場合はMilkodeの検索インデックスとctags(Emacs用)を貼ります

$ milk add .
package    : bgm
github     : hitode909/bgm
result     : 1 packages, 237 records, 237 add. (7.45sec)
*milkode*  : 24 packages, 9032 records in /Users/ongaeshi/.milkode/db/milkode.db.

タグファイルはmilk updateと一緒に更新されるように設定します。

$ milk config update_with_ctags_e true
$ milk update

読む

これで準備完了です。後はそれぞれ好きな方法で。

私は始めにMilkodeのWebアプリを立ち上げます。ざっとブラウザでコードの概要を掴んでからエディタで細部を読んでいきます。関数の間はタグジャンプで移動して、この関数はどこから呼ばれているのか?などはMilkodeで検索して見つけます。

$ milk web

関連データは全てディレクトリ以下にあるのでソースコードに直接日本語のメモも書きます。書き込んだ場所はgit diffで取ることも出来ますしキリのよい所でコミットも出来るので便利です。

まとめ

手順をまとめて書くと以下のようになります。

git clone git@github.com:hitode909/bgm.git
cd bgm
bundle install --path vendor/bundle
git add .
git commit -m "Add vendor/bundle"
milk add .
milk config update_with_ctags_e true
milk update

割とスクリプト化出来そうな気がしてきました。次回はbgm.rbを読んでいきます。