tps_reporter 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d21f4bd77a71d9c987856ac5f0f584704749296a
4
- data.tar.gz: cc243b6990b860aa4c8891ab2394a88e02bd6eff
3
+ metadata.gz: 6ca34432146f58fced0ce7797a8ee1a50a842c3b
4
+ data.tar.gz: 78b442712fd0a2d687586d174c82cc758f4bbec8
5
5
  SHA512:
6
- metadata.gz: 7b773a7577899cb5e6fb9441e4d7820f7390306a4d0de6f7491ec3481184b31d37bfa7363dd5142c577f7f6b1b69136c4ecfa0648854e470d5cc271ff17f1990
7
- data.tar.gz: 7691a2a6ef3f16dfe6fafe767c45535d638056b060bae90edb6c0258ad9924dd56a360b853e21fad62729d106f57735459dcf357caf52f1c89b4c8bc47e547fb
6
+ metadata.gz: 699b6087e62fe5e154f5797bee9cd349580a774a0ea27cccd90d0cc56eff15e4842378d6115a64a0325720ddb51e16d08cc20f817e30c1aacbe906537be37113
7
+ data.tar.gz: 49dfb6eaf9fe7dff6540dc5371ff7ee4bf69a268f71fcceb738095f5327394d1ffb992793fd3610dd5ba4e17c6c01fa4150c3c28eb17665cd36fb25545cbc030
data/GUIDE.md CHANGED
@@ -11,26 +11,25 @@ List down the sprints.
11
11
 
12
12
  Then simply add the sprint ID to your tasks.
13
13
 
14
- # tasks.yml
14
+ # tasks.taskpaper
15
15
  Sprints:
16
16
  s1: Sprint 1 (Nov 1-15)
17
17
  s2: Sprint 2 (Nov 16-30)
18
18
  s3: Sprint 3 (Dec 1-15)
19
19
 
20
20
  Beta release:
21
- Account:
22
- Login: [s1]
23
- Logout: [s1, done]
24
- Signup: [s2]
21
+ - Account
22
+ - Login @s1
23
+ - Logout @s1 @done
24
+ - Signup @s2
25
25
 
26
26
  It's also recursive--you can put sprints in your parent tasks under `_`:
27
27
 
28
28
  Beta release:
29
- Blog:
30
- _: [s3]
31
- Create posts:
32
- Read posts:
33
- Delete posts:
29
+ - Blog @s3
30
+ - Create posts
31
+ - Read posts
32
+ - Delete posts
34
33
 
35
34
  Trello card linking support
36
35
  ---------------------------
@@ -40,8 +39,8 @@ the short URL ID for the Trello card. You can see the short ID in Trello by
40
39
  clicking "more..." inside the card popup.
41
40
 
42
41
  Beta release:
43
- Blog: [tr/Xh3pAGp1]
44
- Account management:
42
+ - Blog @tr/Xh3pAGp1
43
+ - Account management
45
44
 
46
45
  You can also link the card numbers, but you have to define the main Trello board
47
46
  URL. Simply add `Trello URL: ____` to the top of the file.
data/HISTORY.md CHANGED
@@ -1,3 +1,8 @@
1
+ v0.4.0 - June 13, 2013
2
+ ----------------------
3
+
4
+ * TaskPaper support! Tasks are now stored in `tasks.taskpaper` by default.
5
+
1
6
  v0.3.0 - June 13, 2013
2
7
  ----------------------
3
8
 
data/README.md CHANGED
@@ -14,7 +14,7 @@ Install TPS (Ruby):
14
14
  $ gem install tps_reporter
15
15
 
16
16
  ...then generate a sample file. (or create `tasks.yml` based on [this sample
17
- file.][s])
17
+ file.][sample])
18
18
 
19
19
  $ tps sample
20
20
 
@@ -22,52 +22,48 @@ Edit it, then generate the report:
22
22
 
23
23
  $ tps open
24
24
 
25
- [s]: https://github.com/rstacruz/tps_reporter/blob/master/data/sample.yml
25
+ [sample]: https://github.com/rstacruz/tps_reporter/blob/master/data/sample.taskpaper
26
26
 
