Class: DNote::Notes

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/dnote/notes.rb

Overview

Developer Notes

This class goes through you source files and compiles a list of any labeled comments. Labels are all-cap single word prefixes to a comment ending in a colon.

Special labels do not require the colon. By default these are TODO, FIXME, OPTIMIZE, THINK and DEPRECATE.

TODO: Add ability to read header notes. They often
      have a outline format, rather then the single line.

++

Constant Summary collapse

DEFAULT_PATHS =

Default paths (all ruby scripts).

['**/*.rb'].freeze
DEFAULT_LABELS =

Default note labels to look for in source code. (NOT CURRENTLY USED!)

%w(TODO FIXME OPTIMIZE THINK DEPRECATE).freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(files, options = {}) ⇒ Notes

New set of notes for give files and optional special labels.



48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/dnote/notes.rb', line 48

def initialize(files, options = {})
  @files   = [files].flatten
  @labels  = [options[:labels] || DEFAULT_LABELS].flatten.compact
  @colon   = options[:colon].nil? ? true : options[:colon]
  @marker  = options[:marker]
  @url     = options[:url]
  @context = options[:context] || 0

  @remark  = {}

  parse
end

Instance Attribute Details

#colonObject

Require label colon? Default is true.



36
37
38
# File 'lib/dnote/notes.rb', line 36

def colon
  @colon
end

#contextObject

Number of lines of context to show.



45
46
47
# File 'lib/dnote/notes.rb', line 45

def context
  @context
end

#filesObject

Files to search for notes.



30
31
32
# File 'lib/dnote/notes.rb', line 30

def files
  @files
end

#labelsObject

Labels to document. Defaults are: TODO, FIXME, OPTIMIZE and DEPRECATE.



33
34
35
# File 'lib/dnote/notes.rb', line 33

def labels
  @labels
end

#markerObject

Specific remark marker (nil for auto).



39
40
41
# File 'lib/dnote/notes.rb', line 39

def marker
  @marker
end

#notesObject (readonly)

Array of notes.



62
63
64
# File 'lib/dnote/notes.rb', line 62

def notes
  @notes
end

#urlObject

Link template.



42
43
44
# File 'lib/dnote/notes.rb', line 42

def url
  @url
end

Instance Method Details

#by_fileObject

Organize notes into a hash with filename for keys.



199
200
201
202
203
204
205
206
207
208
209
# File 'lib/dnote/notes.rb', line 199

def by_file
  @by_file ||= begin
    list = {}
    notes.each do |note|
      list[note.file] ||= []
      list[note.file] << note
      list[note.file].sort!
    end
    list
  end
end

#by_file_labelObject

Organize notes into a hash with filenames for keys, followed by a hash with labels for keys.



228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/dnote/notes.rb', line 228

def by_file_label
  @by_file_label ||= begin
    list = {}
    notes.each do |note|
      list[note.file] ||= {}
      list[note.file][note.label] ||= []
      list[note.file][note.label] << note
      list[note.file][note.label].sort!
    end
    list
  end
end

#by_labelObject

Organize notes into a hash with labels for keys.



186
187
188
189
190
191
192
193
194
195
196
# File 'lib/dnote/notes.rb', line 186

def by_label
  @by_label ||= begin
    list = {}
    notes.each do |note|
      list[note.label] ||= []
      list[note.label] << note
      list[note.label].sort
    end
    list
  end
end

#by_label_fileObject

Organize notes into a hash with labels for keys, followed by a hash with filename for keys.



213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/dnote/notes.rb', line 213

def by_label_file
  @by_label_file ||= begin
    list = {}
    notes.each do |note|
      list[note.label] ||= {}
      list[note.label][note.file] ||= []
      list[note.label][note.file] << note
      list[note.label][note.file].sort!
    end
    list
  end
end

#countsObject

Notes counts by label.



65
66
67
68
69
70
71
72
73
# File 'lib/dnote/notes.rb', line 65

def counts
  @counts ||= begin
    h = {}
    by_label.each do |label, notes|
      h[label] = notes.size
    end
    h
  end
end

#each(&block) ⇒ Object

Iterate through notes.



76
77
78
# File 'lib/dnote/notes.rb', line 76

def each(&block)
  notes.each(&block)
end

#empty?Boolean

No notes?

Returns:

  • (Boolean)


