cardigan 0.0.3 → 0.0.4
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/README.rdoc +21 -6
- data/lib/cardigan/cli.rb +2 -1
- data/lib/cardigan/command/batch_update_cards.rb +24 -0
- data/lib/cardigan/command/claim_cards.rb +17 -0
- data/lib/cardigan/command/create_card.rb +13 -0
- data/lib/cardigan/command/destroy_cards.rb +16 -0
- data/lib/cardigan/command/filter_cards.rb +19 -0
- data/lib/cardigan/command/list_cards.rb +21 -0
- data/lib/cardigan/command/open_card.rb +17 -0
- data/lib/cardigan/command/open_workflow.rb +17 -0
- data/lib/cardigan/command/select_columns.rb +20 -0
- data/lib/cardigan/command/unclaim_cards.rb +17 -0
- data/lib/cardigan/command/unfilter_cards.rb +13 -0
- data/lib/cardigan/context.rb +8 -4
- data/lib/cardigan/entry_context.rb +18 -5
- data/lib/cardigan/filtered_repository.rb +31 -0
- data/lib/cardigan/repository.rb +2 -2
- data/lib/cardigan/root_context.rb +29 -97
- data/lib/cardigan/text_report_formatter.rb +4 -2
- data/lib/cardigan/workflow_context.rb +37 -0
- data/lib/cardigan/workflow_repository.rb +16 -0
- metadata +16 -2
data/README.rdoc
CHANGED
@@ -16,7 +16,7 @@ A simple command line project task tracking tool.
|
|
16
16
|
|
17
17
|
cardigan
|
18
18
|
|
19
|
-
This will prompt for your name and email address (
|
19
|
+
This will prompt for your name and email address (and store them in ~/.cardigan), create a folder called .cards in the current directory and enter a shell. The idea is that you will run this at the root of a git/hg/svn/whatever repository and manage the cards in the same way you manage your source code.
|
20
20
|
|
21
21
|
cardigan >
|
22
22
|
|
@@ -29,21 +29,36 @@ You start in listing mode.
|
|
29
29
|
The commands available are (with the awesome power of tab completion):
|
30
30
|
|
31
31
|
* quit or exit or ctrl-d - exit
|
32
|
-
* list - shows all cards
|
32
|
+
* list - shows all cards with an index
|
33
33
|
* filter <filter> - sets the filter for cards - this is ruby code such as card[:name].start_with?('a')
|
34
|
-
* claim <numbers> - sets the owner of the specified cards (by index
|
35
|
-
* unclaim <numbers> - removes the owner from the specified cards (by index
|
34
|
+
* claim <numbers> - sets the owner of the specified cards (by index from the list)
|
35
|
+
* unclaim <numbers> - removes the owner from the specified cards (by index from the list)
|
36
36
|
* create <name> - creates a card with the specified name
|
37
37
|
* open <name> - creates or opens the card and enters edit mode
|
38
38
|
* columns - lists or changes the columns to be displayed by the list command
|
39
|
-
* destroy <numbers> - deletes the specified cards (by index
|
39
|
+
* destroy <numbers> - deletes the specified cards (by index from the list)
|
40
|
+
* set <key> <numbers> - prompts for a field value and sets it on all specified cards (by index from the list)
|
41
|
+
* workflow - enters workflow editing mode
|
40
42
|
|
41
43
|
== Editing mode
|
42
44
|
|
43
45
|
* quit or exit or ctrl-d - exit
|
44
46
|
* show - dumps the values of all card field values
|
45
47
|
* set <key> - creates a new field and prompts for the new value
|
48
|
+
* to <status> - changes the status of the card to the given status (the tab completion will be populated with the valid subsequent statuses from the current status)
|
49
|
+
|
50
|
+
== Workflow mode
|
51
|
+
|
52
|
+
Workflow is pretty simple - it is just for convenience in specifiying the set of valid statuses for cards with a specific status.
|
53
|
+
|
54
|
+
The only purpose is to populate tab completion in editing mode for a card.
|
55
|
+
|
56
|
+
* quit or exit or ctrl-d - exit
|
57
|
+
* show - dumps the current workflow (statuses with their valid subsequent statuses)
|
58
|
+
* create <status> - creates a new status
|
59
|
+
* add <status> <statuses> - add the specified statuses as valid transitions from status
|
60
|
+
* remove <status> <statuses> - remove the specified statuses as valid transitions from status
|
46
61
|
|
47
62
|
== Future plans
|
48
63
|
|
49
|
-
Refer to the .cards for detailed story breakdown but
|
64
|
+
Refer to the .cards for detailed story breakdown but importing, exporting and generating pretty html reports/charts.
|
data/lib/cardigan/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'cardigan/io'
|
2
2
|
require 'cardigan/root_context'
|
3
3
|
require 'cardigan/repository'
|
4
|
+
require 'cardigan/workflow_repository'
|
4
5
|
|
5
6
|
module Cardigan
|
6
7
|
class Cli
|
@@ -21,7 +22,7 @@ module Cardigan
|
|
21
22
|
@home.store CONFIG_FILE, config
|
22
23
|
end
|
23
24
|
name = "\"#{config[:name]}\" <#{config[:email]}>"
|
24
|
-
RootContext.new(@io, Repository.new('.cards'), name).push
|
25
|
+
RootContext.new(@io, Repository.new('.cards'), name, WorkflowRepository.new('.')).push
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Cardigan
|
2
|
+
module Command
|
3
|
+
class BatchUpdateCards
|
4
|
+
def initialize repository, io
|
5
|
+
@repository, @io = repository, io
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute text
|
9
|
+
key, *rest = text.scan(/\w+/)
|
10
|
+
value = @io.ask("Enter the new value for #{key}")
|
11
|
+
@repository.each_card_from_indices(rest.join(' ')) do |card|
|
12
|
+
if value.empty?
|
13
|
+
@io.say "removing #{key} from '#{card['name']}'"
|
14
|
+
card.delete key
|
15
|
+
else
|
16
|
+
@io.say "setting #{key} to '#{value}' for '#{card['name']}'"
|
17
|
+
card[key] = value
|
18
|
+
end
|
19
|
+
@repository.save card
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Cardigan
|
2
|
+
module Command
|
3
|
+
class ClaimCards
|
4
|
+
def initialize repository, io
|
5
|
+
@repository, @io = repository, io
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute numbers
|
9
|
+
@repository.each_card_from_indices(numbers) do |card|
|
10
|
+
@io.say "claiming \"#{card['name']}\""
|
11
|
+
card['owner'] = @name
|
12
|
+
@repository.save card
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cardigan
|
2
|
+
module Command
|
3
|
+
class DestroyCards
|
4
|
+
def initialize repository, io
|
5
|
+
@repository, @io = repository, io
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute numbers
|
9
|
+
@repository.each_card_from_indices(numbers) do |card|
|
10
|
+
@io.say "destroying \"#{card['name']}\""
|
11
|
+
@repository.destroy card
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Cardigan
|
2
|
+
module Command
|
3
|
+
class FilterCards
|
4
|
+
def initialize repository, io
|
5
|
+
@repository, @io = repository, io
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute filter
|
9
|
+
@repository.filter = filter
|
10
|
+
begin
|
11
|
+
@io.say "#{@repository.cards.length} cards match filter"
|
12
|
+
rescue Exception => e
|
13
|
+
@io.say "Invalid expression:\n#{e.message}"
|
14
|
+
@repository.filter = nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'cardigan/text_report_formatter'
|
2
|
+
|
3
|
+
module Cardigan
|
4
|
+
module Command
|
5
|
+
class ListCards
|
6
|
+
def initialize repository, io
|
7
|
+
@repository, @io = repository, io
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute name
|
11
|
+
cards = @repository.cards
|
12
|
+
formatter = TextReportFormatter.new @io
|
13
|
+
a = 0
|
14
|
+
@repository.columns.each do |column|
|
15
|
+
formatter.add_column(column, @repository.max_field_length(column))
|
16
|
+
end
|
17
|
+
formatter.output cards
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'cardigan/entry_context'
|
2
|
+
|
3
|
+
module Cardigan
|
4
|
+
module Command
|
5
|
+
class OpenCard
|
6
|
+
def initialize repository, workflow_repository, io
|
7
|
+
@repository, @workflow_repository, @io = repository, workflow_repository, io
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute name
|
11
|
+
card = @repository.find_or_create(name)
|
12
|
+
EntryContext.new(@io, @workflow_repository, card).push
|
13
|
+
@repository.save card
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'cardigan/workflow_context'
|
2
|
+
|
3
|
+
module Cardigan
|
4
|
+
module Command
|
5
|
+
class OpenWorkflow
|
6
|
+
def initialize workflow_repository, io
|
7
|
+
@workflow_repository, @io = workflow_repository, io
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute name
|
11
|
+
workflow = @workflow_repository.load
|
12
|
+
WorkflowContext.new(@io, workflow).push
|
13
|
+
@workflow_repository.save workflow
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Cardigan
|
2
|
+
module Command
|
3
|
+
class SelectColumns
|
4
|
+
def initialize repository, io
|
5
|
+
@repository, @io = repository, io
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute text
|
9
|
+
if text
|
10
|
+
@repository.columns = text.scan(/\w+/)
|
11
|
+
else
|
12
|
+
@io.say "current columns: #{@repository.columns.join(',')}"
|
13
|
+
columns = Set.new
|
14
|
+
@repository.cards.each {|card| columns += card.keys }
|
15
|
+
@io.say "available columns: #{columns.sort.join(',')}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Cardigan
|
2
|
+
module Command
|
3
|
+
class UnclaimCards
|
4
|
+
def initialize repository, io
|
5
|
+
@repository, @io = repository, io
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute numbers
|
9
|
+
@repository.each_card_from_indices(numbers) do |card|
|
10
|
+
@io.say "unclaiming \"#{card['name']}\""
|
11
|
+
card.delete('owner')
|
12
|
+
@repository.save card
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/cardigan/context.rb
CHANGED
@@ -3,9 +3,9 @@ require 'readline'
|
|
3
3
|
module Cardigan
|
4
4
|
module Context
|
5
5
|
def refresh
|
6
|
-
|
6
|
+
commands = respond_to?(:refresh_commands) ? refresh_commands : []
|
7
7
|
Readline.completion_proc = lambda do |text|
|
8
|
-
(@commands + ['quit', 'exit']).grep( /^#{Regexp.escape(text)}/ ).sort
|
8
|
+
(commands + @commands.keys + ['quit', 'exit']).grep( /^#{Regexp.escape(text)}/ ).sort
|
9
9
|
end
|
10
10
|
Readline.completer_word_break_characters = ''
|
11
11
|
end
|
@@ -33,11 +33,15 @@ module Cardigan
|
|
33
33
|
end
|
34
34
|
puts
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def process_command name, parameter=nil
|
38
38
|
m = "#{name}_command".to_sym
|
39
39
|
if respond_to?(m)
|
40
|
-
send(m, parameter)
|
40
|
+
send(m, parameter)
|
41
|
+
return
|
42
|
+
end
|
43
|
+
if @commands[name]
|
44
|
+
@commands[name].execute parameter
|
41
45
|
else
|
42
46
|
@io.say 'unknown command'
|
43
47
|
end
|
@@ -3,17 +3,30 @@ require 'cardigan/context'
|
|
3
3
|
module Cardigan
|
4
4
|
class EntryContext
|
5
5
|
include Context
|
6
|
-
|
7
|
-
def initialize io, entry
|
8
|
-
@io, @entry = io, entry
|
6
|
+
|
7
|
+
def initialize io, workflow_repository, entry
|
8
|
+
@io, @workflow_repository, @entry = io, workflow_repository, entry
|
9
9
|
@prompt_text = "#{File.expand_path('.').split('/').last.slice(0..0)}/#{entry['name']} > "
|
10
|
-
@commands =
|
10
|
+
@commands = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def refresh_commands
|
14
|
+
commands = ['set', 'show']
|
15
|
+
status = @entry['status'] || 'none'
|
16
|
+
@workflow_repository.load[status].each do |s|
|
17
|
+
commands << "now #{s}"
|
18
|
+
end
|
19
|
+
commands
|
20
|
+
end
|
21
|
+
|
22
|
+
def now_command status
|
23
|
+
@entry['status'] = status
|
11
24
|
end
|
12
25
|
|
13
26
|
def set_command key
|
14
27
|
@entry[key] = @io.ask("Enter the new value for #{key}")
|
15
28
|
end
|
16
|
-
|
29
|
+
|
17
30
|
def show_command ignored=nil
|
18
31
|
@entry.keys.sort.each do |key|
|
19
32
|
@io.say "#{key}: #{@entry[key]}"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Cardigan
|
4
|
+
class FilteredRepository
|
5
|
+
attr_accessor :filter, :columns, :sort
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@repository, :refresh, :save, :destroy, :find_or_create
|
10
|
+
|
11
|
+
def initialize repository, sort, *columns
|
12
|
+
@repository, @sort, @columns = repository, sort, columns
|
13
|
+
end
|
14
|
+
|
15
|
+
def cards
|
16
|
+
cards = @filter ? @repository.cards.select {|card| eval @filter } : @repository.cards
|
17
|
+
cards.sort {|a,b| a[sort] <=> b[sort] }
|
18
|
+
end
|
19
|
+
|
20
|
+
def max_field_length name
|
21
|
+
cards.map {|card| card[name] ? card[name].length : 0 }.max
|
22
|
+
end
|
23
|
+
|
24
|
+
def each_card_from_indices numbers
|
25
|
+
c = cards
|
26
|
+
numbers.scan(/\d+/).each do |n|
|
27
|
+
yield c[n.to_i - 1]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/cardigan/repository.rb
CHANGED
@@ -2,112 +2,44 @@ require 'rubygems'
|
|
2
2
|
require 'uuidtools'
|
3
3
|
require 'set'
|
4
4
|
require 'cardigan/context'
|
5
|
-
require 'cardigan/
|
6
|
-
require 'cardigan/
|
5
|
+
require 'cardigan/filtered_repository'
|
6
|
+
require 'cardigan/command/batch_update_cards'
|
7
|
+
require 'cardigan/command/claim_cards'
|
8
|
+
require 'cardigan/command/create_card'
|
9
|
+
require 'cardigan/command/destroy_cards'
|
10
|
+
require 'cardigan/command/filter_cards'
|
11
|
+
require 'cardigan/command/list_cards'
|
12
|
+
require 'cardigan/command/open_card'
|
13
|
+
require 'cardigan/command/open_workflow'
|
14
|
+
require 'cardigan/command/select_columns'
|
15
|
+
require 'cardigan/command/unclaim_cards'
|
16
|
+
require 'cardigan/command/unfilter_cards'
|
7
17
|
|
8
18
|
module Cardigan
|
9
19
|
class RootContext
|
10
20
|
include Context
|
11
21
|
|
12
|
-
def initialize io, repository, name
|
13
|
-
@io, @repository, @name = io, repository, name
|
22
|
+
def initialize io, repository, name, workflow_repository
|
23
|
+
@io, @repository, @name, @workflow_repository = io, FilteredRepository.new(repository, 'name', 'name'), name, workflow_repository
|
14
24
|
@prompt_text = "#{File.expand_path('.').split('/').last} > "
|
15
|
-
@
|
25
|
+
@commands = {
|
26
|
+
'claim' => Command::ClaimCards.new(@repository, @io),
|
27
|
+
'columns' => Command::SelectColumns.new(@repository, @io),
|
28
|
+
'create' => Command::CreateCard.new(@repository),
|
29
|
+
'destroy' => Command::DestroyCards.new(@repository, @io),
|
30
|
+
'filter' => Command::FilterCards.new(@repository, @io),
|
31
|
+
'list' => Command::ListCards.new(@repository, @io),
|
32
|
+
'open' => Command::OpenCard.new(@repository, @workflow_repository, @io),
|
33
|
+
'set' => Command::BatchUpdateCards.new(@repository, @io),
|
34
|
+
'unclaim' => Command::UnclaimCards.new(@repository, @io),
|
35
|
+
'unfilter' => Command::UnfilterCards.new(@repository),
|
36
|
+
'workflow' => Command::OpenWorkflow.new(@workflow_repository, @io)
|
37
|
+
}
|
16
38
|
end
|
17
39
|
|
18
40
|
def refresh_commands
|
19
41
|
@repository.refresh
|
20
|
-
@
|
21
|
-
@repository.cards.each do |card|
|
22
|
-
@commands << "open #{card['name']}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def create_command name
|
27
|
-
@repository.save @repository.find_or_create(name)
|
28
|
-
end
|
29
|
-
|
30
|
-
def open_command name
|
31
|
-
card = @repository.find_or_create(name)
|
32
|
-
EntryContext.new(@io, card).push
|
33
|
-
@repository.save card
|
34
|
-
end
|
35
|
-
|
36
|
-
def destroy_command numbers
|
37
|
-
each_card_from_indices(numbers) do |card|
|
38
|
-
@io.say "destroying \"#{card['name']}\""
|
39
|
-
@repository.destroy card
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def list_command ignored
|
44
|
-
cards = sorted_selection
|
45
|
-
formatter = TextReportFormatter.new @io
|
46
|
-
a = 0
|
47
|
-
@columns.each do |column|
|
48
|
-
formatter.add_column(column, max_field_length(cards, column))
|
49
|
-
end
|
50
|
-
formatter.output cards
|
51
|
-
end
|
52
|
-
|
53
|
-
def unfilter_command ignored
|
54
|
-
@filter = nil
|
55
|
-
end
|
56
|
-
|
57
|
-
def columns_command text
|
58
|
-
if text
|
59
|
-
@columns = text.scan(/\w+/)
|
60
|
-
else
|
61
|
-
@io.say "current columns: #{@columns.join(',')}"
|
62
|
-
columns = Set.new
|
63
|
-
sorted_selection.each do |card|
|
64
|
-
columns += card.keys
|
65
|
-
end
|
66
|
-
@io.say "available columns: #{columns.sort.join(',')}"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def filter_command code
|
71
|
-
@filter = code
|
72
|
-
begin
|
73
|
-
cards = @repository.cards.select {|card| eval @filter }
|
74
|
-
@io.say "#{cards.count} cards match filter"
|
75
|
-
rescue Exception => e
|
76
|
-
@io.say "Invalid expression:\n#{e.message}"
|
77
|
-
@filter = nil
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def claim_command numbers
|
82
|
-
each_card_from_indices(numbers) do |card|
|
83
|
-
@io.say "claiming \"#{card['name']}\""
|
84
|
-
card['owner'] = @name
|
85
|
-
@repository.save card
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def unclaim_command numbers
|
90
|
-
each_card_from_indices(numbers) do |card|
|
91
|
-
@io.say "claiming \"#{card['name']}\""
|
92
|
-
card.delete('owner')
|
93
|
-
@repository.save card
|
94
|
-
end
|
95
|
-
end
|
96
|
-
private
|
97
|
-
def each_card_from_indices numbers
|
98
|
-
cards = sorted_selection
|
99
|
-
numbers.scan(/\d+/).each do |n|
|
100
|
-
yield cards[n.to_i - 1]
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def max_field_length cards, name
|
105
|
-
cards.map {|card| card[name] ? card[name].length : 0 }.max
|
106
|
-
end
|
107
|
-
|
108
|
-
def sorted_selection
|
109
|
-
cards = @filter ? @repository.cards.select {|card| eval @filter } : @repository.cards
|
110
|
-
cards.sort {|a,b| a['name'] <=> b['name'] }
|
42
|
+
@repository.cards.map {|card| "open #{card['name']}" }
|
111
43
|
end
|
112
44
|
end
|
113
|
-
end
|
45
|
+
end
|
@@ -18,7 +18,9 @@ module Cardigan
|
|
18
18
|
row 'index', @columns.map {|tuple| tuple.first }
|
19
19
|
hline
|
20
20
|
hashes.each_with_index do |h,i|
|
21
|
-
|
21
|
+
first = (i+1).to_s
|
22
|
+
values = @columns.map {|tuple| h[tuple.first]}
|
23
|
+
row first, values
|
22
24
|
end
|
23
25
|
hline
|
24
26
|
end
|
@@ -26,7 +28,7 @@ private
|
|
26
28
|
def hline
|
27
29
|
@io.say ' ' + '-' * @width
|
28
30
|
end
|
29
|
-
|
31
|
+
|
30
32
|
def row first, values
|
31
33
|
a = "| #{first.ljust(@heading.length)} | "
|
32
34
|
@columns.each_with_index do |tuple, index|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'cardigan/context'
|
2
|
+
|
3
|
+
module Cardigan
|
4
|
+
class WorkflowContext
|
5
|
+
include Context
|
6
|
+
|
7
|
+
def initialize io, entry
|
8
|
+
@io, @entry = io, entry
|
9
|
+
@prompt_text = "#{File.expand_path('.').split('/').last.slice(0..0)}/workflow > "
|
10
|
+
@commands = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def refresh_commands
|
14
|
+
['create', 'add', 'remove', 'show']
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_command key
|
18
|
+
@entry[key] = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_command text
|
22
|
+
name, *states = text.scan(/\w+/)
|
23
|
+
@entry[name] += states
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_command text
|
27
|
+
name, *states = text.scan(/\w+/)
|
28
|
+
@entry[name] -= states
|
29
|
+
end
|
30
|
+
|
31
|
+
def show_command ignored=nil
|
32
|
+
@entry.keys.sort.each do |key|
|
33
|
+
@io.say "#{key}: #{@entry[key].join(',')}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cardigan
|
2
|
+
class WorkflowRepository
|
3
|
+
def initialize path
|
4
|
+
@directory = Directory.new(path)
|
5
|
+
@path = '.card_workflow'
|
6
|
+
end
|
7
|
+
|
8
|
+
def save workflow
|
9
|
+
@directory.store @path, workflow
|
10
|
+
end
|
11
|
+
|
12
|
+
def load
|
13
|
+
@directory.has_file?(@path) ? @directory.load(@path) : {}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cardigan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Ryall
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-03-
|
12
|
+
date: 2010-03-14 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -34,13 +34,27 @@ extra_rdoc_files: []
|
|
34
34
|
|
35
35
|
files:
|
36
36
|
- lib/cardigan/cli.rb
|
37
|
+
- lib/cardigan/command/batch_update_cards.rb
|
38
|
+
- lib/cardigan/command/claim_cards.rb
|
39
|
+
- lib/cardigan/command/create_card.rb
|
40
|
+
- lib/cardigan/command/destroy_cards.rb
|
41
|
+
- lib/cardigan/command/filter_cards.rb
|
42
|
+
- lib/cardigan/command/list_cards.rb
|
43
|
+
- lib/cardigan/command/open_card.rb
|
44
|
+
- lib/cardigan/command/open_workflow.rb
|
45
|
+
- lib/cardigan/command/select_columns.rb
|
46
|
+
- lib/cardigan/command/unclaim_cards.rb
|
47
|
+
- lib/cardigan/command/unfilter_cards.rb
|
37
48
|
- lib/cardigan/context.rb
|
38
49
|
- lib/cardigan/directory.rb
|
39
50
|
- lib/cardigan/entry_context.rb
|
51
|
+
- lib/cardigan/filtered_repository.rb
|
40
52
|
- lib/cardigan/io.rb
|
41
53
|
- lib/cardigan/repository.rb
|
42
54
|
- lib/cardigan/root_context.rb
|
43
55
|
- lib/cardigan/text_report_formatter.rb
|
56
|
+
- lib/cardigan/workflow_context.rb
|
57
|
+
- lib/cardigan/workflow_repository.rb
|
44
58
|
- bin/cardigan
|
45
59
|
- README.rdoc
|
46
60
|
- MIT-LICENSE
|