cards 0.7 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGES.txt +9 -0
  2. data/README.txt +1 -1
  3. data/Rakefile +7 -1
  4. data/examples/csv to dot/generate_card_walls +3 -3
  5. data/examples/custom csv builder/Stories.csv +16 -0
  6. data/examples/custom csv builder/Stories.tracker.csv +29 -0
  7. data/examples/custom csv builder/generate_card_wall +31 -0
  8. data/examples/excel to visio/Business Processes.xls +0 -0
  9. data/examples/excel to visio/TPS-small.png +0 -0
  10. data/examples/excel to visio/generate card walls.rb +10 -0
  11. data/examples/excel to visio/readme.html +104 -0
  12. data/examples/importing into tracker api/Stories.csv +16 -0
  13. data/examples/importing into tracker api/Voting Example.numbers +0 -0
  14. data/examples/importing into tracker api/appscript_example.rb +18 -0
  15. data/examples/importing into tracker api/from_numbers_09 +50 -0
  16. data/examples/importing into tracker api/generate_card_wall +32 -0
  17. data/examples/importing into tracker api/osa.rb +39 -0
  18. data/examples/numbers to omnigraffle/Voting Example.numbers +0 -0
  19. data/examples/numbers to omnigraffle/generate_card_walls +11 -9
  20. data/lib/cards.rb +3 -1
  21. data/lib/cards/csv_builder.rb +36 -34
  22. data/lib/cards/csv_parser.rb +6 -44
  23. data/lib/cards/numbers_parser.rb +43 -0
  24. data/lib/cards/swim_lanes.rb +1 -0
  25. data/lib/cards/tabular_parser.rb +78 -0
  26. data/lib/cards/tracker_csv.rb +15 -13
  27. data/lib/cards/writers/dot_writer.rb +6 -2
  28. data/spec/cards/csv_parser_spec.rb +22 -4
  29. data/spec/cards/numbers_parser_spec.rb +25 -0
  30. data/spec/fixtures/Voting Example.numbers +0 -0
  31. metadata +37 -17
  32. data/Manifest.txt +0 -40
  33. data/examples/csv to dot/Stories.dot +0 -63
  34. data/examples/numbers to omnigraffle/Voting Example.numbers/Contents/PkgInfo +0 -1
  35. data/examples/numbers to omnigraffle/Voting Example.numbers/QuickLook/Thumbnail.jpg +0 -0
  36. data/examples/numbers to omnigraffle/Voting Example.numbers/document-thumbnail.tiff +0 -0
  37. data/examples/numbers to omnigraffle/Voting Example.numbers/index.xml.gz +0 -0
  38. data/examples/numbers to omnigraffle/Voting Example/Cards-Goals.csv +0 -7
  39. data/examples/numbers to omnigraffle/Voting Example/Cards-Stories.csv +0 -16
  40. data/examples/numbers to omnigraffle/Voting Example/Cards-Workflow.csv +0 -7
data/CHANGES.txt CHANGED
@@ -1,5 +1,14 @@
1
1
  = Change Log
2
2
 
3
+ == Version 0.9
4
+
5
+ * example that directly imports into tracker api
6
+ * direct exports out of numbers '09
7
+
8
+ == Version 0.8
9
+
10
+ * example of custom csv builder
11
+
3
12
  == Version 0.7
4
13
 
5
14
  * fixing the dot writer
data/README.txt CHANGED
@@ -1,4 +1,4 @@
1
- = Project: CardWallGen
1
+ = Project: Cards
2
2
 
3
3
  == Description
4
4
 
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ require 'hoe'
11
11
  require 'lib/cards'
12
12
 
13
13
  desc "Default Task"
14
- task :default => [:spec]
14
+ task :default => [:generate_manifest, :spec]
15
15
 
16
16
  task :test => :spec
17
17
 
@@ -19,6 +19,12 @@ Spec::Rake::SpecTask.new(:spec) do |t|
19
19
  t.spec_files = FileList['spec/**/*_spec.rb']
20
20
  end
21
21
 
22
+ task :generate_manifest do
23
+ File.open("Manifest.txt", "w") do |f|
24
+ f << FileList["CHANGES.txt", "Rakefile", "README.txt", "examples/**/*", "lib/**/*", "spec/**/*"].to_a.join("\n")
25
+ end
26
+ end
27
+
22
28
  desc "export to dot file"
23
29
  task :run_dot do
24
30
  file = ENV["FILE"] || SAMPLE_FILE
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
-
3
2
  require 'rubygems'
3
+ gem 'cards'
4
4
  require 'cards'
5
-
6
5
  include Cards
7
6
 
7
+
8
8
  def csv_file(name)
9
9
  CsvParser.new(File.dirname(__FILE__) + "/#{name}.csv")
10
10
  end
@@ -22,4 +22,4 @@ end
22
22
  puts "generated Stories.dot"
23
23
 
24
24
  # uncomment this line if you want to see the generated file
