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 +8 -0
- data/README.rdoc +1 -0
- data/VERSION +1 -1
- data/lib/saga.rb +1 -0
- data/lib/saga/document.rb +4 -0
- data/lib/saga/planning.rb +65 -0
- data/lib/saga/runner.rb +6 -0
- data/saga.gemspec +7 -4
- data/templates/default/document.erb +4 -0
- data/templates/saga/document.erb +4 -0
- data/test/saga_document_spec.rb +22 -3
- data/test/saga_formatter_spec.rb +12 -0
- data/test/saga_planning_spec.rb +47 -0
- data/test/saga_runner_spec.rb +8 -0
- metadata +46 -17
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.
|
1
|
+
0.5.1
|
data/lib/saga.rb
CHANGED
data/lib/saga/document.rb
CHANGED
@@ -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.
|
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-
|
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.
|
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::
|
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"])
|
data/templates/saga/document.erb
CHANGED
data/test/saga_document_spec.rb
CHANGED
@@ -26,7 +26,26 @@ describe "A Document" do
|
|
26
26
|
document.definitions.keys.should == sections
|
27
27
|
end
|
28
28
|
|
29
|
-
it "
|
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 "
|
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 "
|
84
|
+
it "autofills ids" do
|
66
85
|
document = Saga::Document.new
|
67
86
|
document.autofill_ids
|
68
87
|
|
data/test/saga_formatter_spec.rb
CHANGED
@@ -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
|
data/test/saga_runner_spec.rb
CHANGED
@@ -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
|
-
|
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-
|
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
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
37
|
name: activesupport
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
35
51
|
- !ruby/object:Gem::Dependency
|
36
52
|
name: mocha-on-bacon
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
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.
|
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
|