81
82
83
# File 'lib/dnote/notes.rb', line 81

def empty?
  notes.empty?
end

#guess_marker(file) ⇒ Object

Guess marker based on file extension. Fallsback to ‘#’ if the extension is unknown.

TODO: Continue to add comment types.



262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/dnote/notes.rb', line 262

def guess_marker(file)
  return @marker if @marker # forced marker

  case File.extname(file)
  when '.js', '.c', 'cpp', '.css'
    '//'
  when '.bas'
    "'"
  when '.sql', '.ada'
    '--'
  when '.asm'
    ';'
  else
    '#'
  end
end

#match(line, lineno, file) ⇒ Object

Is this line a note?



131
132
133
134
135
136
137
# File 'lib/dnote/notes.rb', line 131

def match(line, lineno, file)
  if labels.empty?
    match_general(line, lineno, file)
  else
    match_special(line, lineno, file)
  end
end

#match_general(line, lineno, file) ⇒ Object

Match notes that are labeled with a colon.



164
165
166
167
168
169
170
171
172
# File 'lib/dnote/notes.rb', line 164

def match_general(line, lineno, file)
  rec = nil
  if (md = match_general_regex(file).match(line))
    label = md[1]
    text = md[2]
    rec = Note.new(self, file, label, lineno, text, remark(file))
  end
  rec
end

#match_general_regex(file) ⇒ Object

Keep in mind that general non-colon matches have a higher potential of false positives.



176
177
178
179
180
181
182
183
# File 'lib/dnote/notes.rb', line 176

def match_general_regex(file)
  mark = remark(file)
  if colon
    /#{mark}\s*([A-Z]+)[:]\s+(.*?)$/
  else
    /#{mark}\s*([A-Z]+)\s+(.*?)$/
  end
end

#match_special(line, lineno, file) ⇒ Object

Match special notes.



140
141
142
143
144
145
146
147
148
149
# File 'lib/dnote/notes.rb', line 140

def match_special(line, lineno, file)
  rec = nil
  labels.each do |label|
    if (md = match_special_regex(label, file).match(line))
      text = md[1]
      rec = Note.new(self, file, label, lineno, text, remark(file))
    end
  end
  rec
end

#match_special_regex(label, file) ⇒ Object

– TODO: ruby-1.9.1-p378 reports: ‘match’: invalid byte sequence in UTF-8 ++



154
155
156
157
158
159
160
161
# File 'lib/dnote/notes.rb', line 154

def match_special_regex(label, file)
  mark = remark(file)
  if colon
    /#{mark}\s*#{Regexp.escape(label)}[:]\s+(.*?)$/
  else
    /#{mark}\s*#{Regexp.escape(label)}[:]?\s+(.*?)$/
  end
end

#parseObject

Gather notes. – TODO: Play golf with Notes#parse. ++



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/dnote/notes.rb', line 89

def parse
  records = []
  files.each do |fname|
    next unless File.file?(fname)

    mark = remark(fname)
    lineno = 0
    note = nil
    text = nil
    capt = nil
    File.readlines(fname).each do |line|
      lineno += 1
      note = match(line, lineno, fname)
      if note
        text = note.text
        capt = note.capture
        records << note
      elsif text
        case line
        when /^\s*#{mark}+\s*$/, /^\s*#{mark}\-\-/, /^\s*#{mark}\+\+/
          text.strip!
          text = nil
        when /^\s*#{mark}/
          if text[-1, 1] == "\n"
            text << line.gsub(/^\s*#{mark}\s*/, '')
          else
            text << "\n" << line.gsub(/^\s*#{mark}\s*/, '')
          end
        else
          text.strip!
          text = nil
        end
      elsif line !~ /^\s*#{mark}/
        capt << line if capt && capt.size < context
      end
    end
  end

  @notes = records.sort
end

#remark(file) ⇒ Object



251
252
253
254
255
256
# File 'lib/dnote/notes.rb', line 251

def remark(file)
  @remark[File.extname(file)] ||= begin
    mark = guess_marker(file)
    Regexp.escape(mark)
  end
end

#to_aObject

Convert to an array of hashes.



242
243
244
# File 'lib/dnote/notes.rb', line 242

def to_a
  notes.map(&:to_h)
end

#to_hObject

Same as #by_label.



247
248
249
# File 'lib/dnote/notes.rb', line 247

def to_h
  by_label
end