QuerlyでRubyをgrepする


何がうれしいの?

通常の grep コマンドよりも、Rubyコードに適したきめ細かい検索ができます。

どうやって?

まず、インストールします。

$ gem install querly

次に querly find コマンドを実行します。

app/ ディレクトリ内のRubyファイルに対して、任意の引数を与えた save! メソッド呼び出しを検索します。

$ querly find 'save!(...)' app/
  app/models/tweet.rb:100:6           tweet.save!
  app/models/notification.rb:36:8               notification.save!
  app/models/notification.rb:173:8              notification.save!
  app/models/html_variant.rb:16:4           save!
  app/models/github_issue.rb:32:4           issue.save!
  app/controllers/comments_controller.rb:134:6        @comment.save!
  app/controllers/internal/users_controller.rb:127:6          MentorRelationship.new(mentee_id: mentee.id, mentor_id: @user.id).save!
  app/controllers/internal/users_controller.rb:131:6          MentorRelationship.new(mentee_id: @user.id, mentor_id: mentor.id).save!
  app/controllers/users_controller.rb:82:7          if current_user.save!
  app/controllers/giveaways_controller.rb:50:9        if @user.save!
  app/services/authorization_service.rb:68:6          user.save!
  app/services/authorization_service.rb:100:6         identity.save!
  app/labor/podcast_feed.rb:42:4            ep.save!
13 results

app/ ディレクトリ内のRubyファイルに対して、 self レシーバからの任意の引数を与えた save! メソッド呼び出しを検索します。

$ querly find 'self.save!(...)' app/
  app/models/html_variant.rb:16:4           save!
1 results

name= メソッド呼び出し(代入)を検索します。

$ querly find 'name=(...)' app/
  app/controllers/html_variants_controller.rb:20:6            @html_variant.name = @fork.name + " FORK-#{rand(10000)}"
  app/services/authorization_service.rb:61:8            user.name = auth.info.nickname
  app/services/rss_reader/assembler.rb:72:10              iframe.name = "p"
  app/services/rss_reader/assembler.rb:89:10              bq.name = "p"
  app/services/rss_reader/assembler.rb:99:10              iframe.name = "p"
  app/labor/html_cleaner.rb:18:6              el.name = "p"
6 results

引数に String を指定した name= メソッド呼び出しを検索します。

$ querly find 'name=(:string:)' app/
  app/services/rss_reader/assembler.rb:72:10              iframe.name = "p"
  app/services/rss_reader/assembler.rb:89:10              bq.name = "p"
  app/services/rss_reader/assembler.rb:99:10              iframe.name = "p"
  app/labor/html_cleaner.rb:18:6              el.name = "p"
4 results

Article.where メソッド呼び出しで…、引数のパターンは実際の例をご覧ください。
(コードを見た方が早いかと

$ querly find 'Article.where(published: :bool:, user_id: _)' app/
  app/controllers/pages_controller.rb:78:4          Article.where(user_id: ApplicationConfig["DEVTO_USER_ID"], published: true).
  app/labor/article_analytics_fetcher.rb:7:24       articles_to_check = Article.where(user_id: user_id, published: true)
2 results

*上記は thepracticaldev/dev.to リポジトリに対して実行した結果です。

そもそもQuerlyとは

特有のパターン言語によって、Rubyのメソッド呼び出しパターンを検出するためのツールです。

soutaro/querly: Query Method Calls from Ruby Programs

普通は、 querly.yml というYAMLファイルにプロジェクト固有のパターンをルール化して、自動でチェックする、といった使い方をします。

rules:
  - id: sample.debug_print
    pattern:
      - self.p
      - self.pp
    message: Delete debug print

詳しくは、以下の記事が参考になります。

まとめ

grep コマンドよりは遅いですが、きめ細かい検索ができるのでめちゃくちゃ便利です。

querly find とタイプするのが面倒なので、私は普段 ruby-grep というエイリアスを使っています。

.bashrc
alias ruby-grep='querly find'

Rubyistの皆さん、ぜひ試してみてください!