25
- # `open "#{File.dirname(__FILE__)}/Stories.dot"`
25
+ # `open "#{File.dirname(__FILE__)}/Stories.dot"`
@@ -0,0 +1,16 @@
1
+ Activity,Task,Story,Note,Estimate,Priority
2
+ Voter,Vote on question,Ability to see question,,1,H
3
+ ,,Ability to see choices,,1,M
4
+ ,,Ability to choose,This is the server trip,2,H
5
+ ,Navigate questions,Ability to continue to next / prev,,1,H
6
+ ,,Ability to see list of questions,This includes ability to jump to that question,4,H
7
+ ,Submit,Ability to return to new screen,,1,M
8
+ Admin,Create questions,Ability to enter question,,4,H
9
+ ,,Ability to reorder question,,4,H
10
+ ,,Ability to enter multiple choice question,,1,L
11
+ ,,Ability to enter text question,,1,H
12
+ ,,Ability to enter long text question,,1,H
13
+ ,,Ability to enter list question,,2,L
14
+ ,Compile votes,Ability to see results in spreadsheet,,4,H
15
+ ,,Ability to see summary of results,This includes percentage of each question answering which answer,2,M
16
+ ,Announce winners,,,,
@@ -0,0 +1,29 @@
1
+ Story,Labels,Story Type,Estimate,Description,Priority
2
+ Ability to see question,"Vote on question, H",,1,"while Voter
3
+ ",2
4
+ Ability to see choices,"Vote on question, M",,1,"while Voter
5
+ ",1
6
+ Ability to choose,"Vote on question, H",,2,"while Voter
7
+ This is the server trip",2
8
+ Ability to continue to next / prev,"Navigate questions, H",,1,"while Voter
9
+ ",2
10
+ Ability to see list of questions,"Navigate questions, H",,4,"while Voter
11
+ This includes ability to jump to that question",2
12
+ Ability to return to new screen,"Submit, M",,1,"while Voter
13
+ ",1
14
+ Ability to enter question,"Create questions, H",,4,"while Admin
15
+ ",2
16
+ Ability to reorder question,"Create questions, H",,4,"while Admin
17
+ ",2
18
+ Ability to enter multiple choice question,"Create questions, L",,1,"while Admin
19
+ ",0
20
+ Ability to enter text question,"Create questions, H",,1,"while Admin
21
+ ",2
22
+ Ability to enter long text question,"Create questions, H",,1,"while Admin
23
+ ",2
24
+ Ability to enter list question,"Create questions, L",,2,"while Admin
25
+ ",0
26
+ Ability to see results in spreadsheet,"Compile votes, H",,4,"while Admin
27
+ ",2
28
+ Ability to see summary of results,"Compile votes, M",,2,"while Admin
29
+ This includes percentage of each question answering which answer",1
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ gem 'cards'
4
+ require 'cards'
5
+ include Cards
6
+
7
+
8
+ def csv_file(name)
9
+ CsvParser.new(File.dirname(__FILE__) + "/#{name}.csv")
10
+ end
11
+
12
+ class Tracker < CsvBuilder
13
+ PRIORITY = %w(L M H)
14
+
15
+ def header
16
+ ["Story", "Labels", "Story Type", "Estimate", "Description", "Priority"]
17
+ end
18
+
19
+ def add_story(name, row = {})
20
+ @csv << [
21
+ name,
22
+ "#{@task}, #{row[:priority]}",
23
+ nil,
24
+ row[:estimate],
25
+ "while #{@activity}\n#{row[:note]}",
26
+ PRIORITY.index(row[:priority])
27
+ ]
28
+ end
29
+ end
30
+
31
+ Tracker.from csv_file("Stories")
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/CardWallGenerator/include.rb'
2
+
3
+
4
+ data = load_excel_data 'Business Processes.xls', 1
5
+ create_visio_document data, 'Caution.vsd'
6
+
7
+ data = load_excel_data 'Business Processes.xls', 2
8
+ create_visio_document data, 'TPS.vsd'
9
+
10
+
@@ -0,0 +1,104 @@
1
+ <html>
2
+ <head>
3
+ <title>Card Wall Generator</title>
4
+ </head>
5
+ <body>
6
+ <div align="center">
7
+ <div style="width:800;" align="left">
8
+ <h1>Card Wall Generator</h1>
9
+
10
+
11
+
12
+ <h2>What is it?</h2>
13
+ <hr/>
14
+
15
+ <p>
16
+ this tool will take an excel spreadsheet with a hierarchical story list in it, and generate
17
+ a "card wall" in visio from it.
18
+ </p>
19
+
20
+ <p style="text-align:right">
21
+ <img src="TPS-small.png"><br>
22
+ <i>a "card wall"</i>
23
+ </p>
24
+
25
+ <p>
26
+ the spreadsheet might look like - <a href="business processes.xls">business processes.xls</a>
27
+ </p>
28
+
29
+ <p>
30
+ and the card wall might look like - <a href="TPS.vsd">TPS.vsd</a><br>
31
+ </p>
32
+
33
+
34
+
35
+
36
+ <h2>Installation</h2>
37
+ <hr/>
38
+
39
+ <h3>You will need:</h3>
40
+
41
+ <ul>
42
+ <li>Windows - sorry only works on windows right now...
43
+ <li>Excel
44
+ <li>Visio
45
+ <li>Ruby - download it from here - <a href="http://rubyforge.org/projects/rubyinstaller/">http://rubyforge.org/projects/rubyinstaller/</a>
46
+ </ul>
47
+
48
+ <p>
49
+ Once you have all those installed, you can test your installation by double clicking the
50
+ "generate card walls.rb" file. It should open excel for a second, then open up visio and
51
+ generate 2 card walls.
52
+ </p>
53
+
54
+ <h3>The Driver File</h3>
55
+
56
+ <p>
57
+ What the card wall generator does is configured by the "generate card walls.rb" file. Open
58
+ it up and take a look. You should see stuff like :
59
+ </p>
60
+
61
+ <code><pre>
62
+ data = load_excel_data 'Business Processes.xls', 1
63
+ create_visio_document data, 'Caution.vsd'
64
+ </pre></code>
65
+
66
+ <p>You can customize this for your needs. Basically copy these 2 lines for every card wall
67
+ you want to create, and substitute these for the values :
68
+ <ul>
69
+ <li>excel file with the master story list - "Business Processes.xls"
70
+ <li>index of the sheet within the excel file - "1"
71
+ <li>visio file that will be created - "Caution.vsd"
72
+ </ul>
73
+ </p>
74
+
75
+
76
+
77
+ <h2>More Information</h2>
78
+ <hr/>
79
+
80
+ <p>Visit the project website at :</p>
81
+
82
+ <p><a href="http://rubyforge.org/projects/cardwallgen">http://rubyforge.org/projects/cardwallgen</a></p>
83
+
84
+ <p>The documentation is still pretty sparse. If you can find someone that knows ruby, have them poke
85
+ around, and they'll probably be able to figure out how to do most things. Otherwise, email the list
86
+ at cardwallgen-users@rubyforge.org, or sign up for the list at the project website.</p>
87
+
88
+
89
+
90
+
91
+ <h2>License</h2>
92
+ <hr/>
93
+
94
+ <p>
95
+ <i>Copyright (C) 2006 Jeremy Stell-Smith</i>
96
+ </p>
97
+
98
+ <p>
99
+ This software is distributed under the LGPL license.
100
+ </p>
101
+ </div>
102
+ </div>
103
+ </body>
104
+ </html>
@@ -0,0 +1,16 @@
1
+ Activity,Task,Story,Note,Estimate,Priority
2
+ Voter,Vote on question,Ability to see question,,1,H
3
+ ,,Ability to see choices,,1,M
4
+ ,,Ability to choose,This is the server trip,2,H
5
+ ,Navigate questions,Ability to continue to next / prev,,1,H
6
+ ,,Ability to see list of questions,This includes ability to jump to that question,3,H
7
+ ,Submit,Ability to return to new screen,,1,M
8
+ Admin,Create questions,Ability to enter question,,3,H
9
+ ,,Ability to reorder question,,3,H
10
+ ,,Ability to enter multiple choice question,,1,L
11
+ ,,Ability to enter text question,,1,H
12
+ ,,Ability to enter long text question,,1,H
13
+ ,,Ability to enter list question,,2,L
14
+ ,Compile votes,Ability to see results in spreadsheet,,3,H
15
+ ,,Ability to see summary of results,This includes percentage of each question answering which answer,2,M
16
+ ,Announce winners,,,,
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'appscript'
3
+
4
+ itunes = Appscript.app('iTunes')
5
+
6
+ track = itunes.current_track
7
+ p track # <OSA::Itunes::FileTrack:0x1495e20>
8
+ p track.name # "Over The Rainbow"
9
+ p track.artist # "Keith Jarrett"
10
+ p track.duration # 362.368988037109
11
+ p track.date_added.to_s # "2006-06-30"
12
+ p track.enabled? # true
13
+
14
+ # Play the selected track.
15
+ itunes.play
16
+
17
+ # Fade the volume.
18
+ 100.times { |i| itunes.sound_volume = i; sleep 0.1 }
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require File.dirname(__FILE__) + "/../../lib/cards" # you probably want to include the gem version
4
+ require 'rest_client'
5
+
6
+ token = "d6b1b5ded944959aec78754ff9f018bd"
7
+ project_id = "9989"
8
+ priority = %w(L M H)
9
+
10
+ project = RestClient::Resource.new("http://www.pivotaltracker.com/services/v2/projects/#{project_id}",
11
+ :headers => { "X-TrackerToken" => token })
12
+
13
+ # puts project["stories?filter=type:bug"].get
14
+
15
+ require 'rbosa'
16
+ numbers = OSA.app('Numbers')
17
+
18
+ # itunes = OSA.app('iTunes')
19
+ # track = itunes.current_track
20
+ # p track # <OSA::Itunes::FileTrack:0x1495e20>
21
+ # p track.name # "Over The Rainbow"
22
+ # p track.artist # "Keith Jarrett"
23
+ # p track.duration # 362.368988037109
24
+ # p track.date_added.to_s # "2006-06-30"
25
+ # p track.enabled? # true
26
+ #
27
+
28
+
29
+
30
+
31
+
32
+
33
+ csv = Cards::CsvParser.new(File.dirname(__FILE__) + "/Stories.csv")
34
+ rows = csv.denormalized_rows(:story, [:activity, :task])
35
+ rows = rows.sort_by {|row| priority.index(row[:priority])}
36
+
37
+ rows.each do |row|
38
+ puts "adding #{row[:story]}"
39
+
40
+ params = {}
41
+ params[:name] = row[:story]
42
+ # params[:story_type] = "bug"
43
+ params[:current_state] = "unstarted"
44
+ params[:requested_by] = "Cards Test User"
45
+ params[:estimate] = row[:estimate]
46
+ params[:description] = "while #{row[:activity]}\n#{row[:note]}"
47
+
48
+ # project["stories"].post(:story => params)
49
+ end
50
+
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require File.dirname(__FILE__) + "/../../lib/cards" # you probably want to include the gem version
4
+ require 'rest_client'
5
+
6
+ token = "d6b1b5ded944959aec78754ff9f018bd"
7
+ project_id = "9989"
8
+ priority = %w(L M H)
9
+
10
+ project = RestClient::Resource.new("http://www.pivotaltracker.com/services/v2/projects/#{project_id}",
11
+ :headers => { "X-TrackerToken" => token })
12
+
13
+ # puts project["stories?filter=type:bug"].get
14
+
15
+ csv = Cards::CsvParser.new(File.dirname(__FILE__) + "/Stories.csv")
16
+ rows = csv.denormalized_rows(:story, [:activity, :task])
17
+ rows = rows.sort_by {|row| priority.index(row[:priority])}
18
+
19
+ rows.each do |row|
20
+ puts "adding #{row[:story]}"
21
+
22
+ params = {}
23
+ params[:name] = row[:story]
24
+ # params[:story_type] = "bug"
25
+ params[:current_state] = "unstarted"
26
+ params[:requested_by] = "Cards Test User"
27
+ params[:estimate] = row[:estimate]
28
+ params[:description] = "while #{row[:activity]}\n#{row[:note]}"
29
+
30
+ project["stories"].post(:story => params)
31
+ end
32
+
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'rbosa'
3
+
4
+ def find_table(document, name)
5
+ document.sheets.each do |sheet|
6
+ sheet.tables.each do |table|
7
+ return table
8
+ end
9
+ end
10
+ end
11
+
12
+ numbers = OSA.app('Numbers')
13
+ document = numbers.open(File.dirname(__FILE__) + "/Voting Example.numbers")
14
+ table = find_table(document, "Stories")
15
+
16
+ p table.name
17
+ table.rows.each do |row|
18
+ values = []
19
+ row.cells.map do |cell|
20
+ values << cell.name << cell.value
21
+ end
22
+ p values
23
+ end
24
+
25
+ # itunes = OSA.app('iTunes')
26
+ #
27
+ # track = itunes.current_track
28
+ # p track # <OSA::Itunes::FileTrack:0x1495e20>
29
+ # p track.name # "Over The Rainbow"
30
+ # p track.artist # "Keith Jarrett"
31
+ # p track.duration # 362.368988037109
32
+ # p track.date_added.to_s # "2006-06-30"
33
+ # p track.enabled? # true
34
+ #
35
+ # # Play the selected track.
36
+ # itunes.play
37
+ #
38
+ # # Fade the volume.
39
+ # 100.times { |i| itunes.sound_volume = i; sleep 0.1 }
@@ -1,29 +1,31 @@
1
1
  #!/usr/bin/env ruby
