todidnt 0.0.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/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ ruby '1.9.3'
3
+
4
+ group 'test' do
5
+ gem 'minitest'
6
+ gem 'mocha'
7
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ metaclass (0.0.1)
5
+ minitest (5.0.8)
6
+ mocha (0.14.0)
7
+ metaclass (~> 0.0.1)
8
+ trollop (2.0)
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ minitest
15
+ mocha
16
+ trollop
data/README ADDED
@@ -0,0 +1,9 @@
1
+ TODO:
2
+
3
+ - tests
4
+ - actual logging that is not putsing
5
+ - optimize blames
6
+ - html report?
7
+ - filter by person or time
8
+ - handle FIXME/XXX/custom
9
+ - stats
data/bin/todidnt ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require_relative '../lib/todidnt'
6
+
7
+ options = {:path => '.'}
8
+ ARGV.options do |opts|
9
+ opts.on('-p', '--path PATH', 'Git directory to run Todidnt in (default: current directory)') do |path|
10
+ options[:path] = path
11
+ end
12
+
13
+ opts.on_tail('-h', '--help', 'Show this message') do
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.parse!
19
+ end
20
+
21
+ Todidnt::Runner.start(options)
@@ -0,0 +1,26 @@
1
+ module Todidnt
2
+ class GitCommand
3
+ def initialize(command, options)
4
+ @command = command
5
+ @options = options
6
+ end
7
+
8
+ def output_lines
9
+ run!.strip.split(/\n/)
10
+ end
11
+
12
+ def run!
13
+ `git #{command_with_options}`
14
+ end
15
+
16
+ def command_with_options
17
+ full_command = @command.to_s
18
+
19
+ for option in @options
20
+ full_command << " #{option.join(' ')}"
21
+ end
22
+
23
+ full_command
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module Todidnt
2
+ class GitRepo
3
+ def initialize(path)
4
+ expanded_path = File.expand_path(path)
5
+
6
+ if File.exist?(File.join(expanded_path, '.git'))
7
+ @working_dir = expanded_path
8
+ else
9
+ $stderr.puts "Whoops, #{expanded_path} is not a git repository!"
10
+ exit
11
+ end
12
+ end
13
+
14
+ def run(&blk)
15
+ unless Dir.pwd == @working_dir
16
+ Dir.chdir(@working_dir) do
17
+ yield @working_dir
18
+ end
19
+ else
20
+ yield
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ module Todidnt
2
+ class TodoLine
3
+ IGNORE = %r{assets/js|third_?party|node_modules|jquery|Binary}
4
+
5
+ attr_reader :filename, :line_number, :content, :author
6
+
7
+ def self.all(expressions)
8
+ options = [['-n']]
9
+ expressions.each { |e| options << ['-e', e] }
10
+
11
+ grep = GitCommand.new(:grep, options)
12
+ grep.output_lines.map do |line|
13
+ filename, line_number, content = line.split(/:/, 3)
14
+ unless filename =~ IGNORE
15
+ lines = self.new(filename, line_number.to_i, content.strip[0..100])
16
+ end
17
+ end.compact
18
+ end
19
+
20
+ def initialize(filename, line_number, content)
21
+ @filename = filename
22
+ @line_number = line_number
23
+ @content = content
24
+ end
25
+
26
+ # TODO: This logic should probably be moved out somewhere else
27
+ def populate_blame
28
+ options = [
29
+ ['--line-porcelain'],
30
+ ['-L', "#{@line_number},#{@line_number}"],
31
+ [@filename]
32
+ ]
33
+
34
+ blame = GitCommand.new(:blame, options)
35
+ blame.output_lines.each do |line|
36
+ if (author = /author (.*)/.match(line))
37
+ @author = author[1]
38
+ elsif (author_time = /author-time (.*)/.match(line))
39
+ @timestamp = author_time[1].to_i
40
+ end
41
+ end
42
+ end
43
+
44
+ def pretty_time
45
+ Time.at(@timestamp).strftime('%F')
46
+ end
47
+
48
+ def pretty
49
+ "#{pretty_time} (#{author}, #{filename}:#{line_number}): #{content}"
50
+ end
51
+ end
52
+ end
data/lib/todidnt.rb ADDED
@@ -0,0 +1,25 @@
1
+ require_relative 'todidnt/git_repo'
2
+ require_relative 'todidnt/git_command'
3
+ require_relative 'todidnt/todo_line'
4
+
5
+ module Todidnt
6
+ class Runner
7
+ def self.start(options)
8
+ GitRepo.new(options[:path]).run do |path|
9
+ puts "Running in #{path || 'current directory'}..."
10
+ lines = TodoLine.all(["TODO"])
11
+ puts "Found #{lines.count} TODOs. Blaming..."
12
+
13
+ lines.each_with_index do |todo, i|
14
+ todo.populate_blame
15
+ $stdout.write "\rBlamed: #{i}/#{lines.count}"
16
+ end
17
+
18
+ puts "\nResults:"
19
+ lines.each do |line|
20
+ puts line.pretty
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
data/test/lib.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ require 'mocha/setup'
4
+
5
+ require_relative '../lib/todidnt'
6
+
7
+ class Test < MiniTest::Spec
8
+ end
data/test/todo_line.rb ADDED
@@ -0,0 +1,86 @@
1
+ require_relative 'lib'
2
+
3
+ class TestTodoLine < Test
4
+ before do
5
+ GitCommand.any_instance.stubs(:run!)
6
+ end
7
+
8
+ describe '.all' do
9
+ describe 'unit' do
10
+ it 'constructs the correct `git grep` command' do
11
+ grep = mock()
12
+ grep.stubs(:output_lines => [])
13
+
14
+ GitCommand.expects(:new).with(:grep, [['-n'], ['-e', 'hello']]).returns(grep)
15
+ TodoLine.all(['hello'])
16
+
17
+ GitCommand.expects(:new).with(:grep, [['-n'], ['-e', 'hello'], ['-e', 'goodbye']]).returns(grep)
18
+ TodoLine.all(['hello', 'goodbye'])
19
+ end
20
+
21
+ it 'creates a TodoLine object for each result line properly' do
22
+ GitCommand.any_instance.expects(:output_lines).returns(
23
+ [
24
+ 'filename.rb:12: content',
25
+ 'other_filename.rb:643: TODO'
26
+ ]
27
+ )
28
+
29
+ TodoLine.expects(:new).with('filename.rb', 12, 'content')
30
+ TodoLine.expects(:new).with('other_filename.rb', 643, 'TODO')
31
+
32
+ TodoLine.all(['anything'])
33
+ end
34
+ end
35
+
36
+ describe 'functional' do
37
+ it 'returns a list of TodoLine objects as matches' do
38
+ GitCommand.any_instance.expects(:output_lines).returns(
39
+ [
40
+ 'filename.rb:12: content',
41
+ 'other_filename.rb:643: TODO'
42
+ ]
43
+ )
44
+
45
+ todos = TodoLine.all(['anything'])
46
+ assert_equal 2, todos.count
47
+
48
+ assert_equal 'filename.rb', todos.first.filename
49
+ assert_equal 12, todos.first.line_number
50
+ assert_equal 'content', todos.first.content
51
+
52
+ assert_equal 'other_filename.rb', todos.last.filename
53
+ assert_equal 643, todos.last.line_number
54
+ assert_equal 'TODO', todos.last.content
55
+ end
56
+
57
+ it 'ignores lines matching IGNORE list' do
58
+ GitCommand.any_instance.expects(:output_lines).returns(
59
+ [
60
+ 'filename.rb:12: content',
61
+ 'thirdparty/other_filename.rb:643: TODO'
62
+ ]
63
+ )
64
+
65
+ todos = TodoLine.all(['anything'])
66
+ assert_equal 1, todos.count
67
+
68
+ assert_equal 'filename.rb', todos.first.filename
69
+ assert_equal 12, todos.first.line_number
70
+ assert_equal 'content', todos.first.content
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#populate_blame' do
76
+ it 'constructs the correct `git blame` command' do
77
+ # TODO
78
+ skip
79
+ end
80
+
81
+ it 'sets author, timestamp properties on the TodoLine object' do
82
+ # TODO
83
+ skip
84
+ end
85
+ end
86
+ end
data/todidnt.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'todidnt'
3
+ s.version = '0.0.0'
4
+ s.summary = 'Todidnt'
5
+ s.description = "Todidnt finds and dates todos in your git repository."
6
+ s.authors = ["Amber Feng"]
7
+ s.email = 'amber.feng@gmail.com'
8
+
9
+ s.add_development_dependency('minitest')
10
+ s.add_development_dependency('mocha')
11
+
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files -- test/*`.split("\n")
14
+ s.executables = ['todidnt']
15
+ s.require_paths = %w[lib]
16
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: todidnt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Amber Feng
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitest
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mocha
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Todidnt finds and dates todos in your git repository.
47
+ email: amber.feng@gmail.com
48
+ executables:
49
+ - todidnt
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - Gemfile
54
+ - Gemfile.lock
55
+ - README
56
+ - bin/todidnt
57
+ - lib/todidnt.rb
58
+ - lib/todidnt/git_command.rb
59
+ - lib/todidnt/git_repo.rb
60
+ - lib/todidnt/todo_line.rb
61
+ - test/lib.rb
62
+ - test/todo_line.rb
63
+ - todidnt.gemspec
64
+ homepage:
65
+ licenses: []
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 1.8.23
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Todidnt
88
+ test_files:
89
+ - test/lib.rb
90
+ - test/todo_line.rb