xmlresume2x 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,453 @@
1
+ # Configuration for the resume converter -*- ruby -*-
2
+
3
+ begin
4
+ require 'iconv'
5
+
6
+ def convert( text )
7
+ Iconv::iconv( "ISO-8859-1", "utf-8", text )[0]
8
+ end
9
+ rescue LoadError
10
+ def convert( text )
11
+ enc = []
12
+ text.unpack('U*').each do |num|
13
+ if num <= 0xFF
14
+ enc << num
15
+ else
16
+ STDERR.puts("Could not encode UTF-8 value #{num}")
17
+ enc << ??
18
+ end
19
+ end
20
+ enc.pack('C*')
21
+ end
22
+ end
23
+
24
+ common_file = File.join( File.dirname( __FILE__ ), '..', 'common', "common#{Converter::CONFIG_EXT}" )
25
+ load_config( File.read( common_file ), common_file )
26
+
27
+ #####################################################
28
+ # Global Constants
29
+
30
+ CHAR_REPLACE_TABLE = {
31
+ '#' => '\#',
32
+ '$' => "\\$",
33
+ '%' => '\%',
34
+ '^' => '\^{}',
35
+ '&' => '\&',
36
+ '_' => '\_',
37
+ '{' => '\{',
38
+ '}' => '\}',
39
+ '~' => '\~{}',
40
+ '\\' => '$\backslash$',
41
+ }
42
+ CHAR_REPLACE_REGEXP = Regexp.new( CHAR_REPLACE_TABLE.keys.map { |key| Regexp.escape( key ) }.join('|') )
43
+
44
+ SEPARATOR = "\\tabularnewline\\tabularnewline\n"
45
+ GAP="5pt"
46
+
47
+ def newline
48
+ "\\newline{}\n"
49
+ end
50
+
51
+ #####################################################
52
+ # Processors for simple elements
53
+
54
+ add_processor 'SubParaProcessor' do |element|
55
+ element.para.join( newline )
56
+ end
57
+
58
+ #####################################################
59
+ # Inline elements
60
+
61
+ processor 'link' => 'LinkProcessor' do |link|
62
+ value = get_children_value( link, :rawText => true )
63
+ href = get_value( link._href, :rawText => true )
64
+ if value != href
65
+ "#{get_children_value( link )} (\\url{#{href}})"
66
+ else
67
+ "\\url{#{value}}"
68
+ end
69
+ end
70
+
71
+ processor 'emphasis' => 'EmphasisProcessor' do |em|
72
+ '\textit{' + get_children_value( em ) + '}'
73
+ end
74
+
75
+ processor 'citation' => 'CitationProcessor' do |citation|
76
+ '\textit{' + get_children_value( citation ) + '}'
77
+ end
78
+
79
+ processor 'url' => 'UrlProcessor' do |url|
80
+ '\url{' + get_children_value( url, :rawText => true ) + '}'
81
+ end
82
+
83
+ processor 'email' => 'EmailProcessor' do |email|
84
+ call_processor( 'UrlProcessor', email )
85
+ end
86
+
87
+ processor 'period' => 'PeriodProcessor' do |period|
88
+ "#{period.from}--#{period.to}"
89
+ end
90
+
91
+ processor :text => 'TextProcessor' do |text, options|
92
+ text = text.dup
93
+ offset = 0
94
+ unless options[:rawText]
95
+ while index = text.index( CHAR_REPLACE_REGEXP, offset )
96
+ text[index, $&.length] = CHAR_REPLACE_TABLE[$&]
97
+ offset = index + CHAR_REPLACE_TABLE[$&].length
98
+ end
99
+ end
100
+ text = options[:verbatim] ? text.gsub( /\n/, newline ) : text.gsub( /\s+/, ' ' )
101
+ convert( text )
102
+ end
103
+
104
+ #####################################################
105
+ # General elements
106
+
107
+ processor 'projects' => 'ProjectsProcessor' do |projects|
108
+ projects.project.join( '' )
109
+ end
110
+
111
+ processor 'project' => 'ProjectProcessor' do |project|
112
+ '\item ' + ( project._title.nil? ? "" : "\\textit{#{project._title}}. " ) + get_children_value( project )
113
+ end
114
+
115
+
116
+ #####################################################
117
+ # Resume elements
118
+
119
+ processor 'resume' => 'ResumeProcessor' do |resume|
120
+ resume.options[:to_s] = true
121
+ language = case self.lang
122
+ when 'de' then 'german'
123
+ when 'en' then 'english'
124
+ when 'fr' then 'french'
125
+ when 'da' then 'danish'
126
+ when 'it' then 'italian'
127
+ when 'es' then 'spanish'
128
+ when 'fi' then 'finnish'
129
+ when 'pt' then 'portuguese'
130
+ when 'sv' then 'swedish'
131
+ else 'english'
132
+ end
133
+ str = "
134
+ \\documentclass[ps2pdf,helvetica,narrow,#{language},notitle,noflag]{europecv}
135
+ \\usepackage[T1]{fontenc}
136
+ \\usepackage[a4paper,top=1.5cm,left=1.5cm,right=1.5cm,bottom=2.5cm]{geometry}
137
+ \\usepackage[#{language}]{babel}
138
+ \\usepackage{url}
139
+ \\usepackage{graphicx}
140
+ \\usepackage{hyperref}
141
+ \\usepackage{color}
142
+ \\usepackage{paralist}
143
+
144
+ \\definecolor{linkcolor}{rgb}{0,0,1}
145
+ \\definecolor{anchorcolor}{rgb}{0,0,0}
146
+ \\definecolor{citecolor}{rgb}{0,0.4,0.4}
147
+ \\definecolor{urlcolor}{rgb}{0,0,0.5}
148
+ \\definecolor{filecolor}{rgb}{1,0,0}
149
+ \\definecolor{menucolor}{rgb}{1,0,0}
150
+ \\definecolor{pagecolor}{rgb}{1,0,0}
151
+
152
+ \\hypersetup{
153
+ colorlinks,
154
+ % colors
155
+ linkcolor=linkcolor,
156
+ anchorcolor=anchorcolor,
157
+ citecolor=citecolor,
158
+ filecolor=filecolor,
159
+ menucolor=menucolor,
160
+ pagecolor=pagecolor,
161
+ urlcolor=urlcolor,
162
+ % pdf strings
163
+ pdftitle={Curriculum Vitae},
164
+ pdfauthor={#{resume.header.name}},
165
+ pdfcreator={#{resume.header.name}},
166
+ bookmarks=false, bookmarksopen=false
167
+ }
168
+
169
+ \\renewcommand{\\ttdefault}{phv}
170
+ \\setlength{\\plitemsep}{1ex}
171
+ \\setdefaultleftmargin{1em}{}{}{}{}{}
172
+
173
+ \\ecvlastname{#{resume.header.name.surname}}
174
+ \\ecvfirstname{#{resume.header.name.firstname}}
175
+ "
176
+ str << "\\ecvaddress{#{resume.header.address}}\n" if resume.header.address
177
+ if resume.header.contact.phone
178
+ phones = resume.header.contact.phone.collect {|phone| "#{phone._location || 'Phone'}: #{phone}" }.join( newline )
179
+ str << "\\ecvtelephone{#{phones}}\n"
180
+ end
181
+ if resume.header.contact.fax
182
+ faxes = resume.header.contact.fax.collect {|fax| "#{fax._location || 'Fax'}: #{fax}" }.join( newline )
183
+ str << "\\ecvfax{#{faxes}}\n"
184
+ end
185
+ str << "\\ecvemail{\\large\\textbf{#{resume.header.contact.email.join( newline )}}}\n" if resume.header.contact.email
186
+ str << "\\ecvdateofbirth{#{resume.header.birth}}\n" if resume.header.birth
187
+ str += "
188
+ \\begin{document}
189
+ \\selectlanguage{#{language}}
190
+ "
191
+ str << " \\ecvfootnote{#{resume.lastModified}}\n" if resume.lastModified
192
+ str += "
193
+ \\begin{center}
194
+ \\Large\\textbf{\\textsc{#{keyword(:Resume)} \\\\ #{keyword(:Of)} \\\\ #{resume.header.name}}}
195
+ \\end{center}
196
+
197
+ \\begin{europecv}
198
+ \\ecvpersonalinfo
199
+ "
200
+ if resume.history
201
+ str += "
202
+ \\ecvsection{#{keyword(:History_Title)}}
203
+ #{resume.history.join("\n\n")}
204
+ "
205
+ end
206
+ if resume.academics
207
+ str += "
208
+ \\ecvsection{#{keyword(:Education_Title)}}
209
+ #{resume.academics.join("\n\n") if resume.academics}
210
+ "
211
+ end
212
+ if resume.skillarea
213
+ str += "
214
+ \\ecvsection{#{keyword(:Skills_Title)}}
215
+ #{resume.skillarea.join("\n\n") if resume.skillarea}
216
+ "
217
+ end
218
+ if resume.interests
219
+ str += "
220
+ \\ecvsection{#{keyword(:Interests_Title)}}
221
+ #{resume.interests.join("\n\n") if resume.interests}
222
+ "
223
+ end
224
+ if resume.pubs || resume.memberships || resume.awards || resume.clearances || resume.referees
225
+ str += "
226
+ \\ecvsection{#{keyword :AdditionalInformation}}
227
+ #{resume.memberships.join("\n\n") if resume.memberships}
228
+ #{resume.awards.join("\n\n") if resume.awards}
229
+ #{resume.clearances.join("\n\n") if resume.clearances}
230
+ #{resume.pubs.join("\n\n") if resume.pubs}
231
+ #{resume.referees.join("\n\n") if resume.referees}
232
+ "
233
+ end
234
+ str += "
235
+ \\end{europecv}
236
+
237
+ \\end{document}
238
+ "
239
+ end
240
+
241
+ #####################################################
242
+ # Job specific elements
243
+
244
+ processor 'history' => 'HistoryProcessor' do |history|
245
+ history.job.join( SEPARATOR )
246
+ end
247
+
248
+ processor 'job' => 'JobProcessor' do |job|
249
+ str = "
250
+ \\ecvitem*{#{keyword(:Dates)}}{#{job.period || job.date}}\\nopagebreak
251
+ \\ecvitem*{#{keyword(:History_Employer)}}{#{job.employer}" + (job.location.nil? ? '}' : " (#{job.location})}") + "\\nopagebreak
252
+ \\ecvitem*{#{keyword(:History_Occupation)}}{#{job.jobtitle}}\\nopagebreak
253
+ "
254
+ str << "\\ecvitem*{#{keyword(:History_MainActivities)}}{#{job.description}}\\nopagebreak\n" if job.description
255
+ str << "\\ecvitem*{#{keyword(:Projects)}}{\\vspace{-1ex}\\begin{compactitem}
256
+ #{job.projects}
257
+ \\end{compactitem}\\vspace{-2ex}}\\nopagebreak\n" if job.projects
258
+ str << "\\ecvitem*{#{keyword(:History_Achievements)}}{\\vspace{-1ex}\\begin{compactitem}
259
+ #{job.achievements}
260
+ \\end{compactitem}\\vspace{-2ex}}\\nopagebreak\n" if job.achievements
261
+ str
262
+ end
263
+
264
+ processor 'achievements' => 'AchievementsProcessor' do |achievements|
265
+ achievements.achievement.collect {|a| "\\item #{a}\n"}.join( '' )
266
+ end
267
+
268
+ #####################################################
269
+ # Academics specific elements
270
+
271
+ processor 'academics' => 'AcademicsProcessor' do |academics|
272
+ academics.degrees.degree.join( SEPARATOR )
273
+ end
274
+
275
+ def gpa_type( type )
276
+ if type == 'major'
277
+ keyword( :Education_Gpa_Major )
278
+ else
279
+ keyword( :Education_Gpa_Overall )
280
+ end
281
+ end
282
+
283
+ processor 'degree' => 'DegreeProcessor' do |degree|
284
+ str = ''
285
+
286
+ if degree.period || degree.date
287
+ str << "\\ecvitem*{#{keyword(:Dates)}}{#{degree.period || degree.date}}\\nopagebreak\n"
288
+ end
289
+
290
+ if degree.institution
291
+ str << "\\ecvitem*{#{keyword(:Education_Organization)}}{#{degree.institution}"
292
+ str << " (#{degree.location})" if degree.location
293
+ str << "}\\nopagebreak\n"
294
+ end
295
+
296
+ str << "\\ecvitem*{#{keyword(:Education_Level)}}{#{degree.level}"
297
+ str << " -- #{degree.annotation}" if degree.annotation
298
+ str << "}\\nopagebreak\n"
299
+
300
+ str << "\\ecvitem*{#{keyword(:Education_MajorStudies)}}{#{degree.major.join(', ')}}\\nopagebreak\n" if degree.major
301
+ str << "\\ecvitem*{#{keyword(:Education_MinorStudies)}}{#{degree.minor.join(', ')}}\\nopagebreak\n" if degree.minor
302
+ str << "\\ecvitem*{#{gpa_type(degree.gpa._type)}}{#{degree.gpa}}\\nopagebreak\n" if degree.gpa
303
+ str << "\\ecvitem*{#{keyword(:Education_Subjects)}}{#{degree.subjects}}\\nopagebreak\n" if degree.subjects
304
+ str << "\\ecvitem*{#{keyword(:Projects)}}{\\vspace{-1ex}\\begin{compactitem}
305
+ #{degree.projects}
306
+ \\end{compactitem}\\vspace{-2ex}}\\nopagebreak\n" if degree.projects
307
+ str
308
+ end
309
+
310
+ processor 'subjects' => 'SubjectsProcessor' do |subjects|
311
+ subjects.subject.join( newline )
312
+ end
313
+
314
+ processor 'subject' => 'SubjectProcessor' do |subject|
315
+ "#{subject.title}: #{subject.result}"
316
+ end
317
+
318
+ processor 'gpa' => 'GpaProcessor' do |gpa|
319
+ str = "#{gpa.score}"
320
+ str << " #{keyword(:Education_Gpa_Outof)} #{gpa.possible}" if gpa.possible
321
+ str << " (#{gpa.note})" if gpa.note
322
+ str
323
+ end
324
+
325
+ #####################################################
326
+ # Skill specific elements
327
+
328
+ processor 'skillarea' => 'SkillareaProcessor' do |skillarea|
329
+ "\\ecvitem[#{GAP}]{#{skillarea.title || keyword(:Skills_Title)}}{\\vspace{-2.3ex}\\begin{compactitem}
330
+ #{skillarea.skillset.join( '' )}
331
+ \\end{compactitem}}\n"
332
+ end
333
+
334
+ processor 'skillset' => 'SkillsetProcessor' do |skillset|
335
+ str = "\\item #{skillset.title ? "\\textit{#{skillset.title}}: " : ''}"
336
+ str << skillset.skill.collect {|skill| "#{skill}#{skill._level ? " (#{skill._level})" : "" }"}.join( ', ' )
337
+ str + "\n"
338
+ end
339
+
340
+ #####################################################
341
+ # Interest specific elements
342
+
343
+ processor 'interests' => 'InterestsProcessor' do |interests|
344
+ "\\ecvitem[#{GAP}]{#{interests.title || keyword(:Interests_Title)}}{\\vspace{-2.3ex}\\begin{compactitem}
345
+ #{interests.interest.join('')}
346
+ \\end{compactitem}}\n"
347
+ end
348
+
349
+ processor 'interest' => 'InterestProcessor' do |interest|
350
+ "\\item \\textit{#{interest.title}}#{interest.description ? ': ' + interest.description.to_s : ''}\n"
351
+ end
352
+
353
+ #####################################################
354
+ # Publication specific elements
355
+
356
+ processor 'pubs' => 'PubsProcessor' do |pubs|
357
+ "\\ecvitem[#{GAP}]{#{keyword(:Publications_Title)}}{#{pubs.pub.join("#{newline}#{newline}")}}\n"
358
+ end
359
+
360
+ processor 'pub' => 'PubProcessor' do |pub|
361
+ title = (pub.artTitle.nil? ? "" : "\\textit{#{pub.artTitle}}. #{keyword(:Publications_In).capitalize} ") + "\\textit{#{pub.bookTitle}}"
362
+ "#{pub.author.join(', ')}: #{title}. #{pub.publisher}, #{pub.date}. #{pub.pageNums}"
363
+ end
364
+
365
+ processor 'author' => 'AuthorProcessor' do |author|
366
+ if author._name.nil?
367
+ get_children_value( author )
368
+ else
369
+ get_value( author.__element.elements["//name[@id='#{author._name}']"] )
370
+ end
371
+ end
372
+
373
+ #####################################################
374
+ # Keyword specific elements
375
+
376
+ processor 'keywords' => 'KeywordsProcessor' do |keywords|
377
+ keywords.keyword.join(', ')
378
+ end
379
+
380
+ #####################################################
381
+ # Membership specific elements
382
+
383
+ processor 'memberships' => 'MembershipsProcessor' do |memberships|
384
+ "\\ecvitem[#{GAP}]{#{memberships.title}}{\\vspace{-2.3ex}\\begin{compactitem}
385
+ #{memberships.membership.join("")}
386
+ \\end{compactitem}}"
387
+ end
388
+
389
+ processor 'membership' => 'MembershipProcessor' do |m|
390
+ organization = if m.organization
391
+ str = "#{m.organization}"
392
+ str << " (#{m.location})" if m.location
393
+ str
394
+ end
395
+ "\\item " + [m.title, organization, m.date || m.period, m.description].compact.join( newline )
396
+ end
397
+
398
+ #####################################################
399
+ # Clearance specific elements
400
+
401
+ processor 'clearances' => 'ClearancesProcessor' do |clearances|
402
+ "\\ecvitem[#{GAP}]{#{clearances.title || keyword(:SecurityClearances_Title)}}{\\vspace{-2.3ex}\\begin{compactitem}
403
+ #{clearances.clearance.join("")}
404
+ \\end{compactitem}}"
405
+ end
406
+
407
+ processor 'clearance' => 'ClearanceProcessor' do |c|
408
+ str = "\\item #{[c.level, c.organization, c.date, c.period].compact.join( ', ' )}"
409
+ str << "#{newline}#{c.note}" if c.note
410
+ str
411
+ end
412
+
413
+ #####################################################
414
+ # Award specific elements
415
+
416
+ processor 'awards' => 'AwardsProcessor' do |awards|
417
+ "\\ecvitem[#{GAP}]{#{awards.title || keyword(:Awards_Title)}}{\\vspace{-2.3ex}\\begin{compactitem}
418
+ #{awards.award.join("")}
419
+ \\end{compactitem}}"
420
+ end
421
+
422
+ processor 'award' => 'AwardProcessor' do |a|
423
+ str = "\\item #{[a.title, a.organization, a.date, a.period].compact.join( ', ' )}"
424
+ str << "#{newline}#{a.description}" if a.description
425
+ str
426
+ end
427
+
428
+ #####################################################
429
+ # Referee specific elements
430
+
431
+ processor 'referees' => 'RefereesProcessor' do |referees|
432
+ "\\ecvitem[#{GAP}]{#{keyword(:Referees_Title)}}{#{referees.referee.join("#{newline}#{newline}")}}"
433
+ end
434
+
435
+ processor 'referee' => 'RefereeProcessor' do |r|
436
+ [r.name, r.title, r.organization, r.address, r.contact].compact.join( newline )
437
+ end
438
+
439
+ #####################################################
440
+ # Copyright specific elements
441
+
442
+ processor 'copyright' => 'CopyrightProcessor' do |c|
443
+ str = "Copyright \251 #{c.year} #{c.name}"
444
+ str << "#{newline}#{c.legalnotice}" if c.legalnotice
445
+ str
446
+ end
447
+
448
+ #####################################################
449
+ # LastModified specific elements
450
+
451
+ processor 'lastModified' => 'LastModifiedProcessor' do |l|
452
+ "#{keyword(:LastModified)} #{l.date}"
453
+ end