2
- # this doesn't actually read the numbers document, you must export csv from numbers as we've done here,
3
- # the csv can then be parsed and turned into omnigraffle
4
-
5
2
  require 'rubygems'
3
+ gem 'cards'
6
4
  require 'cards'
5
+ require 'cards/numbers_parser'
7
6
  include Cards
8
7
 
9
- def csv_file(name)
10
- CsvParser.new(File.dirname(__FILE__) + "/Voting Example/Cards-#{name}.csv")
8
+ # this requires numbers '09, before that you must export to csv and use the csv parser
9
+
10
+ def table(name)
11
+ file = File.dirname(__FILE__) + "/Voting Example.numbers"
12
+ NumbersParser.new(file, name)
11
13
  end
12
14
 
13
15
  CardWall.colors[:goal] = :green
14
16
  CardWall.writer = GraffleWriter
15
17
 
16
- CardWall.from csv_file("Goals") do
18
+ CardWall.from table("Goals") do
17
19
  column :goal
18
20
  end
19
21
 
20
- CardWall.from csv_file("Workflow") do
22
+ CardWall.from table("Workflow") do
21
23
  row :role
22
24
  column :task, :wrap_at => 5
23
25
  end
24
26
 
25
- CardWall.from csv_file("Stories") do
26
- row :role
27
+ CardWall.from table("Stories") do
28
+ row :activity
27
29
  row :task
