twkb 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -0
- data/bin/twkb +6 -0
- data/lib/twkb.rb +50 -0
- data/lib/twkb/config.rb +78 -0
- data/lib/twkb/formatter.rb +48 -0
- data/lib/twkb/task.rb +13 -0
- data/lib/twkb/version.rb +3 -0
- data/twkb.gemspec +23 -0
- metadata +13 -6
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use default@twkb
|
data/bin/twkb
ADDED
data/lib/twkb.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'twkb/config'
|
2
|
+
require 'twkb/task'
|
3
|
+
require 'twkb/formatter'
|
4
|
+
|
5
|
+
module TWKB
|
6
|
+
class App
|
7
|
+
attr_accessor :config
|
8
|
+
attr_accessor :board_name
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
@config = TWKB::Config.new
|
12
|
+
@board_name = get_board_name options[:board_name]
|
13
|
+
populate_stages
|
14
|
+
end
|
15
|
+
|
16
|
+
def print_table
|
17
|
+
formatter = TWKB::Formatter.new(:stages => @config.stages, :cell_width => @config['view.cell_width'])
|
18
|
+
puts formatter.table
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def get_board_name(name = nil)
|
23
|
+
name || @config['board_name'] || 'personal'
|
24
|
+
end
|
25
|
+
|
26
|
+
def populate_stages
|
27
|
+
tasks = TWKB::Task.all(:board => @board_name)
|
28
|
+
@config.stage_names.each do |stage|
|
29
|
+
@config.stages[stage][:tasks] = tasks.select{|task|
|
30
|
+
task['stage'] == stage && task['status'] == 'pending'
|
31
|
+
}.sort_by{|k| k['urgency']}.reverse
|
32
|
+
|
33
|
+
# Truncate headers to match cell width
|
34
|
+
@config.stages[stage][:label][:value] = @config.stages[stage][:label][:value][0..@config['view.cell_width']]
|
35
|
+
|
36
|
+
if @config.stages[stage][:wip]
|
37
|
+
label_value = "\n(#{@config.stages[stage][:tasks].length}/#{@config.stages[stage][:wip]})"
|
38
|
+
@config.stages[stage][:label][:value] << label_value[0..@config['view.cell_width']]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# 'Done' is special
|
43
|
+
if @config.stage_names.include? 'done'
|
44
|
+
@config.stages['done'][:tasks] = tasks.select{ |task|
|
45
|
+
task['status'] == 'completed'
|
46
|
+
}.sort_by{|k| k['end'] }.reverse[0..@config['view.done_tasks']-1]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/twkb/config.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'parseconfig'
|
2
|
+
|
3
|
+
module TWKB
|
4
|
+
class Config
|
5
|
+
attr_reader :stage_names
|
6
|
+
attr_accessor :stages
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
read
|
10
|
+
prepare
|
11
|
+
build_stages
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](val)
|
15
|
+
@config[val]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def defaults
|
21
|
+
{
|
22
|
+
'twkb.view.cell_width' => '15',
|
23
|
+
'twkb.view.stages.alignment' => 'center',
|
24
|
+
'twkb.view.done_tasks' => '5',
|
25
|
+
'twkb.stages' => 'backlog,next,inprogress,waiting,done',
|
26
|
+
'twkb.stages.backlog.wip' => '10',
|
27
|
+
'twkb.stages.backlog.label.value' => 'Backlog',
|
28
|
+
'twkb.stages.next.wip' => '5',
|
29
|
+
'twkb.stages.next.label.value' => 'Next',
|
30
|
+
'twkb.stages.inprogress.wip' => '3',
|
31
|
+
'twkb.stages.inprogress.label.value' => 'In progress',
|
32
|
+
'twkb.stages.waiting.wip' => '6',
|
33
|
+
'twkb.stages.waiting.label.value' => 'Waiting',
|
34
|
+
'twkb.stages.done.label.value' => 'Done'
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def read
|
39
|
+
begin
|
40
|
+
user_config = ParseConfig.new("#{Dir.home}/.taskrc")
|
41
|
+
if user_config.params['twkb.stages'] and user_config.params['twkb.stages'].empty?
|
42
|
+
user_config.params['twkb.stages'] = defaults['twkb.stages']
|
43
|
+
end
|
44
|
+
@config = defaults.merge(user_config.params)
|
45
|
+
rescue Errno::EACCES
|
46
|
+
puts "Failed to read the configuration. Using defaults."
|
47
|
+
@config = defaults
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def prepare
|
52
|
+
@config.keys.each do |k|
|
53
|
+
# Convert numbers to integers for convenience
|
54
|
+
if @config[k] =~ /^\d+$/
|
55
|
+
@config[k] = @config[k].to_i
|
56
|
+
end
|
57
|
+
# Remove the 'twkb' part for convenience
|
58
|
+
@config[k.gsub(/^twkb\.(.*)/, '\1')] = @config.delete(k)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_stages
|
63
|
+
@stage_names = self['stages'].split(',')
|
64
|
+
@stages = {}
|
65
|
+
@stage_names.each do |stage|
|
66
|
+
@stages[stage] = {
|
67
|
+
:tasks => [],
|
68
|
+
:wip => self["stages.#{stage}.wip"].to_i || nil,
|
69
|
+
:label => {
|
70
|
+
:value => self["stages.#{stage}.label.value"] || stage,
|
71
|
+
:alignment => (self["stages.#{stage}.label.alignment"] || self["view.stages.alignment"]).to_sym
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'terminal-table'
|
2
|
+
require 'rainbow'
|
3
|
+
|
4
|
+
module TWKB
|
5
|
+
class Formatter
|
6
|
+
def initialize(options)
|
7
|
+
raise ArgumentError, 'Missing :stages argument' unless options[:stages]
|
8
|
+
raise ArgumentError, ':stages is not a Hash' unless options[:stages].is_a? Hash
|
9
|
+
@cell_width = options[:cell_width]
|
10
|
+
@cell_width ||= 15
|
11
|
+
@stages = options[:stages]
|
12
|
+
prepare
|
13
|
+
end
|
14
|
+
|
15
|
+
def table
|
16
|
+
stage_labels = @stages.keys.map{|k,v| @stages[k][:label]}
|
17
|
+
Terminal::Table.new :headings => stage_labels, :rows => [@lanes]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def color_box(text, width=15, fg=:black, bg=:white)
|
23
|
+
lines = text.scan /.{1,#{width}}/
|
24
|
+
lines.map!{|line| "#{line.ljust(width).background(bg).foreground(fg)}\n"}
|
25
|
+
lines.join
|
26
|
+
end
|
27
|
+
|
28
|
+
def prepare
|
29
|
+
@lanes = Array.new
|
30
|
+
@stages.each do |k, v|
|
31
|
+
tasks = v[:tasks]
|
32
|
+
text = String.new
|
33
|
+
# Makes sure empty columns have the correct cell width
|
34
|
+
text << ' ' * @cell_width if tasks.count == 0
|
35
|
+
tasks.each do |k, v|
|
36
|
+
next unless k
|
37
|
+
if k['status'] == 'completed'
|
38
|
+
text << color_box("#{k['description']}", @cell_width)
|
39
|
+
else
|
40
|
+
text << color_box("#{k['id']}) #{k['description']}", @cell_width)
|
41
|
+
end
|
42
|
+
text << "\n"
|
43
|
+
end
|
44
|
+
@lanes << text
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/twkb/task.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module TWKB
|
4
|
+
module Task
|
5
|
+
def Task.all(udas = {})
|
6
|
+
f_udas = udas.map {|k,v| "#{k}:#{v}"}.join(' ')
|
7
|
+
cmd = "task rc.verbose=nothing rc.json.array=yes #{f_udas} export"
|
8
|
+
IO.popen(cmd, 'r:UTF-8') { |output|
|
9
|
+
JSON.parse(output.read)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/twkb/version.rb
ADDED
data/twkb.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "twkb/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'twkb'
|
7
|
+
s.version = TWKB::VERSION
|
8
|
+
s.date = '2013-05-01'
|
9
|
+
s.summary = "TaskWarrior Kanban"
|
10
|
+
s.description = "A command line utility based on task warrior to create kanban boards."
|
11
|
+
s.authors = ["Kim Nørgaard"]
|
12
|
+
s.email = 'jasen@jasen.dk'
|
13
|
+
s.files = ["lib/twkb.rb"]
|
14
|
+
s.homepage = ""
|
15
|
+
|
16
|
+
s.add_runtime_dependency 'terminal-table', '~>1.4.5'
|
17
|
+
s.add_runtime_dependency 'parseconfig', '~>1.0.2'
|
18
|
+
s.add_runtime_dependency 'rainbow', '~>1.1.4'
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- "Kim N\xC3\xB8rgaard"
|
@@ -61,14 +61,21 @@ dependencies:
|
|
61
61
|
version_requirements: *id003
|
62
62
|
description: A command line utility based on task warrior to create kanban boards.
|
63
63
|
email: jasen@jasen.dk
|
64
|
-
executables:
|
65
|
-
|
64
|
+
executables:
|
65
|
+
- twkb
|
66
66
|
extensions: []
|
67
67
|
|
68
68
|
extra_rdoc_files: []
|
69
69
|
|
70
|
-
files:
|
71
|
-
|
70
|
+
files:
|
71
|
+
- .rvmrc
|
72
|
+
- bin/twkb
|
73
|
+
- lib/twkb.rb
|
74
|
+
- lib/twkb/config.rb
|
75
|
+
- lib/twkb/formatter.rb
|
76
|
+
- lib/twkb/task.rb
|
77
|
+
- lib/twkb/version.rb
|
78
|
+
- twkb.gemspec
|
72
79
|
has_rdoc: true
|
73
80
|
homepage: ""
|
74
81
|
licenses: []
|