saga 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.kick CHANGED
@@ -1,12 +1,20 @@
1
1
  recipe :ignore
2
2
  ignore(/(^tmp|\.DS_Store)$/)
3
3
 
4
+ process do |files|
5
+ if files.delete('stories.txt')
6
+ system "./bin/saga planning stories.txt"
7
+ end
8
+ end
9
+
4
10
  recipe :ruby
5
11
  process do |files|
6
12
  Ruby.run_tests(files.take_and_map do |file|
7
13
  case file
8
14
  when %r{^lib/(.+)\.rb$}
9
15
  "test/#{$1.gsub('/', '_')}_spec.rb"
16
+ when %r{^templates}
17
+ "test/saga_formatter_spec.rb"
10
18
  when %r{^test/(.+)_spec\.rb$}
11
19
  file
12
20
  when %r{^test/cases}
data/README.rdoc CHANGED
@@ -59,6 +59,7 @@ The document ends with a list of definitions. Here we define words used througho
59
59
  convert <filename> - convert the stories to HTML
60
60
  inspect <filename> - print the internals of the document
61
61
  autofill <filename> - adds an id to stories without one
62
+ planning <filename> - shows the planning of stories in iterations
62
63
 
63
64
  Options:
64
65
  -h, --help Show help
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.1
data/lib/saga.rb CHANGED
@@ -7,6 +7,7 @@ module Saga
7
7
  autoload :Document, 'saga/document'
8
8
  autoload :Formatter, 'saga/formatter'
9
9
  autoload :Parser, 'saga/parser'
10
+ autoload :Planning, 'saga/planning'
10
11
  autoload :Runner, 'saga/runner'
11
12
  autoload :Tokenizer, 'saga/tokenizer'
12
13
 
data/lib/saga/document.rb CHANGED
@@ -33,6 +33,10 @@ module Saga
33
33
  stories.inject(0) { |total, (_, stories)| total + stories.length }
34
34
  end
35
35
 
36
+ def empty?
37
+ length == 0
38
+ end
39
+
36
40
  def autofill_ids
37
41
  unused_ids = unused_ids(length - used_ids.length)
38
42
  stories.each do |_, stories|
@@ -0,0 +1,65 @@
1
+ module Saga
2
+ class Planning
3
+ BLANK_ITERATION = {:story_count => 0, :estimate_total_in_hours => 0}
4
+
5
+ def initialize(document)
6
+ @document = document
7
+ end
8
+
9
+ def iterations
10
+ @document.stories.values.flatten.inject({}) do |properties, story|
11
+ if story[:estimate]
12
+ iteration = story[:iteration] || -1
13
+ properties[iteration] ||= BLANK_ITERATION.dup
14
+ properties[iteration][:story_count] += 1
15
+ properties[iteration][:estimate_total_in_hours] += self.class.estimate_to_hours(story[:estimate])
16
+ end
17
+ properties
18
+ end
19
+ end
20
+
21
+ def total
22
+ total = BLANK_ITERATION.dup
23
+ iterations.each do |iteration, properties|
24
+ total[:story_count] += properties[:story_count]
25
+ total[:estimate_total_in_hours] += properties[:estimate_total_in_hours]
26
+ end
27
+ total
28
+ end
29
+
30
+ def to_s
31
+ if @document.empty?
32
+ "There are no stories yet."
33
+ else
34
+ parts = iterations.keys.sort.map do |iteration|
35
+ self.class.format_properties(iteration, iterations[iteration])
36
+ end
37
+ formatted_totals = self.class.format_properties(false, total)
38
+ parts << '-'*formatted_totals.length
39
+ parts << formatted_totals
40
+ parts.join("\n")
41
+ end
42
+ end
43
+
44
+ def self.estimate_to_hours(estimate)
45
+ case estimate[1]
46
+ when :days
47
+ estimate[0] * 8
48
+ when :weeks
49
+ estimate[0] * 40
50
+ else
51
+ estimate[0]
52
+ end
53
+ end
54
+
55
+ def self.format_properties(iteration, properties)
56
+ if iteration
57
+ label = (iteration == -1) ? "Unplanned" : "Iteration #{iteration}"
58
+ else
59
+ label = 'Total'
60
+ end
61
+ story_column = (properties[:story_count] == 1) ? "#{properties[:story_count]} story" : "#{properties[:story_count]} stories"
62
+ "#{label.ljust(14)}: #{properties[:estimate_total_in_hours]} (#{story_column})"
63
+ end
64
+ end
65
+ end
data/lib/saga/runner.rb CHANGED
@@ -16,6 +16,7 @@ module Saga
16
16
  opts.separator " convert <filename> - convert the stories to HTML"
17
17
  opts.separator " inspect <filename> - print the internals of the document"
18
18
  opts.separator " autofill <filename> - adds an id to stories without one"
19
+ opts.separator " planning <filename> - shows the planning of stories in iterations"
19
20
  opts.separator ""
20
21
  opts.separator "Options:"
21
22
  opts.on("-h", "--help", "Show help") do
@@ -62,6 +63,9 @@ module Saga
62
63
  Saga::Formatter.format(document, :template => 'saga')
63
64
  end
64
65
 
66
+ def planning(filename)
67
+ Saga::Planning.new(Saga::Parser.parse(File.read(filename))).to_s
68
+ end
65
69
 
66
70
  def run_command(command, options)
67
71
  case command
@@ -73,6 +77,8 @@ module Saga
73
77
  write_parsed_document(File.expand_path(@argv[1]))
74
78
  when 'autofill'
75
79
  puts autofill(File.expand_path(@argv[1]))
80
+ when 'planning'
81
+ puts planning(File.expand_path(@argv[1]))
76
82
  else
77
83
  puts convert(File.expand_path(command))
78
84
  end
data/saga.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{saga}
8
- s.version = "0.5.0"
8
+ s.version = "0.5.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Manfred Stienstra"]
12
- s.date = %q{2010-04-02}
12
+ s.date = %q{2010-06-21}
13
13
  s.default_executable = %q{saga}
