todo_or_die 0.0.1
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 +7 -0
- data/.gitignore +8 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +44 -0
- data/README.md +136 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/todo_or_die.rb +37 -0
- data/lib/todo_or_die/overdue_error.rb +4 -0
- data/lib/todo_or_die/version.rb +3 -0
- data/todo_or_die.gemspec +24 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e96cc61c209d86d2cc3c4caddf881ada4c803ab16f20f5184b43fae0542c6032
|
4
|
+
data.tar.gz: 73ae688e244d5ce0b960a5a931f53c98dc94813d38833aab0126168c2ad17ef8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8c1775674c7f182cb34633e5f0ddeed7dd2272f041d2ccbd93b3f693382884eea36d06a557bbdc9633f6e29741d291ff09ffb1a8a53e28ba4a4f8ec481666326
|
7
|
+
data.tar.gz: abebfad5178929b2237c88d25a1ee0df15190377b207a99371d6d27314edb74fd1e8f31898628222d424536e19289f70291c42925505e83cfe9ae5e3757cf434
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
todo_or_die (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.0)
|
10
|
+
jaro_winkler (1.5.1)
|
11
|
+
minitest (5.11.3)
|
12
|
+
parallel (1.12.1)
|
13
|
+
parser (2.5.3.0)
|
14
|
+
ast (~> 2.4.0)
|
15
|
+
powerpack (0.1.2)
|
16
|
+
rainbow (3.0.0)
|
17
|
+
rake (12.3.2)
|
18
|
+
rubocop (0.61.1)
|
19
|
+
jaro_winkler (~> 1.5.1)
|
20
|
+
parallel (~> 1.10)
|
21
|
+
parser (>= 2.5, != 2.5.1.1)
|
22
|
+
powerpack (~> 0.1)
|
23
|
+
rainbow (>= 2.2.2, < 4.0)
|
24
|
+
ruby-progressbar (~> 1.7)
|
25
|
+
unicode-display_width (~> 1.4.0)
|
26
|
+
ruby-progressbar (1.10.0)
|
27
|
+
standard (0.0.23)
|
28
|
+
rubocop (>= 0.60)
|
29
|
+
timecop (0.9.1)
|
30
|
+
unicode-display_width (1.4.1)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
bundler
|
37
|
+
minitest
|
38
|
+
rake
|
39
|
+
standard
|
40
|
+
timecop
|
41
|
+
todo_or_die!
|
42
|
+
|
43
|
+
BUNDLED WITH
|
44
|
+
1.17.2
|
data/README.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# TODO or Die!
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
Stick this in your Gemfile and bundle it:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem "todo_or_die"
|
9
|
+
```
|
10
|
+
|
11
|
+
Once required, you can mark TODOs for yourself anywhere you like:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
TodoOrDie("Update after APIv2 goes live", by: Date.civil(2019, 2, 4))
|
15
|
+
```
|
16
|
+
|
17
|
+
To understand why you would ever call a method to write a comment, read on.
|
18
|
+
|
19
|
+
### The awful way you used to procrastinate
|
20
|
+
|
21
|
+
In the Bad Old Days™, if you had a bit of code you knew needed to change later,
|
22
|
+
you might leave yourself a code comment to remind yourself or some future
|
23
|
+
traveler to implement it.
|
24
|
+
|
25
|
+
Here's the real world example code comment that inspired this gem:
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
class UsersController < ApiController
|
29
|
+
# TODO: remember to delete after JS app has propagated
|
30
|
+
def show
|
31
|
+
redirect_to root_path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
This was bad. The comment did nothing to remind myself or anyone else to
|
37
|
+
actually delete the code. Because no one was working on this part of the system
|
38
|
+
for a while, the _continued existence of the redirect_ eventually resulted in an
|
39
|
+
actual support incident (long story).
|
40
|
+
|
41
|
+
### The cool new way you put off coding now
|
42
|
+
|
43
|
+
So I did what any programmer would do in the face of an intractable social
|
44
|
+
problem: I wrote code in the vain hope of solving it without having to talk to
|
45
|
+
anyone.
|
46
|
+
|
47
|
+
To use the gem, try replacing one of your TODO comments with something like
|
48
|
+
this:
|
49
|
+
|
50
|
+
``` ruby
|
51
|
+
class UsersController < ApiController
|
52
|
+
TodoOrDie("delete after JS app has propagated", by: Time.parse("2019-02-04"))
|
53
|
+
def show
|
54
|
+
redirect_to root_path
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Nothing will happen at all until February 4th, at which point the gem will
|
60
|
+
raise an error whenever this class is loaded until someone deals with it.
|
61
|
+
|
62
|
+
### What kind of error?
|
63
|
+
|
64
|
+
It depends on whether `Rails` is defined.
|
65
|
+
|
66
|
+
#### When you're writing Real Ruby
|
67
|
+
|
68
|
+
If you're not using Rails (i.e. `defined?(Rails)` is false), then the gem will
|
69
|
+
raise a `TodoOrDie::OverdueError` whenever a TODO is overdue. The message looks
|
70
|
+
like this:
|
71
|
+
|
72
|
+
```
|
73
|
+
TODO: "Visit Wisconsin" came due on 2016-11-9. Do it!
|
74
|
+
```
|
75
|
+
|
76
|
+
#### When `Rails` is a thing
|
77
|
+
|
78
|
+
If TodoOrDie sees that `Rails` is defined, it'll assume you probably don't want
|
79
|
+
this tool to run outside development and test, so it'll log the error message to
|
80
|
+
`Rails.logger.warn` in production and raise the error otherwise.
|
81
|
+
|
82
|
+
### Wait, won't raising time-based errors throughout my app ruin my weekend?
|
83
|
+
|
84
|
+
Sure will! It's TODO or Die, not TODO and Remember to Pace Yourself.
|
85
|
+
|
86
|
+
Still, people will probably get mad if you break production because you forgot
|
87
|
+
to remove an A/B test, so I'd [strongly recommend you read what the default hook
|
88
|
+
actually does](lib/todo_or_die.rb) before you commit any to-do items to your
|
89
|
+
codebase.
|
90
|
+
|
91
|
+
You can customize the gem's behavior by passing in your own callable
|
92
|
+
lambda/proc/thing like this:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
TodoOrDie.config(
|
96
|
+
die: ->(message, due_at) {
|
97
|
+
if message.include?("Karen")
|
98
|
+
raise "Hey Karen your code's broke"
|
99
|
+
end
|
100
|
+
}
|
101
|
+
)
|
102
|
+
```
|
103
|
+
|
104
|
+
Now, any `TodoOrDie()` invocations in your codebase (other than Karen's) will be
|
105
|
+
ignored. (You can reset this with `TodoOrDie.reset`).
|
106
|
+
|
107
|
+
## When is this useful?
|
108
|
+
|
109
|
+
Any time you know the code needs to change, but it can't change right now, and
|
110
|
+
you lack some other reliable means of ensuring yourself (or your team)
|
111
|
+
will actually follow through on making the change later.
|
112
|
+
|
113
|
+
However, recall that [LeBlanc's
|
114
|
+
Law](https://www.quora.com/What-resources-could-I-read-about-Leblancs-law)
|
115
|
+
states that `Later == Never`, countless proofs of which have been demonstrated
|
116
|
+
by software teams around the world. Some common examples:
|
117
|
+
|
118
|
+
* A feature flag was added to the app, and the old code path is still present,
|
119
|
+
long after all production traffic has been migrated with a useless `TODO:
|
120
|
+
delete` comment to keep it company
|
121
|
+
* A failing test is blocking the build and there's an urgent pressure to deploy,
|
122
|
+
and insufficient time to fix the test, so somebody wants to comment the test
|
123
|
+
out "for now"
|
124
|
+
* You're a real funny person and you think it'd be hilarious to make a bunch of
|
125
|
+
Jim's tests start failing on Christmas morning
|
126
|
+
|
127
|
+
# Pro-tip
|
128
|
+
|
129
|
+
Cute Rails date helpers are awesome, but don't think you're going to be able to
|
130
|
+
do this and actually accomplish anything:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
TodoOrDie("Update after APIv2 goes live", 2.weeks.from_now)
|
134
|
+
```
|
135
|
+
|
136
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "todo_or_die"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/todo_or_die.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require "todo_or_die/version"
|
2
|
+
require "todo_or_die/overdue_error"
|
3
|
+
|
4
|
+
# The namespace
|
5
|
+
module TodoOrDie
|
6
|
+
DEFAULT_CONFIG = {
|
7
|
+
die: ->(message, due_at) {
|
8
|
+
error_message = <<~MSG
|
9
|
+
TODO: "#{message}" came due on #{due_at.strftime("%Y-%m-%d")}. Do it!
|
10
|
+
MSG
|
11
|
+
|
12
|
+
if defined?(Rails) && Rails.env.production?
|
13
|
+
Rails.logger.warn(error_message)
|
14
|
+
else
|
15
|
+
raise TodoOrDie::OverdueTodo.new(error_message)
|
16
|
+
end
|
17
|
+
},
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def self.config(options = {})
|
21
|
+
@config ||= reset
|
22
|
+
@config.merge!(options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.reset
|
26
|
+
@config = DEFAULT_CONFIG.dup
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# The main event
|
31
|
+
def TodoOrDie(message, by:) # rubocop:disable Naming/MethodName
|
32
|
+
due_at = by.to_time
|
33
|
+
|
34
|
+
if Time.now >= due_at
|
35
|
+
TodoOrDie.config[:die].call(message, due_at)
|
36
|
+
end
|
37
|
+
end
|
data/todo_or_die.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "todo_or_die"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "todo_or_die"
|
7
|
+
spec.version = TodoOrDie::VERSION
|
8
|
+
spec.authors = ["Justin Searls"]
|
9
|
+
spec.email = ["searls@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Write TODOs in code that ensure you actually do them"
|
12
|
+
spec.homepage = "https://github.com/testdouble/todo_or_die"
|
13
|
+
|
14
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
15
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
end
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_development_dependency "bundler"
|
20
|
+
spec.add_development_dependency "rake"
|
21
|
+
spec.add_development_dependency "minitest"
|
22
|
+
spec.add_development_dependency "standard"
|
23
|
+
spec.add_development_dependency "timecop"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: todo_or_die
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Searls
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-01-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: standard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: timecop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- searls@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- Gemfile
|
92
|
+
- Gemfile.lock
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- bin/console
|
96
|
+
- bin/setup
|
97
|
+
- lib/todo_or_die.rb
|
98
|
+
- lib/todo_or_die/overdue_error.rb
|
99
|
+
- lib/todo_or_die/version.rb
|
100
|
+
- todo_or_die.gemspec
|
101
|
+
homepage: https://github.com/testdouble/todo_or_die
|
102
|
+
licenses: []
|
103
|
+
metadata: {}
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubygems_version: 3.0.1
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Write TODOs in code that ensure you actually do them
|
123
|
+
test_files: []
|