resumetools 0.2.7.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.
@@ -0,0 +1,125 @@
1
+ module ResumeTools
2
+
3
+ class Exporter
4
+ def initialize(resume)
5
+ @resume = resume
6
+ @content = ""
7
+ end
8
+
9
+ def run
10
+ reset!
11
+ write_header
12
+ blank_line
13
+
14
+ @resume.sections.each_with_index do |section, n|
15
+ write_section section
16
+ blank_line if (n < @resume.sections.length - 1)
17
+ end
18
+
19
+ @content
20
+ end
21
+
22
+ private
23
+
24
+ def reset!
25
+ @content = ""
26
+ end
27
+
28
+ def write_header
29
+ write_contact_info :full_name
30
+ write_contact_info :address1
31
+ write_contact_info :address2
32
+ write_contact_info :telephone
33
+ write_contact_info :email
34
+ write_contact_info :url
35
+ end
36
+
37
+ def write_contact_info(info)
38
+ # TODO: make this smoother
39
+ case info
40
+ when :full_name
41
+ line "#N #{@resume.full_name}" unless @resume.full_name.blank?
42
+ when :address1
43
+ line "#A #{@resume.address1}" if @resume.has_address1?
44
+ when :address2
45
+ line "#A #{@resume.address2}" if @resume.has_address2?
46
+ when :telephone
47
+ line "#T #{@resume.telephone}" if @resume.has_telephone?
48
+ when :email
49
+ line "#E #{@resume.email}" if @resume.has_email?
50
+ when :url
51
+ line "#U #{@resume.url}" if @resume.has_url?
52
+ end
53
+ end
54
+
55
+ def write_section(section)
56
+ line "= #{section.title}"
57
+ write_para(section.para) if section.has_para?
58
+
59
+ section.items.each_with_index do |item, n|
60
+ write_item item
61
+ end
62
+
63
+ section.periods.each_with_index do |period, n|
64
+ write_period period
65
+ blank_line if (n < section.periods.length - 1)
66
+ end
67
+ end
68
+
69
+ def write_para(para)
70
+ line "---"
71
+ line para
72
+ line "---"
73
+ end
74
+
75
+ def write_item(item)
76
+ line "- #{item.text}"
77
+ end
78
+
79
+ def write_period(period)
80
+ line "+ #{period.title}"
81
+ line ">O #{period.organization}" if period.has_organization?
82
+ line ">L #{period.location}" if period.has_location?
83
+ write_dates(period)
84
+
85
+ if period.has_items?
86
+ period.items.each_with_index do |item, n|
87
+ write_item item
88
+ end
89
+ end
90
+ end
91
+
92
+ def write_dates(period)
93
+ text = ""
94
+ if period.has_dtstart? && period.has_dtend?
95
+ text = "#{period.dtstart} to #{period.dtend}"
96
+ elsif period.has_dtstart? && !period.has_dtend?
97
+ text = period.dtstart
98
+ elsif !period.has_dtstart? && period.has_dtend?
99
+ text = period.dtend
100
+ else
101
+ text = ""
102
+ end
103
+ line ">D #{text}" unless text.blank?
104
+ end
105
+
106
+ def blank_line
107
+ @content << "\n"
108
+ end
109
+
110
+ def line(text)
111
+ @content << text << "\n"
112
+ end
113
+ end
114
+
115
+ module Export
116
+ def export
117
+ exporter = Exporter.new(self)
118
+ exporter.run
119
+ end
120
+ end
121
+
122
+ Resume.class_eval do
123
+ include Export
124
+ end
125
+ end
@@ -0,0 +1,79 @@
1
+ require 'json/pure'
2
+
3
+ module ResumeTools
4
+ module Renderer
5
+ class JSON
6
+ def initialize(resume)
7
+ @resume = resume
8
+ end
9
+
10
+ def render(opts={})
11
+ frame = {
12
+ :full_name => @resume.full_name,
13
+ :url => @resume.url,
14
+ :email => @resume.email,
15
+ :telephone => @resume.telephone,
16
+ :address1 => @resume.address1,
17
+ :address2 => @resume.address2,
18
+ :sections => @resume.sections.map { |section| section.json_frame }
19
+ }
20
+ ::JSON.generate(frame)
21
+ end
22
+ end
23
+
24
+ module JSONHelpers
25
+ module SectionMethods
26
+ def json_frame
27
+ frame = {
28
+ :title => self.title,
29
+ :para => self.para,
30
+ :items => self.items.map { |item| item.json_frame },
31
+ :periods => self.periods.map { |period| period.json_frame }
32
+ }
33
+ end
34
+ end
35
+
36
+ module ItemMethods
37
+ def json_frame
38
+ frame = { :text => self.text }
39
+ end
40
+ end
41
+
42
+ module PeriodMethods
43
+ def json_frame
44
+ frame = {
45
+ :title => self.title,
46
+ :location => self.location,
47
+ :organization => self.organization,
48
+ :dtstart => self.dtstart,
49
+ :dtend => self.dtend,
50
+ :items => self.items.map { |item| item.json_frame }
51
+ }
52
+ end
53
+ end
54
+ end
55
+
56
+ module JSONMethods
57
+ def render_json(opts={})
58
+ renderer = JSON.new(self)
59
+ renderer.render(opts)
60
+ end
61
+ end
62
+ end
63
+
64
+ Section.class_eval do
65
+ include Renderer::JSONHelpers::SectionMethods
66
+ end
67
+
68
+ Period.class_eval do
69
+ include Renderer::JSONHelpers::PeriodMethods
70
+ end
71
+
72
+ Item.class_eval do
73
+ include Renderer::JSONHelpers::ItemMethods
74
+ end
75
+
76
+ Resume.class_eval do
77
+ include Renderer::JSONMethods
78
+ end
79
+ end
@@ -0,0 +1,161 @@
1
+ # coding: utf-8
2
+
3
+ #--
4
+ # Copyright (c) 2009 Virgil Dimaguila
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person
7
+ # obtaining a copy of this software and associated documentation
8
+ # files (the "Software"), to deal in the Software without
9
+ # restriction, including without limitation the rights to use,
10
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the
12
+ # Software is furnished to do so, subject to the following
13
+ # conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
+ # OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+
28
+ gems = [
29
+ ['prawn', '>= 0.5.1'],
30
+ ['prawn-core', '>= 0.5.1'],
31
+ ['prawn-layout', '>= 0.2.1'],
32
+ ['prawn-format', '>= 0.2.1']
33
+ ]
34
+
35
+ gems.each do |name, version|
36
+ if version
37
+ gem name, version
38
+ else
39
+ gem name
40
+ end
41
+ end
42
+
43
+ require "prawn"
44
+ require "prawn/format"
45
+ require "prawn/layout"
46
+ require "prawn/measurement_extensions"
47
+
48
+ module ResumeTools
49
+ module Renderer
50
+ module PDF
51
+
52
+ FONT_DIR = File.join(File.dirname(__FILE__), '..', '..', 'fonts')
53
+ MARGINS = [1.0, 1.0, 1.0, 1.0]
54
+ FONT_SIZES = {
55
+ :default => 9,
56
+ :header => 14,
57
+ :contact => 9,
58
+ :section => 10,
59
+ :para => 9,
60
+ :item => 9,
61
+ :period => 12
62
+ }
63
+ DATE_FORMAT = "%B, %Y"
64
+
65
+ # Render to PDF
66
+ def render_pdf(opts={})
67
+ pdf = Prawn::Document.new(
68
+ :info => {},
69
+ :top_margin => MARGINS[0].in,
70
+ :left_margin => MARGINS[1].in,
71
+ :bottom_margin => MARGINS[2].in,
72
+ :right_margin => MARGINS[3].in
73
+ )
74
+
75
+ pdf.font_families.update(
76
+ "VeraSans" => {
77
+ :normal => File.expand_path("Vera.ttf", FONT_DIR),
78
+ :bold => File.expand_path("VeraBd.ttf", FONT_DIR),
79
+ :italic => File.expand_path("VeraIt.ttf", FONT_DIR),
80
+ :bold_italic => File.expand_path("VeraBI.ttf", FONT_DIR)
81
+ }
82
+ )
83
+
84
+ # Set default font
85
+ pdf.font("Helvetica", :style => :normal, :size => FONT_SIZES[:default], :kerning => true)
86
+
87
+ # Name
88
+ pdf.text self.full_name, :style => :bold, :size => FONT_SIZES[:header], :align => :center
89
+
90
+ # Contact info
91
+ self.header_lines.each do |line|
92
+ pdf.text line, :align => :center
93
+ end
94
+
95
+ pdf.pad_bottom 20 do
96
+ end
97
+
98
+ # Sections
99
+ self.sections.each do |section|
100
+ pdf.pad_top(20) do
101
+ # Section title
102
+ pdf.text section.title, :style => :bold, :size => FONT_SIZES[:section]
103
+
104
+ # Section paragraph
105
+ unless section.para.blank?
106
+ pdf.span(pdf.bounds.width - 10, :position => 10) do
107
+ pdf.pad_top(5) { pdf.text section.para, :size => FONT_SIZES[:para] }
108
+ end
109
+ end
110
+
111
+ # Section items
112
+ unless section.items.empty?
113
+ pdf.table section.items.map { |item| [" •", item.text] },
114
+ :font_size => FONT_SIZES[:item],
115
+ :column_widths => { 0 => 20, 1 => 420 },
116
+ :border_style => :none,
117
+ :border_color => "ffffff",
118
+ :vertical_padding => 4,
119
+ :horizontal_padding => 0,
120
+ :align => { 0 => :left, 1 => :left }
121
+ end
122
+
123
+ # Periods
124
+ section.periods.each do |period|
125
+ pdf.span(pdf.bounds.width - 10, :position => 10) do
126
+ pdf.pad_top(5) do
127
+ # Period title
128
+ pdf.pad_top(5) { pdf.text period.title, :style => :bold, :size => FONT_SIZES[:period] }
129
+
130
+ # Period details
131
+ pdf.span(pdf.bounds.width - 10, :position => 10) do
132
+ pdf.text(period.line, :size => FONT_SIZES[:default])
133
+ end
134
+
135
+ # Period items
136
+ unless period.items.empty?
137
+ pdf.table period.items.map { |item| [" •", item.text] },
138
+ :font_size => FONT_SIZES[:item],
139
+ :column_widths => { 0 => 20, 1 => 420 },
140
+ :border_style => :none,
141
+ :border_color => "ffffff",
142
+ :vertical_padding => 4,
143
+ :horizontal_padding => 0,
144
+ :align => { 0 => :center, 1 => :left }
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ pdf.render
153
+ end
154
+
155
+ end #module PDF
156
+ end #module Renderer
157
+
158
+ Resume.class_eval do
159
+ include Renderer::PDF
160
+ end
161
+ end #module ResumeTools
@@ -0,0 +1,143 @@
1
+ require 'text/format'
2
+
3
+ module ResumeTools
4
+ module Renderer
5
+ class PlainText
6
+ def initialize(resume)
7
+ @resume = resume
8
+ end
9
+
10
+ def render(opts={})
11
+ @opts = {
12
+ :item_bullet => '-',
13
+ :header_filler => '-',
14
+ :newline => "\n",
15
+ :first_indent => 0,
16
+ :columns => 80,
17
+ :indent => 2,
18
+ :centered_top => true,
19
+ :lined_headers => true
20
+ }
21
+ @opts.merge!(opts)
22
+ @format = Text::Format.new
23
+ @format.first_indent = @opts[:first_indent]
24
+ @format.columns = @opts[:columns]
25
+
26
+ top_line @resume.full_name unless @resume.full_name.blank?
27
+ top_line @resume.address1 if @resume.has_address1?
28
+ top_line @resume.address2 if @resume.has_address2?
29
+ top_line @resume.telephone if @resume.has_telephone?
30
+ top_line @resume.email if @resume.has_email?
31
+ top_line @resume.url if @resume.has_url?
32
+ blank_line
33
+
34
+ @resume.sections.each_with_index do |section, n|
35
+ render_section(section)
36
+ blank_line if (n < @resume.sections.length - 1)
37
+ end
38
+ content
39
+ end
40
+
41
+ private
42
+
43
+ def render_section(section)
44
+ header section.title
45
+ render_paragraph(section.para) if section.has_paragraph?
46
+
47
+ section.items.each_with_index do |item, n|
48
+ push_margin do
49
+ render_item(item)
50
+ end
51
+ blank_line if (n < section.items.length - 1)
52
+ end
53
+
54
+ section.periods.each_with_index do |period, n|
55
+ push_margin do
56
+ render_period period
57
+ end
58
+ blank_line if (n < section.periods.length - 1)
59
+ end
60
+ end
61
+
62
+ def top_line(text)
63
+ if @opts[:centered_top]
64
+ center text
65
+ else
66
+ add_line text
67
+ end
68
+ end
69
+
70
+ def render_period(period)
71
+ add_line(period.title) if period.title
72
+ add_line period.line
73
+
74
+ if period.has_items?
75
+ blank_line
76
+ push_margin do
77
+ period.items.each_with_index do |item, n|
78
+ render_item item
79
+ blank_line if (n < period.items.length - 1)
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def render_item(item)
86
+ add_line "#{@opts[:item_bullet]} " + item.text
87
+ end
88
+
89
+ def render_paragraph(para)
90
+ push_margin { add_line para }
91
+ end
92
+
93
+ def reset_content
94
+ @text_content = String.new
95
+ end
96
+
97
+ def content
98
+ @text_content ||= String.new
99
+ end
100
+
101
+ def center(line)
102
+ line = @opts[:newline] if line.nil?
103
+ content << @format.center(line)
104
+ end
105
+
106
+ def add_line(line="")
107
+ line = @opts[:newline] if line.nil?
108
+ content << @format.format(line)
109
+ end
110
+
111
+ def blank_line
112
+ content << @opts[:newline]
113
+ end
114
+
115
+ def push_margin(cols=0, &block)
116
+ cols = @opts[:indent] if (cols == 0)
117
+ previous_margin = @format.left_margin
118
+ @format.left_margin = @format.left_margin + cols
119
+ block.call
120
+ @format.left_margin = previous_margin
121
+ end
122
+
123
+ def header(text)
124
+ add_line(text)
125
+ add_line(@opts[:header_filler] * text.length) if @opts[:lined_headers]
126
+ blank_line
127
+ end
128
+ end #class PlainText
129
+
130
+ module PlainTextMethods
131
+ # Render to plain text
132
+ def render_plain_text(opts={})
133
+ renderer = PlainText.new(self)
134
+ renderer.render(opts)
135
+ end
136
+ end #module Methods
137
+
138
+ end #module Renderer
139
+
140
+ Resume.class_eval do
141
+ include Renderer::PlainTextMethods
142
+ end
143
+ end #module ResumeTools