annotations 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []