koi 0.2.2 → 0.2.3
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/VERSION +1 -1
- data/koi.gemspec +5 -4
- data/lib/koi.rb +67 -30
- data/spec/koi_spec.rb +31 -5
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
data/koi.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{koi}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["cloudhead"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2010-03-06}
|
13
13
|
s.default_executable = %q{koi}
|
14
14
|
s.description = %q{minimalist console-based task management for hackers}
|
15
15
|
s.email = %q{self@cloudhead.net}
|
@@ -57,3 +57,4 @@ Gem::Specification.new do |s|
|
|
57
57
|
s.add_dependency(%q<mutter>, [">= 0.4"])
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
data/lib/koi.rb
CHANGED
@@ -5,12 +5,16 @@ require 'fileutils'
|
|
5
5
|
|
6
6
|
module Koi
|
7
7
|
|
8
|
-
Path = {root: ".koi", db: ".koi/database.yml"}
|
8
|
+
Path = {root: ".koi", db: ".koi/database.yml", paths: ".koi/paths"}
|
9
9
|
|
10
10
|
def self.init dir = Dir.pwd
|
11
11
|
unless init?
|
12
12
|
FileUtils.mkdir File.join(dir, Path[:root])
|
13
13
|
FileUtils.touch File.join(dir, Path[:db])
|
14
|
+
FileUtils.mkdir File.join(ENV['HOME'], Path[:root]) rescue nil
|
15
|
+
File.open(File.join(ENV['HOME'], Path[:paths]), 'a+') do |f|
|
16
|
+
f.write File.expand_path(dir).to_s
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
@@ -20,15 +24,15 @@ module Koi
|
|
20
24
|
end
|
21
25
|
|
22
26
|
def self.init? dir = root
|
23
|
-
File.exist? File.join(dir, Path[:
|
27
|
+
File.exist? File.join(dir, Path[:db]) if dir
|
24
28
|
end
|
25
|
-
|
29
|
+
|
26
30
|
def self.run *args
|
27
31
|
cmd = Command.new(*args)
|
28
32
|
cmd[:silent] = true
|
29
33
|
cmd.run
|
30
34
|
end
|
31
|
-
|
35
|
+
|
32
36
|
def self.version
|
33
37
|
File.read(File.join(File.dirname(__FILE__), '..', 'VERSION')).strip
|
34
38
|
end
|
@@ -49,7 +53,7 @@ module Koi
|
|
49
53
|
:init, :add, :list, :tag,
|
50
54
|
:done, :did, :log, :status,
|
51
55
|
:remove, :float, :sink,
|
52
|
-
:ls, :rm
|
56
|
+
:ls, :rm, :rise
|
53
57
|
]
|
54
58
|
Initializers = [:init, :add]
|
55
59
|
Special = {"!" => :done, "?" => :status}
|
@@ -61,13 +65,14 @@ module Koi
|
|
61
65
|
@param = param =~ /^\d+$/ ? param.to_i : param
|
62
66
|
@options = options || {}
|
63
67
|
@db = Koi.init?? Database.new(File.join(Koi.root, Path[:db])) : Database.new
|
64
|
-
@mut = Mutter.new(blue: '#', underline: "''", cyan: '@@', green: '!!', yellow: '^').clear(:default)
|
68
|
+
@mut = Mutter.new(blue: '#', underline: "''", red: '++', cyan: '@@', green: '!!', yellow: '^').clear(:default)
|
65
69
|
end
|
66
70
|
|
67
71
|
def run
|
68
72
|
if Commands.include? @command
|
69
73
|
if Koi.init? or Initializers.include? @command
|
70
74
|
if !@param or @command == :add or @param = @db.find(@param)
|
75
|
+
@param ||= @db.last if [:float, :sink, :rm, :tag, :done].include? @command
|
71
76
|
if send(@command, *[@param, *@args].compact.flatten)
|
72
77
|
save
|
73
78
|
else
|
@@ -77,39 +82,37 @@ module Koi
|
|
77
82
|
err "task wasn't found"
|
78
83
|
end
|
79
84
|
else
|
80
|
-
err "'
|
85
|
+
err "'koi' is not initialized here, please run `koi init`"
|
81
86
|
end
|
82
87
|
else
|
83
88
|
err "#{@command} is not a valid command."
|
84
89
|
end
|
85
90
|
end
|
86
|
-
|
91
|
+
|
87
92
|
def []= key, val
|
88
93
|
@options[key] = val
|
89
94
|
end
|
90
|
-
|
95
|
+
|
91
96
|
def [] key
|
92
97
|
@options[key]
|
93
98
|
end
|
94
99
|
|
95
100
|
def init
|
96
101
|
unless Koi.init
|
97
|
-
err "'
|
102
|
+
err "'koi' has already been initialized here"
|
98
103
|
else
|
99
104
|
true
|
100
105
|
end
|
101
106
|
end
|
102
|
-
|
107
|
+
|
103
108
|
def status
|
104
109
|
out "in the water (#{@db.select {|e| e.new? }.size})"
|
105
110
|
|
106
111
|
self.list 5
|
107
112
|
|
108
|
-
out "recently fished (#{@db.select {|e| e.completed? }.size})"
|
109
|
-
|
110
113
|
@db.select {|e| e[:status] == :completed }.
|
111
114
|
sort_by {|e| e[:completed_at] }[0..3].reverse.each do |e|
|
112
|
-
out "
|
115
|
+
out " #[x]# !!#{e[:title]}!!"
|
113
116
|
end
|
114
117
|
|
115
118
|
out
|
@@ -121,9 +124,9 @@ module Koi
|
|
121
124
|
#
|
122
125
|
def list count = 10, index = -1
|
123
126
|
out
|
124
|
-
|
125
|
-
@db.
|
126
|
-
out "#[#{index += 1}]
|
127
|
+
|
128
|
+
@db.list[0..count].each do |e|
|
129
|
+
out " #[#{index += 1}]##{e.sticky?? "++ + ++" : " "}''#{e[:title]}'' @@#{e[:tags].join(' ')}@@" unless e[:status] == :removed
|
127
130
|
end.tap do |list|
|
128
131
|
out " !!nothing left to do!!" if list.size.zero?
|
129
132
|
end
|
@@ -132,11 +135,24 @@ module Koi
|
|
132
135
|
true
|
133
136
|
end
|
134
137
|
alias :ls list
|
135
|
-
|
136
|
-
def
|
138
|
+
|
139
|
+
def swim entry, n
|
140
|
+
v = @db.index(entry) + @db.size / 3 * n
|
141
|
+
@db.delete entry
|
142
|
+
@db.insert([[v, 0].max, @db.size].min, entry)
|
143
|
+
end
|
144
|
+
|
145
|
+
def rise entry
|
146
|
+
swim entry, -1
|
147
|
+
end
|
148
|
+
|
149
|
+
def sink entry
|
150
|
+
swim entry, 1
|
137
151
|
end
|
138
152
|
|
139
|
-
def
|
153
|
+
def float entry
|
154
|
+
entry[:sticky] = ! entry[:sticky]
|
155
|
+
true
|
140
156
|
end
|
141
157
|
|
142
158
|
#
|
@@ -145,9 +161,9 @@ module Koi
|
|
145
161
|
def log
|
146
162
|
@db.map do |entity|
|
147
163
|
Entity::Status.map do |status|
|
148
|
-
{ title:
|
164
|
+
{ title: entity[:title],
|
149
165
|
action: status,
|
150
|
-
time:
|
166
|
+
time: entity[:"#{status}_at"].strftime("%Y/%m/%d %H:%m")
|
151
167
|
} if entity[:"#{status}_at"]
|
152
168
|
end.compact
|
153
169
|
end.flatten.sort_by {|e| e[:time]}.reverse.each do |entry|
|
@@ -188,7 +204,7 @@ module Koi
|
|
188
204
|
def save
|
189
205
|
File.open(File.join(Koi.root, Path[:db]), 'w') {|f| f.write @db.to_yaml }
|
190
206
|
end
|
191
|
-
|
207
|
+
|
192
208
|
#
|
193
209
|
# Mark task as :removed (doesn't show up anywhere)
|
194
210
|
#
|
@@ -214,13 +230,32 @@ module Koi
|
|
214
230
|
if key.is_a? String
|
215
231
|
@data.find {|e| e[:title].include? key }
|
216
232
|
elsif key.is_a? Fixnum
|
217
|
-
@data.select {|e| e[:status] == :created}
|
233
|
+
entities = @data.select {|e| e[:status] == :created}
|
234
|
+
(entities.select(&:sticky?) + entities.reject(&:sticky?))[key]
|
218
235
|
else
|
219
236
|
raise ArgumentError, "key must be a String or Fixnum, but is #{key.class}"
|
220
237
|
end
|
221
238
|
end
|
222
239
|
alias :[] find
|
223
|
-
|
240
|
+
|
241
|
+
def fresh
|
242
|
+
@data.select {|e| e.new? }
|
243
|
+
end
|
244
|
+
|
245
|
+
def list
|
246
|
+
fresh.select(&:sticky?) + fresh.reject(&:sticky?)
|
247
|
+
end
|
248
|
+
|
249
|
+
#
|
250
|
+
# Hash-like methods on @data
|
251
|
+
#
|
252
|
+
def size; fresh.size end
|
253
|
+
def first; fresh.first end
|
254
|
+
def last; fresh.last end
|
255
|
+
def delete(arg) @data.delete arg end
|
256
|
+
def insert(*args) @data.insert *args end
|
257
|
+
def index(*args, &blk) @data.index *args, &blk end
|
258
|
+
|
224
259
|
def load path = @path || Path[:db]
|
225
260
|
@data = if db = YAML.load_file(path)
|
226
261
|
db.map {|e| Entity.new(e) }
|
@@ -250,17 +285,19 @@ module Koi
|
|
250
285
|
self.replace status: :created,
|
251
286
|
created_at: Time.now,
|
252
287
|
owner: ENV['USER'],
|
253
|
-
|
254
|
-
|
255
|
-
depth: 0,
|
256
|
-
tags: []
|
288
|
+
tags: [],
|
289
|
+
sticky: false
|
257
290
|
merge!(data)
|
258
291
|
end
|
259
|
-
|
292
|
+
|
260
293
|
def new?
|
261
294
|
self[:status] == :created
|
262
295
|
end
|
263
296
|
|
297
|
+
def sticky?
|
298
|
+
self[:sticky]
|
299
|
+
end
|
300
|
+
|
264
301
|
def status= st
|
265
302
|
self[:status] = st
|
266
303
|
self[:"#{st}_at"] = Time.now
|
data/spec/koi_spec.rb
CHANGED
@@ -6,12 +6,21 @@ describe Koi do
|
|
6
6
|
context "in a new project" do
|
7
7
|
before(:each) do
|
8
8
|
FileUtils.rm_rf(Koi::Path[:root])
|
9
|
+
FileUtils.rm_rf(File.join(ENV['HOME'], Koi::Path[:root]))
|
9
10
|
end
|
10
11
|
|
11
|
-
it "should initialize the directory" do
|
12
|
+
it "should initialize the .koi directory" do
|
12
13
|
Koi.run(:init)
|
13
|
-
File.exist?(Koi::Path[:root]).should
|
14
|
-
File.exist?(Koi::Path[:db]).should
|
14
|
+
File.exist?(Koi::Path[:root]).should == true
|
15
|
+
File.exist?(Koi::Path[:db]).should == true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should create a .koi in ~" do
|
19
|
+
Koi.run(:init)
|
20
|
+
File.exist?(File.join(ENV['HOME'], Koi::Path[:root])).
|
21
|
+
should == true
|
22
|
+
File.read(File.join(ENV['HOME'], Koi::Path[:paths])).
|
23
|
+
split(/\n/).should include(File.expand_path(Dir.pwd))
|
15
24
|
end
|
16
25
|
|
17
26
|
it "should warn that the project isn't initialized" do
|
@@ -23,12 +32,12 @@ describe Koi do
|
|
23
32
|
before(:all) do
|
24
33
|
Koi.init!
|
25
34
|
end
|
26
|
-
|
35
|
+
|
27
36
|
context "with no tasks" do
|
28
37
|
it "shouldn't try to init" do
|
29
38
|
-> {Koi.run(:init)}.should raise_error(SystemExit)
|
30
39
|
end
|
31
|
-
|
40
|
+
|
32
41
|
it "should warn about invalid commands" do
|
33
42
|
-> {Koi.run(:choo)}.should raise_error(SystemExit)
|
34
43
|
end
|
@@ -70,9 +79,26 @@ describe Koi do
|
|
70
79
|
@db.load.find(TASKS[1])[:tags].should include("food")
|
71
80
|
end
|
72
81
|
|
82
|
+
it "should rise tasks" do
|
83
|
+
Koi.run(:rise, TASKS[2])
|
84
|
+
@db.load[1][:title].should == TASKS[2]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should sink tasks" do
|
88
|
+
Koi.run(:sink, TASKS[1])
|
89
|
+
@db.load.last[:title].should == TASKS[1]
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should sticky tasks" do
|
93
|
+
Koi.run(:float, TASKS[2])
|
94
|
+
@db.load.list[0][:title].should == TASKS[2]
|
95
|
+
@db.load.find(TASKS[2])[:sticky].should be_true
|
96
|
+
end
|
97
|
+
|
73
98
|
it "should warn when the task wasn't found" do
|
74
99
|
-> {Koi.run(:did, "celery")}.should raise_error(SystemExit)
|
75
100
|
end
|
76
101
|
end
|
77
102
|
end
|
78
103
|
end
|
104
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: koi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- cloudhead
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-03-06 00:00:00 -05:00
|
13
13
|
default_executable: koi
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|