28
30
  column :story, :wrap_at => 4 do |card, row|
29
31
  card.name = " #{row[:estimate]}\n\n#{card.name}" unless row[:estimate].blank?
data/lib/cards.rb CHANGED
@@ -9,9 +9,11 @@ require 'cards/card_wall'
9
9
  require 'cards/writers/dot_writer'
10
10
  require 'cards/writers/graffle_writer'
11
11
 
12
+ # csv builders
13
+ require 'cards/csv_builder'
12
14
  require 'cards/master_story_list'
13
15
  require 'cards/tracker_csv'
14
16
 
15
17
  module Cards
16
- VERSION = "0.7"
18
+ VERSION = "0.9"
17
19
  end
@@ -1,46 +1,48 @@
1
- class CsvBuilder
2
- def initialize(file_name)
3
- @file_name = file_name
4
- @file = File.open(file_name, "wb")
5
- @csv = CSV::Writer.create(@file)
6
- @csv << header
7
- end
1
+ module Cards
2
+ class CsvBuilder
3
+ def initialize(file_name)
4
+ @file_name = file_name
5
+ @file = File.open(file_name, "wb")
6
+ @csv = CSV::Writer.create(@file)
7
+ @csv << header
8
+ end
8
9
 
9
- def header
10
- raise "implement me"
11
- end
10
+ def header
11
+ raise "implement me"
12
+ end
12
13
 
13
- def self.from(parser)
14
- builder = self.new(parser.default_output_file + ".#{self.to_s.gsub("Cards::", "").downcase}.csv")
14
+ def self.from(parser)
15
+ builder = self.new(parser.default_output_file + ".#{self.to_s.gsub("Cards::", "").downcase}.csv")
15
16
 
16
- parser.each_row do |row|
17
- builder.process(row)
18
- end
17
+ parser.each_row do |row|
18
+ builder.process(row)
19
+ end
19
20
 
20
- builder.done
21
- end
21
+ builder.done
22
+ end
22
23
 
23
- def process(row)
24
- [:activity, :task, :story].each do |handler|
25
- send("add_#{handler}", row[handler], row) if row[handler]
24
+ def process(row)
25
+ [:activity, :task, :story].each do |handler|
26
+ send("add_#{handler}", row[handler], row) if row[handler]
27
+ end
26
28
  end
27
- end
28
29
 
29
- def add_activity(name, params = {})
30
- @activity = name
31
- end
30
+ def add_activity(name, params = {})
31
+ @activity = name
32
+ end
32
33
 
33
- def add_task(name, params = {})
34
- @task = name
35
- end
34
+ def add_task(name, params = {})
35
+ @task = name
36
+ end
36
37
 
37
- def add_story(name, params = {})
38
- raise "implement me"
39
- end
38
+ def add_story(name, params = {})
39
+ raise "implement me"
40
+ end
40
41
 
41
- def done
42
- @csv.close
43
- @file.close
44
- `open #{@file_name.gsub(' ', '\\ ')}`
42
+ def done
43
+ @csv.close
44
+ @file.close
45
+ `open #{@file_name.gsub(' ', '\\ ')}`
46
+ end
45
47
  end