27
27
  Format
28
28
  ------
29
29
 
30
- The tasks file, usually `tasks.yml`, is in YAML format.
30
+ The tasks file, usually `tasks.taskpaper`, is in [TaskPaper] format.
31
31
 
32
- Tasks are always keys (ie, they all end in `:`). They can be nested as far
33
- as you like.
32
+ They're simply a hierarchy of projects and tasks.
34
33
 
35
34
  ``` yaml
36
35
  Edit users:
37
- Register and signup:
38
- Login and logout:
36
+ - Register and signup
37
+ - Login and logout
39
38
  ```
40
39
 
41
- To define task metadata for *leaf* tasks, add it as an array inside the task:
40
+ You can tag some projects or tasks.
42
41
 
43
42
  ``` yaml
44
- Manage employees: [done]
45
- ```
46
-
47
- Or for *branch* tasks, add it under the `_` task:
43
+ Facebook connect:
44
+ - Register via Facebook @done
45
+ - Capture email
48
46
 
49
- ``` yaml
50
- Manage employees:
51
- _: [done]
52
- Creating employees:
53
- Editing employees:
47
+ Manage employees: @done
48
+ - Create user
49
+ - Edit user
54
50
  ```
55
51
 
56
- The metadata is just a simple YAML array that you can conveniently define using
57
- `[tag1, tag2, etc]`. Allowed metadata are:
52
+ The following tags are recognized:
58
53
 
59
- - `done`
60
- - `in progress`
61
- - `pt/2839478` *(Pivotal tracker ID. Links to a Pivotal tracker story.)*
62
- - `tr/LabxGP3` *(Trello card short name. Links to a Trello card.)*
63
- - `0pt` *(points; influences percentage. needs to end in __pt__ or __pts__.)*
64
- - `10%` *(task progress. implies __in progress__.)*
54
+ - `@done`
55
+ - `@in_progress`
56
+ - `@pt/2839478` *(Pivotal tracker ID. Links to a Pivotal tracker story.)*
57
+ - `@tr/LabxGP3` *(Trello card short name. Links to a Trello card.)*
58
+ - `@0pt` *(points; influences percentage. needs to end in __pt__ or __pts__.)*
59
+ - `@10%` *(task progress. implies __in progress__.)*
65
60
 
66
61
  Example:
67
62
 
68
63
  ``` yaml
69
- Creating employees: [40%]
70
- Editing employees: [done, 2pts]
64
+ Employee management:
65
+ - Creating employees @40%
66
+ - Editing employees @done @2pts
71
67
  ```
72
68
 
73
69
  Exporting to PDF or image
@@ -86,3 +82,39 @@ looks like this:
86
82
  ![Comamnd line reporter][cli]
87
83
 
88
84
  [cli]: https://img.skitch.com/20120204-ccb2guerhrjmj3rht3e4ies4ur.png
85
+
86
+ Sprints
87
+ -------
88
+
89
+ You can define sprints to help you see the workload of each sprint. First,
90
+ define your sprints on top of your file like so (this is a TaskPaper project
91
+ with notes):
92
+
93
+ ``` yaml
94
+ Sprints:
95
+ s1: Sprint 1 (May 1)
96
+ s2: Sprint 2 (May 8)
97
+ s3: Sprint 3 (May 15)
98
+ ```
99
+
100
+ The names are all arbitrary; `s1`..`s3` is just used here for convention; feel
101
+ free to use any string you like. (say, `week1`..`week7` works well for some
102
+ projects.)
103
+
104
+ Then use the names as tags (in this case, `@s1`, `@s2`):
105
+
106
+ ``` yaml
107
+ Blog:
108
+ - Writing articles @s1
109
+ - Publishing @s2
110
+ ```
111
+
112
+
113
+ Old YAML syntax
114
+ ---------------
115
+
116
+ The old (v0.3.0) YAML syntax is still supported, see the [v0.3.0 readme] for
117
+ more info.
118
+
119
+ [v0.3.0 readme]: http://github.com/rstacruz/tps_reporter/blob/v0.3.0/README.md
120
+ [TaskPaper]: http://www.hogbaysoftware.com/products/taskpaper
data/bin/tps CHANGED
@@ -62,7 +62,7 @@ module TPS::Command
62
62
  exit 130
