LoginSignup
8
8

More than 5 years have passed since last update.

rake routes の出力をハックする

Last updated at Posted at 2015-08-05

この文書では、人に見やすい形に成形されて表示される(その代わりプログラムで処理しづらい) rake routes の出力結果を csv とかに変える方法について記します。

主に著者の環境である rails 3.2.22 を対象にしていきたいと思います。

Rails 3.2.22

さて、routes タスクそのものは railties-3.2.22/lib/rails/tasks/routes.rake で定義されています(ので抜粋しておきます)。

desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
task :routes => :environment do
  Rails.application.reload_routes!
  all_routes = Rails.application.routes.routes

  require 'rails/application/route_inspector'
  inspector = Rails::Application::RouteInspector.new
  puts inspector.format(all_routes, ENV['CONTROLLER']).join "\n"
end

タスクの前半2行をコピペして独自タスクを作るのが鮮やかそうではあります。
しかし、 all_routes の中身は Journey::Routes のインスタンスとなっており、よくわかりません。
(https://github.com/rails/rails/blob/v3.2.22/actionpack/actionpack.gemspec#L28 を見るとわかるけど、また別の依存 gem )

Journey を無視して Rails::Application::RouteInspector を読むと #format_routes という、とてもわかりやすいメソッドを見つけられるはずです。


module Rails
  class Application
    class RouteInspector # :nodoc:
      def formatted_routes(routes)
        name_width = routes.map{ |r| r[:name].length }.max
        verb_width = routes.map{ |r| r[:verb].length }.max
        path_width = routes.map{ |r| r[:path].length }.max

        routes.map do |r|
          "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
        end
      end
    end
  end
end

あとはこれにパッチを当てるだけですが、 rake routes は Rake タスクなので、 lib ディレクトリのロードがどうも怪しかったりします・・・ので、 lib/task/patch.rake とかにこんなパッチを書けば良いでしょう。


module RouteFormatCSVPatch
  def formatted_routes(routes)
    routes.map do |r|
      "#{r[:name]},#{r[:verb]},#{r[:path]},#{r[:reqs]}"
    end
  end
end

require 'rails/application/route_inspector'
Rails::Application::RouteInspector.send(:prepend, RouteFormatCSVPatch)

外部エンジンなどを使って route が足された場合などには正しい CSV にならない(外部エンジン表記が途中行に入る)ですが、まぁ、前よりかはましでしょう。
(完璧を目指すなら#formatted_routes_for_engines にもパッチを当てること)

Rails 4.x

4系では、より拡張がしやすくなっています。
同じくタスクが定義されている railties-4.2.3/lib/rails/tasks/routes.rake からソースを抜粋しましょう。


desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
task routes: :environment do
  all_routes = Rails.application.routes.routes
  require 'action_dispatch/routing/inspector'
  inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
  puts inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, ENV['CONTROLLER'])
end

フォーマッターが別クラスで用意されているので、パッチを当てるより、独自フォーマッターを定義してやる手法の方が良さそうです。

例えば、こんな感じのタスクを lib/task/route.rake とかに書くと良いでしょう。


namespace :routes do

  class CSVFormatter
    def initialize
      @csv = []
      @current_section = "Application"
    end

    def result
      @buffer.join("\n")
    end

    def section_title(title)
      @current_section = title
    end

    def section(routes)
      routes.each do |r|
        @buffer << "#{r[:name]},#{r[:verb]},#{r[:path]},#{r[:reqs]}"
      end
    end

    def header(routes)
      @buffer << "Prefix, Verb, URI Pattern, Controller#Action"
    end

    def no_routes
      @buffer << ""
    end
  end

  desc 'Print out all defined routes on CSV'
  task csv: :environment do
    all_routes = Rails.application.routes.routes
    require 'action_dispatch/routing/inspector'
    inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
    puts inspector.format(CSVFormatter.new, ENV['CONTROLLER'])
  end
end
8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8