todo_lint 0.3.1 → 0.4.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.
- 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