63
63
  end
64
64
 
65
- FileUtils.cp TPS.root('data', 'sample.yml'), fn
65
+ FileUtils.cp TPS.root('data', 'sample.taskpaper'), fn
66
66
  info "Created '#{fn}'."
67
67
  info "Edit it, then use `tps html` to generate HTML from it."
68
68
  end
@@ -102,8 +102,8 @@ private
102
102
  def tasks_filename
103
103
  ARGV.extract('-f') ||
104
104
  ENV['TPS_FILE'] ||
105
- Dir['./{Tasksfile,tasks.yml}'].first ||
106
- "tasks.yml"
105
+ Dir['./{Tasksfile,tasks.yml,tasks.taskpaper}'].first ||
106
+ "tasks.taskpaper"
107
107
  end
108
108
 
109
109
  def output(&blk)
@@ -122,7 +122,11 @@ private
122
122
  end
123
123
 
124
124
  begin
125
- TPS::TaskList.new yaml: fn
125
+ if fn.match(/\.taskpaper/)
126
+ TPS::TaskList.new taskpaper: fn
127
+ else
128
+ TPS::TaskList.new yaml: fn
129
+ end
126
130
  rescue Psych::SyntaxError => e
127
131
  err "Parse error: #{e.message}"
128
132
  exit 256
@@ -0,0 +1,25 @@
1
+ Version 1:
2
+
3
+ This file is in TaskPaper format.
4
+ Tabs are used to indent.
5
+ Each task begins with a "- ".
6
+ Projects end with a ":".
7
+ Tags are in the format "@tag_name".
8
+ All other lines (such as these) are considered as notes,
9
+ and are to be ignored.
10
+
11
+ - User signup
12
+ - Register for an account
13
+ - Log in @done
14
+ - Forget password
15
+
16
+ - Manage users @in_progress
17
+ - Create users @in_progress
18
+ - Delete users
19
+ - User profile page
20
+
21
+ - Blog
22
+ - Creating new posts @done
23
+ - Comments @done
24
+ - Moderating comments @done
25
+
data/lib/tps.rb CHANGED
@@ -26,7 +26,9 @@ module TPS
26
26
  autoload :TaskList, 'tps/task_list'
27
27
  autoload :CliReporter, 'tps/cli_reporter'
28
28
  autoload :Sprint, 'tps/sprint'
29
+ autoload :TaskPaper, 'tps/taskpaper'
29
30
  autoload :BarFormatter, 'tps/bar_formatter'
31
+ autoload :TaskPaperShim, 'tps/taskpaper_shim'
30
32
 
31
33
  require 'tps/version'
32
34
 
data/lib/tps/task_list.rb CHANGED
@@ -10,6 +10,8 @@ module TPS
10
10
 
11
11
  data = if options[:yaml]
12
12
  YAML::load_file options[:yaml]
13
+ elsif options[:taskpaper]
14
+ TaskPaperShim.load options[:taskpaper]
13
15
  elsif options[:data]
14
16
  options[:data]
15
17
  else
