rails-route-checker 0.2.2 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c2ee3366805e8dbc68755df5f5ce5e1342f5be11
4
- data.tar.gz: 9ce06f8c42d7f2940ee45ab82ad491afce95f2fa
2
+ SHA256:
3
+ metadata.gz: f97ee66f59a03025db7fab6e63fa8b0ff74f9b058b5f57fd87d3da88bed310e3
4
+ data.tar.gz: 0c5ecf132b1a53cf812fe4af8404658b097e2058859afeb6114531321e42d9f8
5
5
  SHA512:
6
- metadata.gz: da784f02dd0cb29e448fb698e89196709a2b7be7b080b4d7e9c8770bf11bc66ec158907da3f51e9ff81fc3ebdf355dad4d047aebdb80675b4953038a0355ee3f
7
- data.tar.gz: 87d43f4feca31e8f58820570439fddbe97be9499ea5828a8111b9439e9e75df068c2d0bf5ae085c91b43dc1d3a452e548b996daeefd7b314489e5710233b311d
6
+ metadata.gz: 14840d1099677ef965aaf077c33b043527ea6a95d1591c53683b38782ba275d460ae5701b4f284dd34513cafde6a5cda6a94476477f5f7ebbd7604df641a2420
7
+ data.tar.gz: 01361ddc934b7e73351dc3294bc5e584339b6125ecadc6d1807ccbac25acc632ee14f1da9a94df7044e85e7fd2eb7286d9ffda11ebb32ba840eaf9116e6b8d1a
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
  gemspec
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'rails-route-checker'
4
5
  require 'optparse'
@@ -24,6 +25,6 @@ end.parse!
24
25
 
25
26
  options[:config_file] = '.rails-route-checker.yml' if File.exist?('.rails-route-checker.yml') && !options[:config_file]
26
27
 
27
- rrc = RailsRouteChecker::Runner.new(options)
28
+ rrc = RailsRouteChecker::Runner.new(**options)
28
29
  puts rrc.output
29
30
  exit rrc.issues? ? 1 : 0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'rails-route-checker/app_interface'
2
4
  require_relative 'rails-route-checker/config_file'
3
5
  require_relative 'rails-route-checker/loaded_app'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  class AppInterface
3
5
  def initialize(**opts)
@@ -10,7 +12,7 @@ module RailsRouteChecker
10
12
  action = r.requirements[:action]
11
13
 
12
14
  next if options[:ignored_controllers].include?(controller)
13
- next if controller_information.key?(controller) && controller_information[controller][:actions].include?(action)
15
+ next if controller_has_action?(controller, action)
14
16
 