46
48
  end
@@ -1,60 +1,22 @@
1
1
  require 'csv'
2
+ require 'cards/tabular_parser'
2
3
 
3
4
  module Cards
4
5
  class CsvParser
6
+ include TabularParser
7
+
5
8
  def initialize(file)
6
9
  @file = file
7
10
  end
8
11
 
9
- def rows
10
- rows = []
11
- each_row {|row| rows << row}
12
- rows
13
- end
14
-
15
- def each_row
16
- header = nil
12
+ def each_unparsed_row
17
13
  CSV.open(@file, 'r') do |row|
18
- if header.nil?
19
- header = define_header(row)
20
- else
21
- yield Row.new(header, row)
22
- end
14
+ yield row
23
15
  end
24
16
  end
25
-
17
+
26
18
  def default_output_file
27
19
  File.basename(@file).sub(/\..*/, '')
28
20
  end
29
-
30
- private
31
-
32
- def define_header(header_row)
33
- header = {}
34
- header_row.each_with_index do |name, i|
35
- header[name.downcase.gsub(' ', '_').to_sym] = i
36
- end
37
- return header
38
- end
39
-
40
- class Row
41
- def initialize(header, row)
42
- @header, @row = header, row
43
- end
44
-
45
- def [](key)
46
- index = @header[key] || raise("can't find column header #{key.inspect} in #{@header.inspect}")
47
- @row[index]
48
- end
49
-
50
- def to_h
51
- h = {}
52
- @header.each_key do |column_header|
53
- val = @row[@header[column_header]]
54
- h[column_header] = val unless val.blank?
55
- end
56
- h
57
- end
58
- end
59
21
  end
60
22
  end
@@ -0,0 +1,43 @@
1
+ require 'rbosa'
2
+ require 'cards/tabular_parser'
3
+
4
+ module Cards
5
+ class NumbersParser
6
+ include TabularParser
7
+
8
+ def initialize(file, table_name)
9
+ @file, @table_name = file, table_name
10
+ end
11
+
12
+ def each_unparsed_row
13
+ numbers = OSA.app('Numbers')
14
+ document = numbers.open(@file)
15
+ table = find_table(document, @table_name)
16
+
17
+ table.rows.each do |row|
18
+ values = []
19
+ row.cells.map do |cell|
20
+ value = cell.value
21
+ value = nil if value == 0
22
+ values << value
23
+ end
24
+ yield values
25
+ end
26
+ end
27
+
28
+ def default_output_file
29
+ @table_name
30
+ end
31
+
32
+ private
33
+
34
+ def find_table(document, name)
35
+ document.sheets.each do |sheet|
36
+ sheet.tables.each do |table|
37
+ return table if table.name.downcase == name.downcase
38
+ end
39
+ end
40
+ raise "table #{name} not found in #{document.name}"
41
+ end
42
+ end
43
+ end
@@ -1,5 +1,6 @@
1
1
  require 'cards/card_wall'
2
2
 
3
+ # todo ...
3
4
  module Cards
4
5
  class SwimLanes < CardWall
5
6
  def initialize
@@ -0,0 +1,78 @@
1
+ module Cards
2
+ module TabularParser
3
+ def rows
4
+ rows = []
5
+ each_row {|row| rows << row}
6
+ rows
7
+ end
8
+
9
+ def each_row
10
+ header = nil
11
+ each_unparsed_row do |row|
12
+ if header.nil?
13
+ header = define_header(row)
14
+ else
15
+ yield Row.new(header, row)
16
+ end
17
+ end
18
+ end
19
+
20
+ # this method will turn something of the form
21
+ #
22
+ # activity | task | story |
23
+ # a | | |
24
+ # | b | |
25
+ # | | c |
26
+ # | | d |
27
+ #
28
+ # into
29
+ #
30
+ # activity | task | story |
31
+ # a | b | c |
32
+ # a | b | d |
33
+ #
34
+ def denormalized_rows(key_column, columns_to_denormalize)
35
+ last_row = {}
36
+ rows = []
37
+ each_row do |row|
38
+ row = row.to_h
39
+ columns_to_denormalize.each do |c|
40
+ row[c] = last_row[c] if row[c].blank?
41
+ end
42
+ rows << row unless row[key_column].blank?
43
+ last_row = row
44
+ end
45
+ rows
46
+ end
47
+
48
+ private
49
+
50
+ def define_header(header_row)
51
+ header = {}
52
+ header_row.each_with_index do |name, i|
53
+ header[name.downcase.gsub(' ', '_').to_sym] = i
54
+ end
55
+ return header
56
+ end
57
+
58
+ class Row
59
+ def initialize(header, row)
60
+ @header, @row = header, row
61
+ end
62
+
63
+ def [](key)
64
+ index = @header[key] || raise("can't find column header #{key.inspect} in #{@header.inspect}")
65
+ @row[index]
66
+ end
67
+
68
+ def to_h
69
+ h = {}
70
+ @header.each_key do |column_header|
71
+ val = @row[@header[column_header]]
72
+ h[column_header] = val unless val.blank?
73
+ end
74
+ h
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,19 +1,21 @@
1
1
  require 'cards/csv_builder'
2
2
 
3
- class TrackerCsv < CsvBuilder
4
- def header
5
- ["Story", "Labels", "Story Type", "Estimate", "Description"]
6
- end
3
+ module Cards
4
+ class TrackerCsv < CsvBuilder
5
+ def header
6
+ ["Story", "Labels", "Story Type", "Estimate", "Description"]
7
+ end
7
8
 
8
- def add_story(name, params = {})
9
- return unless [nil, '', 'Story', 'Chore'].include?(params[:story_type])
9
+ def add_story(name, params = {})
10
+ return unless [nil, '', 'Story', 'Chore'].include?(params[:story_type])
10
11
 
