Class: RailsRoutesAnalyzer::RouteAnalysis
- Inherits:
-
Object
- Object
- RailsRoutesAnalyzer::RouteAnalysis
- Defined in:
- lib/rails_routes_analyzer/route_analysis.rb
Instance Attribute Summary collapse
-
#app ⇒ Object
Returns the value of attribute app.
-
#only_except ⇒ Object
Returns the value of attribute only_except.
-
#only_only ⇒ Object
Returns the value of attribute only_only.
-
#route_calls ⇒ Object
Returns the value of attribute route_calls.
-
#route_lines ⇒ Object
Returns the value of attribute route_lines.
-
#route_log ⇒ Object
Returns the value of attribute route_log.
-
#verbose ⇒ Object
Returns the value of attribute verbose.
Instance Method Summary collapse
- #all_unique_issues_file_names ⇒ Object
- #analyse_route_call(**kwargs) ⇒ Object
- #analyze! ⇒ Object
-
#analyze_action_availability(controller, route_call, **opts) ⇒ Object
Checks which if any actions referred to by the route don’t exist.
- #clear_data ⇒ Object
- #generate_route_lines ⇒ Object
- #implemented_routes ⇒ Object
-
#initialize(app: Rails.application, verbose: false, only_only: false, only_except: false) ⇒ RouteAnalysis
constructor
A new instance of RouteAnalysis.
- #issues ⇒ Object
- #non_issues ⇒ Object
- #prepare_for_analysis ⇒ Object
- #print_report ⇒ Object
- #resource_route_suggested_param(present) ⇒ Object
- #route_calls_for_file_name(full_filename) ⇒ Object
- #route_lines_for_file(full_filename) ⇒ Object
Constructor Details
#initialize(app: Rails.application, verbose: false, only_only: false, only_except: false) ⇒ RouteAnalysis
Returns a new instance of RouteAnalysis.
14 15 16 17 18 19 20 21 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 14 def initialize(app: Rails.application, verbose: false, only_only: false, only_except: false) self.app = app self.verbose = verbose self.only_only = only_only self.only_except = only_except analyze! end |
Instance Attribute Details
#app ⇒ Object
Returns the value of attribute app.
11 12 13 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 11 def app @app end |
#only_except ⇒ Object
Returns the value of attribute only_except.
11 12 13 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 11 def only_except @only_except end |
#only_only ⇒ Object
Returns the value of attribute only_only.
11 12 13 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 11 def only_only @only_only end |
#route_calls ⇒ Object
Returns the value of attribute route_calls.
12 13 14 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 12 def route_calls @route_calls end |
#route_lines ⇒ Object
Returns the value of attribute route_lines.
12 13 14 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 12 def route_lines @route_lines end |
#route_log ⇒ Object
Returns the value of attribute route_log.
12 13 14 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 12 def route_log @route_log end |
#verbose ⇒ Object
Returns the value of attribute verbose.
11 12 13 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 11 def verbose @verbose end |
Instance Method Details
#all_unique_issues_file_names ⇒ Object
134 135 136 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 134 def all_unique_issues_file_names issues.map(&:full_filename).uniq.sort end |
#analyse_route_call(**kwargs) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 68 def analyse_route_call(**kwargs) controller_class_name = "#{kwargs[:controller_name]}_controller".camelize opts = kwargs.merge(controller_class_name: controller_class_name) route_call = RouteCall.new(opts) route_calls << route_call controller = nil begin controller = Object.const_get(controller_class_name) rescue LoadError, RuntimeError, NameError => e route_call.add_issue RouteIssue::NoController.new(error: e.) return end if controller.nil? route_call.add_issue RouteIssue::NoController.new(error: "#{controller_class_name} is nil") return end analyze_action_availability(controller, route_call, **opts) end |
#analyze! ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 39 def analyze! clear_data prepare_for_analysis RouteInterceptor.route_data.each do |(file_location, route_creation_method, controller_name), action_names| analyse_route_call( file_location: file_location, route_creation_method: route_creation_method, controller_name: controller_name, action_names: action_names.uniq.sort, ) end route_log.concat RouteInterceptor.route_log generate_route_lines end |
#analyze_action_availability(controller, route_call, **opts) ⇒ Object
Checks which if any actions referred to by the route don’t exist.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 93 def analyze_action_availability(controller, route_call, **opts) present, missing = opts[:action_names].partition { |name| controller.action_methods.include?(name.to_s) } route_call[:present_actions] = present if present.any? if SINGLE_METHODS.include?(opts[:route_creation_method]) # NOTE a single call like 'get' can add multiple actions if called in a loop if missing.present? route_call.add_issue RouteIssue::NoAction.new(missing_actions: missing) end return end return if missing.empty? # Everything is perfect, all routes match an action if present.sort == RESOURCE_ACTIONS.sort # Should happen only if RESOURCE_ACTIONS doesn't match which actions rails supports raise "shouldn't get all methods being present and yet some missing at the same time: #{present.inspect} #{missing.inspect}" end suggested_param = resource_route_suggested_param(present) route_call.add_issue RouteIssue::Resources.new(suggested_param: suggested_param) end |
#clear_data ⇒ Object
23 24 25 26 27 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 23 def clear_data self.route_lines = [] self.route_calls = [] self.route_log = [] end |
#generate_route_lines ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 56 def generate_route_lines calls_per_line = route_calls.group_by do |record| [record.full_filename, record.line_number] end calls_per_line.each do |(full_filename, line_number), records| route_lines << RouteLine.new(full_filename: full_filename, line_number: line_number, records: records) end end |
#implemented_routes ⇒ Object
142 143 144 145 146 147 148 149 150 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 142 def implemented_routes Set.new.tap do |implemented_routes| route_calls.each do |route_call| (route_call.present_actions || []).each do |action| implemented_routes << [route_call.controller_class_name, action] end end end end |
#issues ⇒ Object
126 127 128 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 126 def issues route_calls.select(&:issue?) end |
#non_issues ⇒ Object
130 131 132 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 130 def non_issues route_calls.reject(&:issue?) end |
#prepare_for_analysis ⇒ Object
29 30 31 32 33 34 35 36 37 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 29 def prepare_for_analysis app.eager_load! # all controller classes need to be loaded ::ActionDispatch::Routing::Mapper::Mapping.prepend RouteInterceptor RouteInterceptor.route_log.clear app.reload_routes! end |
#print_report ⇒ Object
156 157 158 159 160 161 162 163 164 165 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 156 def print_report if issues.empty? puts "No route issues found" return end issues.each do |issue| puts issue.human_readable_error(verbose: verbose) end end |
#resource_route_suggested_param(present) ⇒ Object
118 119 120 121 122 123 124 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 118 def resource_route_suggested_param(present) if (present.size < 4 || only_only) && !only_except "only: [#{present.sort.map { |x| ":#{x}" }.join(', ')}]" else "except: [#{(RESOURCE_ACTIONS - present).sort.map { |x| ":#{x}" }.join(', ')}]" end end |
#route_calls_for_file_name(full_filename) ⇒ Object
138 139 140 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 138 def route_calls_for_file_name(full_filename) route_calls.select { |record| record.full_filename == full_filename.to_s } end |
#route_lines_for_file(full_filename) ⇒ Object
152 153 154 |
# File 'lib/rails_routes_analyzer/route_analysis.rb', line 152 def route_lines_for_file(full_filename) route_lines.select { |line| line.full_filename == full_filename.to_s } end |