15
17
  {
16
18
  controller: controller,
@@ -37,6 +39,16 @@ module RailsRouteChecker
37
39
  end
38
40
  end
39
41
 
42
+ def controller_has_action?(controller, action)
43
+ return false unless controller_information.key?(controller)
44
+
45
+ info = controller_information[controller]
46
+ return true if info[:actions].include?(action)
47
+ return true if info[:lookup_context]&.template_exists?("#{controller}/#{action}")
48
+
49
+ false
50
+ end
51
+
40
52
  def generate_undef_view_path_calls
41
53
  generate_undef_view_path_calls_erb + generate_undef_view_path_calls_haml
42
54
  end
@@ -54,6 +66,7 @@ module RailsRouteChecker
54
66
  filter = lambda do |path_or_url|
55
67
  return false if match_in_whitelist?(filename, path_or_url)
56
68
  return false if match_defined_in_view?(controller, path_or_url)
69
+
57
70
  true
58
71
  end
59
72
 
@@ -80,6 +93,7 @@ module RailsRouteChecker
80
93
  filter = lambda do |path_or_url|
81
94
  return false if match_in_whitelist?(filename, path_or_url)
82
95
  return false if match_defined_in_view?(controller, path_or_url)
96
+
83
97
  true
84
98
  end
85
99
 
@@ -100,6 +114,7 @@ module RailsRouteChecker
100
114
  filter = lambda do |path_or_url|
101
115
  return false if match_in_whitelist?(filename, path_or_url)
102
116
  return false if match_defined_in_ruby?(controller, path_or_url)
117
+
103
118
  return true
104
119
  end
105
120
 
@@ -110,18 +125,21 @@ module RailsRouteChecker
110
125
  def match_in_whitelist?(filename, path_or_url)
111
126
  possible_route_name = path_or_url.sub(/_(?:url|path)$/, '')
112
127
  return true if options[:ignored_paths].include?(possible_route_name)
128
+
113
129
  (options[:ignored_path_whitelist][filename] || []).include?(path_or_url)
114
130
  end
115
131
 
116
132
  def match_defined_in_view?(controller, path_or_url)
117
133
  possible_route_name = path_or_url.sub(/_(?:url|path)$/, '')
118
134
  return true if loaded_app.all_route_names.include?(possible_route_name)
135
+
119
136
  controller && controller[:helpers].include?(path_or_url)
120
137
  end
121
138
 
122
139
  def match_defined_in_ruby?(controller, path_or_url)
123
140
  possible_route_name = path_or_url.sub(/_(?:url|path)$/, '')
124
141
  return true if loaded_app.all_route_names.include?(possible_route_name)
142
+
125
143
  controller && controller[:instance_methods].include?(path_or_url)
126
144
  end
127
145
 
@@ -132,6 +150,7 @@ module RailsRouteChecker
132
150
  while possible_controller_path.any?
133
151
  controller_name = possible_controller_path.join('/')
134
152
  return controller_information[controller_name] if controller_exists?(controller_name)
153
+
135
154
  possible_controller_path = possible_controller_path[0..-2]
136
155
  end
137
156
  controller_information['application']
@@ -140,12 +159,14 @@ module RailsRouteChecker
140
159
  def controller_from_ruby_file(filename)
141
160
  controller_name = (filename.match(%r{app/controllers/(.*)_controller.rb}) || [])[1]
142
161
  return controller_information[controller_name] if controller_exists?(controller_name)
162
+
143
163
  controller_information['application']
144
164
  end
145
165
 
146
166
  def controller_exists?(controller_name)
147
167
  return false unless controller_name
148
- File.exists?("app/controllers/#{controller_name}_controller.rb")
168
+
169
+ File.exist?("app/controllers/#{controller_name}_controller.rb")
149
170
  end
150
171
  end
151
172
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  class ConfigFile
3
5
  def initialize(filename)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  class LoadedApp
3
5
  def initialize
@@ -40,14 +42,13 @@ module RailsRouteChecker
40
42
  @controller_information ||= ActionController::Base.descendants.map do |controller|
41
43
  next if controller.controller_path.start_with?('rails/')
42
44
 
43
- instance_methods = (controller.instance_methods.map(&:to_s) + controller.private_instance_methods.map(&:to_s))
44
-
45
45
  [
46
46
  controller.controller_path,
47
47
  {
48
48
  helpers: controller.helpers.methods.map(&:to_s),
49
49
  actions: controller.action_methods.to_a,
50
- instance_methods: instance_methods.compact.uniq
50
+ instance_methods: instance_methods(controller),
51
+ lookup_context: lookup_context(controller)
51
52
  }
52
53
  ]
53
54
  end.compact.to_h
@@ -57,6 +58,16 @@ module RailsRouteChecker
57
58
 
58
59
  attr_reader :app
59
60
 
61
+ def lookup_context(controller)
62
+ return nil unless controller.instance_methods.include?(:default_render)
63
+
64
+ ActionView::LookupContext.new(controller._view_paths, {}, controller._prefixes)
65
+ end
66
+
67
+ def instance_methods(controller)
68
+ (controller.instance_methods.map(&:to_s) + controller.private_instance_methods.map(&:to_s)).compact.uniq
69
+ end
70
+
60
71
  def suppress_output
61
72
  begin
62
73
  original_stderr = $stderr.clone
@@ -76,7 +87,7 @@ module RailsRouteChecker
76
87
  end
77
88
 
78
89
  def attempt_to_load_default_controllers
79
- # rubocop:disable Lint/HandleExceptions
90
+ # rubocop:disable Lint/SuppressedException
80
91
  begin
81
92
  ::Rails::InfoController
82
93
  rescue NameError # ignored
@@ -89,7 +100,7 @@ module RailsRouteChecker
89
100
  ::Rails::MailersController
90
101
  rescue NameError # ignored
91
102
  end
92
- # rubocop:enable Lint/HandleExceptions
103
+ # rubocop:enable Lint/SuppressedException
93
104
  end
94
105
 
95
106
  def reject_route?(route)
@@ -102,6 +113,7 @@ module RailsRouteChecker
102
113
  action = route.requirements[:action]
103
114
  return true unless controller && action
104
115
  return true if controller.start_with?('rails/')
116
+
105
117
  false
106
118
  end
107
119
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module ErbParser
@@ -5,23 +7,7 @@ module RailsRouteChecker
5
7
  def run(filename, **opts)
6
8
  file_source = opts[:source] || File.read(filename)
7
9
 
8
- next_ruby_source_line_num = 1
9
- ruby_source = ''
10
- source_map = {}
11
-
12
- file_source.split("\n").each_with_index do |line, line_num|
13
- ruby_lines = process_line(line)
14
- next unless ruby_lines.any?
15
-
16
- ruby_source += ruby_lines.join("\n") + "\n"
17
- ruby_lines.length.times do |i|
18
- source_map[next_ruby_source_line_num + i] = line_num + 1
19
- end
20
- next_ruby_source_line_num += ruby_lines.length
21
- end
22
-
23
- opts[:source] = ruby_source
24
- opts[:source_map] = source_map
10
+ opts.merge!(process_file(file_source))
25
11
 
26
12
  RailsRouteChecker::Parsers::RubyParser.run(filename, **opts)
27
13
  end
@@ -46,6 +32,28 @@ module RailsRouteChecker
46
32
  end
47
33
  ruby_lines
48
34
  end
35
+
36
+ def process_file(source)
37
+ next_ruby_source_line_num = 1
38
+ ruby_source = ''
39
+ source_map = {}
40
+
41
+ source.split("\n").each_with_index do |line, line_num|
42
+ ruby_lines = process_line(line)
43
+ next unless ruby_lines.any?
44
+
45
+ ruby_source += ruby_lines.join("\n") + "\n"
46
+ ruby_lines.length.times do |i|
47
+ source_map[next_ruby_source_line_num + i] = line_num + 1
48
+ end
49
+ next_ruby_source_line_num += ruby_lines.length
50
+ end
51
+
52
+ {
53
+ source: ruby_source,
54
+ source_map: source_map
55
+ }
56
+ end
49
57
  end
50
58
  end
51
59
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'haml_parser/document'
2
4
  require_relative 'haml_parser/tree/node'
3
5
  require_relative 'haml_parser/tree/filter_node'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -9,9 +11,10 @@ module RailsRouteChecker
9
11
  @source_lines = @source.split(/\r\n|\r|\n/)
10
12
 
11
13
  version = Gem::Version.new(Haml::VERSION).approximate_recommendation
14
+ options = Haml::Options.new
12
15
  original_tree = case version
13
- when '~> 4.0', '~> 4.1' then Haml::Parser.new(@source, Haml::Options.new).parse
14
- when '~> 5.0' then Haml::Parser.new(options).call(@source)
16
+ when '~> 4.0', '~> 4.1' then Haml::Parser.new(@source, options).parse
17
+ when '~> 5.0', '~> 5.1', '~> 5.2' then Haml::Parser.new(options).call(@source)
15
18
  else raise "Cannot handle Haml version: #{version}"
16
19
  end
17
20
 
@@ -21,9 +24,7 @@ module RailsRouteChecker
21
24
  private
22
25
 
23
26
  def process_tree(original_tree)
24
- if Gem::Requirement.new('~> 4.0.0').satisfied_by?(Gem.loaded_specs['haml'].version)
25
- original_tree.children.pop
26
- end
27
+ original_tree.children.pop if Gem::Requirement.new('~> 4.0.0').satisfied_by?(Gem.loaded_specs['haml'].version)
27
28
 
28
29
  convert_tree(original_tree)
29
30
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -53,6 +55,7 @@ module RailsRouteChecker
53
55
  yield
54
56
 
55
57
  return unless start_block
58
+
56
59
  @indent_level -= 1
57
60
  add_line('end', node)
58
61
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -68,7 +70,7 @@ module RailsRouteChecker
68
70
  next_sibling = siblings.next(self)
69
71
  return next_sibling if next_sibling
70
72
 
71
- parent.successor if parent
73
+ parent&.successor
72
74
  end
73
75
 
74
76
  def next_node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module HamlParser
@@ -18,7 +20,7 @@ module RailsRouteChecker
18
20
  end
19
21
 
20
22
  def attributes_source
21
- @attr_source ||=
23
+ @attr_source ||= # rubocop:disable Naming/MemoizedInstanceVariableName
22
24
  begin
23
25
  _explicit_tag, static_attrs, rest =
24
26
  source_code.scan(/\A\s*(%[-:\w]+)?([-:\w\.\#]*)(.*)/m)[0]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  module Parsers
3
5
  module Loader
@@ -21,6 +23,7 @@ module RailsRouteChecker
21
23
 
22
24
  def haml_available?
23
25
  return @haml_available if defined?(@haml_available)
26
+
24
27
  @haml_available = gem_installed?('haml')
25
28
  end
26
29
 
@@ -46,6 +49,7 @@ module RailsRouteChecker
46
49
  def if_unloaded(parser)
47
50
  @loaded_parsers ||= {}
48
51
  return false if @loaded_parsers[parser]
52
+
49
53
  yield
50
54
  @loaded_parsers[parser] = true
51
55
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ripper'
2
4
 
3
5
  module RailsRouteChecker
@@ -6,15 +8,16 @@ module RailsRouteChecker
6
8
  class << self
7
9
  def run(filename, **opts)
8
10
  file_source = opts[:source] || File.read(filename)
11
+ process_file(filename, file_source, opts)
12
+ end
9
13
 
10
- items = []
14
+ private
11
15
 
12
- deep_iterator(Ripper.sexp(file_source)) do |item, extra_data|
13
- scope = extra_data[:scope]
14
- next unless %i[vcall fcall].include?(scope[-2])
15
- next unless scope[-1] == :@ident
16
- next unless item.end_with?('_path', '_url')
16
+ def process_file(filename, source, opts)
17
+ items = []
17
18
 
19
+ deep_iterator(Ripper.sexp(source)) do |item, extra_data|
20
+ next unless item_is_url_call?(item, extra_data)
18
21
  next if opts[:filter].respond_to?(:call) && !opts[:filter].call(item)
19
22
 
20
23
  line = extra_data[:position][0]
@@ -26,30 +29,43 @@ module RailsRouteChecker
26
29
  items
27
30
  end
28
31
 
29
- private
32
+ def item_is_url_call?(item, extra_data)
33
+ scope = extra_data[:scope]
34
+ return false unless %i[vcall fcall].include?(scope[-2])
35
+ return false unless scope[-1] == :@ident
36
+ return false unless item.end_with?('_path', '_url')
37
+
38
+ true
39
+ end
30
40
 
31
41
  def deep_iterator(list, current_scope = [], current_line_num = [], &block)
32
- if list.is_a?(Array)
33
- if list[0].is_a?(Symbol)
34
- current_scope << list[0]
35
-
36
- if list[-1].is_a?(Array) && list[-1].length == 2 && list[-1].all? { |item| item.is_a?(Integer) }
37
- current_line_num = list[-1]
38
- list = list[0..-2]
39
- end
40
-
41
- list[1..-1].each do |item|
42
- deep_iterator(item, current_scope, current_line_num, &block)
43
- end
44
- current_scope.pop
45
- else
46
- list.each do |item|
47
- deep_iterator(item, current_scope, current_line_num, &block)
48
- end
42
+ return deep_iterate_array(list, current_scope, current_line_num, &block) if list.is_a?(Array)
43
+
44
+ yield(list, { scope: current_scope, position: current_line_num }) unless list.nil?
45
+ end
46
+
47
+ def deep_iterate_array(list, current_scope, current_line_num, &block)
48
+ unless list[0].is_a?(Symbol)
49
+ list.each do |item|
50
+ deep_iterator(item, current_scope, current_line_num, &block)
49
51
  end
50
- elsif !list.nil?
51
- yield(list, { scope: current_scope, position: current_line_num })
52
+ return
53
+ end
54
+
55
+ current_scope << list[0]
56
+
57
+ last_list_item = list[-1]
58
+ if last_list_item.is_a?(Array) &&
59
+ last_list_item.length == 2 &&
60
+ last_list_item.all? { |item| item.is_a?(Integer) }
61
+ current_line_num = last_list_item
62
+ list = list[0..-2]
63
+ end
64
+
65
+ list[1..-1].each do |item|
66
+ deep_iterator(item, current_scope, current_line_num, &block)
52
67
  end
68
+ current_scope.pop
53
69
  end
54
70
  end
55
71
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
4
  class Runner
3
5
  def initialize(**opts)
@@ -14,7 +16,7 @@ module RailsRouteChecker
14
16
  end
15
17
 
16
18
  def issues?
17
- issues.values.flatten(1).count > 1
19
+ issues.values.flatten(1).count.positive?
18
20
  end
19
21
 
20
22
  def output
@@ -31,7 +33,7 @@ module RailsRouteChecker
31
33
  private
32
34
 
33
35
  def app_interface
34
- @app_interface ||= RailsRouteChecker::AppInterface.new(@options)
36
+ @app_interface ||= RailsRouteChecker::AppInterface.new(**@options)
35
37
  end
36
38
 
37
39
  def missing_actions_output
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsRouteChecker
2
- VERSION = '0.2.2'.freeze
4
+ VERSION = '0.2.7'
3
5
  end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
 
2
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'rails-route-checker/version'
5
6
 
@@ -22,7 +23,7 @@ Gem::Specification.new do |spec|
22
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
24
  spec.require_paths = ['lib']
24
25
 
25
- spec.add_development_dependency 'bundler', '~> 1.15'
26
- spec.add_development_dependency 'rake', '~> 10.0'
27
- spec.add_development_dependency 'rubocop', '~> 0.51'
26
+ spec.add_development_dependency 'bundler', '~> 2.1'
27
+ spec.add_development_dependency 'rake', '~> 13.0'
28
+ spec.add_development_dependency 'rubocop', '~> 0.86'
28
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-route-checker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Allie
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-12 00:00:00.000000000 Z
11
+ date: 2020-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.15'
19
+ version: '2.1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.15'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rubocop
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.51'
47
+ version: '0.86'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0.51'
54
+ version: '0.86'
55
55
  description: A linting tool that helps you find any routes defined in your routes.rb
56
56
  file that don't have a corresponding controller action, and find any _path or _url
57
57
  calls that don't have a corresponding route in the routes.rb file.
@@ -102,8 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  requirements: []
105
- rubyforge_project:
106
- rubygems_version: 2.6.12
105
+ rubygems_version: 3.1.2
107
106
  signing_key:
108
107
  specification_version: 4
109
108
  summary: A linting tool for your Rails routes