# The following code is based on Bones 2.5.1 # module Bones # A helper class used to find and display any annotations in a collection of # project files. # class AnnotationExtractor class Annotation < Struct.new(:line, :tag, :text) # Returns a string representation of the annotation. If the # :tag parameter is given as +true+, then the annotation tag # will be included in the string. # def to_s( opts = {} ) s = "[%3d] " % line s << "[#{tag}] " if opts[:tag] s << text end end # Enumerate all the annoations for the given _project_ and _tag_. This # will search for all athe annotations and display them on standard # output. # def self.enumerate tag, id = nil, opts = {} extractor = new(tag, id) extractor.display(extractor.find, opts) end attr_reader :tag, :id # Creates a new annotation extractor configured to use the _project_ open # strcut and to search for the given _tag_ (which can be more than one tag # via a regular expression 'or' operation -- i.e. THIS|THAT|OTHER) # def initialize tag, id @tag = tag @id = @id_rgxp = nil unless id.nil? or id.empty? @id = id @id_rgxp = Regexp.new(Regexp.escape(id), Regexp::IGNORECASE) end end # Iterate over all the files in the project and extract annotations from # the those files. Returns the results as a hash for display. # def find results = {} rgxp = %r/(#{tag}):?\s*(.*?)(?:\s*(?:-?%>|\*+\/))?$/o files = Dir.glob("lib/**/*.rb") files += Dir.glob("test/**/*.rb") files += Dir.glob("bin/*") files.each do |fn| results.update(extract_annotations_from(fn, rgxp)) end results end # Extract any annotations from the given _file_ using the regular # expression _pattern_ provided. # def extract_annotations_from( file, pattern ) lineno = 0 result = File.readlines(file).inject([]) do |list, line| lineno += 1 next list unless m = pattern.match(line) next list << Annotation.new(lineno, m[1], m[2]) unless id text = m[2] if text =~ @id_rgxp list << Annotation.new(lineno, m[1], text) end list end result.empty? ? {} : { file => result } end # Print the results of the annotation extraction to the screen. If the # :tags option is set to +true+, then the annotation tag will be # displayed. # def display( results, opts = {} ) results.keys.sort.each do |file| puts "#{file}:" results[file].each do |note| puts " * #{note.to_s(opts)}" end puts end end end # class AnnotationExtractor end # module Bones note_tags = ["TODO", "FIXME", "OPTIMIZE"] desc "Enumerate all annotations" task :notes do |t| id = if t.application.top_level_tasks.length > 1 t.application.top_level_tasks.slice!(1..-1).join(' ') end Bones::AnnotationExtractor.enumerate( note_tags.join('|'), id, :tag => true) end namespace :notes do note_tags.each do |tag| desc "Enumerate all #{tag} annotations" task tag.downcase.to_sym do |t| id = if t.application.top_level_tasks.length > 1 t.application.top_level_tasks.slice!(1..-1).join(' ') end Bones::AnnotationExtractor.enumerate(tag, id) end end end