todidnt 0.0.0 → 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/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
  ruby '1.9.3'
3
3
 
4
+ gem 'chronic'
5
+
4
6
  group 'test' do
5
7
  gem 'minitest'
6
8
  gem 'mocha'
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ Todidnt
2
+ ====
3
+
4
+ (:construction: This project is currently under construction! :construction:)
5
+
6
+ Todidnt is a utility to help you track down TODOs and FIXMEs that you always
7
+ said you'd do but haven't done yet.
8
+
9
+ Usage
10
+ ----
11
+
12
+ Install the gem:
13
+
14
+ gem install todidnt
15
+
16
+ Then, run `todidnt` in any Git repository directory:
17
+
18
+ $ todidnt
19
+
20
+ TODO[1]
21
+ ----
22
+
23
+ - Optimizing blame step
24
+ - Filtering by author, label
25
+ - Fancy formatted reports
26
+ - TODO stats
27
+
28
+ Credit
29
+ ----
30
+
31
+ Paul Battley (@threedaymonk) for initial idea/implementation and witty name.
32
+
33
+ 1: Oh, the irony.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ task :test do
2
+ $LOAD_PATH << './test'
3
+ Dir.glob('test/test_*.rb').each { |t| require File.basename(t) }
4
+ end
data/bin/todidnt CHANGED
@@ -1,15 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'optparse'
4
-
5
- require_relative '../lib/todidnt'
4
+ require 'todidnt'
6
5
 
7
6
  options = {:path => '.'}
7
+ command = ARGV.shift
8
+
8
9
  ARGV.options do |opts|
9
10
  opts.on('-p', '--path PATH', 'Git directory to run Todidnt in (default: current directory)') do |path|
10
11
  options[:path] = path
11
12
  end
12
13
 
14
+ opts.on('-d', '--date STRING', 'Fuzzy string for overdue date comparison, e.g. last week or 7/2/2013 (default: today)') do |date|
15
+ options[:date] = date
16
+ end
17
+
13
18
  opts.on_tail('-h', '--help', 'Show this message') do
14
19
  puts opts
15
20
  exit
@@ -18,4 +23,4 @@ ARGV.options do |opts|
18
23
  opts.parse!
19
24
  end
20
25
 
21
- Todidnt::Runner.start(options)
26
+ Todidnt::CLI.run(command, options)
@@ -2,7 +2,7 @@ module Todidnt
2
2
  class TodoLine
3
3
  IGNORE = %r{assets/js|third_?party|node_modules|jquery|Binary}
4
4
 
5
- attr_reader :filename, :line_number, :content, :author
5
+ attr_reader :filename, :line_number, :content, :author, :timestamp
6
6
 
7
7
  def self.all(expressions)
8
8
  options = [['-n']]
data/lib/todidnt.rb CHANGED
@@ -1,10 +1,57 @@
1
- require_relative 'todidnt/git_repo'
2
- require_relative 'todidnt/git_command'
3
- require_relative 'todidnt/todo_line'
1
+ require 'todidnt/git_repo'
2
+ require 'todidnt/git_command'
3
+ require 'todidnt/todo_line'
4
+
5
+ require 'chronic'
4
6
 
5
7
  module Todidnt
6
- class Runner
7
- def self.start(options)
8
+ class CLI
9
+ VALID_COMMANDS = %w{all overdue}
10
+
11
+ def self.run(command, options)
12
+ if command && VALID_COMMANDS.include?(command)
13
+ self.send(command, options)
14
+ elsif command
15
+ $stderr.puts("Sorry, `#{command}` is not a valid command.")
16
+ exit
17
+ else
18
+ $stderr.puts("You must specify a command! Try `todidnt all`.")
19
+ end
20
+ end
21
+
22
+ def self.all(options)
23
+ all_lines = self.all_lines(options)
24
+
25
+ puts "\nResults:"
26
+ all_lines.sort_by do |line|
27
+ line.timestamp
28
+ end.each do |line|
29
+ puts line.pretty
30
+ end
31
+ end
32
+
33
+ def self.overdue(options)
34
+ date = Chronic.parse(options[:date] || 'now', :context => :past)
35
+ if date.nil?
36
+ $stderr.puts("Invalid date passed: #{options[:date]}")
37
+ exit
38
+ else
39
+ puts "Finding overdue TODOs (created before #{date.strftime('%F')})..."
40
+ end
41
+
42
+ all_lines = self.all_lines(options)
43
+
44
+ puts "\nResults:"
45
+ all_lines.sort_by do |line|
46
+ line.timestamp
47
+ end.select do |line|
48
+ line.timestamp < date.to_i
49
+ end.each do |line|
50
+ puts line.pretty
51
+ end
52
+ end
53
+
54
+ def self.all_lines(options)
8
55
  GitRepo.new(options[:path]).run do |path|
9
56
  puts "Running in #{path || 'current directory'}..."
10
57
  lines = TodoLine.all(["TODO"])
@@ -15,10 +62,7 @@ module Todidnt
15
62
  $stdout.write "\rBlamed: #{i}/#{lines.count}"
16
63
  end
17
64
 
18
- puts "\nResults:"
19
- lines.each do |line|
20
- puts line.pretty
21
- end
65
+ lines
22
66
  end
23
67
  end
24
68
  end
data/test/lib.rb CHANGED
@@ -1,8 +1,11 @@
1
+ unless defined? Todidnt
2
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
3
+ require 'todidnt'
4
+ end
5
+
1
6
  require 'minitest/spec'
2
7
  require 'minitest/autorun'
3
8
  require 'mocha/setup'
4
9
 
5
- require_relative '../lib/todidnt'
6
-
7
10
  class Test < MiniTest::Spec
8
11
  end
@@ -0,0 +1,108 @@
1
+ require 'lib'
2
+
3
+ class TestTodoLine < Test
4
+ before do
5
+ Todidnt::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
+ Todidnt::GitCommand.expects(:new).with(:grep, [['-n'], ['-e', 'hello']]).returns(grep)
15
+ Todidnt::TodoLine.all(['hello'])
16
+
17
+ Todidnt::GitCommand.expects(:new).with(:grep, [['-n'], ['-e', 'hello'], ['-e', 'goodbye']]).returns(grep)
18
+ Todidnt::TodoLine.all(['hello', 'goodbye'])
19
+ end
20
+
21
+ it 'creates a TodoLine object for each result line properly' do
22
+ Todidnt::GitCommand.any_instance.expects(:output_lines).returns(
23
+ [
24
+ 'filename.rb:12: content',
25
+ 'other_filename.rb:643: TODO'
26
+ ]
27
+ )
28
+
29
+ Todidnt::TodoLine.expects(:new).with('filename.rb', 12, 'content')
30
+ Todidnt::TodoLine.expects(:new).with('other_filename.rb', 643, 'TODO')
31
+
32
+ Todidnt::TodoLine.all(['anything'])
33
+ end
34
+ end
35
+
36
+ describe 'functional' do
37
+ it 'returns a list of TodoLine objects as matches' do
38
+ Todidnt::GitCommand.any_instance.expects(:output_lines).returns(
39
+ [
40
+ 'filename.rb:12: content',
41
+ 'other_filename.rb:643: TODO'
42
+ ]
43
+ )
44
+
45
+ todos = Todidnt::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
+ Todidnt::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 = Todidnt::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
+ blame = mock()
78
+ blame.expects(:output_lines).returns([])
79
+ Todidnt::GitCommand.expects(:new).with(:blame,
80
+ [
81
+ ['--line-porcelain'],
82
+ ['-L', '50,50'],
83
+ ['filename.rb']
84
+ ]
85
+ ).returns(blame)
86
+
87
+ todo_line = Todidnt::TodoLine.new('filename.rb', 50, 'commit message')
88
+ todo_line.populate_blame
89
+ end
90
+
91
+ it 'sets author, timestamp properties on the TodoLine object' do
92
+ blame = mock()
93
+ blame.expects(:output_lines).returns(
94
+ %w{
95
+ 39efeb14a9 1 1
96
+ author Amber Feng
97
+ author-time 1383882788
98
+ author-mail <amber.feng@gmail.com>,
99
+ summary Commit message,
100
+ }
101
+ )
102
+ Todidnt::GitCommand.expects(:new).returns(blame)
103
+
104
+ todo_line = Todidnt::TodoLine.new('filename.rb', 50, 'commit message')
105
+ todo_line.populate_blame
106
+ end
107
+ end
108
+ end
data/todidnt.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'todidnt'
3
- s.version = '0.0.0'
3
+ s.version = '0.1.0'
4
4
  s.summary = 'Todidnt'
5
5
  s.description = "Todidnt finds and dates todos in your git repository."
6
6
  s.authors = ["Amber Feng"]
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.add_development_dependency('mocha')
11
11
 
12
12
  s.files = `git ls-files`.split("\n")
13
- s.test_files = `git ls-files -- test/*`.split("\n")
13
+ s.test_files = `git ls-files -- test/test_*.rb`.split("\n")
14
14
  s.executables = ['todidnt']
15
15
  s.require_paths = %w[lib]
16
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: todidnt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-07 00:00:00.000000000 Z
12
+ date: 2013-11-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -52,14 +52,15 @@ extra_rdoc_files: []
52
52
  files:
53
53
  - Gemfile
54
54
  - Gemfile.lock
55
- - README
55
+ - README.md
56
+ - Rakefile
56
57
  - bin/todidnt
57
58
  - lib/todidnt.rb
58
59
  - lib/todidnt/git_command.rb
59
60
  - lib/todidnt/git_repo.rb
60
61
  - lib/todidnt/todo_line.rb
61
62
  - test/lib.rb
62
- - test/todo_line.rb
63
+ - test/test_todo_line.rb
63
64
  - todidnt.gemspec
64
65
  homepage:
65
66
  licenses: []
@@ -86,5 +87,4 @@ signing_key:
86
87
  specification_version: 3
87
88
  summary: Todidnt
88
89
  test_files:
89
- - test/lib.rb
90
- - test/todo_line.rb
90
+ - test/test_todo_line.rb
data/README DELETED
@@ -1,9 +0,0 @@
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/test/todo_line.rb DELETED
@@ -1,86 +0,0 @@
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