11
- @csv << [
12
- name,
13
- @task,
14
- params[:story_type],
15
- nil, # params[:estimate],
16
- "#{@activity}\n#{params[:description]}"
17
- ]
12
+ @csv << [
13
+ name,
14
+ @task,
15
+ params[:story_type],
16
+ nil, # params[:estimate],
17
+ "#{@activity}\n#{params[:description]}"
18
+ ]
19
+ end
18
20
  end
19
21
  end
@@ -1,7 +1,11 @@
1
1
  module Cards
2
2
  class DotWriter
3
- def initialize(file_name)
4
- @file = File.open(file_name + ".dot", "w")
3
+ def initialize(file)
4
+ if file.respond_to? :puts
5
+ @file = file
6
+ else
7
+ @file = File.open(file + ".dot", "w")
8
+ end
5
9
  @node_color = {:green => "darkseagreen1", :blue => "lightblue", :red => "pink", :yellow => "lightyellow"}
6
10
  @nodes = []
7
11
 
@@ -7,22 +7,40 @@ include Cards
7
7
  describe CsvParser do
8
8
  include FileSandbox
9
9
 
10
- it "should parse csv" do
10
+ before do
11
11
  sandbox.new :file => 'tmp.csv', :with_contents =>
12
12
  "activity,task,story,estimate
13
13
  manage email,,
14
14
  ,read email,
15
15
  ,,display email body
16
- manage email,think about email,,1
16
+ manage email,think about email,mow the lawn,1
17
17
  ,read email,,2
18
18
  ,,display email body,3"
19
-
19
+ end
20
+
21
+ it "should parse csv" do
20
22
  rows = CsvParser.new(sandbox['tmp.csv'].path).rows
21
23
  rows[0].to_h.should == {:activity => 'manage email'}
22
24
  rows[1].to_h.should == {:task => 'read email'}
23
25
  rows[2].to_h.should == {:story => 'display email body'}
24
- rows[3].to_h.should == {:activity => 'manage email', :task => 'think about email', :estimate => "1"}
26
+ rows[3].to_h.should == {:activity => 'manage email', :task => 'think about email', :story => 'mow the lawn', :estimate => "1"}
25
27
  rows[4].to_h.should == {:task => 'read email', :estimate => "2"}
26
28
  rows[5].to_h.should == {:story => 'display email body', :estimate => "3"}
27
29
  end
30
+
31
+ it "should denormalize rows" do
32
+ rows = CsvParser.new(sandbox['tmp.csv'].path).denormalized_rows(:story, [:activity, :task])
33
+ rows.size.should == 3
34
+ rows[0].should == {:activity => 'manage email',
35
+ :task => 'read email',
36
+ :story => 'display email body'}
37
+ rows[1].should == {:activity => 'manage email',
38
+ :task => 'think about email',
39
+ :story => 'mow the lawn',
40
+ :estimate => "1"}
41
+ rows[2].should == {:activity => 'manage email',
42
+ :task => 'read email',
43
+ :story => 'display email body',
44
+ :estimate => '3'}
45
+ end
28
46
  end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'cards/numbers_parser'
3
+
4
+ # not the best test, but it will do
5
+ describe Cards::NumbersParser do
6
+ describe "each_row" do
7
+ it "should find all rows in Voting Example" do
8
+ file = File.expand_path(File.dirname(__FILE__) + "/../fixtures/Voting Example.numbers")
9
+ parser = Cards::NumbersParser.new(file, "Workflow")
10
+ rows = parser.rows
11
+ rows[0].to_h.should == {:role => "Voter", :task => "Vote on question"}
12
+ rows[1].to_h.should == {:task => "Navigate questions"}
13
+ rows[2].to_h.should == {:task => "Submit"}
14
+ rows[3].to_h.should == {:role => "Admin", :task => "Create questions"}
15
+ rows[4].to_h.should == {:task => "Compile votes"}
16
+ rows[5].to_h.should == {:task => "Announce winners"}
17
+ end
18
+ end
19
+
20
+ describe "default_output_file" do
21
+ it "should be the table name" do
22
+ Cards::NumbersParser.new("some file.numbers", "larry").default_output_file.should == "larry"
23
+ end
24
+ end
25
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cards
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.7"
4
+ version: "0.9"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Stell-Smith
@@ -9,17 +9,18 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-06 00:00:00 -07:00
12
+ date: 2009-03-05 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: hoe
17
+ type: :development
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
20
21
  - - ">="
21
22
  - !ruby/object:Gem::Version
22
- version: 1.5.3
23
+ version: 1.8.2
23
24
  version:
24
25
  description: CardWallGen is a program that reads a requirements map and generates a view of it. Typically it reads it from excel or csv and generates a graphical view in visio or omnigraffle, though it may also generate another csv view of it.
25
26
  email: jeremystellsmith@gmail.com
@@ -29,48 +30,67 @@ extensions: []
29
30
 
30
31
  extra_rdoc_files:
31
32
  - CHANGES.txt
32
- - Manifest.txt
33
33
  - README.txt
34
34
  files:
35
35
  - CHANGES.txt
36
- - Manifest.txt
37
- - README.txt
38
36
  - Rakefile
39
- - examples/csv to dot/Stories.csv
40
- - examples/csv to dot/Stories.dot
37
+ - README.txt
38
+ - examples/csv to dot
41
39
  - examples/csv to dot/generate_card_walls
