pivotalprinter 0.2.0 → 0.3.0

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/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  pkg
3
3
  Gemfile.lock
4
4
  .rvmrc
5
+ .DS_Store
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  # vim: set ft=ruby:
2
2
 
3
- source "http://rubygems.org"
3
+ source :rubygems
4
4
 
5
5
  gemspec
6
+
7
+ gem 'utils'
@@ -1,3 +1,18 @@
1
+ === 0.3.0 2013-01-07
2
+
3
+ * Always show estimated points for all story types.
4
+ * Some refactoring of the code.
5
+ * Improved the images a bit (I think).
6
+ * Display project name on each story card.
7
+
8
+ === 0.2.0 2012-11-27
9
+
10
+ * Adds more information on the ticket.
11
+
12
+ === 0.1.8 2011-10-25
13
+
14
+ * Allow for ruby 1.9 compatibility.
15
+
1
16
  === 0.1.7 2011-07-19
2
17
 
3
18
  * use a newver prawn version
@@ -1,17 +1,21 @@
1
+ COPYING
2
+ Gemfile
1
3
  History.txt
2
4
  Manifest.txt
3
5
  PostInstall.txt
4
6
  README.rdoc
5
7
  Rakefile
6
8
  bin/pivotalprinter
7
- images/bug.png
8
- images/chore.png
9
- images/feature.png
10
- images/release.png
11
9
  lib/pivotalprinter.rb
12
10
  lib/pivotalprinter/client.rb
13
- lib/pivotalprinter/story.rb
11
+ lib/pivotalprinter/images/bug.png
12
+ lib/pivotalprinter/images/chore.png
13
+ lib/pivotalprinter/images/feature.png
14
+ lib/pivotalprinter/images/release.png
14
15
  lib/pivotalprinter/iteration.rb
16
+ lib/pivotalprinter/printer.rb
17
+ lib/pivotalprinter/story.rb
18
+ lib/pivotalprinter/version.rb
15
19
  pivotalprinter.gemspec
16
20
  script/console
17
21
  script/destroy
@@ -5,149 +5,4 @@ require 'pivotalprinter'
5
5
 
6
6
  class String; include Term::ANSIColor; end
7
7
 
