Skip to content

Commit

Permalink
[Fix rubocop#2968] Added DocumentationMethod Cop.
Browse files Browse the repository at this point in the history
  • Loading branch information
sooyang committed Jul 27, 2016
1 parent 08be435 commit 47ad567
Show file tree
Hide file tree
Showing 5 changed files with 716 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## master (unreleased)

* [#2968](https://github.com/bbatsov/rubocop/issues/2968): Add new `Style/DocumentationMethod` cop. ([@sooyang][])

### Changes

* [#3341](https://github.com/bbatsov/rubocop/issues/3341): Exclude RSpec tests from inspection by `Style/NumericPredicate` cop. ([@drenmi][])
Expand Down Expand Up @@ -2299,3 +2301,4 @@
[@haziqhafizuddin]: https://github.com/haziqhafizuddin
[@dvandersluis]: https://github.com/dvandersluis
[@QuinnHarris]: https://github.com/QuinnHarris
[@sooyang]: https://github.com/sooyang
7 changes: 7 additions & 0 deletions config/disabled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ Style/Copyright:
Description: 'Include a copyright notice in each file before any code.'
Enabled: false

Style/DocumentationMethod:
Description: 'Public methods.'
Enabled: false
Exclude:
- 'spec/**/*'
- 'test/**/*'

Style/Encoding:
Description: 'Use UTF-8 as the source file encoding.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#utf-8'
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
require 'rubocop/cop/style/copyright'
require 'rubocop/cop/style/def_with_parentheses'
require 'rubocop/cop/style/preferred_hash_methods'
require 'rubocop/cop/style/documentation_method'
require 'rubocop/cop/style/documentation'
require 'rubocop/cop/style/dot_position'
require 'rubocop/cop/style/double_negation'
Expand Down
173 changes: 173 additions & 0 deletions lib/rubocop/cop/style/documentation_method.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# encoding: utf-8
# frozen_string_literal: true
module RuboCop
module Cop
module Style
# This cop checks for missing documentation comment for public method.
#
# @example
# # declaring methods outside of a class
#
# # bad
#
# def method
# puts "method"
# end
#
# class MyClass
# end
#
# # good
#
# # Method Comment
# def method
# puts "method"
# end
#
# class MyClass
# end
#
# @example
# # declaring methods inside a class
#
# # bad
#
# class MyClass
# def method
# puts 'method'
# end
# end
#
# # good
#
# class MyClass
# # Method Comment
# def method
# puts 'method'
# end
# end
#
# @example
# # declaring methods inside a module
#
# # bad
#
# module MyModule
# def method
# puts 'method'
# end
# end
#
# #good
#
# module MyModule
# # Method Comment
# def method
# puts 'method'
# end
# end
#
# # singleton methods
#
# # bad
#
# class MyClass
# end
#
# my_class = MyClass.new
#
# def my_class.method
# puts 'method'
# end
#
# # good
#
# class MyClass
# end
#
# my_class = MyClass.new
#
# # Method Comment
# def my_class.method
# puts 'method'
# end
#
class DocumentationMethod < Cop
include AnnotationComment
include OnMethodDef
MSG = 'Missing top-level %s documentation method comment.'.freeze
METHOD_TYPE = %w(private protected).freeze

def_node_matcher :constant_definition?, '{def casgn}'

def on_def(node)
check_offenses(node)
end

def on_method_def(node, _method_name, _args, _body)
check_offenses(node)
end

private

def check_offenses(node)
_name, _body = *node

line = node.loc.line
return if node.ancestors.first.to_a.include? method_type
return if (processed_source[0..line].map(&:strip) &
METHOD_TYPE).any?
ast_with_comments = processed_source.ast_with_comments
return if associated_comment?(node, ast_with_comments)
add_offense(node, :keyword, format(MSG, :module))
end

def namespace?(body_node)
return false unless body_node

case body_node.type
when :begin
body_node.children.all? { |node| constant_definition?(node) }
else
constant_definition?(body_node)
end
end

# Returns true if the node has a comment on the line above it that
# isn't an annotation.
def associated_comment?(node, ast_with_comments)
preceding_comments = preceding_comments(node, ast_with_comments)
return false if preceding_comments.empty?

distance = node.loc.keyword.line - preceding_comments.last.loc.line
return false if distance > 1
return false unless comment_line_only?(preceding_comments.last)

# As long as there's at least one comment line that isn't an
# annotation, it's OK.
preceding_comments.any? do |comment|
!annotation?(comment) && !interpreter_directive_comment?(comment)
end
end

def preceding_comments(node, ast_with_comments)
ast_with_comments[node].select { |c| c.loc.line < node.loc.line }
end

def comment_line_only?(comment)
source_buffer = comment.loc.expression.source_buffer
comment_line = source_buffer.source_line(comment.loc.line)
comment_line =~ /^\s*#/
end

def interpreter_directive_comment?(comment)
comment.text =~ /^#\s*(frozen_string_literal|encoding):/
end

def method_type
:private || :protected
end
end
end
end
end
Loading

0 comments on commit 47ad567

Please sign in to comment.