twkb 0.0.1 → 0.0.2

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/.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: []