rubocop-sketchup 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +20 -19
  3. data/assets/output.html.erb +301 -301
  4. data/config/default.yml +379 -355
  5. data/lib/rubocop-sketchup.rb +49 -48
  6. data/lib/rubocop/sketchup.rb +12 -12
  7. data/lib/rubocop/sketchup/config.rb +63 -63
  8. data/lib/rubocop/sketchup/cop.rb +111 -111
  9. data/lib/rubocop/sketchup/cop/bugs/material_name.rb +108 -0
  10. data/lib/rubocop/sketchup/cop/bugs/render_mode.rb +72 -0
  11. data/lib/rubocop/sketchup/cop/bugs/uniform_scaling.rb +36 -0
  12. data/lib/rubocop/sketchup/cop/deprecations/add_separator_to_menu.rb +25 -25
  13. data/lib/rubocop/sketchup/cop/deprecations/operation_next_transparent.rb +30 -30
  14. data/lib/rubocop/sketchup/cop/deprecations/require_all.rb +27 -27
  15. data/lib/rubocop/sketchup/cop/deprecations/set_texture_projection.rb +26 -26
  16. data/lib/rubocop/sketchup/cop/deprecations/show_ruby_panel.rb +25 -25
  17. data/lib/rubocop/sketchup/cop/deprecations/sketchup_set.rb +30 -30
  18. data/lib/rubocop/sketchup/cop/performance/openssl.rb +41 -41
  19. data/lib/rubocop/sketchup/cop/performance/operation_disable_ui.rb +33 -33
  20. data/lib/rubocop/sketchup/cop/performance/selection_bulk.rb +79 -79
  21. data/lib/rubocop/sketchup/cop/performance/type_check.rb +63 -63
  22. data/lib/rubocop/sketchup/cop/performance/typename.rb +24 -24
  23. data/lib/rubocop/sketchup/cop/requirements/api_namespace.rb +30 -30
  24. data/lib/rubocop/sketchup/cop/requirements/exit.rb +32 -32
  25. data/lib/rubocop/sketchup/cop/requirements/extension_namespace.rb +108 -108
  26. data/lib/rubocop/sketchup/cop/requirements/file_structure.rb +97 -97
  27. data/lib/rubocop/sketchup/cop/requirements/gem_install.rb +45 -45
  28. data/lib/rubocop/sketchup/cop/requirements/get_extension_license.rb +95 -95
  29. data/lib/rubocop/sketchup/cop/requirements/global_constants.rb +38 -38
  30. data/lib/rubocop/sketchup/cop/requirements/global_include.rb +42 -42
  31. data/lib/rubocop/sketchup/cop/requirements/global_methods.rb +65 -65
  32. data/lib/rubocop/sketchup/cop/requirements/global_variables.rb +95 -95
  33. data/lib/rubocop/sketchup/cop/requirements/language_handler_globals.rb +46 -46
  34. data/lib/rubocop/sketchup/cop/requirements/load_path.rb +83 -83
  35. data/lib/rubocop/sketchup/cop/requirements/minimal_registration.rb +73 -73
  36. data/lib/rubocop/sketchup/cop/requirements/observers_start_operation.rb +161 -161
  37. data/lib/rubocop/sketchup/cop/requirements/register_extension.rb +45 -45
  38. data/lib/rubocop/sketchup/cop/requirements/ruby_core_namespace.rb +291 -291
  39. data/lib/rubocop/sketchup/cop/requirements/ruby_stdlib_namespace.rb +634 -634
  40. data/lib/rubocop/sketchup/cop/requirements/shipped_extensions_namespace.rb +61 -61
  41. data/lib/rubocop/sketchup/cop/requirements/sketchup_extension.rb +119 -119
  42. data/lib/rubocop/sketchup/cop/requirements/sketchup_require.rb +163 -163
  43. data/lib/rubocop/sketchup/cop/suggestions/add_group.rb +49 -49
  44. data/lib/rubocop/sketchup/cop/suggestions/compatibility.rb +121 -117
  45. data/lib/rubocop/sketchup/cop/suggestions/dc_internals.rb +34 -34
  46. data/lib/rubocop/sketchup/cop/suggestions/file_encoding.rb +78 -78
  47. data/lib/rubocop/sketchup/cop/suggestions/model_entities.rb +58 -58
  48. data/lib/rubocop/sketchup/cop/suggestions/monkey_patched_api.rb +45 -45
  49. data/lib/rubocop/sketchup/cop/suggestions/operation_name.rb +137 -103
  50. data/lib/rubocop/sketchup/cop/suggestions/sketchup_find_support_file.rb +39 -39
  51. data/lib/rubocop/sketchup/cop/suggestions/tool_drawing_bounds.rb +44 -44
  52. data/lib/rubocop/sketchup/cop/suggestions/tool_invalidate.rb +66 -66
  53. data/lib/rubocop/sketchup/cop/suggestions/tool_user_input.rb +41 -41
  54. data/lib/rubocop/sketchup/cop/suggestions/toolbar_timer.rb +65 -65
  55. data/lib/rubocop/sketchup/dc_globals.rb +24 -24
  56. data/lib/rubocop/sketchup/dc_methods.rb +130 -130
  57. data/lib/rubocop/sketchup/extension_project.rb +65 -65
  58. data/lib/rubocop/sketchup/features.rb +738 -738
  59. data/lib/rubocop/sketchup/formatter/extension_review.rb +269 -259
  60. data/lib/rubocop/sketchup/inject.rb +19 -19
  61. data/lib/rubocop/sketchup/namespace.rb +47 -47
  62. data/lib/rubocop/sketchup/namespace_checker.rb +46 -46
  63. data/lib/rubocop/sketchup/no_comment_disable.rb +17 -17
  64. data/lib/rubocop/sketchup/range_help.rb +52 -52
  65. data/lib/rubocop/sketchup/sketchup_target_range.rb +75 -0
  66. data/lib/rubocop/sketchup/sketchup_version.rb +117 -87
  67. data/lib/rubocop/sketchup/tool_checker.rb +43 -43
  68. data/lib/rubocop/sketchup/version.rb +5 -5
  69. data/rubocop-sketchup.gemspec +27 -27
  70. metadata +8 -4
