annotations 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in annotations.gemspec
4
+ gemspec
5
+
6
+ # TODO: Test me
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2012 David Demaree
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ Portions of this software are extracted from Railties, part of the Ruby
25
+ on Rails project (http://github.com/rails/rails), copyright (c) 2004-2011
26
+ David Heinemeier Hansson. Ruby on Rails is open source software released
27
+ under the MIT license.
data/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # Annotations
2
+
3
+ Extracts and displays annotations from source code comments like these:
4
+
5
+ class MyModel
6
+ def find(id)
7
+ # TODO: Find the thing
8
+ end
9
+ end
10
+
11
+ The output looks like this:
12
+
13
+ ./lib/my_model.rb:
14
+ * [ 17] [TODO] Find the thing
15
+
16
+ If this looks familiar from Rails, it's because Annotations is derived/forked from the annotations code in Rails 3.2.1, now extracted into its own gem so it can be used in non-Rails (or even non-Ruby) projects.
17
+
18
+ Annotations looks for TODO, FIXME, and OPTIMIZE comments in the following kinds of source code files:
19
+
20
+ <table>
21
+ <thead>
22
+ <tr class="header-row">
23
+ <th>Syntax</th>
24
+ <th>Supported file extensions</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <tr>
29
+ <td><b>Ruby</b></td>
30
+ <td>.rb, .builder, Gemfile, Rakefile</td>
31
+ </tr>
32
+ <tr>
33
+ <td><b>ERb</b></td>
34
+ <td>.erb, .rhtml</td>
35
+ </tr>
36
+ <tr>
37
+ <td><b>CoffeeScript</b></td>
38
+ <td>.coffee</td>
39
+ </tr>
40
+ <tr>
41
+ <td><b>Sass</b></td>
42
+ <td>.scss, .sass</td>
43
+ </tr>
44
+ <tr>
45
+ <td><b>PHP</b></td>
46
+ <td>.php</td>
47
+ </tr>
48
+ </tbody>
49
+ </table>
50
+
51
+ ## Installation
52
+
53
+ Add this line to your application's Gemfile:
54
+
55
+ gem 'annotations'
56
+
57
+ Or install it yourself as:
58
+
59
+ $ gem install annotations
60
+
61
+ ## Usage
62
+
63
+ Add the Annotations tasks to your Rakefile:
64
+
65
+ ```ruby
66
+ require 'annotations/rake_task'
67
+
68
+ Annotations::RakeTask.new
69
+ ```
70
+
71
+ This will add the following tasks:
72
+
73
+ $ bundle exec rake -T notes
74
+ rake notes # Enumerate all annotations
75
+ rake notes:custom[annotation] # Enumerate a custom annotation
76
+ rake notes:fixme # Enumerate all FIXME annotations
77
+ rake notes:optimize # Enumerate all OPTIMIZE annotations
78
+ rake notes:todo # Enumerate all TODO annotations
79
+
80
+ If you want to name the tasks something other than "notes", just pass the name you want to use into `RakeTask.new`:
81
+
82
+ ```ruby
83
+ Annotations::RakeTask.new(:devnotes)
84
+ ```
85
+
86
+ You can also set the default tag list when defining the task, using this block syntax:
87
+
88
+ ```ruby
89
+ Annotations::RakeTask.new do |t|
90
+ # This will add an additional 'WTF' annotation; it will be included in
91
+ # `rake notes`, and a `rake notes:wtf` task will be added
92
+ t.tags = [:fixme, :optimize, :todo, :wtf]
93
+ end
94
+ ```
95
+
96
+ ## Roadmap
97
+
98
+ * Ability to set/limit the search path(s) for annotations (currently set to '.')
99
+ * Color output
100
+ * Standalone command-line tool (e.g. `annotations wtf todo --color`)
101
+ * More robust handling of different extensions/comment formats, plus the ability to easily add in new ones
102
+ * Test coverage!!
103
+
104
+ ## Contributing
105
+
106
+ Fork the project, make some changes on a feature branch, then send a pull request.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "annotations/rake_task"
4
+
5
+ Annotations::RakeTask.new(:notes)
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/annotations/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["David Demaree"]
6
+ gem.email = ["ddemaree@gmail.com"]
7
+ gem.description = %q{Source code annotations, extracted from Rails.}
8
+ gem.summary = %q{Extracts and displays tagged annotations from your source code.}
9
+ gem.homepage = "http://github.com/ddemaree/annotations"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "annotations"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Annotations::VERSION
17
+
18
+ gem.add_runtime_dependency "rake"
19
+ end
@@ -0,0 +1,114 @@
1
+ module Annotations
2
+ # Implements the logic behind the rake tasks for annotations like
3
+ #
4
+ # rake notes
5
+ # rake notes:optimize
6
+ #
7
+ # and friends. See <tt>rake -T notes</tt> and <tt>railties/lib/tasks/annotations.rake</tt>.
8
+ #
9
+ # Annotation objects are triplets <tt>:line</tt>, <tt>:tag</tt>, <tt>:text</tt> that
10
+ # represent the line where the annotation lives, its tag, and its text. Note
11
+ # the filename is not stored.
12
+ #
13
+ # Annotations are looked for in comments and modulus whitespace they have to
14
+ # start with the tag optionally followed by a colon. Everything up to the end
15
+ # of the line (or closing ERB comment tag) is considered to be their text.
16
+ class Extractor
17
+ # TODO: Test me
18
+ class Annotation < Struct.new(:line, :tag, :text)
19
+
20
+ # Returns a representation of the annotation that looks like this:
21
+ #
22
+ # [126] [TODO] This algorithm is simple and clearly correct, make it faster.
23
+ #
24
+ # If +options+ has a flag <tt>:tag</tt> the tag is shown as in the example above.
25
+ # Otherwise the string contains just line and text.
26
+ def to_s(options={})
27
+ s = "[%3d] " % line
28
+ s << "[#{tag}] " if options[:tag]
29
+ s << text
30
+ end
31
+ end
32
+
33
+ # Prints all annotations with tag +tag+ under the root directories +app+, +lib+,
34
+ # and +test+ (recursively). Only filenames with extension +.builder+, +.rb+,
35
+ # +.rxml+, +.rhtml+, or +.erb+ are taken into account. The +options+
36
+ # hash is passed to each annotation's +to_s+.
37
+ #
38
+ # This class method is the single entry point for the rake tasks.
39
+ def self.enumerate(tag, options={})
40
+ extractor = new(tag)
41
+ extractor.display(extractor.find, options)
42
+ end
43
+
44
+ attr_reader :tag
45
+
46
+ def initialize(tag)
47
+ @tag = tag
48
+ end
49
+
50
+ # Returns a hash that maps filenames under +dirs+ (recursively) to arrays
51
+ # with their annotations. Only files with annotations are included, and only
52
+ # those with extension +.builder+, +.rb+, +.rxml+, +.rhtml+, and +.erb+
53
+ # are taken into account.
54
+ # TODO: Make dirs configurable
55
+ def find(dirs=%w(.))
56
+ dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
57
+ end
58
+
59
+ # Returns a hash that maps filenames under +dir+ (recursively) to arrays
60
+ # with their annotations. Only files with annotations are included, and only
61
+ # those with extension +.builder+, +.rb+, +.rxml+, +.rhtml+, and +.erb+
62
+ # are taken into account.
63
+ def find_in(dir)
64
+ results = {}
65
+
66
+ Dir.glob("#{dir}/*") do |item|
67
+ next if File.basename(item)[0] == ?.
68
+
69
+ if File.directory?(item)
70
+ results.update(find_in(item))
71
+ # Ruby source code
72
+ elsif item =~ /\.(ru|builder|coffee|(r(?:b|xml|js)))$/
73
+ results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
74
+ # Other Ruby source files (Rake, Bundler)
75
+ elsif item =~ /(Rakefile|Gemfile|Guardfile)$/
76
+ results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
77
+ # ERb templates
78
+ elsif item =~ /\.(rhtml|erb)$/
79
+ results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
80
+ # Sass, JavaScript, PHP, other source with double-slash comments
81
+ elsif item =~ /\.(s(?:a|c)ss|js|php)$/
82
+ results.update(extract_annotations_from(item, /\/\/\s*(#{tag}):?\s*(.*)$/))
83
+ end
84
+ end
85
+
86
+ results
87
+ end
88
+
89
+ # If +file+ is the filename of a file that contains annotations this method returns
90
+ # a hash with a single entry that maps +file+ to an array of its annotations.
91
+ # Otherwise it returns an empty hash.
92
+ def extract_annotations_from(file, pattern)
93
+ lineno = 0
94
+ result = File.readlines(file).inject([]) do |list, line|
95
+ lineno += 1
96
+ next list unless line =~ pattern
97
+ list << Annotation.new(lineno, $1, $2)
98
+ end
99
+ result.empty? ? {} : { file => result }
100
+ end
101
+
102
+ # Prints the mapping from filenames to annotations in +results+ ordered by filename.
103
+ # The +options+ hash is passed to each annotation's +to_s+.
104
+ def display(results, options={})
105
+ results.keys.sort.each do |file|
106
+ puts "#{file}:"
107
+ results[file].each do |note|
108
+ puts " * #{note.to_s(options)}"
109
+ end
110
+ puts
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,70 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+ require 'annotations'
4
+
5
+ module Annotations
6
+ class RakeTask < ::Rake::TaskLib
7
+
8
+ attr_accessor :name, :tags
9
+
10
+ def initialize(name = :notes)
11
+ @name = name
12
+ @tags = [:optimize, :fixme, :todo]
13
+ define
14
+ end
15
+
16
+ def tags_to_pattern
17
+ @tags.map { |t| t.to_s.upcase }.join("|")
18
+ end
19
+
20
+ # Define tasks
21
+ def define
22
+ desc "Enumerate all annotations"
23
+ task name do
24
+ Annotations::Extractor.enumerate(tags_to_pattern, :tag => true)
25
+ end
26
+
27
+ namespace name do
28
+ tags.each do |tagname|
29
+ desc "Enumerate all #{tagname.to_s.upcase} annotations"
30
+ task tagname.to_sym do
31
+ Annotations::Extractor.enumerate(tagname.to_s.upcase, :tag => true)
32
+ end
33
+ end
34
+
35
+ desc "Enumerate a custom annotation, specify with ANNOTATION=CUSTOM"
36
+ task :custom, :annotation do |annotation|
37
+ puts annotation
38
+ SourceAnnotationExtractor.enumerate ENV['ANNOTATION']
39
+ end
40
+ end
41
+
42
+ # desc name == :notes ? "Compile assets" : "Compile #{name} assets"
43
+ # desc "Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)"
44
+ # task name do
45
+ # with_logger do
46
+ # manifest.compile(assets)
47
+ # end
48
+ # end
49
+
50
+ # desc name == :assets ? "Remove all assets" : "Remove all #{name} assets"
51
+ # task "clobber_#{name}" do
52
+ # with_logger do
53
+ # manifest.clobber
54
+ # end
55
+ # end
56
+
57
+ # task :clobber => ["clobber_#{name}"]
58
+
59
+ # desc name == :assets ? "Clean old assets" : "Clean old #{name} assets"
60
+ # task "clean_#{name}" do
61
+ # with_logger do
62
+ # manifest.clean(keep)
63
+ # end
64
+ # end
65
+
66
+ # task :clean => ["clean_#{name}"]
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module Annotations
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "annotations/version"
2
+
3
+ module Annotations
4
+ end
5
+
6
+ require "annotations/extractor"
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: annotations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Demaree
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70261740354860 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70261740354860
25
+ description: Source code annotations, extracted from Rails.
26
+ email:
27
+ - ddemaree@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - annotations.gemspec
38
+ - lib/annotations.rb
39
+ - lib/annotations/extractor.rb
40
+ - lib/annotations/rake_task.rb
41
+ - lib/annotations/version.rb
42
+ homepage: http://github.com/ddemaree/annotations
43
+ licenses: []
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ segments:
55
+ - 0
56
+ hash: 1938988108369687575
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ segments:
64
+ - 0
65
+ hash: 1938988108369687575
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.11
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Extracts and displays tagged annotations from your source code.
72
+ test_files: []