resume 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,49 @@
1
+ == The Ruby Based Ruby Resume' Generator
2
+ This is a fun little project for defining your resume in Ruby. You say your a Rubyist, but is your resume written in a DSL? I didn't think so! Using the Ruby Resume' Generator, you too can be a total geek!
3
+
4
+ == Example
5
+ # ruby_coder.rb
6
+ class RubyCoder
7
+ include Resume
8
+ contact :email => %w(ruby coder net), :phone => %w(800 444 3333)
9
+ attended "XYZU", :in => "Gemology", :with => "PHD", :graduated => "1999"
10
+ worked :at => "Gem Cutting, Inc.", :description => "cut all kinds of rubies", :position => "cuter", :tenure => 2008
11
+ built %w(ruby-cuts.tv)
12
+ using %w(ruby haml datamapper)
13
+ practicing %w(agile bdd juggling)
14
+ story %w(I'm a ruby coder of some skill and whatnot. You should hire be because I'm cool.)
15
+ end
16
+
17
+ Then, with this gem installed you can pop out a slick little resume'
18
+
19
+ > resume ruby_coder.rb
20
+
21
+ Ruby Coder
22
+ ruby@coder.net 800.444.3333
23
+ --------------------------------------------------------------------------------
24
+ Attended XYZU Gemology for PHD
25
+ --------------------------------------------------------------------------------
26
+ Worked at Gem Cutting, Inc. as a cuter 2008
27
+ cut all kinds of rubies
28
+ --------------------------------------------------------------------------------
29
+ Sites
30
+ ruby-cuts.tv
31
+ --------------------------------------------------------------------------------
32
+ Technologies
33
+ ruby - haml - datamapper
34
+ --------------------------------------------------------------------------------
35
+ Practices
36
+ agile - bdd - juggling
37
+ --------------------------------------------------------------------------------
38
+ I'm a ruby coder of some skill and whatnot. You should hire be because I'm cool.
39
+
40
+ You can also write a PDF file by supplying the -pdf parameter
41
+
42
+ > resume examples/ruby_coder.rb -pdf
43
+ Printing PDF to RubyCoder.pdf
44
+
45
+ == Notes
46
+ Feel free to leave any and all of the various sections out. You can call most methods multiple times and the data
47
+ will simply get added to the list of items.
48
+
49
+ If you want a different format, feel free to hack away. If you can't you probably shouldn't be using this anyway.
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+
4
+ require 'optparse'
5
+ require 'open-uri'
6
+ require File.join(File.dirname(__FILE__), '../lib/resume')
7
+ require File.join(File.dirname(__FILE__), '../lib/pdf_printer')
8
+
9
+ options = {}
10
+ opts = OptionParser.new do |opts|
11
+ opts.banner = "Usage: resume [options] <resume location>"
12
+
13
+ opts.on("-pdf", "Create a PDF") do |pdf|
14
+ options[:pdf] = pdf
15
+ end
16
+
17
+ opts.on("-ruby", "Shows the Ruby code to create this resume") do |ruby|
18
+ options[:ruby] = ruby
19
+ end
20
+
21
+ opts.on_tail("-h", "--help", "Show this message") do
22
+ puts opts
23
+ exit
24
+ end
25
+ opts.parse!
26
+ opts
27
+ end
28
+
29
+ if(ARGV.last =~ /^-/ or ARGV.empty?)
30
+ puts opts
31
+ puts "Resume to print must be supplied."
32
+ exit
33
+ end
34
+
35
+ resume_class_string = open(ARGV.last).read
36
+ eval(resume_class_string)
37
+ resume_class_name = resume_class_string.match(/class\s(.*)/)[1]
38
+ resume_class = eval("#{resume_class_name}.new.class")
39
+
40
+ if(options[:ruby])
41
+ puts resume_class_string
42
+ end
43
+
44
+ if(options[:pdf])
45
+ printer = PDFPrinter.new(resume_class)
46
+ puts "Printing PDF to #{printer.filename}"
47
+ printer.print
48
+ else
49
+ resume_class.pretty_print
50
+ end
51
+
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'prawn'
3
+
4
+ class PDFPrinter
5
+ attr_accessor :resume
6
+
7
+ def initialize(resume)
8
+ self.resume = resume
9
+ end
10
+
11
+ def filename
12
+ "#{self.resume.name}.pdf"
13
+ end
14
+
15
+ def print
16
+ resume = self.resume
17
+ Prawn::Document.generate filename do
18
+ font "Helvetica"
19
+ header margin_box.top_left do
20
+ text resume.my_name, :align => :center, :size => 32
21
+ text resume.print_contact, :align => :center
22
+ stroke_horizontal_rule
23
+ end
24
+ move_down(50)
25
+ if(resume.has_schools?)
26
+ text "Education", :align => :right
27
+ text resume.print_schools, :align => :left
28
+ stroke_horizontal_rule
29
+ end
30
+ if(resume.has_jobs?)
31
+ text "Employment", :align => :right
32
+ text resume.print_jobs, :align => :left
33
+ stroke_horizontal_rule
34
+ end
35
+
36
+ if(resume.has_applications?)
37
+ text "Sites", :align => :right
38
+ text resume.print_array(resume.applications), :align => :center
39
+ stroke_horizontal_rule
40
+ end
41
+
42
+ if(resume.has_technologies?)
43
+ text "Technologies", :align => :right
44
+ text resume.print_array(resume.technologies), :align => :center
45
+ stroke_horizontal_rule
46
+ end
47
+
48
+ if(resume.has_practices?)
49
+ text "Practices", :align => :right
50
+ text resume.print_array(resume.practices), :align => :center
51
+ stroke_horizontal_rule
52
+ end
53
+
54
+ if(resume.has_story?)
55
+ text resume.story_text
56
+ end
57
+
58
+ footer margin_box.bottom_left do
59
+ font "Courier"
60
+ fill_color "999999"
61
+
62
+ text "gem install resume; #{$0} #{$*}", :align => :center, :size => 10
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,154 @@
1
+ module Resume
2
+
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ (base.methods - Object.methods).each do |method|
6
+ base.send(method, Array.new) if method =~ /=$/
7
+ end
8
+ base.contact_info = Hash.new
9
+ base.width = 80 # default width
10
+ end
11
+
12
+ module ClassMethods
13
+ attr_accessor :contact_info, :schools, :jobs, :applications, :technologies, :practices, :width, :story_text
14
+
15
+ def my_name
16
+ self.to_s.gsub(/([A-Z]+)([A-Z][a-z])/,'\1 \2').gsub(/([a-z\d])([A-Z])/,'\1 \2')
17
+ end
18
+
19
+ def contact(opts = {})
20
+ if(email = opts[:email])
21
+ self.contact_info[:email] = email.is_a?(Array) ? email.to_email : (raise Exception.new('Please use an array to define your email address'))
22
+ end
23
+
24
+ if(phone = opts[:phone])
25
+ self.contact_info[:phone] = phone.is_a?(Array) ? phone.to_phone : (raise Exception.new('Please use an array to define your phone number'))
26
+ end
27
+
28
+ end
29
+
30
+ def story(story)
31
+ self.story_text = story.join(" ")
32
+ end
33
+
34
+ # attended "XYZU", :in => "Basket Weaving", :with => "PHD", :graduated => "1999"
35
+ def attended(school, opts = {})
36
+ self.schools << {:name => school, :curriculum => opts[:in], :degree => opts[:with], :graduated => opts[:graduated]}
37
+ end
38
+
39
+ # worked :at => "Acme, Inc.", :description => "bored out of skull", :position => "Monkey", :tenure => 2008
40
+ def worked(opts = {})
41
+ self.jobs << {:company => opts[:at], :description => opts[:description], :position => opts[:position], :tenure => opts[:tenure]}
42
+ end
43
+
44
+ {"built" => "applications", "using" => "technologies", "practicing" => "practices"}.each do |name, accessor|
45
+ class_eval <<-EOV
46
+ def #{name}(args)
47
+ self.#{accessor} = self.#{accessor} + (args.is_a?(Array) ? args : [args])
48
+ end
49
+ EOV
50
+ end
51
+
52
+ def line(width = @width)
53
+ "-".center(width, "-")
54
+ end
55
+
56
+ def pretty_print(out = $>, width = @width)
57
+ print(my_name, out, width, :center)
58
+ print_contact(out, width)
59
+ print(line, out, width)
60
+ print(line, out, width) if print_schools(out, width)
61
+ print(line, out, width) if print_jobs(out, width)
62
+ print(line, out, width) if print_array(applications, "Sites", out, width)
63
+ print(line, out, width) if print_array(technologies, "Technologies", out, width)
64
+ print(line, out, width) if print_array(practices, "Practices", out, width)
65
+ print(story_text, out, width)
66
+ out << "\n"
67
+ end
68
+
69
+ def has_contact_info?
70
+ !contact_info[:email].nil? or !contact_info[:phone].nil?
71
+ end
72
+
73
+ def has_story?
74
+ self.story_text and !self.story_text.empty?
75
+ end
76
+
77
+ %w(schools jobs applications technologies practices story_).each do |name|
78
+ class_eval <<-EOV
79
+ def has_#{name}?
80
+ self.#{name} and !self.#{name}.empty?
81
+ end
82
+ EOV
83
+ end
84
+
85
+ def print_contact(out = "", width = @width)
86
+ row = ""
87
+ row << contact_info[:email] if contact_info[:email]
88
+ row << " " if contact_info[:email] and contact_info[:phone]
89
+ row << contact_info[:phone] if contact_info[:phone]
90
+ print(row, out, width, :center)
91
+ end
92
+
93
+ def print_schools(out = "", width = @width)
94
+ schools.collect { |s|
95
+ row = ""
96
+ row << "Attended #{s[:name]}" if s[:name]
97
+ row << " #{s[:curriculum]}" if s[:curriculum]
98
+ row << " for #{s[:degree]}" if s[:degree]
99
+ row << " graduated #{s[:year]}" if s[:year]
100
+ print(row, out, width, :right)
101
+ }.join("\n")
102
+ end
103
+
104
+ def print_jobs(out = "", width = @width)
105
+ jobs.collect { |j|
106
+ row = ""
107
+ row << "Worked at #{j[:company]}" if j[:company]
108
+ row << " as a #{j[:position]}" if j[:position]
109
+ row << " #{j[:tenure]}" if j[:tenure]
110
+ result = print(row, out, width, :right)
111
+ result += "\n" + print(j[:description], out, width) if j[:description]
112
+ }.join("\n\n")
113
+ end
114
+
115
+ def print_array(array, title = "", out = "", width = @width)
116
+ unless(array.empty?)
117
+ print(title, out, width, :right)
118
+ print(array.join(" - "), out, width)
119
+ end
120
+ end
121
+
122
+ def print(str, out, width, justify = :left)
123
+ if(str.length > width)
124
+ i = str.rindex(' ', width)
125
+ print(str[0, i], out, width, justify)
126
+ print(str[i+1, str.length], out, width, justify)
127
+ elsif(!str.empty?)
128
+ line = str.justify(width, justify)
129
+ out << "\n#{line}"
130
+ line.strip
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ class String
137
+ def justify(width, justify)
138
+ case justify
139
+ when :center: center(width)
140
+ when :left: ljust(width)
141
+ when :right: rjust(width)
142
+ end
143
+ end
144
+ end
145
+
146
+ class Array
147
+ def to_email
148
+ "#{self.first}@#{self[1,size].join('.')}"
149
+ end
150
+
151
+ def to_phone(delimiter = ".")
152
+ self.join(delimiter)
153
+ end
154
+ end
@@ -0,0 +1,270 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/resume')
2
+
3
+ describe Resume do
4
+ before(:each) do
5
+ @empty = EmptyResume
6
+ @resume = DummyResume
7
+ @alternate = AlternateDummyResume
8
+ end
9
+
10
+ it "should do the simplest thing possible" do
11
+ @resume.should_not be_nil
12
+ end
13
+
14
+ it "should have a name based on the class its included in" do
15
+ @resume.my_name.should == "Dummy Resume"
16
+ end
17
+
18
+ it "should even do middle names and more" do
19
+ @alternate.my_name.should == "Alternate Dummy Resume"
20
+ end
21
+
22
+ describe "schools" do
23
+ it "should have no schools if there are none" do
24
+ @empty.schools.should be_empty
25
+ end
26
+
27
+ it "should say its got no schools if there are none" do
28
+ @empty.has_schools?.should be_false
29
+ end
30
+
31
+ it "should include a school if there is one" do
32
+ @resume.schools.first[:name].should == "XYZU"
33
+ end
34
+
35
+ it "should say it has schools if it does" do
36
+ @resume.has_schools?.should be_true
37
+ end
38
+
39
+ it "should include year if supplied" do
40
+ @resume.schools.first[:graduated].should == "1999"
41
+ end
42
+
43
+ it "should include degree if supplied" do
44
+ @resume.schools.first[:degree].should == "PHD"
45
+ end
46
+
47
+ it "should include curriculum if supplied" do
48
+ @resume.schools.first[:curriculum].should == "Basket Weaving"
49
+ end
50
+
51
+ it "should have 1 school if said school is supplied" do
52
+ @resume.schools.size == 1
53
+ end
54
+
55
+ it "should have 2 schools if said schools are supplied" do
56
+ @alternate.schools.size == 2
57
+ end
58
+ end
59
+
60
+ describe "jobs" do
61
+ it "should have no jobs if there are none" do
62
+ @empty.jobs.should be_empty
63
+ end
64
+
65
+ it "should say it has not jobs if there are none" do
66
+ @empty.has_jobs?.should be_false
67
+ end
68
+
69
+ it "should include a job if there is one" do
70
+ @resume.jobs.first[:company].should == "Acme, Inc."
71
+ end
72
+
73
+ it "should say it has jobs if there are some" do
74
+ @resume.has_jobs?.should be_true
75
+ end
76
+
77
+ it "should include a description if there is one" do
78
+ @resume.jobs.first[:description].should == "bored out of skull"
79
+ end
80
+
81
+ it "should include a position if there is one" do
82
+ @resume.jobs.first[:position].should == "Monkey"
83
+ end
84
+
85
+ it "should include a tenure if there is one" do
86
+ @resume.jobs.first[:tenure].should == 2008
87
+ end
88
+ end
89
+
90
+ describe "applications" do
91
+ it "should have no applications if there are none" do
92
+ @empty.applications.should be_empty
93
+ end
94
+
95
+ it "should say it has not apps if there are none" do
96
+ @empty.has_applications?.should be_false
97
+ end
98
+
99
+ it "should have applications if there are some" do
100
+ @resume.applications.should == ["foo.com", "bar.net", "baz.org"]
101
+ end
102
+
103
+ it "should say it has apps if there are some" do
104
+ @resume.has_applications?.should be_true
105
+ end
106
+
107
+ it "should also add applications if there are multiples" do
108
+ @alternate.applications.should == ["biz.gov", "buzz.biz"]
109
+ end
110
+ end
111
+
112
+ describe "technologies" do
113
+ it "should have no technologies if there are none" do
114
+ @empty.technologies.should be_empty
115
+ end
116
+
117
+ it "should say it has no tech if there is none" do
118
+ @empty.has_technologies?.should be_false
119
+ end
120
+
121
+ it "should have technologies if there are some" do
122
+ @resume.technologies.should == ["countin", "readin", "spellin", "typin"]
123
+ end
124
+
125
+ it "should say it has tech if there is some" do
126
+ @resume.has_technologies?.should be_true
127
+ end
128
+
129
+
130
+ it "should also add technologies if there are multiples" do
131
+ @alternate.technologies.should == ["countin", "readin"]
132
+ end
133
+ end
134
+
135
+ describe "practices" do
136
+ it "should have no practices if there are none" do
137
+ @empty.practices.should be_empty
138
+ end
139
+
140
+ it "should say it has no practices if there is none" do
141
+ @empty.has_practices?.should be_false
142
+ end
143
+
144
+ it "should have practices if there are some" do
145
+ @resume.practices.should == ["law", "surgery", "juggling", "golf"]
146
+ end
147
+
148
+ it "should say it has practices if there are some" do
149
+ @resume.has_practices?.should be_true
150
+ end
151
+
152
+ it "should also add practices if there are multiples" do
153
+ @alternate.practices.should == ["law", "surgery"]
154
+ end
155
+ end
156
+
157
+ describe "contact" do
158
+ it "should include email" do
159
+ @resume.contact_info[:email].should == "foo@bar.com"
160
+ end
161
+
162
+ it "should say it has contact_info if there are some" do
163
+ @resume.has_contact_info?.should be_true
164
+ end
165
+
166
+ it "should include phone" do
167
+ @resume.contact_info[:phone].should == "800.444.3333"
168
+ end
169
+ end
170
+
171
+ describe "story" do
172
+ it "should include a story" do
173
+ @resume.story_text.should == "some story that this resume has and it does too"
174
+ end
175
+
176
+ it "should say there is a story" do
177
+ @resume.has_story?.should be_true
178
+ end
179
+
180
+ it "should not include a story if there isn't one" do
181
+ @empty.story_text.should be_empty
182
+ end
183
+
184
+ it "should not say there is a story" do
185
+ @empty.has_story?.should be_false
186
+ end
187
+ end
188
+
189
+ describe "pretty_print" do
190
+ before(:each) do
191
+ @print = ""
192
+ @resume.pretty_print(@print)
193
+ @alt_print = ""
194
+ @alternate.pretty_print(@alt_print)
195
+ end
196
+
197
+ it "should have a line" do
198
+ @resume.line.length.should == @resume.width
199
+ end
200
+
201
+ it "should use the name" do
202
+ @print.should match(/Dummy Resume/)
203
+ end
204
+
205
+ it "should use with a line" do
206
+ @print.should be_include(@resume.line)
207
+ end
208
+
209
+ it "should use the email" do
210
+ @print.should match(/foo@bar.com/)
211
+ end
212
+
213
+ it "should use the phone" do
214
+ @print.should match(/800.444.3333/)
215
+ end
216
+
217
+ it "should print schools out" do
218
+ @alt_print.should match(/Bachelor's/)
219
+ @alt_print.should match(/PHD/)
220
+ end
221
+
222
+ it "should print jobs" do
223
+ @print.should match(/Acme, Inc./)
224
+ @print.should match(/bored out of skull/)
225
+ @print.should match(/Monkey/)
226
+ @print.should match(/2008/)
227
+ end
228
+
229
+ it "should print websites" do
230
+ @print.should match(/foo.com/)
231
+ @print.should match(/bar.net/)
232
+ @print.should match(/baz.org/)
233
+ end
234
+
235
+ it "should print the story" do
236
+ @print.should match(/some story that this resume has and it does too/)
237
+ end
238
+ end
239
+ end
240
+
241
+ class EmptyResume
242
+ include Resume
243
+ end
244
+
245
+ class DummyResume
246
+ include Resume
247
+ contact :email => %w(foo bar com), :phone => %w(800 444 3333)
248
+ attended "XYZU", :in => "Basket Weaving", :with => "PHD", :graduated => "1999"
249
+ worked :at => "Acme, Inc.", :description => "bored out of skull", :position => "Monkey", :tenure => 2008
250
+ built %w(foo.com bar.net baz.org)
251
+ using %w(countin readin spellin typin)
252
+ practicing %w(law surgery juggling golf)
253
+ story %w(some story that this resume has and it does too)
254
+ end
255
+
256
+ class AlternateDummyResume
257
+ include Resume
258
+ attended "XYZU", :in => "Basket Weaving", :with => "Bachelor's", :graduated => "1908"
259
+ attended "XYZU", :in => "Basket Weaving", :with => "PHD", :graduated => "1999"
260
+ worked :at => "Acme, Inc.", :description => "bored out of skull", :position => "Monkey", :tenure => 2008
261
+ worked :at => "Backnecorp", :description => "bored out of back", :position => "Picker", :tenure => 2004
262
+
263
+ built "biz.gov"
264
+ built "buzz.biz"
265
+ using "countin"
266
+ using "readin"
267
+ practicing "law"
268
+ practicing "surgery"
269
+ end
270
+
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: resume
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2008-11-13 00:00:00 -08:00
8
+ summary: A Resume Gem
9
+ require_paths:
10
+ - lib
11
+ email: josh@kleinpeter.org
12
+ homepage: http://j05h.tumblr.com/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: resume
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Josh Kleinpeter
31
+ files:
32
+ - bin/resume
33
+ - lib/pdf_printer.rb
34
+ - lib/resume.rb
35
+ - README
36
+ test_files:
37
+ - spec/resume_spec.rb
38
+ rdoc_options: []
39
+
40
+ extra_rdoc_files:
41
+ - README
42
+ executables:
43
+ - resume
44
+ extensions: []
45
+
46
+ requirements: []
47
+
48
+ dependencies:
49
+ - !ruby/object:Gem::Dependency
50
+ name: prawn
51
+ version_requirement:
52
+ version_requirements: !ruby/object:Gem::Version::Requirement
53
+ requirements:
54
+ - - ">"
55
+ - !ruby/object:Gem::Version
56
+ version: 0.0.0
57
+ version: