todo_lint 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/lib/todo_lint/cli.rb +4 -3
- data/lib/todo_lint/config_file.rb +18 -1
- data/lib/todo_lint/due_date.rb +24 -4
- data/lib/todo_lint/judge.rb +24 -4
- data/lib/todo_lint/todo.rb +61 -8
- data/lib/todo_lint/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8dd171321dda2f34a965d06f4db8a014fbd6972c
|
4
|
+
data.tar.gz: 2790af0c8f0d386ede48b57d7122bbefd141224f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ecf76a06b3f3da22f3d39b9152e4d99aa6fbbe95e7fb377c2211846fba7a55b35f7c8e015daf21cd60cbfd30429fb614b83168cc81c233a0ef3b2752eaffc87
|
7
|
+
data.tar.gz: f59058158b7f2e2bd76be1253106b779987034c947e58fb02ddb09ed3763c0e23d985e0c7d675e06f6faf280e74cf20c6f5ccba38cba1a1b62260a1e82730ca6
|
data/.rubocop.yml
CHANGED
data/lib/todo_lint/cli.rb
CHANGED
@@ -64,7 +64,7 @@ module TodoLint
|
|
64
64
|
files = load_files(finder)
|
65
65
|
files_count = files.count
|
66
66
|
reports = files.map do |file|
|
67
|
-
Todo.within(File.open(file)).map do |todo|
|
67
|
+
Todo.within(File.open(file), :config => @options).map do |todo|
|
68
68
|
reporter = Reporter.new(todo,
|
69
69
|
:judge => Judge.new(todo))
|
70
70
|
reporter.report.tap do |report|
|
@@ -96,11 +96,12 @@ module TodoLint
|
|
96
96
|
finder = FileFinder.new(path, options)
|
97
97
|
files = load_files(finder)
|
98
98
|
files.each do |file|
|
99
|
-
todos += Todo.within(File.open(file))
|
99
|
+
todos += Todo.within(File.open(file), :config => @options)
|
100
100
|
end
|
101
101
|
todos.sort.each.with_index do |todo, num|
|
102
102
|
due_date = if todo.due_date
|
103
|
-
|
103
|
+
tag_context = " via #{todo.tag}" if todo.tag?
|
104
|
+
Rainbow(" (due #{todo.due_date.to_date}#{tag_context})")
|
104
105
|
.public_send(todo.due_date.overdue? ? :red : :blue)
|
105
106
|
else
|
106
107
|
Rainbow(" (no due date)").red
|
@@ -5,12 +5,13 @@ module TodoLint
|
|
5
5
|
class ConfigFile
|
6
6
|
# Parses the config file and loads the options
|
7
7
|
# @api public
|
8
|
-
# @example ConfigFile.new.
|
8
|
+
# @example ConfigFile.new.read_config_file('.todo-lint.yml')
|
9
9
|
# @return [Hash] parsed file-options
|
10
10
|
def read_config_file(file)
|
11
11
|
@config_hash = YAML.load_file(file)
|
12
12
|
@starting_path = File.expand_path(File.split(file).first)
|
13
13
|
@config_options = {}
|
14
|
+
load_tags
|
14
15
|
load_file_exclusions
|
15
16
|
load_extension_inclusions
|
16
17
|
config_options
|
@@ -51,5 +52,21 @@ module TodoLint
|
|
51
52
|
return unless config_hash["Extensions"]
|
52
53
|
config_options[:extensions] = config_hash["Extensions"]
|
53
54
|
end
|
55
|
+
|
56
|
+
# Load the tags from the configuration file as DueDates
|
57
|
+
#
|
58
|
+
# @return is irrelevant
|
59
|
+
# @api private
|
60
|
+
def load_tags
|
61
|
+
config_options[:tags] = {}
|
62
|
+
return unless config_hash["Tags"]
|
63
|
+
config_hash["Tags"].each do |tag, due_date|
|
64
|
+
unless due_date.is_a? Date
|
65
|
+
raise ArgumentError, "#{due_date} is not a date"
|
66
|
+
end
|
67
|
+
|
68
|
+
config_options[:tags]["##{tag}"] = DueDate.new(due_date)
|
69
|
+
end
|
70
|
+
end
|
54
71
|
end
|
55
72
|
end
|
data/lib/todo_lint/due_date.rb
CHANGED
@@ -3,7 +3,18 @@ require "date"
|
|
3
3
|
module TodoLint
|
4
4
|
# When is this todo actually due? When ought we be reminded of this one?
|
5
5
|
class DueDate
|
6
|
-
|
6
|
+
DATE_PATTERN = /(\d{4})-(\d{2})-(\d{2})/
|
7
|
+
ANNOTATION_PATTERN = /\(#{DATE_PATTERN}\)/
|
8
|
+
|
9
|
+
# Parse the date from the todo_lint configuration file
|
10
|
+
# @example
|
11
|
+
# DueDate.from_config_file("2015-04-14")
|
12
|
+
# @return [DueDate] if the annotation is formatted properly
|
13
|
+
# @raise [ArgumentError] if the annotation is not formatted properly
|
14
|
+
# @api public
|
15
|
+
def self.from_config_file(date)
|
16
|
+
from_pattern(date, DATE_PATTERN)
|
17
|
+
end
|
7
18
|
|
8
19
|
# Parse the date from the todo comment's due date annotation
|
9
20
|
# @example
|
@@ -11,14 +22,23 @@ module TodoLint
|
|
11
22
|
# @return [DueDate] if the annotation is formatted properly
|
12
23
|
# @raise [ArgumentError] if the annotation is not formatted properly
|
13
24
|
# @api public
|
14
|
-
def self.from_annotation(
|
15
|
-
|
25
|
+
def self.from_annotation(date)
|
26
|
+
from_pattern(date, ANNOTATION_PATTERN)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Helper method for extracting dates from patterns
|
30
|
+
# @return [DueDate] if pattern matches
|
31
|
+
# @raise [ArgumentError] if pattern does not match
|
32
|
+
# @api private
|
33
|
+
def self.from_pattern(date, pattern)
|
34
|
+
if (match = pattern.match(date))
|
16
35
|
DueDate.new(Date.new(match[1].to_i, match[2].to_i, match[3].to_i))
|
17
36
|
else
|
18
|
-
msg = "not a properly formatted
|
37
|
+
msg = "not a properly formatted date: #{date.inspect}"
|
19
38
|
raise ArgumentError, msg
|
20
39
|
end
|
21
40
|
end
|
41
|
+
private_class_method :from_pattern
|
22
42
|
|
23
43
|
# The actual date object when something is due
|
24
44
|
# @example
|
data/lib/todo_lint/judge.rb
CHANGED
@@ -15,10 +15,30 @@ module TodoLint
|
|
15
15
|
# Judge.new(todo)
|
16
16
|
# @api public
|
17
17
|
def initialize(todo)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
@todo = todo
|
19
|
+
@charge = make_charge
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Which todo is being judged?
|
25
|
+
#
|
26
|
+
# @return [Todo]
|
27
|
+
# @api private
|
28
|
+
attr_reader :todo
|
29
|
+
|
30
|
+
# What is the problem with this todo?
|
31
|
+
#
|
32
|
+
# @return [String] if there's a problem
|
33
|
+
# @return [NilClass] if no charge needed
|
34
|
+
# @api private
|
35
|
+
def make_charge
|
36
|
+
if !todo.annotated?
|
37
|
+
"Missing due date annotation"
|
38
|
+
elsif todo.due_date.overdue? && todo.tag?
|
39
|
+
"Overdue due date #{todo.due_date.to_date} via tag"
|
40
|
+
elsif todo.due_date.overdue?
|
41
|
+
"Overdue due date"
|
22
42
|
end
|
23
43
|
end
|
24
44
|
end
|
data/lib/todo_lint/todo.rb
CHANGED
@@ -5,8 +5,9 @@ module TodoLint
|
|
5
5
|
PATTERN = /
|
6
6
|
(?<flag> TODO ){0}
|
7
7
|
(?<due_date> \(\d{4}-\d{2}-\d{2}\)){0}
|
8
|
+
(?<tag>\#\w+){0}
|
8
9
|
(?<task>.+){0}
|
9
|
-
\g<flag
|
10
|
+
\g<flag>(?:\g<due_date>|(?:\(\g<tag>\)))?: \g<task>
|
10
11
|
/x
|
11
12
|
|
12
13
|
# Search a file for all of the todo/fixme/etc comments within it
|
@@ -14,11 +15,15 @@ module TodoLint
|
|
14
15
|
# Todo.within(File.open("app.rb"))
|
15
16
|
# @api public
|
16
17
|
# @return [Array<Todo>]
|
17
|
-
def self.within(file)
|
18
|
+
def self.within(file, config: RequiredArg.new(:config))
|
18
19
|
file.each_line.with_index.map do |line, line_number|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
next unless present_in?(line)
|
21
|
+
new(
|
22
|
+
line,
|
23
|
+
:line_number => line_number + 1,
|
24
|
+
:path => file.path,
|
25
|
+
:config => config
|
26
|
+
)
|
22
27
|
end.compact
|
23
28
|
end
|
24
29
|
|
@@ -60,11 +65,13 @@ module TodoLint
|
|
60
65
|
# @api public
|
61
66
|
def initialize(line,
|
62
67
|
line_number: RequiredArg.new(:line_number),
|
63
|
-
path: RequiredArg.new(:path)
|
68
|
+
path: RequiredArg.new(:path),
|
69
|
+
config: RequiredArg.new(:config))
|
64
70
|
absent_todo!(line) unless self.class.present_in?(line)
|
65
71
|
@line = line
|
66
72
|
@line_number = line_number
|
67
73
|
@path = path
|
74
|
+
@config = config
|
68
75
|
end
|
69
76
|
|
70
77
|
# Was this todo annotated with a due date?
|
@@ -77,7 +84,7 @@ module TodoLint
|
|
77
84
|
# @return [Boolean]
|
78
85
|
# @api public
|
79
86
|
def annotated?
|
80
|
-
!match[:due_date].nil?
|
87
|
+
!match[:due_date].nil? || !match[:tag].nil?
|
81
88
|
end
|
82
89
|
|
83
90
|
# What is the actual task associated with this todo?
|
@@ -101,7 +108,13 @@ module TodoLint
|
|
101
108
|
# @return [NilClass] if there is no due date
|
102
109
|
# @api public
|
103
110
|
def due_date
|
104
|
-
|
111
|
+
return unless annotated?
|
112
|
+
return @due_date if defined?(@due_date)
|
113
|
+
@due_date = if match[:due_date]
|
114
|
+
DueDate.from_annotation(match[:due_date])
|
115
|
+
elsif match[:tag]
|
116
|
+
lookup_tag_due_date
|
117
|
+
end
|
105
118
|
end
|
106
119
|
|
107
120
|
# What did the developer write to get our attention?
|
@@ -122,6 +135,29 @@ module TodoLint
|
|
122
135
|
(line =~ PATTERN) + 1
|
123
136
|
end
|
124
137
|
|
138
|
+
# Was this todo using a tag (as opposed to a direct due date)?
|
139
|
+
#
|
140
|
+
# @example
|
141
|
+
# todo.tag? #=> true
|
142
|
+
# @return [Boolean]
|
143
|
+
# @api public
|
144
|
+
def tag?
|
145
|
+
!match[:tag].nil?
|
146
|
+
end
|
147
|
+
|
148
|
+
# What tag does this todo use?
|
149
|
+
#
|
150
|
+
# @example
|
151
|
+
# todo.tag #=> "#shipit"
|
152
|
+
# todo.tag #=> nil
|
153
|
+
#
|
154
|
+
# @return [String] if the Todo has a tag
|
155
|
+
# @return [NilClass] if the Todo has no tag
|
156
|
+
# @api public
|
157
|
+
def tag
|
158
|
+
match[:tag]
|
159
|
+
end
|
160
|
+
|
125
161
|
# Which todo is due sooner?
|
126
162
|
#
|
127
163
|
# @example
|
@@ -161,6 +197,12 @@ module TodoLint
|
|
161
197
|
|
162
198
|
private
|
163
199
|
|
200
|
+
# What is the configuration for this code base's todo_lint setup?
|
201
|
+
#
|
202
|
+
# @return [Hash]
|
203
|
+
# @api private
|
204
|
+
attr_reader :config
|
205
|
+
|
164
206
|
# Analyze the line to help identify when the todo is due
|
165
207
|
# @return [MatchData]
|
166
208
|
# @api private
|
@@ -174,5 +216,16 @@ module TodoLint
|
|
174
216
|
def absent_todo!(line)
|
175
217
|
raise ArgumentError, "Not even a todo: #{line.inspect}"
|
176
218
|
end
|
219
|
+
|
220
|
+
# A tag was referenced, so let's see when that's due
|
221
|
+
# @return [DueDate]
|
222
|
+
# @raise [KeyError] if the tag does not reference a due date in the config
|
223
|
+
# @api private
|
224
|
+
def lookup_tag_due_date
|
225
|
+
config.fetch(:tags).fetch(match[:tag])
|
226
|
+
rescue KeyError
|
227
|
+
msg = "#{match[:tag]} tag not defined in config file"
|
228
|
+
raise KeyError, msg
|
229
|
+
end
|
177
230
|
end
|
178
231
|
end
|
data/lib/todo_lint/version.rb
CHANGED