Skip to content

Commit c9a5749

Browse files
authored
Merge pull request rubocop#1433 from ydakuka/1071-fix-an-error-occurring-in-the-rails-file-path-cop-when-file-join-is-used-with-a-variable
[Fix rubocop#1071] Fix `Rails/FilePath` cop to correctly handle `File.join` with variables and ignore leading and multiple slashes in string literal arguments for `Rails.root.join` and `File.join`
2 parents aceb874 + 65199b8 commit c9a5749

File tree

4 files changed

+202
-8
lines changed

4 files changed

+202
-8
lines changed

.rubocop_todo.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ InternalAffairs/OnSendWithoutOnCSend:
2929
# Offense count: 10
3030
# Configuration parameters: CountComments, CountAsOne.
3131
Metrics/ClassLength:
32-
Max: 179
32+
Max: 163
33+
Exclude:
34+
- 'lib/rubocop/cop/rails/file_path.rb'
3335

3436
# Offense count: 41
3537
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1071](https://github.com/rubocop/rubocop-rails/issues/1071): Fix `Rails/FilePath` cop to correctly handle `File.join` with variables and ignore leading and multiple slashes in string literal arguments for `Rails.root.join` and `File.join`. ([@ydakuka][])

lib/rubocop/cop/rails/file_path.rb

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ module Rails
66
# Identifies usages of file path joining process to use `Rails.root.join` clause.
77
# It is used to add uniformity when joining paths.
88
#
9+
# NOTE: This cop ignores leading slashes in string literal arguments for `Rails.root.join`
10+
# and multiple slashes in string literal arguments for `Rails.root.join` and `File.join`.
11+
#
912
# @example EnforcedStyle: slashes (default)
1013
# # bad
1114
# Rails.root.join('app', 'models', 'goober')
@@ -97,7 +100,7 @@ def check_for_extension_after_rails_root_join_in_dstr(node)
97100

98101
def check_for_file_join_with_rails_root(node)
99102
return unless file_join_nodes?(node)
100-
return unless node.arguments.any? { |e| rails_root_nodes?(e) }
103+
return unless valid_arguments_for_file_join_with_rails_root?(node.arguments)
101104

102105
register_offense(node, require_to_s: true) do |corrector|
103106
autocorrect_file_join(corrector, node) unless node.first_argument.array_type?
@@ -108,8 +111,7 @@ def check_for_rails_root_join_with_string_arguments(node)
108111
return unless style == :slashes
109112
return unless rails_root_nodes?(node)
110113
return unless rails_root_join_nodes?(node)
111-
return unless node.arguments.size > 1
112-
return unless node.arguments.all?(&:str_type?)
114+
return unless valid_string_arguments_for_rails_root_join?(node.arguments)
113115

114116
register_offense(node, require_to_s: false) do |corrector|
115117
autocorrect_rails_root_join_with_string_arguments(corrector, node)
@@ -120,15 +122,42 @@ def check_for_rails_root_join_with_slash_separated_path(node)
120122
return unless style == :arguments
121123
return unless rails_root_nodes?(node)
122124
return unless rails_root_join_nodes?(node)
123-
return unless node.arguments.any? { |arg| string_with_slash?(arg) }
125+
return unless valid_slash_separated_path_for_rails_root_join?(node.arguments)
124126

125127
register_offense(node, require_to_s: false) do |corrector|
126128
autocorrect_rails_root_join_with_slash_separated_path(corrector, node)
127129
end
128130
end
129131

130-
def string_with_slash?(node)
131-
node.str_type? && node.source.include?(File::SEPARATOR)
132+
def valid_arguments_for_file_join_with_rails_root?(arguments)
133+
return false unless arguments.any? { |arg| rails_root_nodes?(arg) }
134+
135+
arguments.none? { |arg| arg.variable? || arg.const_type? || string_contains_multiple_slashes?(arg) }
136+
end
137+
138+
def valid_string_arguments_for_rails_root_join?(arguments)
139+
return false unless arguments.size > 1
140+
return false unless arguments.all?(&:str_type?)
141+
142+
arguments.none? { |arg| string_with_leading_slash?(arg) || string_contains_multiple_slashes?(arg) }
143+
end
144+
145+
def valid_slash_separated_path_for_rails_root_join?(arguments)
146+
return false unless arguments.any? { |arg| string_contains_slash?(arg) }
147+
148+
arguments.none? { |arg| string_with_leading_slash?(arg) || string_contains_multiple_slashes?(arg) }
149+
end
150+
151+
def string_contains_slash?(node)
152+
node.str_type? && node.value.include?(File::SEPARATOR)
153+
end
154+
155+
def string_contains_multiple_slashes?(node)
156+
node.str_type? && node.value.include?('//')
157+
end
158+
159+
def string_with_leading_slash?(node)
160+
node.str_type? && node.value.start_with?(File::SEPARATOR)
132161
end
133162

134163
def register_offense(node, require_to_s:, &block)
@@ -226,7 +255,7 @@ def autocorrect_rails_root_join_with_string_arguments(corrector, node)
226255

227256
def autocorrect_rails_root_join_with_slash_separated_path(corrector, node)
228257
node.arguments.each do |argument|
229-
next unless string_with_slash?(argument)
258+
next unless string_contains_slash?(argument)
230259

231260
index = argument.source.index(File::SEPARATOR)
232261
rest = inner_range_of(argument).adjust(begin_pos: index - 1)

spec/rubocop/cop/rails/file_path_spec.rb

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,128 @@
322322
RUBY
323323
end
324324
end
325+
326+
context 'when using File.join with a local variable' do
327+
it 'does not register an offense' do
328+
expect_no_offenses(<<~RUBY)
329+
default_path = '/models'
330+
File.join(Rails.root, 'app', default_path)
331+
RUBY
332+
end
333+
end
334+
335+
context 'when using File.join with an instance variable' do
336+
it 'does not register an offense' do
337+
expect_no_offenses(<<~RUBY)
338+
File.join(Rails.root, 'app', @default_path)
339+
RUBY
340+
end
341+
end
342+
343+
context 'when using File.join with a class variable' do
344+
it 'does not register an offense' do
345+
expect_no_offenses(<<~RUBY)
346+
File.join(Rails.root, 'app', @@default_path)
347+
RUBY
348+
end
349+
end
350+
351+
context 'when using File.join with a global variable' do
352+
it 'does not register an offense' do
353+
expect_no_offenses(<<~RUBY)
354+
File.join(Rails.root, 'app', $default_path)
355+
RUBY
356+
end
357+
end
358+
359+
context 'when using File.join with a constant' do
360+
it 'does not register an offense' do
361+
expect_no_offenses(<<~RUBY)
362+
File.join(Rails.root, 'app', DEFAULT_PATH)
363+
RUBY
364+
end
365+
end
366+
367+
context 'when using Rails.root.join with a local variable' do
368+
it 'does not register an offense' do
369+
expect_no_offenses(<<~RUBY)
370+
default_path = '/models'
371+
Rails.root.join(Rails.root, 'app', default_path)
372+
RUBY
373+
end
374+
end
375+
376+
context 'when using Rails.root.join with an instance variable' do
377+
it 'does not register an offense' do
378+
expect_no_offenses(<<~RUBY)
379+
Rails.root.join(Rails.root, 'app', @default_path)
380+
RUBY
381+
end
382+
end
383+
384+
context 'when using Rails.root.join with a class variable' do
385+
it 'does not register an offense' do
386+
expect_no_offenses(<<~RUBY)
387+
Rails.root.join(Rails.root, 'app', @@default_path)
388+
RUBY
389+
end
390+
end
391+
392+
context 'when using Rails.root.join with a global variable' do
393+
it 'does not register an offense' do
394+
expect_no_offenses(<<~RUBY)
395+
Rails.root.join(Rails.root, 'app', $default_path)
396+
RUBY
397+
end
398+
end
399+
400+
context 'when using Rails.root.join with a constant' do
401+
it 'does not register an offense' do
402+
expect_no_offenses(<<~RUBY)
403+
Rails.root.join(Rails.root, 'app', DEFAULT_PATH)
404+
RUBY
405+
end
406+
end
407+
408+
context 'when using Rails.root.join with a leading slash' do
409+
it 'does not register an offense' do
410+
expect_no_offenses(<<~RUBY)
411+
Rails.root.join('/app/models')
412+
RUBY
413+
end
414+
end
415+
416+
context 'when using Rails.root.join with mixed leading and normal path strings' do
417+
it 'does not register an offense' do
418+
expect_no_offenses(<<~RUBY)
419+
Rails.root.join('/app', 'models')
420+
RUBY
421+
end
422+
end
423+
424+
context 'when using Rails.root.join with mixed normal and leading path strings' do
425+
it 'does not register an offense' do
426+
expect_no_offenses(<<~RUBY)
427+
Rails.root.join('app', '/models')
428+
RUBY
429+
end
430+
end
431+
432+
context 'when using Rails.root.join with multiple slashes in a path' do
433+
it 'does not register an offense' do
434+
expect_no_offenses(<<~RUBY)
435+
Rails.root.join('public//', 'assets')
436+
RUBY
437+
end
438+
end
439+
440+
context 'when using File.join with multiple slashes in a path' do
441+
it 'does not register an offense' do
442+
expect_no_offenses(<<~RUBY)
443+
File.join(Rails.root, 'public//', 'assets')
444+
RUBY
445+
end
446+
end
325447
end
326448

327449
context 'when EnforcedStyle is `arguments`' do
@@ -592,5 +714,45 @@
592714
RUBY
593715
end
594716
end
717+
718+
context 'when using Rails.root.join with a leading slash' do
719+
it 'does not register an offense' do
720+
expect_no_offenses(<<~RUBY)
721+
Rails.root.join('/app/models')
722+
RUBY
723+
end
724+
end
725+
726+
context 'when using Rails.root.join with mixed leading and normal path strings' do
727+
it 'does not register an offense' do
728+
expect_no_offenses(<<~RUBY)
729+
Rails.root.join('/app', 'models')
730+
RUBY
731+
end
732+
end
733+
734+
context 'when using Rails.root.join with mixed normal and leading path strings' do
735+
it 'does not register an offense' do
736+
expect_no_offenses(<<~RUBY)
737+
Rails.root.join('app', '/models')
738+
RUBY
739+
end
740+
end
741+
742+
context 'when using Rails.root.join with multiple slashes in a path' do
743+
it 'does not register an offense' do
744+
expect_no_offenses(<<~RUBY)
745+
Rails.root.join('public//', 'assets')
746+
RUBY
747+
end
748+
end
749+
750+
context 'when using File.join with multiple slashes in a path' do
751+
it 'does not register an offense' do
752+
expect_no_offenses(<<~RUBY)
753+
File.join(Rails.root, 'public//', 'assets')
754+
RUBY
755+
end
756+
end
595757
end
596758
end

0 commit comments

Comments
 (0)