xmlresume2x 0.2.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,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