Milkode 1.8.9 リリース - キーボードショートカットがより便利に

ひそかに1.8.8もリリースしていたのですがブログ書いてなかったのでまとめて。

リリースノート

変更点

特に"ショートカットキーの s が押されると、ページトップにスクロール"と"相対URLモードで起動していると、ショートカットキー S による新タブ検索が行えない問題を修正"のおかげでショートカットキー(milk webを起動して[ヘルプ]->[キーボードショートカット])が大分使いやすくなりました。ぜひお試しください。

インストール

行指向のソースコード検索エンジンと検索アプリです。 数万オーダーのファイルから、目的のキーワードを含む1行を瞬時に検索することが可能です。

$ gem install milkode

http://milkode.ongaeshi.me/

Milkode 1.8.7 リリースしました

プルリクエストによるバグ修正が主です。(ずっとリリースできなくてすいません・・)

  • milk web
    • Remove duplicated :type => :boolean
  • milkweb.yaml
    • :eliminate_extname 属性を追加
    • CodeRay用の :tab_width 属性を追加

リリースノート

インストール

行指向のソースコード検索エンジンと検索アプリです。 数万オーダーのファイルから、目的のキーワードを含む1行を瞬時に検索することが可能です。

$ gem install milkode

http://milkode.ongaeshi.me/

ソースコードを読んでみた - 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を読んでいきます。

Milkodeで作ったデータベースをRroongaで開いて簡単に全文検索する

この記事はGroonga Advent Calendar 2014 - Qiitaの17日の記事です。

Groongaはオープンソースのカラムストア機能付き全文検索エンジンです。RroongaやGrnMiniを使うとRuby経由で簡単にアクセスすることが出来ます。

検索用クエリを工夫してデータを色々な角度から眺めるのは楽しいのですが、全文検索をするスクリプトを書く時に面倒なのは全文検索用のデータベースを用意する部分です。

そこで、

  • データベースの作成は他のアプリケーションを使って行い
  • 検索部分だけを自力で書く

というアイデアを思いつきました。

Milkodeのインストール

今回はソースコード検索エンジンのMilkodeを使います。ソースコード検索エンジンと詠っていますが本質的にはファイルデータベースなので好きなファイル群を登録してRubyスクリプトから検索する、といったことが出来ます。

Milkode - 行指向のソースコード検索エンジン

$ gem install milkode

試しにrailsソースコードでも足しておきましょう。

$ milk init
$ milk add -p git https://github.com/rails/rails.git

データベースを開く

データベースを開いて検索してみます。/Users/ongaeshi/.milkodeは適宜置き換えて下さい。

# -*- coding: utf-8 -*-
require 'groonga'

# データベースを開く
Groonga::Database.open("/Users/ongaeshi/.milkode/db/milkode.db")

# テーブルを開く
documents = Groonga["documents"]
p documents.count               # => 登録されているレコードの数: 2733

# レコードの内容を読む
path = "/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/relation/calculations.rb"
p documents[path].path          # => 絶対パス: "/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/relation/calculations.rb"
p documents[path].package       # => パッケージ名: "rails"
p documents[path].restpath      # => パッケージ名より先のファイルパス: "activerecord/lib/active_record/relation/calculations.rb"
p documents[path].content       # => ファイルの内容: "module ActiveRecord\n  module Calculations..."
p documents[path].timestamp     # => タイムスタンプ: 2014-12-18 02:25:11 +0900
p documents[path].suffix        # => 拡張子: "rb"
puts

# 'column:@''は部分一致、'column:'は完全一致
# http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html

# ファイル内容に以下のキーワードを全て含むレコードを探す
documents.select("content:@def content:@pluck").each do |record|
  p record.path
end
puts

# 内容に'def','pluck'を含み拡張子'md'のもの
documents.select("content:@def content:@pluck suffix:md").each do |record|
  p record.path
end
puts

# パッケージ名'rails'で拡張子'rdoc'
documents.select("package:rails suffix:rdoc").each do |record|
  p record.path
end
puts

# 内容に'pluck'を含みファイルパスに'cases'を含むもの
documents.select("content:@pluck restpath:@cases").each do |record|
  p record.path
end
puts

実行結果

2733
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/relation/calculations.rb"
"rails"
"activerecord/lib/active_record/relation/calculations.rb"
"module ActiveRecord\n  module Calculations\n   ..."
2014-12-18 02:25:11 +0900
"rb"

"/Users/ongaeshi/.milkode/packages/git/rails/actionview/lib/action_view/routing_url_for.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/associations/collection_association.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/null_relation.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/querying.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/relation/calculations.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/relation/finder_methods.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/schema_migration.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/lib/active_record/scoping/named.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/associations/has_many_associations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/associations/has_many_through_associations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/base_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/calculations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/relation/merging_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/relation_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/relations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/models/post.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/guides/source/3_2_release_notes.md"
"/Users/ongaeshi/.milkode/packages/git/rails/guides/source/action_mailer_basics.md"
"/Users/ongaeshi/.milkode/packages/git/rails/guides/source/active_record_querying.md"

