saga 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|