resumetools 0.2.7.0

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