193 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| module RuboCop
 | |
|   module CodeReuseHelpers
 | |
|     # Returns true for a `(send const ...)` node.
 | |
|     def send_to_constant?(node)
 | |
|       node.type == :send && node.children&.first&.type == :const
 | |
|     end
 | |
| 
 | |
|     # Returns `true` if the name of the receiving constant ends with a given
 | |
|     # `String`.
 | |
|     def send_receiver_name_ends_with?(node, suffix)
 | |
|       return false unless send_to_constant?(node)
 | |
| 
 | |
|       receiver_name = name_of_receiver(node)
 | |
| 
 | |
|       receiver_name != suffix &&
 | |
|         receiver_name.end_with?(suffix)
 | |
|     end
 | |
| 
 | |
|     # Returns the file path (as a `String`) for an AST node.
 | |
|     def file_path_for_node(node)
 | |
|       node.location.expression.source_buffer.name
 | |
|     end
 | |
| 
 | |
|     # Returns the name of a constant node.
 | |
|     #
 | |
|     # Given the AST node `(const nil? :Foo)`, this method will return `:Foo`.
 | |
|     def name_of_constant(node)
 | |
|       node.children[1]
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/finders or ee/app/finders.
 | |
|     def in_finder?(node)
 | |
|       in_app_directory?(node, 'finders')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/models or ee/app/models.
 | |
|     def in_model?(node)
 | |
|       in_app_directory?(node, 'models')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/services or ee/app/services.
 | |
|     def in_service_class?(node)
 | |
|       in_app_directory?(node, 'services')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/presenters or
 | |
|     # ee/app/presenters.
 | |
|     def in_presenter?(node)
 | |
|       in_app_directory?(node, 'presenters')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/serializers or
 | |
|     # ee/app/serializers.
 | |
|     def in_serializer?(node)
 | |
|       in_app_directory?(node, 'serializers')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/workers or ee/app/workers.
 | |
|     def in_worker?(node)
 | |
|       in_app_directory?(node, 'workers')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/controllers or
 | |
|     # ee/app/controllers.
 | |
|     def in_controller?(node)
 | |
|       in_app_directory?(node, 'controllers')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in app/graphql/types,
 | |
|     # ee/app/graphql/types, or ee/app/graphql/ee/types.
 | |
|     def in_graphql_types?(node)
 | |
|       in_app_directory?(node, 'graphql/types') || in_app_directory?(node, 'graphql/ee/types')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in lib/api or ee/lib/api.
 | |
|     def in_api?(node)
 | |
|       in_lib_directory?(node, 'api')
 | |
|     end
 | |
| 
 | |
|     # Returns true if the given node resides in spec or ee/spec.
 | |
|     def in_spec?(node)
 | |
|       file_path_for_node(node).start_with?(
 | |
|         ce_spec_directory,
 | |
|         ee_spec_directory
 | |
|       )
 | |
|     end
 | |
| 
 | |
|     # Returns `true` if the given AST node resides in the given directory,
 | |
|     # relative to app and/or ee/app.
 | |
|     def in_app_directory?(node, directory)
 | |
|       file_path_for_node(node).start_with?(
 | |
|         File.join(ce_app_directory, directory),
 | |
|         File.join(ee_app_directory, directory)
 | |
|       )
 | |
|     end
 | |
| 
 | |
|     # Returns `true` if the given AST node resides in the given directory,
 | |
|     # relative to lib and/or ee/lib.
 | |
|     def in_lib_directory?(node, directory)
 | |
|       file_path_for_node(node).start_with?(
 | |
|         File.join(ce_lib_directory, directory),
 | |
|         File.join(ee_lib_directory, directory)
 | |
|       )
 | |
|     end
 | |
| 
 | |
|     # Returns the receiver name of a send node.
 | |
|     #
 | |
|     # For the AST node `(send (const nil? :Foo) ...)` this would return
 | |
|     # `'Foo'`.
 | |
|     def name_of_receiver(node)
 | |
|       name_of_constant(node.children.first).to_s
 | |
|     end
 | |
| 
 | |
|     # Yields every defined class method in the given AST node.
 | |
|     def each_class_method(node)
 | |
|       return to_enum(__method__, node) unless block_given?
 | |
| 
 | |
|       # class << self
 | |
|       #   def foo
 | |
|       #   end
 | |
|       # end
 | |
|       node.each_descendant(:sclass) do |sclass|
 | |
|         sclass.each_descendant(:def) do |def_node|
 | |
|           yield def_node
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       # def self.foo
 | |
|       # end
 | |
|       node.each_descendant(:defs) do |defs_node|
 | |
|         yield defs_node
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     # Yields every send node found in the given AST node.
 | |
|     def each_send_node(node, &block)
 | |
|       node.each_descendant(:send, &block)
 | |
|     end
 | |
| 
 | |
|     # Registers a RuboCop offense for a `(send)` node with a receiver that ends
 | |
|     # with a given suffix.
 | |
|     #
 | |
|     # node - The AST node to check.
 | |
|     # suffix - The suffix of the receiver name, such as "Finder".
 | |
|     # message - The message to use for the offense.
 | |
|     def disallow_send_to(node, suffix, message)
 | |
|       each_send_node(node) do |send_node|
 | |
|         next unless send_receiver_name_ends_with?(send_node, suffix)
 | |
| 
 | |
|         add_offense(send_node, location: :expression, message: message)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def ce_app_directory
 | |
|       File.join(rails_root, 'app')
 | |
|     end
 | |
| 
 | |
|     def ee_app_directory
 | |
|       File.join(rails_root, 'ee', 'app')
 | |
|     end
 | |
| 
 | |
|     def ce_lib_directory
 | |
|       File.join(rails_root, 'lib')
 | |
|     end
 | |
| 
 | |
|     def ee_lib_directory
 | |
|       File.join(rails_root, 'ee', 'lib')
 | |
|     end
 | |
| 
 | |
|     def ce_spec_directory
 | |
|       File.join(rails_root, 'spec')
 | |
|     end
 | |
| 
 | |
|     def ee_spec_directory
 | |
|       File.join(rails_root, 'ee', 'spec')
 | |
|     end
 | |
| 
 | |
|     def rails_root
 | |
|       File.expand_path('..', __dir__)
 | |
|     end
 | |
| 
 | |
|     def ee?
 | |
|       File.exist?(File.expand_path('../ee/app/models/license.rb', __dir__)) && !%w[true 1].include?(ENV['FOSS_ONLY'].to_s)
 | |
|     end
 | |
| 
 | |
|     def jh?
 | |
|       ee? && Dir.exist?(File.expand_path('../jh', __dir__)) && !%w[true 1].include?(ENV['EE_ONLY'].to_s)
 | |
|     end
 | |
|   end
 | |
| end
 |