cardigan 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|