cardigan 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gemtest +0 -0
  2. data/Rakefile +6 -0
  3. data/bin/cardigan +2 -0
  4. data/lib/cardigan/cli.rb +18 -20
  5. data/lib/cardigan/command/add_transitions.rb +27 -0
  6. data/lib/cardigan/command/batch_update_cards.rb +15 -14
  7. data/lib/cardigan/command/change_status.rb +18 -11
  8. data/lib/cardigan/command/change_value.rb +11 -10
  9. data/lib/cardigan/command/claim_cards.rb +15 -13
  10. data/lib/cardigan/command/commit_changes.rb +15 -0
  11. data/lib/cardigan/command/count_cards.rb +6 -2
  12. data/lib/cardigan/command/create_card.rb +14 -11
  13. data/lib/cardigan/command/destroy_cards.rb +15 -13
  14. data/lib/cardigan/command/edit_value.rb +12 -11
  15. data/lib/cardigan/command/export_cards.rb +9 -4
  16. data/lib/cardigan/command/filter_cards.rb +6 -0
  17. data/lib/cardigan/command/import_cards.rb +18 -4
  18. data/lib/cardigan/command/list_cards.rb +5 -0
  19. data/lib/cardigan/command/open_card.rb +20 -12
  20. data/lib/cardigan/command/open_workflow.rb +14 -12
  21. data/lib/cardigan/command/remove_transitions.rb +25 -0
  22. data/lib/cardigan/command/show_entry.rb +12 -10
  23. data/lib/cardigan/command/specify_display_columns.rb +6 -0
  24. data/lib/cardigan/command/specify_sort_columns.rb +6 -0
  25. data/lib/cardigan/command/total_cards.rb +6 -2
  26. data/lib/cardigan/command/unclaim_cards.rb +13 -13
  27. data/lib/cardigan/command/unfilter_cards.rb +6 -0
  28. data/lib/cardigan/commands.rb +10 -0
  29. data/lib/cardigan/entry_context.rb +7 -12
  30. data/lib/cardigan/filtered_repository.rb +9 -5
  31. data/lib/cardigan/io.rb +1 -1
  32. data/lib/cardigan/root_context.rb +21 -23
  33. data/lib/cardigan/workflow_context.rb +12 -29
  34. data/lib/cardigan/workflow_repository.rb +18 -10
  35. data/spec/command/add_transitions_spec.rb +35 -0
  36. data/spec/command/batch_update_cards_spec.rb +9 -0
  37. data/spec/command/change_status_spec.rb +9 -0
  38. data/spec/command/change_value_spec.rb +9 -0
  39. data/spec/command/claim_cards_spec.rb +9 -0
  40. data/spec/command/commit_changes_spec.rb +9 -0
  41. data/spec/command/count_cards_spec.rb +68 -0
  42. data/spec/command/create_card_spec.rb +9 -0
  43. data/spec/command/destroy_cards_spec.rb +9 -0
  44. data/spec/command/edit_value_spec.rb +9 -0
  45. data/spec/command/export_cards_spec.rb +9 -0
  46. data/spec/command/filter_cards_spec.rb +9 -0
  47. data/spec/command/import_cards_spec.rb +9 -0
  48. data/spec/command/list_cards_spec.rb +9 -0
  49. data/spec/command/open_card_spec.rb +9 -0
  50. data/spec/command/open_workflow_spec.rb +9 -0
  51. data/spec/command/remove_transitions_spec.rb +25 -0
  52. data/spec/command/show_entry_spec.rb +9 -0
  53. data/spec/command/specify_display_columns_spec.rb +9 -0
  54. data/spec/command/specify_sort_columns_spec.rb +9 -0
  55. data/spec/command/total_cards_spec.rb +82 -0
  56. data/spec/command/unfilter_cards_spec.rb +9 -0
  57. data/spec/spec_helper.rb +25 -0
  58. data/spec/text_report_formatter_spec.rb +47 -0
  59. metadata +100 -35
  60. data/lib/cardigan/command/select_columns.rb +0 -20
  61. data/lib/cardigan/context.rb +0 -60
  62. data/lib/cardigan/directory.rb +0 -34
  63. data/lib/cardigan/repository.rb +0 -54
  64. data/lib/cardigan/symbol_extensions.rb +0 -3
