koi 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|