"/Users/ongaeshi/.milkode/packages/git/rails/guides/source/3_2_release_notes.md"
"/Users/ongaeshi/.milkode/packages/git/rails/guides/source/action_mailer_basics.md"
"/Users/ongaeshi/.milkode/packages/git/rails/guides/source/active_record_querying.md"

"/Users/ongaeshi/.milkode/packages/git/rails/actionmailer/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/actionpack/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/actionview/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/actionview/RUNNING_UNIT_TESTS.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/activemodel/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/RUNNING_UNIT_TESTS.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/activesupport/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/railties/lib/rails/generators/rails/app/templates/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/railties/lib/rails/generators/rails/plugin/templates/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/railties/RDOC_MAIN.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/railties/README.rdoc"
"/Users/ongaeshi/.milkode/packages/git/rails/RELEASING_RAILS.rdoc"

"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/associations/has_many_associations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/associations/has_many_through_associations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/base_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/calculations_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/relation/merging_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/relation_test.rb"
"/Users/ongaeshi/.milkode/packages/git/rails/activerecord/test/cases/relations_test.rb"

応用: ファイルマッチャー

引数に全てマッチするファイルだけを出力するスクリプト。helmやanythingのインターフェースに使えそう。

require 'groonga'

Groonga::Database.open("/Users/ongaeshi/.milkode/db/milkode.db")
documents = Groonga["documents"]

query = ARGV.map { |e| "restpath:@#{e}" }.join(" ")

documents.select(query).each do |record|
  puts record.path
end
$ ruby filematcher.rb slice hash
/Users/ongaeshi/.milkode/packages/git/rails/activesupport/lib/active_support/core_ext/hash/slice.rb

まとめ

ファイル情報にRubyスクリプト経由で高速にアクセス出来るので割と応用範囲は広いのではないかと考えています。面白い使い方を見つけたら是非ブログやQiitaなどに書いてくれると(私が)喜びます。

Honyomiなど他のGroongaデータベースを使っているアプリケーションでも同じことが出来るのではないかと思います。

Milkode 1.8 をリリース - キーボードショートカット、Herokuへのデプロイに対応、ファイル一覧の表示

  • キーボードショートカットに対応
  • Herokuへのデプロイに対応
  • 'f:*'でパッケージ内のファイル一覧の表示

インストール

$ gem install milkode

ダウンロード, Gems

キーボードショートカットに対応

GitHubのようなキーボードショートカットに対応しました。ヘルプ

  • s .. 検索バーに移動
  • S (テキスト選択) .. 選択したテキストを使って新しいタブで検索

テキスト検索して'S'がお気に入りです。 コピー→検索ボックスに移動→ペースト→検索ボタンをクリック の流れが'S'一発で出来ます。関数を深く追う時などに便利です。

Herokuへのデプロイに対応

HerokuにWebアプリがデプロイ出来るようになりました。

ongaeshi/milkode-on-heroku

  1. あらかじめ Heroku Toolbelt を使えるようにしておきます
  2. ソースコードをcloneしてPACKAGESに読みたいソースコードを記述します
  3. Webページの名前を変更したい時はmilkweb.yamlを編集します
  4. git push heroku master でデプロイされます。
  5. ソースコードを追加したい時や設定を変更したい時は書き換えた後に再度herokuにpushして下さい

詳しくは以前に書いた記事をどうぞ。

'f:*'でファイル一覧を表示

'f:*' がパッケージ単位で表示出来るようになりました。 例えば'f:*' in milkode-on-herokuでmilkode-on-herokuのディレクトリをまたいだ全ファイルが一覧出来るようになります。

ソースコード読む時に、最初にファイルを一覧しながら簡単な用途を記述していくのに便利です。

リリースノート

  • milk web
    • Keyboard shortcuts
      • 's' .. Focus search bar
      • 'S' (Select text) .. Search using a selected text with new tab
    • Add help of keyboard shortcut
    • Hide the favorite list if it is empty
    • Support for filtering by package name in 'f:*' search
    • Support :home_font_size attribute in milkweb.yaml

関連記事

30秒でHerokuにソースコード検索をデプロイできる Milkode on Heroku を作りました。

HerokuでRroongaが使えるようになったので、これはMilkodeもHerokuにデプロイ出来るのではないかと思いチャレンジしてみました。

f:id:tuto0621:20140615140636p:plain

インストール

ongaeshi/milkode-on-heroku

用法

気になるソースコードを意味のある固まり(例えばある言語とプラグインや、アプリとその内部で使われているライブラリなど)でまとめておき、検索出来るようにしておくとなかなか便利です。