data/.gemtest ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ desc 'execute specifications'
4
+ task :test do
5
+ sh 'bundle exec rspec spec'
6
+ end
data/bin/cardigan CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rubygems'
4
+
3
5
  $:.unshift File.dirname(__FILE__)+'/../lib'
4
6
 
5
7
  require 'cardigan/cli'
data/lib/cardigan/cli.rb CHANGED
@@ -1,28 +1,26 @@
1
1
  require 'cardigan/io'
2
2
  require 'cardigan/root_context'
3
- require 'cardigan/repository'
3
+ require 'flat_hash/directory'
4
+ require 'flat_hash/serialiser'
5
+ require 'flat_hash/repository'
4
6
  require 'cardigan/workflow_repository'
5
7
 
6
- module Cardigan
7
- class Cli
8
- CONFIG_FILE = '.cardigan'
8
+ class Cardigan::Cli
9
+ CONFIG_FILE = '.cardigan'
9
10
 
10
- def initialize io=Io.new
11
- @io = io
12
- @home = Directory.new('~')
13
- end
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
- def execute *args
16
- if @home.has_file?(CONFIG_FILE)
17
- config = @home.load(CONFIG_FILE)
18
- else
19
- config = { :name => @io.ask('Enter your full name'),
20
- :email => @io.ask('Enter your email address')
21
- }
22
- @home.store CONFIG_FILE, config
23
- end
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
- module Cardigan
4
- module Command
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
- def execute text
11
- key, *rest = text.scan(/\w+/)
12
- value = @io.ask("Enter the new value for #{key}")
13
- @repository.each_card_from_indices(rest.join(' ')) do |card|
14
- Cardigan::CardEditor.new(card, @io).set key, value
15
- @repository.save card
16
- end
17
- end
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
- module Cardigan
2
- module Command
3
- class ChangeStatus
4
- def initialize entry
5
- @entry = entry
6
- end
7
-
8
- def execute status
9
- @entry['status'] = status
10
- end
11
- end
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
- module Cardigan
4
- module Command
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
- def execute key
11
- Cardigan::CardEditor.new(@entry, @io).set key, @io.ask("Enter the new value for #{key}")
12
- end
13
- end
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
- module Cardigan
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
- 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
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/context'
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
- module Cardigan
2
- module Command
3
- class CreateCard
4
- def initialize repository
5
- @repository = repository
6
- end
1
+ require 'cardigan/commands'
2
+ require 'uuidtools'
7
3
 
8
- def execute name
9
- @repository.save @repository.find_or_create(name)
10
- end
11
- end
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
- module Cardigan
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
- 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
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
- module Cardigan
5
- module Command
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
- def execute key
12
- value = @entry[key] ? @entry[key] : ''
13
- Cardigan::CardEditor.new(@entry, @io).set key, value.to_editor
14
- end
15
- end
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
- card = @repository.load(row[id_index]) if id_index and row[id_index]
18
- @io.say card ? "updating #{card['id']}" : "creating new card"
19
- card = @repository.create unless card
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.save card
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
- 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
4
+ class Cardigan::Command::OpenCard
5
+ attr_reader :usage, :help
9
6
 
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
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
- module Cardigan
4
- module Command
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
- def execute name
11
- workflow = @workflow_repository.load
12
- WorkflowContext.new(@io, workflow).push
13
- @workflow_repository.save workflow
14
- end
15
- end
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
- module Cardigan
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
- def execute ignored=nil
9
- @entry.keys.sort.each { |key| @io.say "#{key}: #{@entry[key].inspect}" }
10
- end
11
- end
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/context'
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