42
- - examples/numbers to omnigraffle/Voting Example.numbers/Contents/PkgInfo
43
- - examples/numbers to omnigraffle/Voting Example.numbers/QuickLook/Thumbnail.jpg
44
- - examples/numbers to omnigraffle/Voting Example.numbers/document-thumbnail.tiff
45
- - examples/numbers to omnigraffle/Voting Example.numbers/index.xml.gz
46
- - examples/numbers to omnigraffle/Voting Example/Cards-Goals.csv
47
- - examples/numbers to omnigraffle/Voting Example/Cards-Stories.csv
48
- - examples/numbers to omnigraffle/Voting Example/Cards-Workflow.csv
40
+ - examples/csv to dot/Stories.csv
41
+ - examples/custom csv builder
42
+ - examples/custom csv builder/generate_card_wall
43
+ - examples/custom csv builder/Stories.csv
44
+ - examples/custom csv builder/Stories.tracker.csv
45
+ - examples/excel to visio
46
+ - examples/excel to visio/Business Processes.xls
47
+ - examples/excel to visio/generate card walls.rb
48
+ - examples/excel to visio/readme.html
49
+ - examples/excel to visio/TPS-small.png
50
+ - examples/importing into tracker api
51
+ - examples/importing into tracker api/appscript_example.rb
52
+ - examples/importing into tracker api/from_numbers_09
53
+ - examples/importing into tracker api/generate_card_wall
54
+ - examples/importing into tracker api/osa.rb
55
+ - examples/importing into tracker api/Stories.csv
56
+ - examples/importing into tracker api/Voting Example.numbers
57
+ - examples/numbers to omnigraffle
49
58
  - examples/numbers to omnigraffle/generate_card_walls
50
- - lib/cards.rb
59
+ - examples/numbers to omnigraffle/Voting Example.numbers
60
+ - lib/cards
51
61
  - lib/cards/builder.rb
52
62
  - lib/cards/card.rb
53
63
  - lib/cards/card_wall.rb
54
64
  - lib/cards/csv_builder.rb
55
65
  - lib/cards/csv_parser.rb
56
66
  - lib/cards/extensions.rb
67
+ - lib/cards/layouts
57
68
  - lib/cards/layouts/column_layout.rb
58
69
  - lib/cards/layouts/nil_layout.rb
59
70
  - lib/cards/layouts/row_layout.rb
60
71
  - lib/cards/master_story_list.rb
72
+ - lib/cards/numbers_parser.rb
61
73
  - lib/cards/swim_lanes.rb
74
+ - lib/cards/tabular_parser.rb
62
75
  - lib/cards/text.rb
63
76
  - lib/cards/tracker_csv.rb
77
+ - lib/cards/writers
64
78
  - lib/cards/writers/dot_writer.rb
65
79
  - lib/cards/writers/graffle_writer.rb
66
80
  - lib/cards/writers/text_writer.rb
81
+ - lib/cards.rb
82
+ - spec/cards
67
83
  - spec/cards/card_spec.rb
68
84
  - spec/cards/card_wall_spec.rb
69
85
  - spec/cards/csv_parser_spec.rb
70
86
  - spec/cards/extensions_spec.rb
87
+ - spec/cards/numbers_parser_spec.rb
71
88
  - spec/cards/swim_lanes_spec.rb
89
+ - spec/cards/writers
72
90
  - spec/cards/writers/dot_writer_spec.rb
73
91
  - spec/cards/writers/text_writer_spec.rb
92
+ - spec/fixtures
93
+ - spec/fixtures/Voting Example.numbers
74
94
  - spec/spec_helper.rb
75
95
  has_rdoc: true
76
96
  homepage: http://rubyforge.org/projects/cardwallgen
@@ -95,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
115
  requirements: []
96
116
 
97
117
  rubyforge_project: cardwallgen
98
- rubygems_version: 1.1.1
118
+ rubygems_version: 1.3.1
99
119
  signing_key:
100
120
  specification_version: 2
101
121
  summary: CardWallGen is a program that reads a requirements map and generates a view of it. Typically it reads it from excel or csv and generates a graphical view in visio or omnigraffle, though it may also generate another csv view of it.
