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.
Files changed (5) hide show
  1. data/VERSION +1 -1
  2. data/koi.gemspec +5 -4
  3. data/lib/koi.rb +67 -30
  4. data/spec/koi_spec.rb +31 -5
  5. metadata +2 -2
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.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 `rake gemspec`
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.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{2009-10-20}
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[:root]) if dir
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 "'it' is not initialized here, please run `it init`"
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 "'it' has already been initialized here"
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 "- !!#{e[:title]}!!"
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.select {|e| e.new? }[0..count].each do |e|
126
- out "#[#{index += 1}]# ''#{e[:title]}'' @@#{e[:tags].join(' ')}@@" unless e[:status] == :removed
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 float
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 sink
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: entity[:title],
164
+ { title: entity[:title],
149
165
  action: status,
150
- time: entity[:"#{status}_at"]
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}[key]
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
- velocity: 0,
254
- freshness: 0,
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 be_true
14
- File.exist?(Koi::Path[:db]).should be_true
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.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: 2009-10-20 00:00:00 -04:00
12
+ date: 2010-03-06 00:00:00 -05:00
13
13
  default_executable: koi
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency