cardigan 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/Rakefile +6 -0
- data/bin/cardigan +2 -0
- data/lib/cardigan/cli.rb +18 -20
- data/lib/cardigan/command/add_transitions.rb +27 -0
- data/lib/cardigan/command/batch_update_cards.rb +15 -14
- data/lib/cardigan/command/change_status.rb +18 -11
- data/lib/cardigan/command/change_value.rb +11 -10
- data/lib/cardigan/command/claim_cards.rb +15 -13
- data/lib/cardigan/command/commit_changes.rb +15 -0
- data/lib/cardigan/command/count_cards.rb +6 -2
- data/lib/cardigan/command/create_card.rb +14 -11
- data/lib/cardigan/command/destroy_cards.rb +15 -13
- data/lib/cardigan/command/edit_value.rb +12 -11
- data/lib/cardigan/command/export_cards.rb +9 -4
- data/lib/cardigan/command/filter_cards.rb +6 -0
- data/lib/cardigan/command/import_cards.rb +18 -4
- data/lib/cardigan/command/list_cards.rb +5 -0
- data/lib/cardigan/command/open_card.rb +20 -12
- data/lib/cardigan/command/open_workflow.rb +14 -12
- data/lib/cardigan/command/remove_transitions.rb +25 -0
- data/lib/cardigan/command/show_entry.rb +12 -10
- data/lib/cardigan/command/specify_display_columns.rb +6 -0
- data/lib/cardigan/command/specify_sort_columns.rb +6 -0
- data/lib/cardigan/command/total_cards.rb +6 -2
- data/lib/cardigan/command/unclaim_cards.rb +13 -13
- data/lib/cardigan/command/unfilter_cards.rb +6 -0
- data/lib/cardigan/commands.rb +10 -0
- data/lib/cardigan/entry_context.rb +7 -12
- data/lib/cardigan/filtered_repository.rb +9 -5
- data/lib/cardigan/io.rb +1 -1
- data/lib/cardigan/root_context.rb +21 -23
- data/lib/cardigan/workflow_context.rb +12 -29
- data/lib/cardigan/workflow_repository.rb +18 -10
- data/spec/command/add_transitions_spec.rb +35 -0
- data/spec/command/batch_update_cards_spec.rb +9 -0
- data/spec/command/change_status_spec.rb +9 -0
- data/spec/command/change_value_spec.rb +9 -0
- data/spec/command/claim_cards_spec.rb +9 -0
- data/spec/command/commit_changes_spec.rb +9 -0
- data/spec/command/count_cards_spec.rb +68 -0
- data/spec/command/create_card_spec.rb +9 -0
- data/spec/command/destroy_cards_spec.rb +9 -0
- data/spec/command/edit_value_spec.rb +9 -0
- data/spec/command/export_cards_spec.rb +9 -0
- data/spec/command/filter_cards_spec.rb +9 -0
- data/spec/command/import_cards_spec.rb +9 -0
- data/spec/command/list_cards_spec.rb +9 -0
- data/spec/command/open_card_spec.rb +9 -0
- data/spec/command/open_workflow_spec.rb +9 -0
- data/spec/command/remove_transitions_spec.rb +25 -0
- data/spec/command/show_entry_spec.rb +9 -0
- data/spec/command/specify_display_columns_spec.rb +9 -0
- data/spec/command/specify_sort_columns_spec.rb +9 -0
- data/spec/command/total_cards_spec.rb +82 -0
- data/spec/command/unfilter_cards_spec.rb +9 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/text_report_formatter_spec.rb +47 -0
- metadata +100 -35
- data/lib/cardigan/command/select_columns.rb +0 -20
- data/lib/cardigan/context.rb +0 -60
- data/lib/cardigan/directory.rb +0 -34
- data/lib/cardigan/repository.rb +0 -54
- data/lib/cardigan/symbol_extensions.rb +0 -3
data/.gemtest
ADDED
File without changes
|
data/Rakefile
ADDED
data/bin/cardigan
CHANGED
data/lib/cardigan/cli.rb
CHANGED
@@ -1,28 +1,26 @@
|
|
1
1
|
require 'cardigan/io'
|
2
2
|
require 'cardigan/root_context'
|
3
|
-
require '
|
3
|
+
require 'flat_hash/directory'
|
4
|
+
require 'flat_hash/serialiser'
|
5
|
+
require 'flat_hash/repository'
|
4
6
|
require 'cardigan/workflow_repository'
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
CONFIG_FILE = '.cardigan'
|
8
|
+
class Cardigan::Cli
|
9
|
+
CONFIG_FILE = '.cardigan'
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def initialize io=Cardigan::Io.new
|
12
|
+
@io = io
|
13
|
+
@home = FlatHash::Directory.new(FlatHash::Serialiser.new,File.expand_path('~'))
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
name = "\"#{config[:name]}\" <#{config[:email]}>"
|
25
|
-
RootContext.new(@io, Repository.new('.cards'), name, WorkflowRepository.new('.')).push
|
26
|
-
end
|
16
|
+
def execute *args
|
17
|
+
config = @home.exist?(CONFIG_FILE) ? @home[CONFIG_FILE] : {}
|
18
|
+
config['name'] = @io.ask('Enter your full name') unless config['name']
|
19
|
+
config['email'] = @io.ask('Enter your email address') unless config['email']
|
20
|
+
@home[CONFIG_FILE] = config
|
21
|
+
repository = FlatHash::Repository.new(FlatHash::Serialiser.new,'.cards')
|
22
|
+
name = "\"#{config['name']}\" <#{config['email']}>"
|
23
|
+
workflow_repository = Cardigan::WorkflowRepository.new('.')
|
24
|
+
Cardigan::RootContext.new(@io, repository, name, workflow_repository).push
|
27
25
|
end
|
28
26
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'cardigan/commands'
|
2
|
+
|
3
|
+
class Cardigan::Command::AddTransitions
|
4
|
+
attr_reader :usage, :help
|
5
|
+
|
6
|
+
def initialize entry, io
|
7
|
+
@entry, @io = entry, io
|
8
|
+
@usage = '<start status> [<subsequent status>]+'
|
9
|
+
@help = 'Creates transitions from a starting status to a number of subsequent statuses'
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute text=nil
|
13
|
+
unless text and !text.empty?
|
14
|
+
@io.say 'missing required start status'
|
15
|
+
return
|
16
|
+
end
|
17
|
+
name, *states = text.scan(/\w+/)
|
18
|
+
if states.empty?
|
19
|
+
@io.say 'missing required subsequent status'
|
20
|
+
return
|
21
|
+
end
|
22
|
+
@entry[name] ||= []
|
23
|
+
states = states.uniq
|
24
|
+
@entry[name] += states
|
25
|
+
states.each {|state| @entry[state] ||= [] }
|
26
|
+
end
|
27
|
+
end
|
@@ -1,20 +1,21 @@
|
|
1
|
+
require 'cardigan/commands'
|
1
2
|
require 'cardigan/card_editor'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
class BatchUpdateCards
|
6
|
-
def initialize repository, io
|
7
|
-
@repository, @io = repository, io
|
8
|
-
end
|
4
|
+
class Cardigan::Command::BatchUpdateCards
|
5
|
+
attr_reader :usage, :help
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
7
|
+
def initialize repository, io
|
8
|
+
@repository, @io = repository, io
|
9
|
+
@usage = '<field> <number>*'
|
10
|
+
@help = 'Sets the specified field to a new value for the specified cards (by index in the list)'
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute text
|
14
|
+
key, *rest = text.scan(/\w+/)
|
15
|
+
value = @io.ask("Enter the new value for #{key}")
|
16
|
+
@repository.each_card_from_indices(rest.join(' ')) do |card|
|
17
|
+
Cardigan::CardEditor.new(card, @io).set key, value
|
18
|
+
@repository[card.id] = card
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
@@ -1,13 +1,20 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
require 'cardigan/commands'
|
2
|
+
|
3
|
+
class Cardigan::Command::ChangeStatus
|
4
|
+
attr_reader :usage, :help
|
5
|
+
|
6
|
+
def initialize entry, workflow_repository
|
7
|
+
@entry, @workflow_repository = entry, workflow_repository
|
8
|
+
@usage = '<new status>'
|
9
|
+
@help = 'Changes the status of the current entry'
|
10
|
+
end
|
11
|
+
|
12
|
+
def completion text
|
13
|
+
status = @entry['status'] || 'none'
|
14
|
+
@workflow_repository.load[status].grep(/^#{text}/).sort || []
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute status
|
18
|
+
@entry['status'] = status
|
12
19
|
end
|
13
20
|
end
|
@@ -1,15 +1,16 @@
|
|
1
|
+
require 'cardigan/commands'
|
1
2
|
require 'cardigan/card_editor'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
class ChangeValue
|
6
|
-
def initialize entry, io
|
7
|
-
@entry, @io = entry, io
|
8
|
-
end
|
4
|
+
class Cardigan::Command::ChangeValue
|
5
|
+
attr_reader :usage, :help
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
def initialize entry, io
|
8
|
+
@entry, @io = entry, io
|
9
|
+
@usage = '<key>'
|
10
|
+
@help = 'Prompt for a new value to associate with the specified key'
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute key
|
14
|
+
Cardigan::CardEditor.new(@entry, @io).set key, @io.ask("Enter the new value for #{key}")
|
14
15
|
end
|
15
16
|
end
|
@@ -1,17 +1,19 @@
|
|
1
|
-
|
2
|
-
module Command
|
3
|
-
class ClaimCards
|
4
|
-
def initialize repository, io, name
|
5
|
-
@repository, @io, @name = repository, io, name
|
6
|
-
end
|
1
|
+
require 'cardigan/commands'
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
class Cardigan::Command::ClaimCards
|
4
|
+
attr_reader :usage, :help
|
5
|
+
|
6
|
+
def initialize repository, io, name
|
7
|
+
@repository, @io, @name = repository, io, name
|
8
|
+
@usage = '<number>*'
|
9
|
+
@help = 'Sets you as the owner of the specified cards (by index in the list)'
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute numbers
|
13
|
+
@repository.each_card_from_indices(numbers || '') do |card|
|
14
|
+
@io.say "claiming \"#{card['name']}\""
|
15
|
+
card['owner'] = @name
|
16
|
+
@repository[card.id] = card
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'cardigan/commands'
|
2
|
+
|
3
|
+
class Cardigan::Command::CommitChanges
|
4
|
+
attr_reader :usage, :help
|
5
|
+
|
6
|
+
def initialize repository, io
|
7
|
+
@io, @repository = io, repository
|
8
|
+
@usage = "<commit message>"
|
9
|
+
@help = "Commits _all_ changes (adds, removes and modifications) to the source control system\nWarning: Use with caution. This will not only commit changes to cards - all modifications will be committed."
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute text=nil
|
13
|
+
@repository.addremovecommit text
|
14
|
+
end
|
15
|
+
end
|
@@ -1,9 +1,13 @@
|
|
1
|
-
require 'cardigan/
|
1
|
+
require 'cardigan/commands'
|
2
2
|
require 'cardigan/text_report_formatter'
|
3
3
|
|
4
4
|
class Cardigan::Command::CountCards
|
5
|
+
attr_reader :usage, :help
|
6
|
+
|
5
7
|
def initialize repository, io
|
6
8
|
@repository, @io = repository, io
|
9
|
+
@usage = "<grouping field>*"
|
10
|
+
@help = "Counts cards aggregated across the specified grouping fields"
|
7
11
|
end
|
8
12
|
|
9
13
|
def execute text=nil
|
@@ -12,7 +16,7 @@ class Cardigan::Command::CountCards
|
|
12
16
|
lengths = Array.new(grouping_fields.size, 0)
|
13
17
|
counts = {}
|
14
18
|
total = 0
|
15
|
-
@repository.each do |card|
|
19
|
+
@repository.cards.each do |card|
|
16
20
|
grouping_fields.each_with_index do |grouping_field,index|
|
17
21
|
lengths[index] = card[grouping_field].size if card[grouping_field] and card[grouping_field].size > lengths[index]
|
18
22
|
end
|
@@ -1,13 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class CreateCard
|
4
|
-
def initialize repository
|
5
|
-
@repository = repository
|
6
|
-
end
|
1
|
+
require 'cardigan/commands'
|
2
|
+
require 'uuidtools'
|
7
3
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
class Cardigan::Command::CreateCard
|
5
|
+
attr_reader :usage, :help
|
6
|
+
|
7
|
+
def initialize repository
|
8
|
+
@repository = repository
|
9
|
+
@usage = '<name>'
|
10
|
+
@help = 'Creates a new card with the specified name (without opening it for editing)'
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute name
|
14
|
+
@repository[UUIDTools::UUID.random_create.to_s] = {'name' => name }
|
12
15
|
end
|
13
|
-
end
|
16
|
+
end
|
@@ -1,16 +1,18 @@
|
|
1
|
-
|
2
|
-
module Command
|
3
|
-
class DestroyCards
|
4
|
-
def initialize repository, io
|
5
|
-
@repository, @io = repository, io
|
6
|
-
end
|
1
|
+
require 'cardigan/commands'
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
class Cardigan::Command::DestroyCards
|
4
|
+
attr_reader :usage, :help
|
5
|
+
|
6
|
+
def initialize repository, io
|
7
|
+
@repository, @io = repository, io
|
8
|
+
@usage = '<number>*'
|
9
|
+
@help = 'Destroys the specified cards (by index in the list)'
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute numbers
|
13
|
+
@repository.each_card_from_indices(numbers) do |card|
|
14
|
+
@io.say "destroying \"#{card['name']}\""
|
15
|
+
@repository.destroy card.id
|
14
16
|
end
|
15
17
|
end
|
16
|
-
end
|
18
|
+
end
|
@@ -1,17 +1,18 @@
|
|
1
|
+
require 'cardigan/commands'
|
1
2
|
require 'splat'
|
2
3
|
require 'cardigan/card_editor'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
class EditValue
|
7
|
-
def initialize entry, io
|
8
|
-
@entry, @io = entry, io
|
9
|
-
end
|
5
|
+
class Cardigan::Command::EditValue
|
6
|
+
attr_reader :usage, :help
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
def initialize entry, io
|
9
|
+
@entry, @io = entry, io
|
10
|
+
@usage = '<key>'
|
11
|
+
@help = 'Launch default editor to specify a new value to associate with the specified key'
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute key
|
15
|
+
value = @entry[key] ? @entry[key] : ''
|
16
|
+
Cardigan::CardEditor.new(@entry, @io).set key, value.to_editor
|
16
17
|
end
|
17
18
|
end
|
@@ -1,17 +1,22 @@
|
|
1
|
+
require 'cardigan/commands'
|
1
2
|
require 'csv'
|
2
3
|
|
3
4
|
class Cardigan::Command::ExportCards
|
5
|
+
attr_reader :usage, :help
|
6
|
+
|
4
7
|
def initialize repository
|
5
8
|
@repository = repository
|
9
|
+
@usage = '<filename>'
|
10
|
+
@help = 'Exports all cards according to the current filter'
|
6
11
|
end
|
7
12
|
|
8
13
|
def execute filename
|
9
14
|
filename += ".csv"
|
10
|
-
columns = @repository.columns
|
15
|
+
columns = @repository.columns - ['id']
|
11
16
|
CSV.open(filename, 'w') do |writer|
|
12
|
-
writer << columns
|
13
|
-
@repository.each do |card|
|
14
|
-
writer << columns.map {|column| card[column] ? card[column] : ''}
|
17
|
+
writer << (['id'] + columns)
|
18
|
+
@repository.cards.each do |card|
|
19
|
+
writer << ([card.id] + columns.map {|column| card[column] ? card[column] : ''})
|
15
20
|
end
|
16
21
|
end
|
17
22
|
end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'cardigan/command/list_cards'
|
2
2
|
|
3
3
|
class Cardigan::Command::FilterCards < Cardigan::Command::ListCards
|
4
|
+
def initialize repository, io
|
5
|
+
super
|
6
|
+
@usage = '<ruby expression>'
|
7
|
+
@help = "Sets the filter on cards to be displayed\nThis filter is a ruby expression that must return a boolean.\nBound variables are card (a hash) and me (a string)"
|
8
|
+
end
|
9
|
+
|
4
10
|
def execute filter
|
5
11
|
@repository.filter = filter
|
6
12
|
begin
|
@@ -1,8 +1,14 @@
|
|
1
|
+
require 'cardigan/commands'
|
1
2
|
require 'csv'
|
3
|
+
require 'uuidtools'
|
2
4
|
|
3
5
|
class Cardigan::Command::ImportCards
|
6
|
+
attr_reader :usage, :help
|
7
|
+
|
4
8
|
def initialize repository, io
|
5
9
|
@repository, @io = repository, io
|
10
|
+
@usage = '<filename>'
|
11
|
+
@help = "Imports cards from the specific csv file.\nNote that if the file does not contain an id column, all new cards will be created.\nOtherwise, existing cards with a matching id will be updated."
|
6
12
|
end
|
7
13
|
|
8
14
|
def execute filename
|
@@ -14,14 +20,22 @@ class Cardigan::Command::ImportCards
|
|
14
20
|
header, id_index = nil, nil
|
15
21
|
CSV.open(filename, 'r') do |row|
|
16
22
|
if header
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
if id_index and row[id_index]
|
24
|
+
id = row[id_index]
|
25
|
+
card = @repository[id] if @repository.exist?(id)
|
26
|
+
end
|
27
|
+
if card
|
28
|
+
puts "updating #{id}"
|
29
|
+
else
|
30
|
+
id = UUIDTools::UUID.random_create.to_s
|
31
|
+
card = {}
|
32
|
+
puts "creating card #{id}"
|
33
|
+
end
|
20
34
|
editor = Cardigan::CardEditor.new(card, @io)
|
21
35
|
header.each_with_index do |field, index|
|
22
36
|
editor.set field, row[index]
|
23
37
|
end
|
24
|
-
@repository
|
38
|
+
@repository[id] = card
|
25
39
|
else
|
26
40
|
header = row
|
27
41
|
id_index = header.find_index('id')
|
@@ -1,8 +1,13 @@
|
|
1
|
+
require 'cardigan/commands'
|
1
2
|
require 'cardigan/text_report_formatter'
|
2
3
|
|
3
4
|
class Cardigan::Command::ListCards
|
5
|
+
attr_reader :usage, :help
|
6
|
+
|
4
7
|
def initialize repository, io
|
5
8
|
@repository, @io = repository, io
|
9
|
+
@usage = ''
|
10
|
+
@help = 'Lists all cards that match the current filter'
|
6
11
|
end
|
7
12
|
|
8
13
|
def execute text
|
@@ -1,17 +1,25 @@
|
|
1
1
|
require 'cardigan/entry_context'
|
2
|
+
require 'uuidtools'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
class OpenCard
|
6
|
-
def initialize repository, workflow_repository, io
|
7
|
-
@repository, @workflow_repository, @io = repository, workflow_repository, io
|
8
|
-
end
|
4
|
+
class Cardigan::Command::OpenCard
|
5
|
+
attr_reader :usage, :help
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
def initialize repository, workflow_repository, io
|
8
|
+
@repository, @workflow_repository, @io = repository, workflow_repository, io
|
9
|
+
@usage = '<card name>'
|
10
|
+
@help = 'Opens the specified card for editing'
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute name
|
14
|
+
entry = @repository.cards.find { |entry| entry['name'] == name }
|
15
|
+
id = entry ? entry.id : UUIDTools::UUID.random_create.to_s
|
16
|
+
entry ||= {'name' => name}
|
17
|
+
original = entry.dup
|
18
|
+
Cardigan::EntryContext.new(@io, @workflow_repository, entry).push
|
19
|
+
@repository[id] = entry unless original == entry
|
20
|
+
end
|
21
|
+
|
22
|
+
def completion text
|
23
|
+
@repository.cards.map {|card| card['name'] }.grep(/^#{Regexp.escape(text)}/).sort
|
16
24
|
end
|
17
25
|
end
|
@@ -1,17 +1,19 @@
|
|
1
|
+
require 'cardigan/commands'
|
1
2
|
require 'cardigan/workflow_context'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
class OpenWorkflow
|
6
|
-
def initialize workflow_repository, io
|
7
|
-
@workflow_repository, @io = workflow_repository, io
|
8
|
-
end
|
4
|
+
class Cardigan::Command::OpenWorkflow
|
5
|
+
attr_reader :usage, :help
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
def initialize workflow_repository, io
|
8
|
+
@workflow_repository, @io = workflow_repository, io
|
9
|
+
@usage = ''
|
10
|
+
@help = 'Opens the current workflow for editing'
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute name
|
14
|
+
workflow = @workflow_repository.load
|
15
|
+
original = workflow.dup
|
16
|
+
Cardigan::WorkflowContext.new(@io, workflow).push
|
17
|
+
@workflow_repository.save workflow unless workflow == original
|
16
18
|
end
|
17
19
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'cardigan/commands'
|
2
|
+
|
3
|
+
class Cardigan::Command::RemoveTransitions
|
4
|
+
attr_reader :usage, :help
|
5
|
+
|
6
|
+
def initialize entry, io
|
7
|
+
@entry, @io = entry, io
|
8
|
+
@usage = '<start status> [<subsequent status>]+'
|
9
|
+
@help = 'Removes transitions from a starting status to a number of subsequent statuses'
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute text=nil
|
13
|
+
unless text and !text.empty?
|
14
|
+
@io.say 'missing required start status'
|
15
|
+
return
|
16
|
+
end
|
17
|
+
name, *states = text.scan(/\w+/)
|
18
|
+
if states.empty?
|
19
|
+
@io.say 'missing required subsequent status'
|
20
|
+
return
|
21
|
+
end
|
22
|
+
name, *states = text.scan(/\w+/)
|
23
|
+
@entry[name] -= states
|
24
|
+
end
|
25
|
+
end
|
@@ -1,13 +1,15 @@
|
|
1
|
-
|
2
|
-
module Command
|
3
|
-
class ShowEntry
|
4
|
-
def initialize entry, io
|
5
|
-
@entry, @io = entry, io
|
6
|
-
end
|
1
|
+
require 'cardigan/commands'
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
class Cardigan::Command::ShowEntry
|
4
|
+
attr_reader :usage, :help
|
5
|
+
|
6
|
+
def initialize entry, io
|
7
|
+
@entry, @io = entry, io
|
8
|
+
@usage = ''
|
9
|
+
@help = 'Shows the entire content of the entry'
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute ignored=nil
|
13
|
+
@entry.keys.sort.each { |key| @io.say "#{key}: #{@entry[key].inspect}" }
|
12
14
|
end
|
13
15
|
end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'cardigan/command/list_cards'
|
2
2
|
|
3
3
|
class Cardigan::Command::SpecifyDisplayColumns < Cardigan::Command::ListCards
|
4
|
+
def initialize repository, io
|
5
|
+
super
|
6
|
+
@usage = '<column>*'
|
7
|
+
@help = 'Specify the list of columns to display'
|
8
|
+
end
|
9
|
+
|
4
10
|
def execute text
|
5
11
|
if text
|
6
12
|
@repository.display_columns = text.scan(/\w+/)
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'cardigan/command/list_cards'
|
2
2
|
|
3
3
|
class Cardigan::Command::SpecifySortColumns < Cardigan::Command::ListCards
|
4
|
+
def initialize repository, io
|
5
|
+
super
|
6
|
+
@usage = '<column>*'
|
7
|
+
@help = 'Specify the list of columns to sort by'
|
8
|
+
end
|
9
|
+
|
4
10
|
def execute text
|
5
11
|
if text
|
6
12
|
@repository.sort_columns = text.scan(/\w+/)
|
@@ -1,9 +1,13 @@
|
|
1
|
-
require 'cardigan/
|
1
|
+
require 'cardigan/commands'
|
2
2
|
require 'cardigan/text_report_formatter'
|
3
3
|
|
4
4
|
class Cardigan::Command::TotalCards
|
5
|
+
attr_reader :usage, :help
|
6
|
+
|
5
7
|
def initialize repository, io
|
6
8
|
@repository, @io = repository, io
|
9
|
+
@usage = '<numeric field> <grouping field>*'
|
10
|
+
@help = 'Calculates totals for the specified numeric field aggregated across the specified grouping fields'
|
7
11
|
end
|
8
12
|
|
9
13
|
def execute text=nil
|
@@ -13,7 +17,7 @@ class Cardigan::Command::TotalCards
|
|
13
17
|
return
|
14
18
|
end
|
15
19
|
counts = {}
|
16
|
-
@repository.each do |card|
|
20
|
+
@repository.cards.each do |card|
|
17
21
|
key = grouping_fields.map {|grouping_field| card[grouping_field] ? card[grouping_field] : ''}
|
18
22
|
value = card[count_field].to_i
|
19
23
|
counts[key] = counts[key] ? counts[key] + value : value
|