data/Manifest.txt DELETED
@@ -1,40 +0,0 @@
1
- CHANGES.txt
2
- Manifest.txt
3
- README.txt
4
- Rakefile
5
- examples/csv to dot/Stories.csv
6
- examples/csv to dot/Stories.dot
7
- examples/csv to dot/generate_card_walls
8
- examples/numbers to omnigraffle/Voting Example.numbers/Contents/PkgInfo
9
- examples/numbers to omnigraffle/Voting Example.numbers/QuickLook/Thumbnail.jpg
10
- examples/numbers to omnigraffle/Voting Example.numbers/document-thumbnail.tiff
11
- examples/numbers to omnigraffle/Voting Example.numbers/index.xml.gz
12
- examples/numbers to omnigraffle/Voting Example/Cards-Goals.csv
13
- examples/numbers to omnigraffle/Voting Example/Cards-Stories.csv
14
- examples/numbers to omnigraffle/Voting Example/Cards-Workflow.csv
15
- examples/numbers to omnigraffle/generate_card_walls
16
- lib/cards.rb
17
- lib/cards/builder.rb
18
- lib/cards/card.rb
19
- lib/cards/card_wall.rb
20
- lib/cards/csv_builder.rb
21
- lib/cards/csv_parser.rb
22
- lib/cards/extensions.rb
23
- lib/cards/layouts/column_layout.rb
24
- lib/cards/layouts/nil_layout.rb
25
- lib/cards/layouts/row_layout.rb
26
- lib/cards/master_story_list.rb
27
- lib/cards/swim_lanes.rb
28
- lib/cards/text.rb
29
- lib/cards/tracker_csv.rb
30
- lib/cards/writers/dot_writer.rb
31
- lib/cards/writers/graffle_writer.rb
32
- lib/cards/writers/text_writer.rb
33
- spec/cards/card_spec.rb
34
- spec/cards/card_wall_spec.rb
35
- spec/cards/csv_parser_spec.rb
36
- spec/cards/extensions_spec.rb
37
- spec/cards/swim_lanes_spec.rb
38
- spec/cards/writers/dot_writer_spec.rb
39
- spec/cards/writers/text_writer_spec.rb
40
- spec/spec_helper.rb
@@ -1,63 +0,0 @@
1
- digraph G {
2
- graph [nodesep=.1, ranksep=.1, ordering=out];
3
- node [shape=box, color=black, style=filled, width=2, height=1.2, fixedsize=true, labeljust="l"];
4
- edge [style=invis, weight=1];
5
- card_0_0 [label="Voter",fillcolor=lightblue];
6
- card_0_1 [label="Vote on question",fillcolor=pink];
7
- card_0_2 [label="Ability to see\nquestion 1",fillcolor=lightyellow];
8
- card_0_3 [label="Ability to see\nchoices 1",fillcolor=lightyellow];
9
- card_0_4 [label="Ability to choose\nThis is the server\ntrip 2",fillcolor=lightyellow];
10
- card_1_1 [label="Navigate questions",fillcolor=pink];
11
- card_1_2 [label="Ability to continue\nto next / prev 1",fillcolor=lightyellow];
12
- card_1_3 [label="Ability to see list\nof questions This\nincludes ability to\njump to that\nquestion 4",fillcolor=lightyellow];
13
- card_2_1 [label="Submit",fillcolor=pink];
14
- card_2_2 [label="Ability to return to\nnew screen 1",fillcolor=lightyellow];
15
- card_3_0 [label="Admin",fillcolor=lightblue];
16
- card_3_1 [label="Create questions",fillcolor=pink];
17
- card_3_2 [label="Ability to enter\nquestion 4",fillcolor=lightyellow];
18
- card_3_3 [label="Ability to reorder\nquestion 4",fillcolor=lightyellow];
19
- card_3_4 [label="Ability to enter\nmultiple choice\nquestion 1",fillcolor=lightyellow];
20
- card_3_5 [label="Ability to enter\ntext question 1",fillcolor=lightyellow];
21
- card_4_2 [label="Ability to enter\nlong text question\n1",fillcolor=lightyellow];
22
- card_4_3 [label="Ability to enter\nlist question 2",fillcolor=lightyellow];
23
- card_5_1 [label="Compile votes",fillcolor=pink];
24
- card_5_2 [label="Ability to see\nresults in\nspreadsheet 4",fillcolor=lightyellow];
25
- card_5_3 [label="Ability to see\nsummary of results\nThis includes\npercentage of each\nquestion answering\nwhich answer 2",fillcolor=lightyellow];
26
- card_6_1 [label="Announce winners",fillcolor=pink];
27
- gap_1_0 [style=invis];
28
- gap_2_0 [style=invis];
29
- gap_4_0 [style=invis];
30
- gap_4_1 [style=invis];
31
- gap_5_0 [style=invis];
32
- gap_6_0 [style=invis];
33
- {rank=same; card_0_0; gap_1_0; gap_2_0; card_3_0; gap_4_0; gap_5_0; gap_6_0};
34
- {rank=same; card_0_1; card_1_1; card_2_1; card_3_1; gap_4_1; card_5_1; card_6_1};
35
- {rank=same; card_0_2; card_1_2; card_2_2; card_3_2; card_4_2; card_5_2};
36
- card_0_0 -> gap_1_0;
37
- gap_1_0 -> gap_2_0;
38
- gap_2_0 -> card_3_0;
39
- card_3_0 -> gap_4_0;
40
- gap_4_0 -> gap_5_0;
41
- gap_5_0 -> gap_6_0;
42
- card_0_0 -> card_0_1;
43
- card_0_1 -> card_0_2;
44
- card_0_2 -> card_0_3;
45
- card_0_3 -> card_0_4;
46
- gap_1_0 -> card_1_1;
47
- card_1_1 -> card_1_2;
48
- card_1_2 -> card_1_3;
49
- gap_2_0 -> card_2_1;
50
- card_2_1 -> card_2_2;
51
- card_3_0 -> card_3_1;
52
- card_3_1 -> card_3_2;
53
- card_3_2 -> card_3_3;
54
- card_3_3 -> card_3_4;
55
- card_3_4 -> card_3_5;
56
- gap_4_0 -> gap_4_1;
57
- gap_4_1 -> card_4_2;
58
- card_4_2 -> card_4_3;
59
- gap_5_0 -> card_5_1;
60
- card_5_1 -> card_5_2;
61
- card_5_2 -> card_5_3;
62
- gap_6_0 -> card_6_1;
63
- }
@@ -1,7 +0,0 @@
1
- Goal,Note
2
- Speed,
3
- Efficiency,For voter & admin
4
- Usability,
5
- Security,
6
- Traceability,
7
- Durability,We probably need to store results in a separate location
@@ -1,16 +0,0 @@
1
- Role,Task,Story,Note,Estimate
2
- Voter,Vote on question,Ability to see question,,1
3
- ,,Ability to see choices,,1
4
- ,,Ability to choose,This is the server trip,2
5
- ,Navigate questions,Ability to continue to next / prev,,1
6
- ,,Ability to see list of questions,This includes ability to jump to that question,4
7
- ,Submit,Ability to return to new screen,,1
8
- Admin,Create questions,Ability to enter question,,4
9
- ,,Ability to reorder question,,4
10
- ,,Ability to enter multiple choice question,,1
11
- ,,Ability to enter text question,,1
12
- ,,Ability to enter long text question,,1
13
- ,,Ability to enter list question,,2
14
- ,Compile votes,Ability to see results in spreadsheet,,4
15
- ,,Ability to see summary of results,This includes percentage of each question answering which answer,2
16
- ,Announce winners,,,
@@ -1,7 +0,0 @@
1
- Role,Task
2
- Voter,Vote on question
3
- ,Navigate questions
4
- ,Submit
5
- Admin,Create questions
6
- ,Compile votes
7
- ,Announce winners