@@ -1,24 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module SketchupPerformance
6
- # `.typename` is very slow, prefer `.is_a?` instead.
7
- #
8
- # `entity.typename == 'Face'` is slow because it performs a string
9
- # comparison. `is_a?` is much faster because it's a simple type check.
10
- class Typename < SketchUp::Cop
11
- MSG = '`.typename` is very slow, prefer `.is_a?` instead.'.freeze
12
-
13
- def on_send(node)
14
- _, method_name = *node
15
- return unless method_name == :typename
16
-
17
- # TODO(thomthom): Should we try to detect use of #typename
18
- # in context of comparing against a string?
19
- add_offense(node, location: :selector)
20
- end
21
- end
22
- end
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SketchupPerformance
6
+ # `.typename` is very slow, prefer `.is_a?` instead.
7
+ #
8
+ # `entity.typename == 'Face'` is slow because it performs a string
9
+ # comparison. `is_a?` is much faster because it's a simple type check.
10
+ class Typename < SketchUp::Cop
11
+ MSG = '`.typename` is very slow, prefer `.is_a?` instead.'.freeze
12
+
13
+ def on_send(node)
14
+ _, method_name = *node
15
+ return unless method_name == :typename
16
+
17
+ # TODO(thomthom): Should we try to detect use of #typename
18
+ # in context of comparing against a string?
19
+ add_offense(node, location: :selector)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,30 +1,30 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module SketchupRequirements
6
- # Do not modify the Sketch API. This will affect other extensions and
7
- # very likely cause them to fail.
8
- #
9
- # This requirement also include adding things into the SketchUp API
10
- # namespace. The API namespace is reserved for future additions to the
11
- # API.
12
- class ApiNamespace < SketchUp::Cop
13
-
14
- include SketchUp::NoCommentDisable
15
- include SketchUp::NamespaceChecker
16
-
17
- MSG = 'Do not modify the SketchUp API.'.freeze
18
-
19
- NAMESPACES = %w[
20
- Geom Layout Sketchup SketchupExtension UI
21
- ].freeze
22
-
23
- def namespaces
24
- NAMESPACES
25
- end
26
-
27
- end
28
- end
29
- end
30
- end
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SketchupRequirements
6
+ # Do not modify the Sketch API. This will affect other extensions and
7
+ # very likely cause them to fail.
8
+ #
9
+ # This requirement also include adding things into the SketchUp API
10
+ # namespace. The API namespace is reserved for future additions to the
11
+ # API.
12
+ class ApiNamespace < SketchUp::Cop
13
+
14
+ include SketchUp::NoCommentDisable
15
+ include SketchUp::NamespaceChecker
16
+
17
+ MSG = 'Do not modify the SketchUp API.'.freeze
18
+
19
+ NAMESPACES = %w[
20
+ Geom Layout Sketchup SketchupExtension UI
21
+ ].freeze
22
+
23
+ def namespaces
24
+ NAMESPACES
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,32 +1,32 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module SketchupRequirements
6
- # Don't attempt to kill the Ruby interpreter by calling `exit` or `exit!`.
7
- # SketchUp will trap `exit` and prevent that, with a message in the
8
- # console. But `exit!` is not trapped and with terminate SketchUp without
9
- # shutting down cleanly.
10
- #
11
- # Use `return`, `next`, `break` or `raise` instead.
12
- class Exit < SketchUp::Cop
13
-
14
- include SketchUp::NoCommentDisable
15
-
16
- MSG = '`exit` attempts to kill the Ruby interpreter. Use `return`, '\
17
- '`next`, `break` or `raise` instead.'.freeze
18
-
19
- # Reference: http://rubocop.readthedocs.io/en/latest/development/
20
- def_node_matcher :exit?, <<-PATTERN
21
- (send {(const nil? :Kernel) nil?} {:exit :exit!} ...)
22
- PATTERN
23
-
24
- def on_send(node)
25
- return unless exit?(node)
26
-
27
- add_offense(node, location: :selector)
28
- end
29
- end
30
- end
31
- end
32
- end
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SketchupRequirements
6
+ # Don't attempt to kill the Ruby interpreter by calling `exit` or `exit!`.
7
+ # SketchUp will trap `exit` and prevent that, with a message in the
8
+ # console. But `exit!` is not trapped and will terminate SketchUp without
9
+ # shutting down cleanly.
10
+ #
11
+ # Use `return`, `next`, `break` or `raise` instead.
12
+ class Exit < SketchUp::Cop
13
+
14
+ include SketchUp::NoCommentDisable
15
+
16
+ MSG = '`exit` attempts to kill the Ruby interpreter. Use `return`, '\
17
+ '`next`, `break` or `raise` instead.'.freeze
18
+
19
+ # Reference: http://rubocop.readthedocs.io/en/latest/development/
20
+ def_node_matcher :exit?, <<-PATTERN
21
+ (send {(const nil? :Kernel) nil?} {:exit :exit!} ...)
22
+ PATTERN
23
+
24
+ def on_send(node)
25
+ return unless exit?(node)
26
+
27
+ add_offense(node, location: :selector)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,108 +1,108 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rubocop/sketchup/cop/requirements/api_namespace'
4
- require 'rubocop/sketchup/cop/requirements/ruby_core_namespace'
5
- require 'rubocop/sketchup/cop/requirements/ruby_stdlib_namespace'
6
-
7
- module RuboCop
8
- module Cop
9
- module SketchupRequirements
10
- # Extensions in SketchUp all share the same Ruby environment on the user's
11
- # machine. Because of this it's important that each extension isolate
12
- # itself to avoid clashing with other extensions.
13
- #
14
- # Extensions submitted to Extension Warehouse is expected to use only one
15
- # root module.
16
- #
17
- # @example Good - this contains everything in the extension.
18
- # module MyExtension
19
- # class Foo
20
- # end
21
- # class Bar
22
- # end
23
- # end
24
- #
25
- # @example Better - this further reduce chance of clashing.
26
- # module MyCompany
27
- # module MyExtension
28
- # class Foo
29
- # end
30
- # class Bar
31
- # end
32
- # end
33
- # end
34
- class ExtensionNamespace < SketchUp::Cop
35
-
36
- include SketchUp::NoCommentDisable
37
- include SketchUp
38
-
39
- def on_class(node)
40
- check_class_or_module(node)
41
- end
42
-
43
- def on_module(node)
44
- check_class_or_module(node)
45
- end
46
-
47
- def check_class_or_module(node)
48
- name = node.defined_module_name
49
- parent = Namespace.new(node.parent_module_name)
50
- namespace = parent.join(name)
51
- # Don't want to process anything that aren't top level namespaces.
52
- return unless parent.top_level?
53
- # Don't check excluded namespaces.
54
- return if exempted?(namespace)
55
-
56
- check_namespace(node, namespace)
57
- end
58
-
59
- # Class variables are normally frowned upon since they leak through all
60
- # instances. However, in this case this is exactly what we want.
61
- # The Cop picks up the first top level namespace it encounters and then
62
- # keep track of whether it detects more top level namespaces.
63
- @@namespace = nil
64
- def check_namespace(node, namespace)
65
- # Make sure the namespace isn't part of reserved namespaces that other
66
- # cops are checking.
67
- return if reserved?(namespace)
68
-
69
- # Remember the first namespace encountered and log an offence if
70
- # more top level namespaces are registered.
71
- top = namespace.first
72
- @@namespace ||= top
73
- return if @@namespace == top
74
-
75
- add_offense(node, location: :name)
76
- end
77
-
78
- def reserved?(namespace)
79
- top = namespace.first
80
- return true if RubyCoreNamespace::NAMESPACES.include?(top)
81
- return true if RubyStdLibNamespace::NAMESPACES.include?(top)
82
- return true if ApiNamespace::NAMESPACES.include?(top)
83
-
84
- false
85
- end
86
-
87
- def message(node)
88
- namespace = Namespace.new(node.defined_module_name).from_root
89
- format('Use a single root namespace. '\
90
- '(Found `%<found>s`; Previously found `%<expected>s`)',
91
- found: namespace, expected: @@namespace)
92
- end
93
-
94
- def exempted?(namespace)
95
- namespace_exceptions.include?(namespace.first)
96
- end
97
-
98
- def namespace_exceptions
99
- exceptions = cop_config['Exceptions'] || []
100
- return exceptions if exceptions.is_a?(Array)
101
-
102
- raise 'exceptions needs to be an array of strings!'
103
- end
104
-
105
- end
106
- end
107
- end
108
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop/sketchup/cop/requirements/api_namespace'
4
+ require 'rubocop/sketchup/cop/requirements/ruby_core_namespace'
5
+ require 'rubocop/sketchup/cop/requirements/ruby_stdlib_namespace'
6
+
7
+ module RuboCop
8
+ module Cop
9
+ module SketchupRequirements
10
+ # Extensions in SketchUp all share the same Ruby environment on the user's
11
+ # machine. Because of this it's important that each extension isolate
12
+ # itself to avoid clashing with other extensions.
13
+ #
14
+ # Extensions submitted to Extension Warehouse is expected to use only one
15
+ # root module.
16
+ #
17
+ # @example Good - this contains everything in the extension.
18
+ # module MyExtension
19
+ # class Foo
20
+ # end
21
+ # class Bar
22
+ # end
23
+ # end
24
+ #
25
+ # @example Better - this further reduce chance of clashing.
26
+ # module MyCompany
27
+ # module MyExtension
28
+ # class Foo
29
+ # end
30
+ # class Bar
31
+ # end
32
+ # end
33
+ # end
34
+ class ExtensionNamespace < SketchUp::Cop
35
+
36
+ include SketchUp::NoCommentDisable
37
+ include SketchUp
38
+
39
+ def on_class(node)
40
+ check_class_or_module(node)
41
+ end
42
+
43
+ def on_module(node)
44
+ check_class_or_module(node)
45
+ end
46
+
47
+ def check_class_or_module(node)
48
+ name = node.defined_module_name
49
+ parent = Namespace.new(node.parent_module_name)
50
+ namespace = parent.join(name)
51
+ # Don't want to process anything that aren't top level namespaces.
52
+ return unless parent.top_level?
53
+ # Don't check excluded namespaces.
54
+ return if exempted?(namespace)
55
+
56
+ check_namespace(node, namespace)
57
+ end
58
+
59
+ # Class variables are normally frowned upon since they leak through all
60
+ # instances. However, in this case this is exactly what we want.
61
+ # The Cop picks up the first top level namespace it encounters and then
62
+ # keep track of whether it detects more top level namespaces.
63
+ @@namespace = nil
64
+ def check_namespace(node, namespace)
65
+ # Make sure the namespace isn't part of reserved namespaces that other
66
+ # cops are checking.
67
+ return if reserved?(namespace)
68
+
69
+ # Remember the first namespace encountered and log an offence if
70
+ # more top level namespaces are registered.
71
+ top = namespace.first
72
+ @@namespace ||= top
73
+ return if @@namespace == top
74
+
75
+ add_offense(node, location: :name)
76
+ end
77
+
78
+ def reserved?(namespace)
79
+ top = namespace.first
80
+ return true if RubyCoreNamespace::NAMESPACES.include?(top)
81
+ return true if RubyStdLibNamespace::NAMESPACES.include?(top)
82
+ return true if ApiNamespace::NAMESPACES.include?(top)
83
+
84
+ false
85
+ end
86
+
87
+ def message(node)
88
+ namespace = Namespace.new(node.defined_module_name).from_root
89
+ format('Use a single root namespace. '\
90
+ '(Found `%<found>s`; Previously found `%<expected>s`)',
91
+ found: namespace, expected: @@namespace)
92
+ end
93
+
94
+ def exempted?(namespace)
95
+ namespace_exceptions.include?(namespace.first)
96
+ end
97
+
98
+ def namespace_exceptions
99
+ exceptions = cop_config['Exceptions'] || []
100
+ return exceptions if exceptions.is_a?(Array)
101
+
102
+ raise 'exceptions needs to be an array of strings!'
103
+ end
104
+
105
+ end
106
+ end
107
+ end
108
+ end
@@ -1,97 +1,97 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module SketchupRequirements
6
- # Check that the extension conform to expected file structure with a
7
- # single root .rb file and a support folder with matching name.
8
- #
9
- # Make sure to match upper and lower case characters between the root .rb
10
- # file and the support folder.
11
- #
12
- # @example
13
- # SketchUp/Plugins
14
- # + ex_hello_world.rb
15
- # + ex_hello_world
16
- # + main.rb
17
- # + ...
18
- class FileStructure < SketchUp::Cop
19
-
20
- include SketchUp::NoCommentDisable
21
- include SketchUp::ExtensionProject
22
- include RangeHelp
23
-
24
- IGNORED_DIRECTORIES = %w[
25
- __MACOSX
26
- ].freeze
27
-
28
- def investigate(processed_source)
29
- return if already_run?
30
-
31
- # Using range similar to RuboCop::Cop::Naming::Filename (file_name.rb)
32
- range = source_range(processed_source.buffer, 1, 0)
33
-
34
- # Find all root Ruby files in the source directory.
35
- pattern = "#{source_path}/*.rb"
36
- root_ruby_files = Dir.glob(pattern)
37
-
38
- # Ensure there is only one root Ruby file.
39
- if root_ruby_files.size != 1
40
- msg = 'Extensions must have exactly one root Ruby (.rb) file. '\
41
- 'Found: %d'
42
- add_offense(nil,
43
- location: range,
44
- message: format(msg, root_ruby_files.size))
45
- return
46
- end
47
-
48
- # Find the root file and collect the sub-directories.
49
- root_file = root_ruby_files.first
50
- extension_basename = File.basename(root_file, '.*')
51
- sub_folders = source_path.children.select(&:directory?)
52
- sub_folders.reject! { |folder|
53
- IGNORED_DIRECTORIES.include?(folder.basename.to_s)
54
- }
55
-
56
- # Ensure there is only one sub-directory.
57
- if sub_folders.size != 1
58
- msg = 'Extensions must have exactly one support directory. Found %d'
59
- add_offense(nil,
60
- location: range,
61
- message: format(msg, sub_folders.size))
62
- return
63
- end
64
-
65
- # Ensure support directory's name match the root Ruby file.
66
- support_directory = sub_folders.first
67
- unless support_directory.basename.to_s == extension_basename
68
- msg = 'Extensions must have a support directory matching the name '\
69
- 'of the root Ruby file. Expected %s, found %s'
70
- msg = format(msg, extension_basename, support_directory.basename)
71
- add_offense(nil,
72
- location: range,
73
- message: msg)
74
- end
75
- end
76
-
77
- private
78
-
79
- @@already_run = false
80
-
81
- def already_run?
82
- return true if @@already_run
83
-
84
- @@already_run = true
85
- false
86
- end
87
-
88
- # rubocop:disable Lint/IneffectiveAccessModifier
89
- def self.reset
90
- @@already_run = false
91
- end
92
- # rubocop:enable Lint/IneffectiveAccessModifier
93
-
94
- end
95
- end
96
- end
97
- end
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SketchupRequirements
6
+ # Check that the extension conform to expected file structure with a
7
+ # single root .rb file and a support folder with matching name.
8
+ #
9
+ # Make sure to match upper and lower case characters between the root .rb
10
+ # file and the support folder.
11
+ #
12
+ # @example
13
+ # SketchUp/Plugins
14
+ # + ex_hello_world.rb
15
+ # + ex_hello_world
16
+ # + main.rb
17
+ # + ...
18
+ class FileStructure < SketchUp::Cop
19
+
20
+ include SketchUp::NoCommentDisable
21
+ include SketchUp::ExtensionProject
22
+ include RangeHelp
23
+
24
+ IGNORED_DIRECTORIES = %w[
25
+ __MACOSX
26
+ ].freeze
27
+
28
+ def investigate(processed_source)
29
+ return if already_run?
30
+
31
+ # Using range similar to RuboCop::Cop::Naming::Filename (file_name.rb)
32
+ range = source_range(processed_source.buffer, 1, 0)
33
+
34
+ # Find all root Ruby files in the source directory.
35
+ pattern = "#{source_path}/*.rb"
36
+ root_ruby_files = Dir.glob(pattern)
37
+
38
+ # Ensure there is only one root Ruby file.
39
+ if root_ruby_files.size != 1
40
+ msg = 'Extensions must have exactly one root Ruby (.rb) file. '\
41
+ 'Found: %d'
42
+ add_offense(nil,
43
+ location: range,
44
+ message: format(msg, root_ruby_files.size))
45
+ return
46
+ end
47
+
48
+ # Find the root file and collect the sub-directories.
49
+ root_file = root_ruby_files.first
50
+ extension_basename = File.basename(root_file, '.*')
51
+ sub_folders = source_path.children.select(&:directory?)
52
+ sub_folders.reject! { |folder|
53
+ IGNORED_DIRECTORIES.include?(folder.basename.to_s)
54
+ }
55
+
56
+ # Ensure there is only one sub-directory.
57
+ if sub_folders.size != 1
58
+ msg = 'Extensions must have exactly one support directory. Found %d'
59
+ add_offense(nil,
60
+ location: range,
61
+ message: format(msg, sub_folders.size))
62
+ return
63
+ end
64
+
65
+ # Ensure support directory's name match the root Ruby file.
66
+ support_directory = sub_folders.first
67
+ unless support_directory.basename.to_s == extension_basename
68
+ msg = 'Extensions must have a support directory matching the name '\
69
+ 'of the root Ruby file. Expected %s, found %s'
70
+ msg = format(msg, extension_basename, support_directory.basename)
71
+ add_offense(nil,
72
+ location: range,
73
+ message: msg)
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ @@already_run = false
80
+
81
+ def already_run?
82
+ return true if @@already_run
83
+
84
+ @@already_run = true
85
+ false
86
+ end
87
+
88
+ # rubocop:disable Lint/IneffectiveAccessModifier
89
+ def self.reset
90
+ @@already_run = false
91
+ end
92
+ # rubocop:enable Lint/IneffectiveAccessModifier
93
+
94
+ end
95
+ end
96
+ end
97
+ end