resme 0.3.1 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.org +19 -0
- data/README.org +272 -0
- data/exe/resme +2 -2
- data/lib/resme/cli/command_semantics.rb +110 -103
- data/lib/resme/cli/command_syntax.rb +252 -204
- data/lib/resme/cli/resume_structure_validator.rb +293 -0
- data/lib/resme/renderer/renderer.rb +6 -50
- data/lib/resme/templates/resume.json.erb +148 -130
- data/lib/resme/templates/resume.md.erb +36 -36
- data/lib/resme/templates/resume.org.erb +54 -51
- data/lib/resme/templates/resume.xml.erb +496 -0
- data/lib/resme/version.rb +1 -1
- data/lib/resme.rb +1 -0
- data/resme.gemspec +6 -9
- metadata +16 -43
- data/README.md +0 -192
- data/lib/resme/templates/europass/eu.xml.erb +0 -491
- data/lib/resme/templates/schema.yml +0 -494
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27d07b29ff7369747e8f43ad9cbdc29efe1023cca20de554f94c02fdc33c57f8
|
4
|
+
data.tar.gz: fc048d5417183cba079e387caa3c08d2540fb937a384aae05759622b91b82846
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77bab2cbc35e21bb7ce669100d6b0f66d4b9f60e496814b35aec3a1fb3346730bbfe0700d884cde697500a479007cbac61dc834dcd358b3b1ab4375e59ee60db
|
7
|
+
data.tar.gz: fa2c84c4358a0c86469f83f11cb8c361a8a90602ed58eadf8cf53701757d4525d1f27f27599fdf361af46a2fcce0243c2e014395375c84a82489834be5b56118
|
data/CHANGELOG.org
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#+TITLE: CHANGELOG
|
2
|
+
#+AUTHOR: Adolfo Villafiorita
|
3
|
+
|
4
|
+
* Version 1.5.0
|
5
|
+
- [user] New command =view= allows to view the template used
|
6
|
+
for generating a resume in a specific format
|
7
|
+
- [user] Check command is now based on ClassyHash
|
8
|
+
- [code] Various changes to the code
|
9
|
+
|
10
|
+
* Version 1.4.0
|
11
|
+
- [user] New option =--skip= allows to skip some top-level sections.
|
12
|
+
You mileage might vary, as some formats might require the
|
13
|
+
information you are trying to skip
|
14
|
+
- [user] New command =generate= is now used to generate the Resume
|
15
|
+
in different formats.
|
16
|
+
- [user] New option =--erb= allows to specify a custom template for
|
17
|
+
generating the resume. Use it in conjunction with =view= (released
|
18
|
+
in version 1.5.0) to jump-start your layout.
|
19
|
+
|
data/README.org
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
#+TITLE: RESME - A Resume Generator
|
2
|
+
#+AUTHOR: Adolfo Villafiorita
|
3
|
+
#+DATE: <2020-07-14 Tue>
|
4
|
+
#+STARTUP: showall
|
5
|
+
|
6
|
+
Keep your resume in YAML and output it in various formats, including
|
7
|
+
Org Mode, Markdown, JSON, and the Europass XML format.
|
8
|
+
|
9
|
+
The rendering engine is based on ERB. This simplifies the creation of
|
10
|
+
new output formats (and extending/modifying the YML structure to one's
|
11
|
+
needs).
|
12
|
+
|
13
|
+
** Installation
|
14
|
+
:PROPERTIES:
|
15
|
+
:CUSTOM_ID: installation
|
16
|
+
:END:
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
#+BEGIN_SRC ruby
|
21
|
+
gem 'resme'
|
22
|
+
#+END_SRC
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
#+BEGIN_EXAMPLE
|
27
|
+
$ bundle
|
28
|
+
#+END_EXAMPLE
|
29
|
+
|
30
|
+
Or install it yourself as:
|
31
|
+
|
32
|
+
#+BEGIN_EXAMPLE
|
33
|
+
$ gem install resme
|
34
|
+
#+END_EXAMPLE
|
35
|
+
|
36
|
+
** Usage
|
37
|
+
:PROPERTIES:
|
38
|
+
:CUSTOM_ID: usage
|
39
|
+
:END:
|
40
|
+
|
41
|
+
Start with:
|
42
|
+
|
43
|
+
#+BEGIN_EXAMPLE
|
44
|
+
resme init
|
45
|
+
#+END_EXAMPLE
|
46
|
+
|
47
|
+
which generates a YML template for your resume in the current directory.
|
48
|
+
Comments in the YML file should help you fill the various entries.
|
49
|
+
Notice that most entries are optional and you can remove sections which
|
50
|
+
are not relevant for your resume.
|
51
|
+
|
52
|
+
You can now generate a resume using one of the existing formats:
|
53
|
+
|
54
|
+
#+begin_example
|
55
|
+
resme --to org resume.yml
|
56
|
+
#+end_example
|
57
|
+
|
58
|
+
Supported formats include:
|
59
|
+
|
60
|
+
- =org=: Org Mode format
|
61
|
+
- =md=: Markdown format
|
62
|
+
- =europass=: Europass format
|
63
|
+
(http://interop.europass.cedefop.europa.eu/web-services/remote-upload/)
|
64
|
+
- =json=: JSON format (https://jsonresume.org/)
|
65
|
+
|
66
|
+
If you are not satisfied with the provided templates, you can write
|
67
|
+
your own (see below).
|
68
|
+
|
69
|
+
Notice that you can specify more than one YML file in input. This allows you to
|
70
|
+
store data about your resume in different files, if you like to do so
|
71
|
+
(e.g., work experiences could be in one file and talks in another).
|
72
|
+
The YML files are merged before processing them.
|
73
|
+
|
74
|
+
Full syntax:
|
75
|
+
|
76
|
+
#+begin_src shell :results raw output :wrap example
|
77
|
+
resme help
|
78
|
+
#+end_src
|
79
|
+
|
80
|
+
#+RESULTS:
|
81
|
+
#+begin_example
|
82
|
+
resme command [options] [args]
|
83
|
+
Available commands:
|
84
|
+
view --template FORMAT # Print template used for format
|
85
|
+
console # enter the console
|
86
|
+
man # print resme manual page
|
87
|
+
help [command] # print command usage
|
88
|
+
init [options] # generate an empty resume.yml file
|
89
|
+
check resume.yml # Check syntax of resume.yml
|
90
|
+
list resume.yml # List main sections in resume.yml
|
91
|
+
version # print version information
|
92
|
+
generate [options] resume.yml ... # output resume
|
93
|
+
#+end_example
|
94
|
+
|
95
|
+
** Checking validity
|
96
|
+
:PROPERTIES:
|
97
|
+
:CUSTOM_ID: checking-validity
|
98
|
+
:END:
|
99
|
+
|
100
|
+
Use the =check= command to verify whether your YAML file conforms with
|
101
|
+
the intended syntax.
|
102
|
+
|
103
|
+
#+BEGIN_SRC ruby
|
104
|
+
resme check resume.yaml
|
105
|
+
#+END_SRC
|
106
|
+
|
107
|
+
** Dates in the resume
|
108
|
+
:PROPERTIES:
|
109
|
+
:CUSTOM_ID: dates-in-the-resume
|
110
|
+
:END:
|
111
|
+
|
112
|
+
Enter dates in the resume in one of the following formats:
|
113
|
+
|
114
|
+
- Any format accepted by Ruby for a full date (year, month, day)
|
115
|
+
- YYYY-MM-DD
|
116
|
+
- YYYY-MM
|
117
|
+
- YYYY
|
118
|
+
|
119
|
+
The third and the forth format allows you to enter "partial" dates
|
120
|
+
(e.g., when the month or the day have been forgotten or are irrelevant).
|
121
|
+
|
122
|
+
** Creating your own templates
|
123
|
+
:PROPERTIES:
|
124
|
+
:CUSTOM_ID: creating-your-own-templates
|
125
|
+
:END:
|
126
|
+
|
127
|
+
The resumes are generated from the YML matter using ERB templates. The
|
128
|
+
provided output formats should support different back ends. Org Mode
|
129
|
+
and Markdown, for instance, easily allow for generation of PDFs, HTML,
|
130
|
+
and ODT, to mention a few.
|
131
|
+
|
132
|
+
However, if you want, you can define your own templates.
|
133
|
+
|
134
|
+
Use the command =view= to print one of the templates used by =resme=
|
135
|
+
and build from that.
|
136
|
+
|
137
|
+
#+begin_example
|
138
|
+
resme view --template md
|
139
|
+
#+end_example
|
140
|
+
|
141
|
+
Notice that all the data in the resume is made available in the =data=
|
142
|
+
variable. Thus, for instance, the following code snippets generates a
|
143
|
+
list of all the work experiences:
|
144
|
+
|
145
|
+
#+BEGIN_EXAMPLE
|
146
|
+
<% data["work"] each do |exp| %>
|
147
|
+
- <%= exp["who"] %>
|
148
|
+
From: <%= exp["from"] %> till: <%= exp["till"] %>
|
149
|
+
<% end %>
|
150
|
+
#+END_EXAMPLE
|
151
|
+
|
152
|
+
To specify your own ERB template to build your resume use the option
|
153
|
+
=-e= (=--erb=). Thus, for instance:
|
154
|
+
|
155
|
+
#+BEGIN_EXAMPLE
|
156
|
+
$ resme render -e template.md.erb [-o output_filename] file.yaml ...
|
157
|
+
#+END_EXAMPLE
|
158
|
+
|
159
|
+
uses =template.md.erb= to generate the resume.
|
160
|
+
|
161
|
+
Some functions can be used in the templates to better control the
|
162
|
+
output.
|
163
|
+
|
164
|
+
String manipulation functions:
|
165
|
+
|
166
|
+
- =clean string= removes any space at the beginning of =string=
|
167
|
+
- =reflow string, n= makes =string= into an array of strings of length
|
168
|
+
lower or equal to =n= (useful if you are outputting a textual format,
|
169
|
+
for instance.
|
170
|
+
|
171
|
+
Dates manipulation functions:
|
172
|
+
|
173
|
+
- =period= generates a string recapping a period. The function abstracts
|
174
|
+
different syntax you can use for entries (i.e., =date= or =from= and
|
175
|
+
=till=) and different values for the entries (e.g., a missing value
|
176
|
+
for =till=)
|
177
|
+
- =year string=, =month string=, =day string= return, respectively the
|
178
|
+
year, month and day from strings in the format =YYYY-MM-DD=s
|
179
|
+
- =has_month input= returns true if =input= has a month, that is, it is
|
180
|
+
a date or it is in the form =YYYY-MM=
|
181
|
+
- =has_day input= returns true if =input= has a day, that is, it is a
|
182
|
+
date or it is in the form =YYYY-MM-DD=
|
183
|
+
|
184
|
+
You can find the templates in =lib/resme/templates=. These might be good
|
185
|
+
starting points if you want to develop your own.
|
186
|
+
|
187
|
+
** Contributing your templates
|
188
|
+
:PROPERTIES:
|
189
|
+
:CUSTOM_ID: contributing-your-templates
|
190
|
+
:END:
|
191
|
+
|
192
|
+
If you develop an output template and want to make it available, please
|
193
|
+
let me know, so that I can include it in future releases of this gem.
|
194
|
+
|
195
|
+
** Development
|
196
|
+
:PROPERTIES:
|
197
|
+
:CUSTOM_ID: development
|
198
|
+
:END:
|
199
|
+
|
200
|
+
After checking out the repo, run =bin/setup= to install dependencies.
|
201
|
+
You can also run =bin/console= for an interactive prompt that will allow
|
202
|
+
you to experiment.
|
203
|
+
|
204
|
+
To install this gem onto your local machine, run
|
205
|
+
=bundle exec rake install=. To release a new version, update the version
|
206
|
+
number in =version.rb=, and then run =bundle exec rake release=, which
|
207
|
+
will create a git tag for the version, push git commits and tags, and
|
208
|
+
push the =.gem= file to [[https://rubygems.org][rubygems.org]].
|
209
|
+
|
210
|
+
** Contributing
|
211
|
+
:PROPERTIES:
|
212
|
+
:CUSTOM_ID: contributing
|
213
|
+
:END:
|
214
|
+
|
215
|
+
Bug reports and pull requests are welcome on GitHub at
|
216
|
+
https://github.com/avillafiorita/resme.
|
217
|
+
|
218
|
+
** License
|
219
|
+
:PROPERTIES:
|
220
|
+
:CUSTOM_ID: license
|
221
|
+
:END:
|
222
|
+
|
223
|
+
The gem is available as open source under the terms of the
|
224
|
+
[[http://opensource.org/licenses/MIT][MIT License]].
|
225
|
+
|
226
|
+
** Change Log
|
227
|
+
|
228
|
+
In =doc/changelog.org=
|
229
|
+
|
230
|
+
** Roadmap
|
231
|
+
:PROPERTIES:
|
232
|
+
:CUSTOM_ID: roadmap
|
233
|
+
:END:
|
234
|
+
|
235
|
+
In =doc/todo.org= ... guess what is my preferred editor!
|
236
|
+
|
237
|
+
** Bugs
|
238
|
+
:PROPERTIES:
|
239
|
+
:CUSTOM_ID: bugs
|
240
|
+
:END:
|
241
|
+
|
242
|
+
There are still slight differences in the syntax of entries and in the
|
243
|
+
way in which the information is formatted in various output formats. For
|
244
|
+
instance, gender and birthdate are used in the Europass format, but not
|
245
|
+
in the Markdown format. This is in part due to the different standards
|
246
|
+
and in part due to personal preferences.
|
247
|
+
|
248
|
+
*Entries are not sorted by date before outputting them. Make sure you
|
249
|
+
put them in the order you want them to appear in your resume.*
|
250
|
+
|
251
|
+
Unknown number of unknown bugs.
|
252
|
+
|
253
|
+
** Release History
|
254
|
+
:PROPERTIES:
|
255
|
+
:CUSTOM_ID: release-history
|
256
|
+
:END:
|
257
|
+
|
258
|
+
- *0.4.0* refactors all generation commands under =generate=, provides
|
259
|
+
new filtering options, adds =-e= option (for custom templates), and
|
260
|
+
refactors various portions of code. It also revises this document
|
261
|
+
and fixes some minor bugs.
|
262
|
+
- *0.3.2* and *0.3.1* fix errors with the Europass format: lists of
|
263
|
+
projects, interests, ... are now properly formatted.
|
264
|
+
- *0.3* introduces output to org-mode, introduces references for the CV,
|
265
|
+
improves output to JSON, adds a =check= command, removes useless blank
|
266
|
+
lines in the output, supports =-%>= in the ERB templates, fixes
|
267
|
+
various typos in the documentation, introduces various new formatting
|
268
|
+
functions, to simplify template generation
|
269
|
+
- *0.2* improves output of volunteering activities and other information
|
270
|
+
in the Europass and *significantly improves error and warning
|
271
|
+
reporting*
|
272
|
+
- *0.1* is the first release
|
data/exe/resme
CHANGED
@@ -1,90 +1,89 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require 'kwalify'
|
1
|
+
require "resme/version"
|
2
|
+
require "readline"
|
3
|
+
require "fileutils"
|
4
|
+
require "date"
|
5
|
+
require "yaml"
|
6
|
+
require "erb"
|
7
|
+
require "json"
|
9
8
|
|
10
9
|
module Resme
|
11
10
|
module CommandSemantics
|
12
|
-
APPNAME =
|
11
|
+
APPNAME = "resme"
|
13
12
|
VERSION = Resme::VERSION
|
14
13
|
|
15
14
|
#
|
16
15
|
# Main App Starts Here!
|
17
16
|
#
|
18
|
-
def self.version
|
17
|
+
def self.version(opts = nil, argv = [])
|
19
18
|
puts "#{APPNAME} version #{VERSION}"
|
20
19
|
end
|
21
20
|
|
22
|
-
def self.man
|
23
|
-
path = File.join(File.dirname(__FILE__), "/../../../README.
|
21
|
+
def self.man(opts = nil, argv = [])
|
22
|
+
path = File.join(File.dirname(__FILE__), "/../../../README.org")
|
24
23
|
file = File.open(path, "r")
|
25
|
-
|
26
|
-
puts contents
|
24
|
+
puts file.read
|
27
25
|
end
|
28
26
|
|
29
|
-
def self.help
|
27
|
+
def self.help(opts = nil, argv = [])
|
30
28
|
all_commands = CommandSyntax.commands
|
31
29
|
|
32
30
|
if argv != []
|
33
|
-
argv.map
|
31
|
+
argv.map do |x|
|
32
|
+
puts all_commands[x.to_sym][:help]
|
33
|
+
puts "\n\n"
|
34
|
+
end
|
34
35
|
else
|
35
|
-
puts "#{APPNAME} command [options] [args]"
|
36
|
-
puts ""
|
37
|
-
|
38
|
-
|
39
|
-
all_commands.keys.each do |key|
|
40
|
-
puts " " + all_commands[key][0].banner
|
36
|
+
puts "#{APPNAME} command [options] [args]\n"
|
37
|
+
puts "Available commands:\n"
|
38
|
+
all_commands.each_key do |key|
|
39
|
+
puts " #{all_commands[key][:options].banner}"
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
|
-
def self.console
|
44
|
+
def self.console(opts, argv = [])
|
46
45
|
all_commands = CommandSyntax.commands
|
47
46
|
all_commands.delete(:console)
|
48
47
|
|
49
48
|
i = 0
|
50
49
|
while true
|
51
50
|
string = Readline.readline("#{APPNAME}:%03d> " % i, true)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
reps all_commands, string.split(' ')
|
51
|
+
# as a courtesy, remove any leading appname string
|
52
|
+
string.gsub!(/^#{APPNAME} /, "")
|
53
|
+
exit 0 if %w[exit quit .].include? string
|
54
|
+
execute all_commands, string.split(" ")
|
57
55
|
i = i + 1
|
58
56
|
end
|
59
57
|
end
|
60
58
|
|
61
59
|
# read-eval-print step
|
62
|
-
|
60
|
+
# check if argv is in any of all_commands, parse options
|
61
|
+
# according to the specification in all_commands and invoke
|
62
|
+
# a function in this class to actually do the work
|
63
|
+
def self.execute(all_commands, argv)
|
63
64
|
if argv == [] or argv[0] == "--help" or argv[0] == "-h"
|
64
|
-
|
65
|
+
help
|
65
66
|
exit 0
|
66
67
|
else
|
67
68
|
command = argv[0]
|
68
|
-
|
69
|
-
if syntax_and_semantics
|
70
|
-
opts = syntax_and_semantics[0]
|
71
|
-
function = syntax_and_semantics[1]
|
72
|
-
|
73
|
-
begin
|
74
|
-
parser = Slop::Parser.new(opts)
|
69
|
+
command_spec = all_commands[command.to_sym]
|
75
70
|
|
76
|
-
|
77
|
-
|
78
|
-
|
71
|
+
if command_spec
|
72
|
+
command_name = command_spec[:name]
|
73
|
+
option_parser = command_spec[:options]
|
79
74
|
|
80
|
-
|
81
|
-
|
82
|
-
|
75
|
+
begin
|
76
|
+
argv.shift # remove command name from ARGV
|
77
|
+
options = {}
|
78
|
+
parser = option_parser.parse!(into: options)
|
79
|
+
eval "CommandSemantics::#{command_name}(options, argv)"
|
83
80
|
rescue Exception => e
|
84
|
-
puts e
|
81
|
+
puts "#{APPNAME} error: #{e}"
|
82
|
+
puts "Help with \"#{APPNAME} help #{command_name}\""
|
85
83
|
end
|
86
84
|
else
|
87
|
-
puts "#{APPNAME}:
|
85
|
+
puts "#{APPNAME} error: "#{command}" is not a valid command."
|
86
|
+
puts "List commands with \"#{APPNAME} help\"."
|
88
87
|
end
|
89
88
|
end
|
90
89
|
end
|
@@ -92,40 +91,37 @@ module Resme
|
|
92
91
|
#
|
93
92
|
# APP SPECIFIC COMMANDS
|
94
93
|
#
|
95
|
-
def self.check
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
## show errors
|
112
|
-
if errors && !errors.empty?
|
113
|
-
for e in errors
|
114
|
-
puts "[#{e.path}] #{e.message}"
|
94
|
+
def self.check(opts, argv)
|
95
|
+
begin
|
96
|
+
document = YAML.load_file(argv[0], permitted_classes: [Date])
|
97
|
+
rescue Psych::SyntaxError => ex
|
98
|
+
puts "The file #{argv[0]} has an invalid structure."
|
99
|
+
puts ex.message
|
100
|
+
exit 1
|
101
|
+
end
|
102
|
+
|
103
|
+
begin
|
104
|
+
errors = ResumeStructureValidator.validate(document)
|
105
|
+
rescue Exception => ex
|
106
|
+
puts "The files #{argv[0]} does not validate"
|
107
|
+
ex.entries.each do |error|
|
108
|
+
puts "#{error[:full_path]}: #{error[:message]}"
|
115
109
|
end
|
116
|
-
|
117
|
-
puts "The file #{argv[0]} validates."
|
110
|
+
exit 1
|
118
111
|
end
|
112
|
+
puts "The file #{argv[0]} has a valid structure."
|
119
113
|
end
|
120
114
|
|
121
|
-
def self.init
|
115
|
+
def self.init(opts, argv)
|
122
116
|
output = opts[:output] || "resume.yml"
|
123
117
|
force = opts[:force]
|
124
|
-
|
118
|
+
path = File.dirname(__FILE__), "/../templates/resume.yml"
|
119
|
+
template = File.join(path)
|
125
120
|
|
126
|
-
# avoid
|
127
|
-
if File.exist?(output)
|
128
|
-
puts "
|
121
|
+
# avoid catastrophe
|
122
|
+
if File.exist?(output) && !force
|
123
|
+
puts "#{APPNAME} error: file #{output} already exists."
|
124
|
+
puts "Use --force if you want to overwrite it."
|
129
125
|
else
|
130
126
|
content = File.read(template)
|
131
127
|
backup_and_write output, content
|
@@ -133,60 +129,71 @@ module Resme
|
|
133
129
|
end
|
134
130
|
end
|
135
131
|
|
136
|
-
def self.
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
puts "
|
132
|
+
def self.list(opts, argv)
|
133
|
+
data = {}
|
134
|
+
argv.each do |file|
|
135
|
+
data = data.merge(YAML.load_file(file, permitted_classes: [Date]))
|
136
|
+
end
|
137
|
+
puts "Sections included in #{argv.join(", ")}:"
|
138
|
+
data.keys.each do |key|
|
139
|
+
puts "- #{key}: #{(data[key] || []).size} entries"
|
140
|
+
end
|
142
141
|
end
|
143
142
|
|
144
|
-
def self.
|
145
|
-
|
146
|
-
template = File.join(File.dirname(__FILE__), "/../templates/resume.
|
147
|
-
|
148
|
-
render argv, template, output
|
149
|
-
puts "Resume generated in #{output}"
|
143
|
+
def self.view(opts, argv)
|
144
|
+
format = opts[:template] == "europass" ? "xml" : opts[:template]
|
145
|
+
template = File.join(File.dirname(__FILE__), "/../templates/resume.#{format}.erb")
|
146
|
+
puts File.read template
|
150
147
|
end
|
151
148
|
|
152
|
-
def self.
|
153
|
-
|
154
|
-
|
149
|
+
def self.generate(opts, argv)
|
150
|
+
format = opts[:to] == "europass" ? "xml" : opts[:to]
|
151
|
+
output = opts[:output] || "resume-#{Date.today}.#{format}"
|
155
152
|
|
156
|
-
|
157
|
-
|
158
|
-
|
153
|
+
if opts[:erb]
|
154
|
+
template = opts[:erb]
|
155
|
+
else
|
156
|
+
template = File.join(File.dirname(__FILE__), "/../templates/resume.#{format}.erb")
|
157
|
+
end
|
159
158
|
|
160
|
-
|
161
|
-
output = opts[:output] || "resume-#{Date.today}.xml"
|
162
|
-
template = File.join(File.dirname(__FILE__), "/../templates/europass/eu.xml.erb")
|
159
|
+
skipped_sections = opts[:skip] || []
|
163
160
|
|
164
|
-
|
161
|
+
if !File.exists?(template)
|
162
|
+
puts "#{APPNAME} error: format #{format} is not understood."
|
163
|
+
end
|
164
|
+
|
165
|
+
render argv, template, output, skipped_sections
|
165
166
|
puts "Resume generated in #{output}"
|
166
|
-
|
167
|
+
|
168
|
+
if format == "xml" then
|
169
|
+
puts "Europass XML generated. Render via, e.g., http://interop.europass.cedefop.europa.eu/web-services/remote-upload/"
|
170
|
+
end
|
167
171
|
end
|
168
172
|
|
169
173
|
private
|
170
174
|
|
171
|
-
def self.render
|
172
|
-
data =
|
175
|
+
def self.render(yml_files, template_name, output_name, skipped_sections)
|
176
|
+
data = {}
|
173
177
|
yml_files.each do |file|
|
174
|
-
data = data.merge(YAML.load_file(file))
|
178
|
+
data = data.merge(YAML.load_file(file, permitted_classes: [Date]))
|
179
|
+
end
|
180
|
+
skipped_sections.each do |section|
|
181
|
+
data.reject! { |k| k == section }
|
175
182
|
end
|
176
|
-
template = File.read(
|
177
|
-
output = ERB.new(template,
|
183
|
+
template = File.read(template_name)
|
184
|
+
output = ERB.new(template, trim_mode: "-").result(binding)
|
178
185
|
# it is difficult to write readable ERBs with no empty lines...
|
179
186
|
# we use gsub to replace multiple empty lines with \n\n in the final output
|
180
187
|
output.gsub!(/([\t ]*\n){3,}/, "\n\n")
|
181
|
-
backup_and_write
|
188
|
+
backup_and_write output_name, output
|
182
189
|
end
|
183
190
|
|
184
|
-
def self.backup
|
191
|
+
def self.backup(filename)
|
185
192
|
FileUtils::cp filename, filename + "~"
|
186
193
|
puts "Backup copy #{filename} created in #{filename}~."
|
187
194
|
end
|
188
195
|
|
189
|
-
def self.backup_and_write
|
196
|
+
def self.backup_and_write(filename, content)
|
190
197
|
backup(filename) if File.exist?(filename)
|
191
198
|
File.open(filename, "w") { |f| f.puts content }
|
192
199
|
end
|