quirk 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.md +23 -0
- data/README.md +82 -0
- data/quirk +24 -0
- data/quirk.rb +239 -0
- data/quirk_test.rb +109 -0
- metadata +84 -0
data/LICENSE.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2012, Hugh Bien
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
Redistributions of source code must retain the above copyright notice, this list
|
8
|
+
of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
Redistributions in binary form must reproduce the above copyright notice, this
|
11
|
+
list of conditions and the following disclaimer in the documentation and/or
|
12
|
+
other materials provided with the distribution.
|
13
|
+
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
15
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
16
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
18
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
19
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
20
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
21
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
22
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
23
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
Description
|
2
|
+
===========
|
3
|
+
|
4
|
+
Quirk is a command line utility for tracking good and bad habits.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
============
|
8
|
+
|
9
|
+
% gem install quirk
|
10
|
+
|
11
|
+
Then configure your habits in a plaintext file:
|
12
|
+
|
13
|
+
% quirk -e
|
14
|
+
mile-run: monday, wednesday, thursday
|
15
|
+
walk-dog: everyday
|
16
|
+
^quit-tv: friday
|
17
|
+
|
18
|
+
If a habit is prefixed with `^`, it means you're trying to break that habit.
|
19
|
+
In this case you're trying to quit TV on Fridays.
|
20
|
+
|
21
|
+
By default, all this does is edit the `~/.quirk` file. You can configure
|
22
|
+
which file to use by setting the environment variable `QUIRKFILE`.
|
23
|
+
|
24
|
+
Usage
|
25
|
+
=====
|
26
|
+
|
27
|
+
When you've done something, mark it with:
|
28
|
+
|
29
|
+
% quirk -m mile-run
|
30
|
+
|
31
|
+
To see a single habit (green days are good, red is bad):
|
32
|
+
|
33
|
+
% quirk -c mile-run
|
34
|
+
Jan 2012
|
35
|
+
Su Mo Tu We Th Fr Sa
|
36
|
+
1 2 3 4 5 6 7
|
37
|
+
8 9 10 11 12 13 14
|
38
|
+
15 16 17 18 19 20 21
|
39
|
+
22 23 24 25 26 27 28
|
40
|
+
29 30 31
|
41
|
+
|
42
|
+
Looking for a specific year?
|
43
|
+
|
44
|
+
% quirk mile-run -y 2011
|
45
|
+
|
46
|
+
See all of your current streaks:
|
47
|
+
|
48
|
+
% quirk -s
|
49
|
+
17 mile-run
|
50
|
+
3 walk-dog
|
51
|
+
-3 quit-tv
|
52
|
+
|
53
|
+
Habits are stored in plaintext in `~/.quirk`. You can use `quirk -e` to
|
54
|
+
add/remove entries. Note that habits start on the day of the first mark
|
55
|
+
by default. You can also specify the first day using `^`:
|
56
|
+
|
57
|
+
2012/01/01 walk-dog
|
58
|
+
2012/01/01 ^quit-tv
|
59
|
+
|
60
|
+
The first line means you walked the dog on `1/1`. The second line means you
|
61
|
+
started the habit of quitting TV. This is especailly handy for starting
|
62
|
+
quitting habits on a green day.
|
63
|
+
|
64
|
+
Zsh Tab Completion
|
65
|
+
==================
|
66
|
+
|
67
|
+
Here's an example zsh completion function:
|
68
|
+
|
69
|
+
#compdef quirk
|
70
|
+
compadd `quirk -l`
|
71
|
+
|
72
|
+
Put this into your `site-functions` directory (wherever `$fpath` points to):
|
73
|
+
|
74
|
+
% echo $fpath
|
75
|
+
/usr/share/zsh/site-functions /usr/share/zsh/4.3.11/functions
|
76
|
+
% sudo vim /usr/share/zsh/site-functions/_quirk
|
77
|
+
|
78
|
+
License
|
79
|
+
=======
|
80
|
+
|
81
|
+
Copyright 2012 Hugh Bien - http://hughbien.com.
|
82
|
+
Released under BSD License, see LICENSE.md for more info.
|
data/quirk
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require File.expand_path('quirk', File.dirname(__FILE__))
|
4
|
+
|
5
|
+
ARGV.options do |o|
|
6
|
+
begin
|
7
|
+
app = Quirk::App.new
|
8
|
+
action = nil
|
9
|
+
o.set_summary_indent(' ')
|
10
|
+
o.banner = "Usage: #{File.basename($0)} [OPTION]"
|
11
|
+
o.define_head "Track good and bad habits (v#{Quirk::VERSION})"
|
12
|
+
o.on('-c', '--calendar habit', 'show calendar') { |h| action = [:calendar, h] }
|
13
|
+
o.on('-e', '--edit', 'edit habits') { action = [:edit] }
|
14
|
+
o.on('-l', '--list', 'list habits') { action = [:list] }
|
15
|
+
o.on('-m', '--mark habit', 'mark for today') { |h| action = [:mark, h] }
|
16
|
+
o.on('-s', '--streaks', 'list streaks') { action = [:streaks] }
|
17
|
+
o.on('-y', '--year year', 'set calendar year') { |y| app.year = y }
|
18
|
+
o.on('-h', '--help', 'show this help message') { puts o; exit }
|
19
|
+
o.parse!
|
20
|
+
action.nil? ? puts(o) : app.send(*action)
|
21
|
+
rescue RuntimeError => e
|
22
|
+
puts e.to_s
|
23
|
+
end
|
24
|
+
end
|
data/quirk.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'colorize'
|
3
|
+
|
4
|
+
module Quirk
|
5
|
+
VERSION = '0.0.2'
|
6
|
+
QUIRKFILE = ENV['QUIRKFILE'] || "#{ENV['HOME']}/.quirk"
|
7
|
+
EDITOR = ENV['EDITOR'] || 'vi'
|
8
|
+
|
9
|
+
def self.today
|
10
|
+
@today || Date.today
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.today=(date) # for testing
|
14
|
+
@today = date
|
15
|
+
end
|
16
|
+
|
17
|
+
class App
|
18
|
+
def initialize(quirkfile = QUIRKFILE)
|
19
|
+
@quirkfile = quirkfile
|
20
|
+
end
|
21
|
+
|
22
|
+
def calendar(habit_id)
|
23
|
+
puts cal.output(habit_id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def edit
|
27
|
+
`#{EDITOR} #{QUIRKFILE} < \`tty\` > \`tty\``
|
28
|
+
end
|
29
|
+
|
30
|
+
def list
|
31
|
+
puts cal.list
|
32
|
+
end
|
33
|
+
|
34
|
+
def mark(habit_id)
|
35
|
+
File.open(@quirkfile, 'a') do |file|
|
36
|
+
if cal.has_habit?(habit_id)
|
37
|
+
file.puts("#{Quirk.today.strftime('%Y/%m/%d')} #{habit_id}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def streaks
|
43
|
+
puts cal.streaks
|
44
|
+
end
|
45
|
+
|
46
|
+
def year=(year)
|
47
|
+
raise "Invalid year: #{year}" if year !~ /\d\d\d\d/
|
48
|
+
cal.year = year.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def cal
|
53
|
+
@cal ||= Calendar.parse(File.read(@quirkfile))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Habit
|
58
|
+
attr_reader :id, :days, :marks
|
59
|
+
|
60
|
+
def initialize(id, days, quitting)
|
61
|
+
@id, @days, @quitting, @marks = id, days, quitting, []
|
62
|
+
end
|
63
|
+
|
64
|
+
def quitting?
|
65
|
+
!!@quitting
|
66
|
+
end
|
67
|
+
|
68
|
+
def mark!(date)
|
69
|
+
@marks << date
|
70
|
+
@marks.sort
|
71
|
+
end
|
72
|
+
|
73
|
+
def mark_first!(date)
|
74
|
+
@first_date = date
|
75
|
+
end
|
76
|
+
|
77
|
+
def first_date
|
78
|
+
@first_date || @marks.first
|
79
|
+
end
|
80
|
+
|
81
|
+
def color_on(date)
|
82
|
+
hit_color = quitting? ? :light_red : :light_green
|
83
|
+
miss_color = quitting? ? :light_green : :light_red
|
84
|
+
last_date = quitting? ? (Quirk.today + 1) : Quirk.today
|
85
|
+
if @marks.empty? ||
|
86
|
+
date < first_date ||
|
87
|
+
date > last_date ||
|
88
|
+
!days.include?(date.wday)
|
89
|
+
:white
|
90
|
+
elsif @marks.include?(date)
|
91
|
+
hit_color
|
92
|
+
else
|
93
|
+
date == last_date && !quitting? ? :white : miss_color
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def streak
|
98
|
+
return 0 if @marks.empty?
|
99
|
+
|
100
|
+
count = 0
|
101
|
+
deltas = {:light_red => -1, :light_green => 1, :white => 0}
|
102
|
+
date = Quirk.today
|
103
|
+
while date >= first_date && (color = color_on(date)) == :white
|
104
|
+
date -= 1
|
105
|
+
end
|
106
|
+
|
107
|
+
init_color = color
|
108
|
+
while date >= first_date
|
109
|
+
color = color_on(date)
|
110
|
+
break if color != init_color && days.include?(date.wday)
|
111
|
+
date -= 1
|
112
|
+
count += deltas[color]
|
113
|
+
end
|
114
|
+
count
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.parse(line)
|
118
|
+
line.strip!
|
119
|
+
line.gsub!(/\s+/, ' ')
|
120
|
+
|
121
|
+
quitting = line =~ /^\^/
|
122
|
+
line = line[1..-1] if quitting
|
123
|
+
id, days = line.split(':', 2).map(&:strip)
|
124
|
+
self.new(id, parse_days(days), quitting)
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.parse_days(text)
|
128
|
+
originals = text.split(',').map(&:strip)
|
129
|
+
days = []
|
130
|
+
if originals.include?('everyday')
|
131
|
+
(0..6).to_a
|
132
|
+
else
|
133
|
+
%w(sunday monday tuesday wednesday
|
134
|
+
thursday friday saturday).each_with_index do |day, index|
|
135
|
+
days << (index) if originals.include?(day)
|
136
|
+
end
|
137
|
+
days
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class Calendar
|
143
|
+
attr_writer :year
|
144
|
+
|
145
|
+
def initialize(habits)
|
146
|
+
@habits = habits.reduce({}) {|hash,habit| hash[habit.id] = habit; hash}
|
147
|
+
end
|
148
|
+
|
149
|
+
def year
|
150
|
+
@year || Quirk.today.year
|
151
|
+
end
|
152
|
+
|
153
|
+
def has_habit?(habit_id)
|
154
|
+
raise "No habit found: #{habit_id}" if !@habits.has_key?(habit_id)
|
155
|
+
true
|
156
|
+
end
|
157
|
+
|
158
|
+
def output(habit_id)
|
159
|
+
return if !has_habit?(habit_id)
|
160
|
+
habit = @habits[habit_id]
|
161
|
+
months = (1..12).map do |month|
|
162
|
+
first = Date.new(year, month, 1)
|
163
|
+
out = "#{first.strftime(' %b ')}\n"
|
164
|
+
out += "Su Mo Tu We Th Fr Sa\n"
|
165
|
+
out += (" " * first.wday)
|
166
|
+
while first.month == month
|
167
|
+
out += (first..(first + (6 - first.wday))).map do |date|
|
168
|
+
if date.year != year || date.month != month
|
169
|
+
' '
|
170
|
+
else
|
171
|
+
len = date.day.to_s.length
|
172
|
+
"#{' ' * (2 - len)}#{date.day.to_s.colorize(habit.color_on(date))}"
|
173
|
+
end
|
174
|
+
end.join(" ")
|
175
|
+
out += "\n"
|
176
|
+
first += 7 - first.wday
|
177
|
+
end
|
178
|
+
out.split("\n")
|
179
|
+
end
|
180
|
+
out = "#{(' ' * 32)}#{year}\n"
|
181
|
+
index = 0
|
182
|
+
while index < 12
|
183
|
+
line = 0
|
184
|
+
max_line = [months[index], months[index+1], months[index+2]].
|
185
|
+
map(&:length).max
|
186
|
+
while line <= max_line
|
187
|
+
out += "#{months[index][line] || (' ' * 20)} "
|
188
|
+
out += "#{months[index+1][line] || ( ' ' * 20)} "
|
189
|
+
out += "#{months[index+2][line]}\n"
|
190
|
+
line += 1
|
191
|
+
end
|
192
|
+
index += 3
|
193
|
+
end
|
194
|
+
out
|
195
|
+
end
|
196
|
+
|
197
|
+
def list
|
198
|
+
@habits.values.map(&:id).sort.join("\n")
|
199
|
+
end
|
200
|
+
|
201
|
+
def mark!(line)
|
202
|
+
date = Date.parse(line.strip.split(/\s+/)[0])
|
203
|
+
originals = line.strip.split(/\s+/, 2)[1].split(',').map(&:strip)
|
204
|
+
originals.each do |original|
|
205
|
+
if original =~ /^\^\s*/
|
206
|
+
original = original.sub(/^\^\s*/, '')
|
207
|
+
habit = @habits[original] if has_habit?(original)
|
208
|
+
habit.mark_first!(date)
|
209
|
+
elsif has_habit?(original)
|
210
|
+
@habits[original].mark!(date)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def streaks
|
216
|
+
pairs = @habits.values.map do |habit|
|
217
|
+
[habit.streak, habit.id]
|
218
|
+
end.sort_by(&:first)
|
219
|
+
len = pairs.map {|p| p.first.to_s.length}.max
|
220
|
+
pairs.map do |count, id|
|
221
|
+
"#{' ' * (len - count.to_s.length)}#{count} #{id}"
|
222
|
+
end.join("\n")
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.parse(text)
|
226
|
+
marks, habits = [], []
|
227
|
+
text.strip.each_line do |line|
|
228
|
+
if line =~ /^\d\d\d\d\/\d\d?\/\d\d?\s+/
|
229
|
+
marks << line
|
230
|
+
elsif line !~ /^\s*$/
|
231
|
+
habits << Habit.parse(line)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
cal = Calendar.new(habits)
|
235
|
+
marks.each { |mark| cal.mark!(mark) }
|
236
|
+
cal
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
data/quirk_test.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require "#{File.dirname(__FILE__)}/quirk"
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
Quirk.today = Date.new(2012, 1, 5) # 1 Su, 2 Mo, 3 Tu, 4 We, 5 Th
|
6
|
+
|
7
|
+
class QuirkAppTest < MiniTest::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@app = Quirk::App.new(File.join(File.dirname(__FILE__), 'quirkfile'))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class QuirkHabitTest < MiniTest::Unit::TestCase
|
14
|
+
def test_parse
|
15
|
+
habit = Quirk::Habit.parse(' running: monday , tuesday, wednesday')
|
16
|
+
assert_equal('running', habit.id)
|
17
|
+
assert_equal([1, 2, 3], habit.days)
|
18
|
+
refute(habit.quitting?)
|
19
|
+
|
20
|
+
habit2 = Quirk::Habit.parse('walk-dog: everyday')
|
21
|
+
assert_equal('walk-dog', habit2.id)
|
22
|
+
assert_equal([0, 1, 2, 3, 4, 5, 6], habit2.days)
|
23
|
+
refute(habit2.quitting?)
|
24
|
+
|
25
|
+
habit3 = Quirk::Habit.parse('^quit-tv: everyday')
|
26
|
+
assert_equal('quit-tv', habit3.id)
|
27
|
+
assert_equal([0, 1, 2, 3, 4, 5, 6], habit3.days)
|
28
|
+
assert(habit3.quitting?)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_color_on
|
32
|
+
habit = Quirk::Habit.parse('running: sunday, monday, wednesday, thursday')
|
33
|
+
habit.mark!(Date.new(2012, 1, 2))
|
34
|
+
habit.mark!(Date.new(2012, 1, 3))
|
35
|
+
assert_equal(:white, habit.color_on(Date.new(2012, 1, 1)))
|
36
|
+
assert_equal(:green, habit.color_on(Date.new(2012, 1, 2)))
|
37
|
+
assert_equal(:white, habit.color_on(Date.new(2012, 1, 3)))
|
38
|
+
assert_equal(:red, habit.color_on(Date.new(2012, 1, 4)))
|
39
|
+
assert_equal(:white, habit.color_on(Date.new(2012, 1, 5)))
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_color_on_quit
|
43
|
+
quit = Quirk::Habit.parse('^quit-tv: sunday, monday, wednesday, thursday')
|
44
|
+
quit.mark!(Date.new(2012, 1, 2))
|
45
|
+
assert_equal(:white, quit.color_on(Date.new(2012, 1, 1)))
|
46
|
+
assert_equal(:red, quit.color_on(Date.new(2012, 1, 2)))
|
47
|
+
assert_equal(:white, quit.color_on(Date.new(2012, 1, 3)))
|
48
|
+
assert_equal(:green, quit.color_on(Date.new(2012, 1, 4)))
|
49
|
+
assert_equal(:green, quit.color_on(Date.new(2012, 1, 5)))
|
50
|
+
|
51
|
+
quit.mark_first!(Date.new(2012, 1, 1))
|
52
|
+
assert_equal(:green, quit.color_on(Date.new(2012, 1, 1)))
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_streak
|
56
|
+
missing = Quirk::Habit.parse('running: everyday')
|
57
|
+
assert_equal(0, missing.streak)
|
58
|
+
|
59
|
+
perfect = Quirk::Habit.parse('running: monday, wednesday')
|
60
|
+
perfect.mark!(Date.new(2012, 1, 2))
|
61
|
+
perfect.mark!(Date.new(2012, 1, 4))
|
62
|
+
assert_equal(2, perfect.streak)
|
63
|
+
|
64
|
+
bad = Quirk::Habit.parse('running: monday, tuesday, wednesday')
|
65
|
+
bad.mark!(Date.new(2012, 1, 1))
|
66
|
+
bad.mark!(Date.new(2012, 1, 2))
|
67
|
+
assert_equal(-2, bad.streak)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_streak_quit
|
71
|
+
missing = Quirk::Habit.parse('^quit-tv: everyday')
|
72
|
+
assert_equal(0, missing.streak)
|
73
|
+
|
74
|
+
perfect = Quirk::Habit.parse('^quit-tv: monday, tuesday')
|
75
|
+
perfect.mark!(Date.new(2011, 12, 31))
|
76
|
+
perfect.mark!(Date.new(2012, 1, 4))
|
77
|
+
assert_equal(2, perfect.streak)
|
78
|
+
|
79
|
+
bad = Quirk::Habit.parse('^quit-tv: sunday, thursday')
|
80
|
+
bad.mark!(Date.new(2012, 1, 1)) # sunday
|
81
|
+
bad.mark!(Date.new(2012, 1, 5)) # thursday
|
82
|
+
assert_equal(-2, bad.streak)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class QuirkCalendarTest < MiniTest::Unit::TestCase
|
87
|
+
def setup
|
88
|
+
@running = Quirk::Habit.parse('running: everyday')
|
89
|
+
@walking = Quirk::Habit.parse('walk-dog: sunday, saturday')
|
90
|
+
@smoking = Quirk::Habit.parse('^smoking: everyday')
|
91
|
+
@cal = Quirk::Calendar.new([@running, @walking, @smoking])
|
92
|
+
@cal.mark!('2012/01/01 ^smoking')
|
93
|
+
@cal.mark!('2012/01/01 running, walk-dog')
|
94
|
+
@cal.mark!('2012/01/02 running, walk-dog')
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_mark
|
98
|
+
assert_equal([Date.new(2012,1,1), Date.new(2012,1,2)], @running.marks)
|
99
|
+
assert_equal([Date.new(2012,1,1), Date.new(2012,1,2)], @walking.marks)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_mark_first
|
103
|
+
assert_equal(Date.new(2012, 1, 1), @smoking.first_date)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_streaks
|
107
|
+
assert_equal("-2 running\n 0 smoking\n 1 walk-dog", @cal.streaks)
|
108
|
+
end
|
109
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: quirk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Hugh Bien
|
9
|
+
autorequire:
|
10
|
+
bindir: .
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-25 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: colorize
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
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: Command line tool for tracking good/bad habits, data stored in plaintext.
|
47
|
+
email:
|
48
|
+
- hugh@hughbien.com
|
49
|
+
executables:
|
50
|
+
- quirk
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- quirk.rb
|
55
|
+
- quirk_test.rb
|
56
|
+
- README.md
|
57
|
+
- LICENSE.md
|
58
|
+
- quirk
|
59
|
+
- ./quirk
|
60
|
+
homepage: https://github.com/hughbien/quirk
|
61
|
+
licenses: []
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.3.6
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.8.23
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Track good and bad habits
|
84
|
+
test_files: []
|