8
- module Pivotalprinter
9
- class ConfigNeeded < StandardError; end
10
- class TokenMissing < StandardError; end
11
- class ProjectMissing < StandardError; end
12
- end
13
-
14
- module Pivotalprinter
15
- class Printer
16
- def run
17
- opts = parse_options
18
- yaml = load_yaml_config
19
- project,token = extract_config(opts, yaml)
20
- Pivotalprinter::Client.project = project
21
- Pivotalprinter::Client.token = token
22
- @stories = case ARGV.last
23
- when "done" then Pivotalprinter::Iteration.open('done').stories
24
- when "backlog" then Pivotalprinter::Iteration.open('backlog').stories
25
- when /^\d+$/ then Pivotalprinter::Story.open(ARGV.map(&:to_i))
26
- else Pivotalprinter::Iteration.open('current').stories
27
- end
28
- generate_output
29
- rescue ConfigNeeded
30
- print_config
31
- rescue TokenMissing
32
- Trollop::die :token, "token must be specified through config file or explicitly"
33
- rescue ProjectMissing
34
- Trollop::die :project, "project must be a valid number or one of the configured projects (#{(yaml.keys - ["default"]).join(", ")}) if no default is configured in $HOME/.pivotalprinterrc"
35
- rescue SystemExit
36
- rescue Exception
37
- puts "[!] There was an error while generating the PDF file... What happened was:".white.on_red
38
- raise
39
- end
40
-
41
- def print_config
42
- puts %{---\ndefault: &default\n token: "YOUR TOKEN HERE"\n project: 123\n\nsome_project:\n <<: *default # so you don't need to rewrite the token\n project: 789}
43
- end
44
-
45
- def parse_options
46
- opts = Trollop::options do
47
- version "pivotalprinter #{Pivotalprinter::VERSION} (c) 2010#{(year = Time.now.year) > 2010 ? "-#{year}" : ''} pkw.de"
48
- banner <<-EOS
49
- Pivotalprinter is an awesome program to print stories from the PivotalTracker.
50
-
51
- Usage:
52
- pivotalprinter [-p PROJECT] [-t TOKEN] [current|backlog|done|STORY]
53
- pivotalprinter --config > ~/.pivotalprinterrc
54
-
55
- Options:
56
- EOS
57
- opt :project, "Project Name defined in $HOME/.pivotalprinterrc or project number", :short => "-p", :type => :string
58
- opt :token, "Pivotaltracker Token", :short => "-t", :type => :string
59
- opt :config, "show example configuration", :short => "-c"
60
- end
61
-
62
- raise ConfigNeeded if opts[:config]
63
- opts
64
- end
65
-
66
- def load_yaml_config
67
- File.exist?("#{ENV["HOME"]}/.pivotalprinterrc") ? YAML::load_file("#{ENV["HOME"]}/.pivotalprinterrc") : {}
68
- end
69
-
70
- def extract_config(opts, yaml)
71
- if opts[:project].nil? && yaml.key?("default")
72
- return yaml["default"]["project"], yaml["default"]["token"]
73
- elsif opts[:project] =~ /[0-9]+/
74
- return opts[:project], (opts[:token] || yaml["default"]["project"])
75
- elsif yaml.key?(opts[:project])
76
- return yaml[opts[:project]]["project"], yaml[opts[:project]]["token"]
77
- else
78
- raise ProjectMissing
79
- end
80
- end
81
-
82
- def generate_output
83
- Prawn::Document.generate("/tmp/stories.pdf", :page_layout => :landscape, :margin => [25, 25, 50, 25], :page_size => 'A4') do |pdf|
84
- @num_cards_on_page = 0
85
- pdf.font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
86
- @stories.each_with_index do |story, i|
87
- # --- Split pages
88
- if i > 0 and i % 4 == 0
89
- # puts "New page..."
90
- pdf.start_new_page
91
- @num_cards_on_page = 1
92
- else
93
- @num_cards_on_page += 1
94
- end
95
-
96
- # --- Define 2x2 grid
97
- pdf.define_grid(:columns => 2, :rows => 2, :gutter => 42)
98
- # pdf.grid.show_all
99
-
100
- row = (@num_cards_on_page + 1) / 4
101
- column = i % 2
102
- padding = 12
103
- cell = pdf.grid( row, column )
104
- cell.bounding_box do
105
-
106
- pdf.stroke_color = "666666"
107
- pdf.stroke_bounds
108
-
109
- pdf.text_box story.name, :size => 14, :height => 50, :overflow => :truncate,
110
- :width => cell.width - (padding * 2) - 50,
111
- :at => [pdf.bounds.left + padding + 50, pdf.bounds.top - padding]
112
-
113
- pdf.text_box story.description, :size => 8, :overflow => :truncate,
114
- :width => cell.width - ( padding * 2), :height => cell.height - (padding * 7),
115
- :at => [pdf.bounds.left + padding, pdf.bounds.top - padding - 55]
116
-
117
- pdf.text_box "Created at: #{story.created_at.strftime('%F')}", :size => 8,
118
- :at => [pdf.bounds.left + padding, pdf.bounds.bottom + padding]
119
-
120
- pdf.text_box "ID: #{story.id}", :size => 8,
121
- :at => [pdf.bounds.left + 110, pdf.bounds.bottom + padding]
122
-
123
- pdf.text_box "State: #{story.current_state}", :size => 8,
124
- :at => [pdf.bounds.left + 170, pdf.bounds.bottom + padding]
125
-
126
- pdf.text_box "Requester: #{story.requested_by}", :size => 8,
127
- :at => [pdf.bounds.left + 240, pdf.bounds.bottom + padding]
128
-
129
-
130
- x, y = 32, 205
131
- if story.story_type == "feature"
132
- pdf.fill_color story.points_background
133
- pdf.fill_circle [x, y], 25
134
- pdf.font_size = 36
135
- pdf.font "Helvetica", :style => :bold
136
- pdf.fill_color 'ffffff'
137
- pdf.draw_text "#{story.points}", :at => [x - 10, y - 12]
138
- pdf.fill_color '000000'
139
- pdf.font_size = 14
140
- pdf.font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf", :style => :normal
141
- else
142
- pdf.image open("#{File.dirname(__FILE__)}/../images/#{story.story_type}.png"), :position => 5, :vposition => 5
143
- end
144
- end
145
- end
146
- end
147
- puts ">>> Generated PDF file in 'stories.pdf' with #{@stories.size} stories".black.on_green
148
- system "open /tmp/stories.pdf"
149
- end
150
- end
151
- end
152
-
153
- Pivotalprinter::Printer.new.run
8
+ Pivotalprinter::Printer.new.run(ARGV)
@@ -1,18 +1,13 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
1
  module Pivotalprinter
5
- require 'rubygems'
6
- require 'pivotalprinter/version'
7
- require 'term/ansicolor'
8
- require 'prawn'
9
- require 'prawn/layout/grid'
10
- require 'tins/xt/full'
11
- require 'trollop'
12
- require 'yaml'
13
- require "open-uri"
14
- require "nokogiri"
15
- require "pivotalprinter/client"
16
- require "pivotalprinter/iteration"
17
- require "pivotalprinter/story"
2
+ class ConfigNeeded < StandardError; end
3
+ class TokenMissing < StandardError; end
4
+ class ProjectMissing < StandardError; end
18
5
  end
6
+
7
+ require 'pivotalprinter/version'
8
+ require 'pivotalprinter/client'
9
+ require 'pivotalprinter/iteration'
10
+ require 'pivotalprinter/story'
11
+ require 'pivotalprinter/printer'
12
+ require 'term/ansicolor'
13
+ require 'tins/xt/full'
@@ -1,3 +1,6 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+
1
4
  module Pivotalprinter
2
5
  class Client
3
6
  class << self
@@ -6,7 +9,8 @@ module Pivotalprinter
6
9
  def get(path, options={})
7
10
  raise TokenMissing if @token.nil?
8
11
  raise ProjectMissing if @project.nil?
9
- open("http://www.pivotaltracker.com/services/v3#{path}", 'X-TrackerToken' => @token, 'Content-Type' => 'application/xml').read
12
+ response = open("http://www.pivotaltracker.com/services/v3#{path}", 'X-TrackerToken' => @token, 'Content-Type' => 'application/xml').read
13
+ Nokogiri::XML.parse(response)
10
14
  end
11
15
  end
12
16
  end
@@ -1,24 +1,23 @@
1
1
  module Pivotalprinter
2
2
  class Iteration
3
-
3
+
4
4
  attr_accessor :stories
5
-
5
+
6
6
  def self.open(name)
7
7
  self.new(name)
8
8
  end
9
-
9
+
10
10
  def initialize(name)
11
11
  @stories = []
12
- extract_stories(Client.get "/projects/#{Client.project}/iterations/#{name}")
12
+ extract_stories Client.get("/projects/#{Client.project}/iterations/#{name}")
13
13
  end
14
-
14
+
15
15
  private
16
-
16
+
17
17
  def extract_stories(response)
18
- response = Nokogiri::XML.parse(response)
19
18
  response.css("story").each do |story|
20
19
  @stories << Story.new(story)
21
20
  end
22
21
  end
23
22
  end
24
- end
23
+ end
@@ -0,0 +1,151 @@
1
+ require 'trollop'
2
+ require 'yaml'
3
+ require 'prawn'
4
+ require 'prawn/layout/grid'
5
+
6
+ module Pivotalprinter
7
+ class Printer
8
+ def run(argv)
9
+ argv = argv.dup
10
+ opts = parse_options
11
+ yaml = load_yaml_config
12
+ project, token = extract_config(opts, yaml)
13
+ Pivotalprinter::Client.project = project
14
+ Pivotalprinter::Client.token = token
15
+ @project_name = (Client.get("/projects/#{project}") / 'project/name').text
16
+ @stories =
17
+ case argv.last
18
+ when "done" then Pivotalprinter::Iteration.open('done').stories
19
+ when "backlog" then Pivotalprinter::Iteration.open('backlog').stories
20
+ when /^\d+$/ then Pivotalprinter::Story.open(argv.map(&:to_i))
21
+ else Pivotalprinter::Iteration.open('current').stories
22
+ end
23
+ generate_output
24
+ rescue ConfigNeeded
25
+ print_config
26
+ rescue TokenMissing
27
+ Trollop::die :token, "token must be specified through config file or explicitly"
28
+ rescue ProjectMissing
29
+ Trollop::die :project, "project must be a valid number or one of the configured projects (#{(yaml.keys - ["default"]).join(", ")}) if no default is configured in $HOME/.pivotalprinterrc"
30
+ rescue Exception
31
+ puts "[!] There was an error while generating the PDF file... What happened was:".white.on_red
32
+ raise
33
+ end
34
+
35
+ def print_config
36
+ puts <<CONFIG
37
+ ---
38
+ default: &default
39
+ token: "YOUR TOKEN HERE"
40
+ project: 123
41
+
42
+ some_project:
43
+ <<: *default # so you don't need to rewrite the token
44
+ project: 789
45
+ CONFIG
46
+ end
47
+
48
+ def parse_options
49
+ opts = Trollop::options do
50
+ version "pivotalprinter #{Pivotalprinter::VERSION} (c) 2010#{(year = Time.now.year) > 2010 ? "-#{year}" : ''} pkw.de"
51
+ banner <<-EOS
52
+ Pivotalprinter is an awesome program to print stories from the PivotalTracker.
53
+
54
+ Usage:
55
+ pivotalprinter [-p PROJECT] [-t TOKEN] [current|backlog|done|STORY]
56
+ pivotalprinter --config > ~/.pivotalprinterrc
57
+
58
+ Options:
59
+ EOS
60
+ opt :project, "Project Name defined in $HOME/.pivotalprinterrc or project number",
61
+ :short => "-p", :type => :string
62
+ opt :token, "Pivotaltracker Token", :short => "-t", :type => :string
63
+ opt :config, "show example configuration", :short => "-c"
64
+ end
65
+
66
+ raise ConfigNeeded if opts[:config]
67
+ opts
68
+ end
69
+
70
+ def load_yaml_config
71
+ File.exist?("#{ENV["HOME"]}/.pivotalprinterrc") ? YAML::load_file("#{ENV["HOME"]}/.pivotalprinterrc") : {}
72
+ end
73
+
74
+ def extract_config(opts, yaml)
75
+ if opts[:project].nil? && yaml.key?("default")
76
+ return yaml["default"]["project"], yaml["default"]["token"]
77
+ elsif opts[:project] =~ /[0-9]+/
78
+ return opts[:project], (opts[:token] || yaml["default"]["project"])
79
+ elsif yaml.key?(opts[:project])
80
+ return yaml[opts[:project]]["project"], yaml[opts[:project]]["token"]
81
+ else
82
+ raise ProjectMissing
83
+ end
84
+ end
85
+
86
+ def generate_output
87
+ Prawn::Document.generate("/tmp/stories.pdf", :page_layout => :landscape, :margin => [25, 25, 50, 25], :page_size => 'A4') do |pdf|
88
+ @num_cards_on_page = 0
89
+ pdf.font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
90
+ @stories.each_with_index do |story, i|
91
+ # --- Split pages
92
+ if i > 0 and i % 4 == 0
93
+ # puts "New page..."
94
+ pdf.start_new_page
95
+ @num_cards_on_page = 1
96
+ else
97
+ @num_cards_on_page += 1
98
+ end
99
+
100
+ # --- Define 2x2 grid
101
+ pdf.define_grid(:columns => 2, :rows => 2, :gutter => 42)
102
+ # pdf.grid.show_all
103
+
104
+ row = (@num_cards_on_page + 1) / 4
105
+ column = i % 2
106
+ padding = 12
107
+ cell = pdf.grid( row, column )
108
+ cell.bounding_box do
109
+ pdf.stroke_color = "666666"
110
+ pdf.stroke_bounds
111
+
112
+ pdf.text_box "#@project_name ##{story.id}", :size => 10, :overflow => :truncate,
113
+ :width => cell.width - ( padding * 2),
114
+ :at => [pdf.bounds.left + padding, pdf.bounds.top - padding / 2 ]
115
+
116
+ pdf.text_box story.name, :size => 14, :height => 50, :overflow => :truncate,
117
+ :width => cell.width - (padding * 2) - 100,
118
+ :at => [pdf.bounds.left + padding + 50, pdf.bounds.top - 2 * padding]
119
+
120
+ pdf.text_box story.description.strip, :size => 8, :overflow => :truncate,
121
+ :width => cell.width - ( padding * 2), :height => cell.height - (padding * 8),
122
+ :at => [pdf.bounds.left + padding, pdf.bounds.top - 2 * padding - 55]
123
+
124
+ pdf.text_box "Created at: #{story.created_at.strftime('%F')}", :size => 8,
125
+ :at => [pdf.bounds.left + padding, pdf.bounds.bottom + padding]
126
+
127
+ pdf.text_box "State: #{story.current_state}", :size => 8,
128
+ :at => [pdf.bounds.left + 120, pdf.bounds.bottom + padding]
129
+
130
+ pdf.text_box "Requester: #{story.requested_by}", :size => 8,
131
+ :at => [pdf.bounds.left + 200, pdf.bounds.bottom + padding]
132
+
133
+ x, y = 32, 205 - padding
134
+ pdf.fill_color story.points_background
135
+ pdf.fill_circle [x, y], 25
136
+ pdf.font_size = 36
137
+ pdf.font "Helvetica", :style => :bold
138
+ pdf.fill_color 'ffffff'
139
+ pdf.draw_text "#{story.points}", :at => [x - 10, y - 12]
140
+ pdf.fill_color '000000'
141
+ pdf.font_size = 14
142
+ pdf.font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf", :style => :normal
143
+ pdf.image open("#{File.dirname(__FILE__)}/images/#{story.story_type}.png"), :position => cell.width - 51, :vposition => 5 + padding
144
+ end
145
+ end
146
+ end
147
+ puts ">>> Generated PDF file in 'stories.pdf' with #{@stories.size} stories".black.on_green
148
+ system "open /tmp/stories.pdf"
149
+ end
150
+ end
151
+ end
@@ -4,7 +4,7 @@ module Pivotalprinter
4
4
  class Story
5
5
  FIELDS = [ :name, :id, :story_type, :estimate, :current_state, :description, :requested_by, :labels, :created_at, :updated_at ]
6
6
  attr_accessor(*FIELDS)
7
-
7
+
8
8
  def initialize(xml)
9
9
  FIELDS.each do |field|
10
10
  value = xml.css("#{field}")
@@ -13,19 +13,18 @@ module Pivotalprinter
13
13
  created_at and self.created_at = Time.parse(created_at)
14
14
  updated_at and self.updated_at = Time.parse(updated_at)
15
15
  end
16
-
16
+
17
17
  def self.open(ids)
18
18
  ids.map do |id|
19
19
  response = Client.get "/projects/#{Client.project}/stories/#{id}"
20
- response = Nokogiri::XML.parse(response)
21
- self.new(response.css('story'))
20
+ self.new(response.css('story'))
22
21
  end
23
22
  end
24
-
23
+
25
24
  def points
26
25
  estimate.to_i >= 0 ? estimate.to_i : '?'
27
26
  end
28
-
27
+
29
28
  def points_background
30
29
  case points
31
30
  when '?' then 'cccccc'
@@ -1,3 +1,3 @@
1
1
  module Pivotalprinter
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pivotalprinter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-27 00:00:00.000000000 Z
12
+ date: 2013-01-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: term-ansicolor
@@ -140,13 +140,14 @@ files:
140
140
  - README.rdoc
141
141
  - Rakefile
142
142
  - bin/pivotalprinter
143
- - images/bug.png
144
- - images/chore.png
145
- - images/feature.png
146
- - images/release.png
147
143
  - lib/pivotalprinter.rb
148
144
  - lib/pivotalprinter/client.rb
145
+ - lib/pivotalprinter/images/bug.png
146
+ - lib/pivotalprinter/images/chore.png
147
+ - lib/pivotalprinter/images/feature.png
148
+ - lib/pivotalprinter/images/release.png
149
149
  - lib/pivotalprinter/iteration.rb
150
+ - lib/pivotalprinter/printer.rb
150
151
  - lib/pivotalprinter/story.rb
151
152
  - lib/pivotalprinter/version.rb
152
153
  - pivotalprinter.gemspec
@@ -169,7 +170,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
169
170
  version: '0'
170
171
  segments:
171
172
  - 0
172
- hash: 3495001522045933990
173
+ hash: -738262424533095811
173
174
  required_rubygems_version: !ruby/object:Gem::Requirement
174
175
  none: false
175
176
  requirements:
@@ -178,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
179
  version: '0'
179
180
  segments:
180
181
  - 0
181
- hash: 3495001522045933990
182
+ hash: -738262424533095811
182
183
  requirements: []
183
184
  rubyforge_project:
184
185
  rubygems_version: 1.8.24
Binary file
Binary file