lib/dnote/notes.rb in mvz-dnote-1.7.2 vs lib/dnote/notes.rb in mvz-dnote-1.8.0

- old
+ new

@@ -1,10 +1,11 @@ +# frozen_string_literal: true + require 'pathname' require 'dnote/note' module DNote - # = 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. @@ -18,14 +19,14 @@ #++ class Notes include Enumerable # Default paths (all ruby scripts). - DEFAULT_PATHS = ["**/*.rb"] + DEFAULT_PATHS = ['**/*.rb'].freeze # Default note labels to look for in source code. (NOT CURRENTLY USED!) - DEFAULT_LABELS = ['TODO', 'FIXME', 'OPTIMIZE', 'THINK', 'DEPRECATE'] + DEFAULT_LABELS = %w(TODO FIXME OPTIMIZE THINK DEPRECATE).freeze # Files to search for notes. attr_accessor :files # Labels to document. Defaults are: +TODO+, +FIXME+, +OPTIMIZE+ and +DEPRECATE+. @@ -42,37 +43,35 @@ # Number of lines of context to show. attr_accessor :context # New set of notes for give +files+ and optional special labels. - def initialize(files, options={}) + def initialize(files, options = {}) @files = [files].flatten @labels = [options[:labels] || DEFAULT_LABELS].flatten.compact @colon = options[:colon].nil? ? true : options[:colon] - @marker = options[:marker] #|| '#' + @marker = options[:marker] @url = options[:url] @context = options[:context] || 0 @remark = {} parse end # Array of notes. - def notes - @notes - end + attr_reader :notes # Notes counts by label. def counts - @counts ||= ( + @counts ||= begin h = {} by_label.each do |label, notes| h[label] = notes.size end h - ) + end end # Iterate through notes. def each(&block) notes.each(&block) @@ -89,50 +88,45 @@ #++ def parse records = [] files.each do |fname| next unless File.file?(fname) - #next unless fname =~ /\.rb$/ # TODO: should this be done? + mark = remark(fname) - lineno, note, text, capt = 0, nil, nil, nil + lineno = 0 + note = nil + text = nil + capt = nil File.readlines(fname).each do |line| - #while line = f.gets - lineno += 1 - note = match(line, lineno, fname) - if note - #file = fname - text = note.text - capt = note.capture - #note = {'label'=>label,'file'=>file,'line'=>line_no,'note'=>text} - records << note - else - if 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 + 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 - if line !~ /^\s*#{mark}/ - capt << line if capt && capt.size < context - end + text << "\n" << line.gsub(/^\s*#{mark}\s*/, '') end + else + text.strip! + text = nil end - #end + elsif line !~ /^\s*#{mark}/ + capt << line if capt && capt.size < context + end end end - @notes = records.sort + @notes = records.sort end # Is this line a note? def match(line, lineno, file) if labels.empty? @@ -144,21 +138,20 @@ # Match special notes. def match_special(line, lineno, file) rec = nil labels.each do |label| - if md = match_special_regex(label, file).match(line) + if (md = match_special_regex(label, file).match(line)) text = md[1] - #rec = {'label'=>label,'file'=>file,'line'=>lineno,'note'=>text} rec = Note.new(self, file, label, lineno, text, remark(file)) end end rec end #-- - # TODO: ruby-1.9.1-p378 reports: `match': invalid byte sequence in UTF-8 + # TODO: ruby-1.9.1-p378 reports: `match': invalid byte sequence in UTF-8 #++ def match_special_regex(label, file) mark = remark(file) if colon /#{mark}\s*#{Regexp.escape(label)}[:]\s+(.*?)$/ @@ -168,153 +161,119 @@ end # Match notes that are labeled with a colon. def match_general(line, lineno, file) rec = nil - if md = match_general_regex(file).match(line) - label, text = md[1], md[2] - #rec = {'label'=>label,'file'=>file,'line'=>lineno,'note'=>text} + 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 - return rec + rec end # Keep in mind that general non-colon matches have a higher potential # of false positives. def match_general_regex(file) mark = remark(file) if colon /#{mark}\s*([A-Z]+)[:]\s+(.*?)$/ - else + else /#{mark}\s*([A-Z]+)\s+(.*?)$/ end end # Organize notes into a hash with labels for keys. def by_label - @by_label ||= ( + @by_label ||= begin list = {} notes.each do |note| list[note.label] ||= [] list[note.label] << note - list[note.label].sort #!{ |a,b| a.line <=> b.line } + list[note.label].sort end list - ) + end end # Organize notes into a hash with filename for keys. def by_file - @by_file ||= ( + @by_file ||= begin list = {} notes.each do |note| list[note.file] ||= [] list[note.file] << note - list[note.file].sort! #!{ |a,b| a.line <=> b.line } + list[note.file].sort! end list - ) + end end # Organize notes into a hash with labels for keys, followed # by a hash with filename for keys. def by_label_file - @by_label ||= ( + @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! #{ |a,b| a.line <=> b.line } + list[note.label][note.file].sort! end list - ) + end end # Organize notes into a hash with filenames for keys, followed # by a hash with labels for keys. def by_file_label - @by_file ||= ( + @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! #{ |a,b| a.line <=> b.line } + list[note.file][note.label].sort! end list - ) + end end # Convert to an array of hashes. def to_a - notes.map{ |n| n.to_h } + notes.map(&:to_h) end # Same as #by_label. def to_h by_label end - # def remark(file) - @remark[File.extname(file)] ||= ( + @remark[File.extname(file)] ||= begin mark = guess_marker(file) Regexp.escape(mark) - ) + end end # Guess marker based on file extension. Fallsback to '#' # if the extension is unknown. # # TODO: Continue to add comment types. 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 - - # Convert to array of hashes then to YAML. - #def to_yaml - # require 'yaml' - # to_a.to_yaml - #end - - # Convert to array of hashes then to JSON. - #def to_json - # begin - # require 'json' - # rescue LoadError - # require 'json_pure' - # end - # to_a.to_json - #end - - # Convert to array of hashes then to a SOAP XML envelope. - #def to_soap - # require 'soap/marshal' - # SOAP::Marshal.marshal(to_a) - #end - - # XOXO microformat. - #-- - # TODO: Would to_xoxo be better organized by label and or file? - #++ - #def to_xoxo - # require 'xoxo' - # to_a.to_xoxo - #end - end - end -