Class: Cane::DocCheck

Inherits:
Struct
  • Object
show all
Defined in:
lib/cane/doc_check.rb

Overview

Creates violations for class definitions that do not have an explantory comment immediately preceding.

Defined Under Namespace

Classes: ClassDefinition

Constant Summary collapse

DESCRIPTION =
"Class and Module definitions require explanatory comments on previous line"
MAGIC_COMMENT_REGEX =

Stolen from ERB source, amended to be slightly stricter to work around some known false positives.

%r"#(\s+-\*-)?\s+(en)?coding\s*[=:]\s*([[:alnum:]\-_]+)"
CLASS_REGEX =
/^\s*(?:class|module)\s+([^\s;]+)/
METHOD_REGEX =
/(?:^|\s)def\s+/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#optsObject

Returns the value of attribute opts

Returns:

  • (Object)

    the current value of opts



8
9
10
# File 'lib/cane/doc_check.rb', line 8

def opts
  @opts
end

Class Method Details

.keyObject



21
# File 'lib/cane/doc_check.rb', line 21

def self.key; :doc; end

.nameObject



22
# File 'lib/cane/doc_check.rb', line 22

def self.name; "documentation checking"; end

.optionsObject



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/cane/doc_check.rb', line 23

def self.options
  {
    doc_glob:    ['Glob to run doc checks over',
                    default:  '{app,lib}/**/*.rb',
                    variable: 'GLOB',
                    clobber:  :no_doc],
    doc_exclude: ['Exclude file or glob from documentation checking',
                    variable: 'GLOB',
                    type: Array,
                    default: [],
                    clobber: :no_doc],
    no_readme:   ['Disable readme checking', cast: ->(x) { !x }],
    no_doc:      ['Disable documentation checking', cast: ->(x) { !x }]
  }
end

Instance Method Details

#class_definition?(line) ⇒ Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/cane/doc_check.rb', line 111

def class_definition?(line)
  line =~ CLASS_REGEX && $1.index('<<') != 0
end

#class_definitions_in(file_name) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/cane/doc_check.rb', line 69

def class_definitions_in(file_name)
  class_definitions = []
  last_line = ""

  Cane::File.iterator(file_name).each_with_index do |line, number|
    if class_definition? line
      class_definitions << ClassDefinition.new({
        line: (number + 1),
        label: extract_class_name(line),
        has_doc: comment?(last_line)
      })
    end

    if method_definition?(line) && !class_definitions.empty?
      class_definitions.last.requires_doc = true
    end

    last_line = line
  end

  class_definitions
end

#comment?(line) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/cane/doc_check.rb', line 115

def comment?(line)
  line =~ /^\s*#/ && !(MAGIC_COMMENT_REGEX =~ line)
end

#excluded?(file) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/cane/doc_check.rb', line 129

def excluded?(file)
  exclusions.include?(file)
end

#exclusionsObject



123
124
125
126
127
# File 'lib/cane/doc_check.rb', line 123

def exclusions
  @exclusions ||= opts.fetch(:doc_exclude, []).flatten.map do |i|
    Dir[i]
  end.flatten.to_set
end

#extract_class_name(line) ⇒ Object



119
120
121
# File 'lib/cane/doc_check.rb', line 119

def extract_class_name(line)
  line.match(CLASS_REGEX)[1]
end

#file_namesObject



103
104
105
# File 'lib/cane/doc_check.rb', line 103

def file_names
  Dir[opts.fetch(:doc_glob)].reject { |file| excluded?(file) }
end

#find_violations(file_name) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/cane/doc_check.rb', line 56

def find_violations(file_name)
  class_definitions_in(file_name).map do |class_definition|
    if class_definition.requires_doc? && class_definition.missing_doc?
      {
        file:        file_name,
        line:        class_definition.line,
        label:       class_definition.label,
        description: DESCRIPTION
      }
    end
  end.compact
end

#method_definition?(line) ⇒ Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/cane/doc_check.rb', line 107

def method_definition?(line)
  line =~ METHOD_REGEX
end

#missing_file_violationsObject



92
93
94
95
96
97
98
99
100
101
# File 'lib/cane/doc_check.rb', line 92

def missing_file_violations
  result = []
  return result if opts[:no_readme]

  if Cane::File.case_insensitive_glob("README*").none?
    result << { description: 'Missing documentation',
                label: 'No README found' }
  end
  result
end

#violationsObject



48
49
50
51
52
53
54
# File 'lib/cane/doc_check.rb', line 48

def violations
  return [] if opts[:no_doc]

  missing_file_violations + worker.map(file_names) {|file_name|
    find_violations(file_name)
  }.flatten
end

#workerObject



133
134
135
# File 'lib/cane/doc_check.rb', line 133

def worker
  Cane.task_runner(opts)
end