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 ADDED
@@ -0,0 +1 @@
1
+ rvm use default@twkb
data/bin/twkb ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'twkb'
4
+
5
+ twkb = TWKB::App.new( :board_name => ARGV.first )
6
+ twkb.print_table
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
@@ -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
@@ -0,0 +1,3 @@
1
+ module TWKB
2
+ VERSION = '0.0.2'
3
+ end
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
- - 1
9
- version: 0.0.1
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: []