14
14
  s.description = %q{Saga is a tool to convert stories syntax to a nicely formatted document.}
15
15
  s.email = %q{manfred@fngtps.com}
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
30
30
  "lib/saga/document.rb",
31
31
  "lib/saga/formatter.rb",
32
32
  "lib/saga/parser.rb",
33
+ "lib/saga/planning.rb",
33
34
  "lib/saga/runner.rb",
34
35
  "lib/saga/tokenizer.rb",
35
36
  "saga.gemspec",
@@ -45,6 +46,7 @@ Gem::Specification.new do |s|
45
46
  "test/saga_document_spec.rb",
46
47
  "test/saga_formatter_spec.rb",
47
48
  "test/saga_parser_spec.rb",
49
+ "test/saga_planning_spec.rb",
48
50
  "test/saga_runner_spec.rb",
49
51
  "test/saga_tokenizer_spec.rb",
50
52
  "test/spec_helper.rb"
@@ -52,12 +54,13 @@ Gem::Specification.new do |s|
52
54
  s.homepage = %q{http://fingertips.github.com}
53
55
  s.rdoc_options = ["--charset=UTF-8"]
54
56
  s.require_paths = ["lib"]
55
- s.rubygems_version = %q{1.3.5}
57
+ s.rubygems_version = %q{1.3.7}
56
58
  s.summary = %q{Saga is a tool to convert stories syntax to a nicely formatted document.}
57
59
  s.test_files = [
58
60
  "test/saga_document_spec.rb",
59
61
  "test/saga_formatter_spec.rb",
60
62
  "test/saga_parser_spec.rb",
63
+ "test/saga_planning_spec.rb",
61
64
  "test/saga_runner_spec.rb",
62
65
  "test/saga_tokenizer_spec.rb",
63
66
  "test/spec_helper.rb"
@@ -67,7 +70,7 @@ Gem::Specification.new do |s|
67
70
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
68
71
  s.specification_version = 3
69
72
 
70
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
73
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
71
74
  s.add_runtime_dependency(%q<erubis>, [">= 2.6"])
72
75
  s.add_runtime_dependency(%q<activesupport>, [">= 2.3"])
73
76
  s.add_development_dependency(%q<mocha-on-bacon>, [">= 0"])
@@ -29,6 +29,10 @@
29
29
  <p class="author"><%= format_author(author) %></p>
30
30
  <% end %>
31
31
 
32
+ <% introduction.each do |paragraph| %>
33
+ <p><%= paragraph %></p>
34
+ <% end %>
35
+
32
36
  <% unless stories.empty? %>
33
37
  <h2>User stories</h2>
34
38
  <% stories.each do |header, stories| %>
@@ -7,6 +7,10 @@ Requirements <%= title %>
7
7
  <% end -%>
8
8
  <% end -%>
9
9
 
10
+ <% introduction.each do |paragraph| %>
11
+ <%= paragraph %>
12
+
13
+ <% end %>
10
14
  USER STORIES
11
15
  <% stories.each do |header, stories| -%>
12
16
  <% if header.strip == '' %>
@@ -26,7 +26,26 @@ describe "A Document" do
26
26
  document.definitions.keys.should == sections
27
27
  end
28
28
 
29
- it "should return a list of used IDs" do
29
+ it "returns the number of stories as its length" do
30
+ document = Saga::Document.new
31
+ document.length == 0
32
+
33
+ document.stories[''] = [{}, {}]
34
+ document.length.should == 2
35
+
36
+ document.stories['Non-functional'] = [{}]
37
+ document.length.should == 3
38
+ end
39
+
40
+ it "know whether the document does or does not have stories" do
41
+ document = Saga::Document.new
42
+ document.should.be.empty
43
+
44
+ document.stories[''] = [{},{}]
45
+ document.should.not.be.empty
46
+ end
47
+
48
+ it "returns a list of used IDs" do
30
49
  document = Saga::Document.new
31
50
  document.used_ids.should == []
32
51
 
@@ -42,7 +61,7 @@ describe "A Document" do
42
61
  document.used_ids.should == [2, 12, 3]
43
62
  end
44
63
 
45
- it "should return a list of unused IDs" do
64
+ it "returns a list of unused IDs" do
46
65
  document = Saga::Document.new
47
66
  document.unused_ids(0).should == []
48
67
  document.unused_ids(3).should == [1,2,3]
@@ -62,7 +81,7 @@ describe "A Document" do
62
81
  document.unused_ids(4).should == [1,3,7,8]
63
82
  end
64
83
 
65
- it "should autofills ids" do
84
+ it "autofills ids" do
66
85
  document = Saga::Document.new
67
86
  document.autofill_ids
68
87
 
@@ -4,6 +4,18 @@ describe "Formatter" do
4
4
  before do
5
5
  @document = Saga::Document.new
6
6
  @document.title = 'Requirements API'
7
+ @document.authors = [
8
+ {:name => 'Thijs van der Vossen', :email => 'thijs@fngtps.com', :company => 'Fingertips', :website => 'http://www.fngtps.com'},
9
+ {:name => 'Manfred Stienstra', :email => 'manfred@fngtps.com', :company => 'Fingertips', :website => 'http://www.fngtps.com'}
10
+ ]
11
+ @document.introduction = [
12
+ 'A web service for interfacing with the service.', 'Exposes a public API to the application.'
13
+ ]
14
+ @document.stories = [
15
+ ['General', [
16
+ {:description => 'As a consumer I would like to use TLS (SSL) so that my connection with the API is secure', :id => 4, :status => 'todo' }
17
+ ]]
18
+ ]
7
19
  end
8
20
 
9
21
  it "formats a saga document to HTML" do
@@ -0,0 +1,47 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe "An empty Planning" do
4
+ before do
5
+ @document = Saga::Document.new
6
+ @planning = Saga::Planning.new(@document)
7
+ end
8
+
9
+ it "shows an empty planning message" do
10
+ @planning.to_s.should == 'There are no stories yet.'
11
+ end
12
+ end
13
+
14
+ describe "A simple Planning" do
15
+ before do
16
+ @document = Saga::Document.new
17
+ @document.stories[''] = [{:estimate => [12, :hours]}]
18
+ @planning = Saga::Planning.new(@document)
19
+ end
20
+
21
+ it "shows a planning" do
22
+ @planning.to_s.should ==
23
+ "Unplanned : 12 (1 story)\n"+
24
+ "----------------------------\n"+
25
+ "Total : 12 (1 story)"
26
+ end
27
+ end
28
+
29
+ describe "A complicated Planning" do
30
+ before do
31
+ @document = Saga::Document.new
32
+ @document.stories[''] = [{:estimate => [12, :hours], :iteration => 1}, {:estimate => [8, :hours]}]
33
+ @document.stories['Developer'] = [{:estimate => [1, :weeks], :iteration => 2}, {:estimate => [1, :hours], :iteration => 2}]
34
+ @document.stories['Writer'] = [{:estimate => [5, :hours], :iteration => 1}, {:estimate => [2, :hours], :iteration => 3}]
35
+ @planning = Saga::Planning.new(@document)
36
+ end
37
+
38
+ it "shows a planning" do
39
+ @planning.to_s.should ==
40
+ "Unplanned : 8 (1 story)\n"+
41
+ "Iteration 1 : 17 (2 stories)\n"+
42
+ "Iteration 2 : 41 (2 stories)\n"+
43
+ "Iteration 3 : 2 (1 story)\n"+
44
+ "------------------------------\n"+
45
+ "Total : 68 (6 stories)"
46
+ end
47
+ end
@@ -88,4 +88,12 @@ describe "A Runner" do
88
88
  runner.run
89
89
  end.should == "output\n"
90
90
  end
91
+
92
+ it "shows an overview of the time planned in the different iterations" do
93
+ runner = Saga::Runner.new(%w(planning requirements.txt))
94
+ runner.expects(:planning).with(File.expand_path('requirements.txt')).returns('output')
95
+ collect_stdout do
96
+ runner.run
97
+ end.should == "output\n"
98
+ end
91
99
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saga
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 1
10
+ version: 0.5.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Manfred Stienstra
@@ -9,39 +15,53 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-04-02 00:00:00 +02:00
18
+ date: 2010-06-21 00:00:00 +02:00
13
19
  default_executable: saga
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: erubis
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 2
32
+ - 6
23
33
  version: "2.6"
24
- version:
34
+ type: :runtime
35
+ version_requirements: *id001
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: activesupport
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
30
41
  requirements:
31
42
  - - ">="
32
43
  - !ruby/object:Gem::Version
44
+ hash: 5
45
+ segments:
46
+ - 2
47
+ - 3
33
48
  version: "2.3"
34
- version:
49
+ type: :runtime
50
+ version_requirements: *id002
35
51
  - !ruby/object:Gem::Dependency
36
52
  name: mocha-on-bacon
37
- type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
40
56
  requirements:
41
57
  - - ">="
42
58
  - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
43
62
  version: "0"
44
- version:
63
+ type: :development
64
+ version_requirements: *id003
45
65
  description: Saga is a tool to convert stories syntax to a nicely formatted document.
46
66
  email: manfred@fngtps.com
47
67
  executables:
@@ -63,6 +83,7 @@ files:
63
83
  - lib/saga/document.rb
64
84
  - lib/saga/formatter.rb
65
85
  - lib/saga/parser.rb
86
+ - lib/saga/planning.rb
66
87
  - lib/saga/runner.rb
67
88
  - lib/saga/tokenizer.rb
68
89
  - saga.gemspec
@@ -78,6 +99,7 @@ files:
78
99
  - test/saga_document_spec.rb
79
100
  - test/saga_formatter_spec.rb
80
101
  - test/saga_parser_spec.rb
102
+ - test/saga_planning_spec.rb
81
103
  - test/saga_runner_spec.rb
82
104
  - test/saga_tokenizer_spec.rb
83
105
  - test/spec_helper.rb
@@ -91,21 +113,27 @@ rdoc_options:
91
113
  require_paths:
92
114
  - lib
93
115
  required_ruby_version: !ruby/object:Gem::Requirement
116
+ none: false
94
117
  requirements:
95
118
  - - ">="
96
119
  - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
97
123
  version: "0"
98
- version:
99
124
  required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
100
126
  requirements:
101
127
  - - ">="
102
128
  - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
103
132
  version: "0"
104
- version:
105
133
  requirements: []
106
134
 
107
135
  rubyforge_project:
108
- rubygems_version: 1.3.5
136
+ rubygems_version: 1.3.7
109
137
  signing_key:
110
138
  specification_version: 3
111
139
  summary: Saga is a tool to convert stories syntax to a nicely formatted document.
@@ -113,6 +141,7 @@ test_files:
113
141
  - test/saga_document_spec.rb
114
142
  - test/saga_formatter_spec.rb
115
143
  - test/saga_parser_spec.rb
144
+ - test/saga_planning_spec.rb
116
145
  - test/saga_runner_spec.rb
117
146
  - test/saga_tokenizer_spec.rb
118
147
  - test/spec_helper.rb