@@ -0,0 +1,171 @@
1
+ # TaskPaper parser
2
+ #
3
+ # node = TaskPaper.parse("Project:\n\t- Hello\n\t- Hi")
4
+ #
5
+ # node.children #=> Array of <Node>
6
+ # node.level #=> 1 (depth)
7
+ #
8
+ # node.text #=> 'do things @done'
9
+ # node.plain_text #=> 'do things'
10
+ # node.tags #=> ['@done']
11
+ #
12
+ # node.node_type
13
+ # node.project?
14
+ # node.task?
15
+ # node.note?
16
+ #
17
+ module TPS::TaskPaper
18
+ class Node
19
+ attr_accessor :level
20
+ attr_accessor :node_type
21
+ attr_accessor :text
22
+ attr_reader :children
23
+ attr_reader :parent
24
+
25
+ DEFAULTS = {
26
+ :level => 0,
27
+ :node_type => :root,
28
+ :text => ''
29
+ }
30
+
31
+ def initialize(options)
32
+ options = DEFAULTS.merge(options)
33
+ options.each { |k, v| instance_variable_set :"@#{k}", v }
34
+ @children = options[:children].map { |data| Node.new data.merge(:parent => self) }
35
+ end
36
+
37
+ def project?
38
+ node_type == :project
39
+ end
40
+
41
+ def task?
42
+ node_type == :task
43
+ end
44
+
45
+ def note?
46
+ node_type == :note
47
+ end
48
+
49
+ def root?
50
+ level == 0
51
+ end
52
+
53
+ def parent?
54
+ !! parent
55
+ end
56
+
57
+ def breadcrumbs
58
+ (parent? ? parent.breadcrumbs : []) + [self]
59
+ end
60
+
61
+ TAG_REGEX = %r[(?:^|\s*)@[^\s]*(?:\([^\)]*\))?]
62
+
63
+ # Returns text without tags
64
+ def plain_text
65
+ text
66
+ .gsub(TAG_REGEX, '')
67
+ .gsub(/\s*:\s*$/, '')
68
+ .strip
69
+ end
70
+
71
+ def tags
72
+ text.scan(TAG_REGEX).map(&:strip)
73
+ end
74
+
75
+ def description
76
+ if children.length > 0
77
+ first_child = children[0]
78
+ return first_child.text if first_child.note?
79
+ end
80
+ end
81
+
82
+ # Returns a TaskPaper document.
83
+ def to_s
84
+ indent = root? ? "" : "\t"
85
+ lines = ""
86
+ lines << to_line_s + "\n" unless root?
87
+ children.each { |node| lines << node.to_s.gsub(/^/, indent) }
88
+ lines
89
+ end
90
+
91
+ def to_line_s
92
+ if project?
93
+ "#{text}:"
94
+ elsif task?
95
+ "- #{text}"
96
+ else
97
+ "#{text}"
98
+ end
99
+ end
100
+
101
+ # Returns a hash from a line
102
+ #
103
+ # parse_line("\t- Hello")
104
+ # #=> { node_type: :task, level: 2, text: "Hello" }
105
+ #
106
+ def self.parse_line(line)
107
+ node = {}
108
+
109
+ node[:level] = line.match(/^(\t*)/) && ($1.length + 1)
110
+
111
+ line = line.strip
112
+ if line =~ /^\- +(.*)$/
113
+ node[:node_type] = :task
114
+ node[:text] = $1
115
+ elsif line =~ /^(.*):((?:\s*#{TAG_REGEX})+)?$/m
116
+ node[:node_type] = :project
117
+ node[:text] = "#{$1}#{$2}"
118
+ else
119
+ node[:node_type] = :note
120
+ node[:text] = line
121
+ end
122
+
123
+ node[:children] = Array.new
124
+ node
125
+ end
126
+
127
+ def walk(&blk)
128
+ results = []
129
+ results << self if yield(self)
130
+ children.each { |node| results += node.walk(&blk) }
131
+ results
132
+ end
133
+ end
134
+
135
+ # Parses a string into a node tree.
136
+ # Returns a node.
137
+ #
138
+ # node = TaskPaper.parse("Project:\n\t- Hello\n\t- Hi")
139
+ #
140
+ def self.parse(string)
141
+ lines = string.split("\n")
142
+
143
+ root = { :node_type => :root, :level => 0, :children => [] }
144
+ ancestry = [root]
145
+ level = 0
146
+
147
+ lines.each_with_index do |line, i|
148
+ next if line.strip == ""
149
+
150
+ node = Node.parse_line(line)
151
+
152
+ if node[:level] <= level # Sibling
153
+ ancestry[node[:level]-1][:children] << node
154
+ elsif node[:level] == level + 1 # Child
155
+ ancestry[level][:children] << node
156
+ ancestry[level+1] = node
157
+ else
158
+ raise "Line #{i}: indentation mismatch (#{node[:level]} tabs found, expected 0..#{level+1})"
159
+ end
160
+
161
+ level = node[:level]
162
+ ancestry[level] = node
163
+ end
164
+
165
+ Node.new(root)
166
+ end
167
+
168
+ def self.load_file(file)
169
+ parse File.read(file)
170
+ end
171
+ end
@@ -0,0 +1,66 @@
1
+ # Converts a TaskPaper document to the internal format (as represented by
2
+ # YAML).
3
+ #
4
+ # hash = TaskPaperShim.load('file.taskpaper')
5
+ # hash = TaskPaperShim.parse("Version 1:\n\t- Login")
6
+ #
7
+ module TPS::TaskPaperShim
8
+ extend self
9
+
10
+ SETTINGS = ['Trello URL']
11
+
12
+ def parse(source)
13
+ node = TPS::TaskPaper.parse(source)
14
+
15
+ hash = work(node)
16
+ hash
17
+ end
18
+
19
+ def work(node)
20
+ return nil if node.tags.empty? && node.children.empty?
21
+ hash = {}
22
+
23
+ # Load tags
24
+ tags = node.tags.map { |s| s.gsub(/^@/, '').gsub(/_/, ' ') }
25
+ if tags.any?
26
+ if node.children.any?
27
+ hash['_'] = tags
28
+ else
29
+ return tags
30
+ end
31
+ end
32
+
33
+ # Load children
34
+ node.children.each do |child|
35
+ text = child.plain_text
36
+
37
+ # For "Trello URL: xxx" settings
38
+ if is_setting?(child)
39
+ child.plain_text =~ /^(.*?): (.*)$/
40
+ hash[$1] = $2
41
+
42
+ # For "s1: Sprint 1" notes
43
+ elsif node.plain_text == "Sprints"
44
+ text.match(/^(.*?): (.*)$/) && hash[$1] = $2
45
+
46
+ # For everything else
47
+ elsif !child.note?
48
+ hash[text] = work(child)
49
+ end
50
+ end
51
+
52
+ hash
53
+ end
54
+
55
+ # Checks if a given node is a settings node
56
+ def is_setting?(node)
57
+ if node.note?
58
+ SETTINGS.any? { |tag| node.plain_text =~ /^#{tag}:/ }
59
+ end
60
+ end
61
+
62
+ def load(file)
63
+ data = File.read(file)
64
+ parse data
65
+ end
66
+ end
data/lib/tps/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module TPS
2
2
  def self.version
3
- "0.3.0"
3
+ "0.4.0"
4
4
  end
5
5
  end
data/tasks.taskpaper ADDED
@@ -0,0 +1,23 @@
1
+ Sprints:
2
+ s1: Sprint 1 (November)
3
+ s2: Sprint 2 (Jan)
4
+ s3: Sprint 3 (December)
5
+
6
+ Version 1:
7
+ This is a note. It will be ignored.
8
+
9
+ User signup: @s1
10
+ - Register for an account
11
+ - Log in @done
12
+ - Forget password
13
+
14
+ - Manage users @in_progress @s1
15
+ - Create users @in_progress @s3
16
+ - Delete users
17
+ - User profile page
18
+
19
+ - Blog
20
+ - Creating new posts @done
21
+ - Comments @done
22
+ - Moderating comments
23
+
@@ -0,0 +1,48 @@
1
+ Milestone 1:
2
+ - First task @25%
3
+
4
+ User login:
5
+ - Login
6
+ - Signup
7
+
8
+ Overridden percent: @50%
9
+ - one @done
10
+ - two @done
11
+ - three @done
12
+
13
+ Explicit points: @15pt
14
+ - one @done
15
+ - two @done
16
+ - three @done
17
+ - four
18
+
19
+ Compound points:
20
+ - one
21
+ - two
22
+ three:
23
+ - sub1 @3pts @done
24
+ - sub2
25
+
26
+ Point rescaling:
27
+ Has 6 sub points, but will be rescaled to 8.
28
+ That is, the done "3" point task is actually worth 4 points.
29
+
30
+ one: @8pts
31
+ - sub1 @3pts @done
32
+ - sub2 @1pt
33
+ - sub3 @1pt
34
+ - sub4 @1pt
35
+
36
+ In progress:
37
+ - one
38
+ - two @in_progress
39
+
40
+ Progress override: @50%
41
+ #7
42
+ It's supposed to be 50% done because of it's subtasks, but
43
+ Defining our own percentage overrides that.
44
+
45
+ - one @done
46
+ - two
47
+
48
+ Milestone 2:
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class SettingsTest < UnitTest
4
+ setup do
5
+ @hash = TPS::TaskPaperShim.parse("Trello URL: http://xyz\nVersion 1:\n\t- Hello")
6
+ end
7
+
8
+ test "use setting" do
9
+ assert_equal "http://xyz", @hash["Trello URL"]
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class TaskpaperTest < UnitTest
4
+ test "parseable" do
5
+ data = File.read('tasks.taskpaper')
6
+ root = TPS::TaskPaper.parse(data)
7
+ end
8
+
9
+ describe "basic doc" do
10
+ setup do
11
+ @source = "Version 1:\n\t- Log in @done"
12
+ @node = TPS::TaskPaper.parse(@source)
13
+ end
14
+
15
+ test "should work" do
16
+ assert_equal @node.to_s.strip, @source
17
+ end
18
+ end
19
+
20
+ describe "shim" do
21
+ setup do
22
+ @hash = TPS::TaskPaperShim.load('tasks.taskpaper')
23
+ end
24
+
25
+ test "should work" do
26
+ expected = {"Sprints"=>{"s1"=>"Sprint 1 (November)", "s2"=>"Sprint 2 (Jan)", "s3"=>"Sprint 3 (December)"}, "Version 1"=>{"User signup"=>{"_"=>["s1"], "Register for an account"=>nil, "Log in"=>["done"], "Forget password"=>nil}, "Manage users"=>{"_"=>["in progress", "s1"], "Create users"=>["in progress", "s3"], "Delete users"=>nil, "User profile page"=>nil}, "Blog"=>{"Creating new posts"=>["done"], "Comments"=>["done"], "Moderating comments"=>["done"]}}}
27
+ assert_equal expected, @hash
28
+ end
29
+ end
30
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tps_reporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rico Sta. Cruz
@@ -54,7 +54,7 @@ files:
54
54
  - Rakefile
55
55
  - bin/tps
56
56
  - data/index.haml
57
- - data/sample.yml
57
+ - data/sample.taskpaper
58
58
  - lib/tps.rb
59
59
  - lib/tps/bar_formatter.rb
60
60
  - lib/tps/cli_reporter.rb
@@ -62,8 +62,12 @@ files:
62
62
  - lib/tps/sprint.rb
63
63
  - lib/tps/task.rb
64
64
  - lib/tps/task_list.rb
65
+ - lib/tps/taskpaper.rb
66
+ - lib/tps/taskpaper_shim.rb
65
67
  - lib/tps/version.rb
68
+ - tasks.taskpaper
66
69
  - test/bar_test.rb
70
+ - test/fixtures/hello.taskpaper
67
71
  - test/fixtures/hello.yml
68
72
  - test/fixtures/markers.yml
69
73
  - test/fixtures/multi_sprints.yml
@@ -71,8 +75,10 @@ files:
71
75
  - test/fixtures/sprints.yml
72
76
  - test/html_test.rb
73
77
  - test/multi_sprints_test.rb
78
+ - test/settings_test.rb
74
79
  - test/sprint_points_test.rb
75
80
  - test/sprint_test.rb
81
+ - test/taskpaper_test.rb
76
82
  - test/test_helper.rb
77
83
  - test/tps_test.rb
78
84
  - tps_reporter.gemspec
data/data/sample.yml DELETED
@@ -1,18 +0,0 @@
1
- Version 1:
2
-
3
- User signup:
4
- Register for an account:
5
- Log in: [done]
6
- Forget password:
7
-
8
- Manage users:
9
- _: [in progress]
10
- Create users: [in progress]
11
- Delete users:
12
- User profile page:
13
-
14
- Blog:
15
- Creating new posts: [done]
16
- Comments: [done]
17
- Moderating comments: [done]
18
-