resme 1.0.0 → 2.0.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.
@@ -1,293 +0,0 @@
1
- require "classy_hash"
2
- require "date"
3
-
4
- module Resme
5
- module ResumeStructureValidator
6
- OPTIONAL_STRING = [:optional, String, NilClass]
7
- OPTIONAL_PARTIAL_DATE = [:optional, Date, String, Integer, NilClass]
8
- PARTIAL_DATE = [Date, String, Integer]
9
-
10
- def self.validate(loaded_yaml)
11
- errors = []
12
- ClassyHash.validate(
13
- loaded_yaml,
14
- SCHEMA,
15
- errors: errors,
16
- strict: true,
17
- raise_errors: true,
18
- full: true
19
- )
20
- errors
21
- end
22
-
23
- #
24
- # This defines the structure of resume.yml
25
- # We validate it with ClassyHash
26
- #
27
- SCHEMA = {
28
- "basics" => {
29
- "first_name" => String,
30
- "middle_name" => OPTIONAL_STRING,
31
- "last_name" => String,
32
- "title" => OPTIONAL_STRING,
33
- "picture" => OPTIONAL_STRING,
34
- "birthdate" => [:optional, Date, NilClass],
35
- "nationality" => OPTIONAL_STRING,
36
- "marital_status" => OPTIONAL_STRING,
37
- "gender" => OPTIONAL_STRING
38
- },
39
- "contacts" => [[ {
40
- "label" => String,
41
- "value" => String
42
- } ]],
43
- "addresses" => [[ {
44
- "label" => String,
45
- "street" => OPTIONAL_STRING,
46
- "zip_code" => [:optional, String, Integer, NilClass],
47
- "city" => OPTIONAL_STRING,
48
- "country" => OPTIONAL_STRING
49
- } ]],
50
- "web_presence" => [:optional,
51
- [[
52
- {
53
- "label" => String,
54
- "value" => String
55
- },
56
- ]],
57
- NilClass
58
- ],
59
- "summary" => OPTIONAL_STRING,
60
- "work" => [:optional,
61
- [[
62
- {
63
- "who" => OPTIONAL_STRING,
64
- "website" => OPTIONAL_STRING,
65
- "address" => OPTIONAL_STRING,
66
- "till" => OPTIONAL_PARTIAL_DATE,
67
- "from" => OPTIONAL_PARTIAL_DATE,
68
- "role" => String,
69
- "summary" => String,
70
- "details" => OPTIONAL_STRING
71
- },
72
- ]],
73
- NilClass
74
- ],
75
- "teaching" => [:optional,
76
- [[
77
- {
78
- "who" => String,
79
- "school" => OPTIONAL_STRING,
80
- "address" => OPTIONAL_STRING,
81
- "till" => OPTIONAL_PARTIAL_DATE,
82
- "from" => OPTIONAL_PARTIAL_DATE,
83
- "role" => String,
84
- "subject" => String,
85
- "summary" => OPTIONAL_STRING,
86
- "details" => OPTIONAL_STRING
87
- }
88
- ]],
89
- NilClass
90
- ],
91
- "projects" => [:optional,
92
- [[
93
- {
94
- "name" => String,
95
- "size" => OPTIONAL_STRING,
96
- "who" => OPTIONAL_STRING,
97
- "till" => OPTIONAL_PARTIAL_DATE,
98
- "from" => OPTIONAL_PARTIAL_DATE,
99
- "role" => String,
100
- "summary" => OPTIONAL_STRING,
101
- }
102
- ]],
103
- NilClass
104
- ],
105
- "other" => [:optional,
106
- [[
107
- {
108
- "who" => OPTIONAL_STRING,
109
- "till" => OPTIONAL_PARTIAL_DATE,
110
- "from" => OPTIONAL_PARTIAL_DATE,
111
- "role" => String,
112
- "summary" => OPTIONAL_STRING,
113
- }
114
- ]],
115
- NilClass
116
- ],
117
- "committees" => [:optional,
118
- [[
119
- {
120
- "who" => String,
121
- "role" => String,
122
- "editions" => [String, Integer],
123
- "url" => OPTIONAL_STRING,
124
- }
125
- ]],
126
- NilClass
127
- ],
128
- "volunteer" => [:optional,
129
- [[
130
- {
131
- "who" => String,
132
- "where" => OPTIONAL_STRING,
133
- "date" => OPTIONAL_PARTIAL_DATE,
134
- "till" => OPTIONAL_PARTIAL_DATE,
135
- "from" => OPTIONAL_PARTIAL_DATE,
136
- "role" => String,
137
- "summary" => OPTIONAL_STRING,
138
- }
139
- ]],
140
- NilClass
141
- ],
142
- "visits" => [:optional,
143
- [[
144
- {
145
- "who" => String,
146
- "address" => OPTIONAL_STRING,
147
- "till" => OPTIONAL_PARTIAL_DATE,
148
- "from" => OPTIONAL_PARTIAL_DATE,
149
- "role" => String,
150
- "summary" => OPTIONAL_STRING,
151
- }
152
- ]],
153
- NilClass
154
- ],
155
- "education" => [:optional,
156
- [[
157
- {
158
- "degree" => OPTIONAL_STRING,
159
- "topic" => OPTIONAL_STRING,
160
- "school" => String,
161
- "address" => OPTIONAL_STRING,
162
- "date" => OPTIONAL_PARTIAL_DATE,
163
- "till" => OPTIONAL_PARTIAL_DATE,
164
- "from" => OPTIONAL_PARTIAL_DATE,
165
- "publish" => TrueClass,
166
- "score" => [:optional, String, Integer, NilClass],
167
- }
168
- ]],
169
- NilClass
170
- ],
171
- "publications" => [:optional,
172
- [[
173
- {
174
- "title" => String,
175
- "authors" => String,
176
- "publisher" => String,
177
- "date" => PARTIAL_DATE,
178
- "url" => OPTIONAL_STRING,
179
- }
180
- ]],
181
- NilClass
182
- ],
183
- "talks" => [:optional,
184
- [[
185
- {
186
- "title" => String,
187
- "venue" => String,
188
- "date" => PARTIAL_DATE,
189
- "url" => OPTIONAL_STRING,
190
- }
191
- ]],
192
- NilClass
193
- ],
194
- "awards" => [:optional,
195
- [[
196
- {
197
- "who" => String,
198
- "address" => OPTIONAL_STRING,
199
- "date" => PARTIAL_DATE,
200
- "title" => String,
201
- "summary" => OPTIONAL_STRING
202
- }
203
- ]],
204
- NilClass
205
- ],
206
- "achievements" => [:optional,
207
- [[
208
- {
209
- "who" => String,
210
- "address" => OPTIONAL_STRING,
211
- "date" => OPTIONAL_PARTIAL_DATE,
212
- "title" => String,
213
- "summary" => OPTIONAL_STRING
214
- }
215
- ]],
216
- NilClass
217
- ],
218
- "software" => [:optional,
219
- [[
220
- {
221
- "title" => String,
222
- "url" => OPTIONAL_STRING,
223
- "programming_language" => OPTIONAL_STRING,
224
- "license" => OPTIONAL_STRING,
225
- "role" => OPTIONAL_STRING,
226
- "summary" => OPTIONAL_STRING,
227
- }
228
- ]],
229
- NilClass
230
- ],
231
- "skills" => [:optional,
232
- [[
233
- {
234
- "name" => String,
235
- "level" => OPTIONAL_STRING,
236
- "summary" => OPTIONAL_STRING,
237
- }
238
- ]],
239
- NilClass
240
- ],
241
- "driving" => [:optional,
242
- [[ { "license" => String, } ]],
243
- NilClass
244
- ],
245
- "languages" => [:optional,
246
- {
247
- "mother_tongues" => [[
248
- {
249
- "code" => OPTIONAL_STRING,
250
- "language" => String,
251
- }
252
- ]],
253
- "foreign" => [:optional,
254
- [[
255
- {
256
- "code" => OPTIONAL_STRING,
257
- "language" => String,
258
- "level" => OPTIONAL_STRING,
259
- "listening" => OPTIONAL_STRING,
260
- "reading" => OPTIONAL_STRING,
261
- "spoken_interaction" => OPTIONAL_STRING,
262
- "spoken_production" => OPTIONAL_STRING,
263
- "writing" => OPTIONAL_STRING
264
- }
265
- ]],
266
- NilClass
267
- ]
268
- },
269
- NilClass
270
- ],
271
- "interests" => [:optional,
272
- [[
273
- {
274
- "name" => String,
275
- "level" => OPTIONAL_STRING,
276
- "summary" => OPTIONAL_STRING,
277
- }
278
- ]],
279
- NilClass
280
- ],
281
- "references" => [:optional,
282
- [[
283
- {
284
- "name" => String,
285
- "reference" => String,
286
- "contacts" => [[ {"label" => String, "value" => String} ]]
287
- }
288
- ]],
289
- NilClass
290
- ]
291
- }
292
- end
293
- end
@@ -1,134 +0,0 @@
1
- #
2
- # Utility functions you might want to use in your ERB
3
- # templates
4
- #
5
-
6
- # remove spaces at the beginning of string
7
- # replace extra spaces and special chars with a single space
8
- def clean string
9
- string.gsub(/^[\t\n ]+/, "").gsub(/[\t\n ]+/, " ")
10
- end
11
-
12
- def full_name data
13
- [data["basics"]["first_name"], data["basics"]["middle_name"], data["basics"]["last_name"]].join(" ")
14
- end
15
-
16
- # break a string into substrings of length chars breaking at spaces
17
- # and newlines
18
- #
19
- # * `string` string to reflow
20
- # * `chars` number of characters to break the string at
21
- # * returns an array of strings of length < chars (with exceptions
22
- # for special cases)
23
- #
24
- # special cases: if one line is longer than chars characters, then
25
- # break at the first space after chars
26
- #
27
- def reflow_to_array string, chars
28
- if string.length < chars
29
- return [clean(string)]
30
- else
31
- chars.downto(0).each do |index|
32
- if string[index] == " " or string[index] == "\n" or string[index] == "\t"
33
- return [clean(string[0..index-1])] + reflow_to_array(string[index+1..-1], chars)
34
- end
35
- end
36
- chars.upto(string.length).each do |index|
37
- if string[index] == " " or string[index] == "\n" or string[index] == "\t"
38
- return [clean(string[0..index-1])] + reflow_to_array(string[index+1..-1], chars)
39
- end
40
- end
41
- return [clean(string)]
42
- end
43
- end
44
-
45
- def reflow_to_string string, chars, indentation = ""
46
- array = reflow_to_array string, chars
47
- output = ""
48
- array.each do |line|
49
- output << indentation + line + "\n"
50
- end
51
- output
52
- end
53
-
54
- # manage dates of an entry flexibly supporting the following formats:
55
- #
56
- # - from - till (with `from` or `till` possibly partial or empty)
57
- # - date (possibly partial)
58
- #
59
- # abstract dates at the year level, taking care of periods if from and
60
- # till are in two different years
61
- def period entry
62
- if entry["date"]
63
- "#{year entry["date"]}"
64
- else
65
- from_year = entry["from"] ? year(entry["from"].to_s) : nil
66
- till_year = entry["till"] ? year(entry["till"].to_s) : nil
67
-
68
- if from_year && till_year && from_year == till_year
69
- from_year
70
- else
71
- "#{from_year} -- #{till_year ? till_year : "today"}"
72
- end
73
- end
74
- end
75
-
76
- # make an entry into an item of a list
77
- # - first argument, entry, is a hash containing the symbols specified in header and
78
- # the following fields: summary and then from, till, or date
79
- # - second argument, header, is an array of symbols, whose values, comma-separated will generate the
80
- # header line
81
- #
82
- # The output is along the lines of:
83
- #
84
- # - value of key1, value of key2
85
- # period
86
- # reflowed summary
87
- def itemize entry, header = ["role", "who", "address"]
88
- <<EOS
89
- - #{clean header.map { |x| entry[x] }.join(", ")}
90
- #{period entry}
91
- #{reflow_to_string entry["summary"], 72, " "}
92
- EOS
93
- end
94
-
95
- # generate a list of org-mode properties from item and exclude summary from the list
96
- def propertify item, indentation=""
97
- output = ":PROPERTIES:\n"
98
- item.each do |k, v|
99
- if not ["summary", "details"].include? k
100
- output << ":#{k.upcase}: #{v}\n"
101
- end
102
- end
103
- output << ":END:"
104
- output.gsub!(/^/, indentation)
105
- end
106
-
107
- # Utility function for managing dates (2015-01-01) and partial dates (2015-05)
108
- def year string
109
- string.to_s[0..3]
110
- end
111
-
112
- def month string
113
- string.to_s[5..6]
114
- end
115
-
116
- def day string
117
- string.to_s[8..9]
118
- end
119
-
120
- def has_month input
121
- if input.class == Date
122
- true
123
- else
124
- input.size >= 7
125
- end
126
- end
127
-
128
- def has_day input
129
- if input.class == Date
130
- true
131
- else
132
- input.size == 10
133
- end
134
- end
@@ -1,155 +0,0 @@
1
- {
2
- "basics": {
3
- "name": <%= full_name(data).to_json %>,
4
- "label": <%= data["basics"]["title"].to_json %>,
5
- <% if data["basics"]["picture"] -%>
6
- "picture": <%= data["basics"]["picture"] %>,
7
- <% end -%>
8
- <% if data["contacts"] -%>
9
- "email": "<%= ((data["contacts"] || []).select { |x| x["label"] == "email" }.first || {})["value"] %>",
10
- "phone": "<%= ((data["contacts"] || []).select { |x| x["label"] == "mobile" }.first || {})["value"] %>",
11
- <% end %>
12
- <% if data["web_presence"] -%>
13
- "website": "<%= ((data["web_presence"] || []).select { |x| x["label"] == "website" }.first || {})["value"] %>",
14
- <% end -%>
15
- <% if data["summary"] -%>
16
- "summary": <%= data["summary"].to_json %>,
17
- <% end -%>
18
- <% if data["addresses"] -%>
19
- "location": {
20
- "address": <%= data["addresses"][0]["street"].to_json %>,
21
- "postalCode": "<%= data["addresses"][0]["zip_code"] %>",
22
- "city": "<%= data["addresses"][0]["city"] %>",
23
- "countryCode": "<%= data["addresses"][0]["country"] %>",
24
- "region": "<%= data["addresses"][0]["region"] %>"
25
- },
26
- <% end -%>
27
- <% if data["web_presence"] -%>
28
- "profiles": [
29
- <% (data["web_presence"] || []).each do |profile| -%>
30
- {
31
- "network": "<%= profile["label"] %>",
32
- "url": "<%= profile["value"] %>"
33
- },
34
- <% end -%>
35
- ]
36
- <% end -%>
37
- },
38
- <% if data["work"] -%>
39
- "work": [
40
- <% (data["work"] || []).each do |job| -%>
41
- {
42
- "company": <%= job["who"].to_json %>,
43
- "position": <%= job["role"].to_json %>,
44
- "website": "<%= job["website"] %>",
45
- "startDate": "<%= job["from"] %>",
46
- "endDate": "<%= job["till"] %>",
47
- "summary": <%= job["summary"].to_json %>
48
- <%# "highlights": [ "Started the company" ] %>
49
- },
50
- <% end -%>
51
- ],
52
- <% end -%>
53
- <% if data["volunteer"] -%>
54
- "volunteer": [
55
- <% (data["volunteer"] || []).each do |job| -%>
56
- {
57
- "organization": <%= job["who"].to_json %>,
58
- "position": <%= job["role"].to_json %>,
59
- "website": "<%= job["website"] %>",
60
- "startDate": "<%= job["from"] %>",
61
- "endDate": "<%= job["till"] %>",
62
- "summary": <%= job["summary"].to_json %>
63
- <%# "highlights": [ "Started the company" ] %>
64
- },
65
- <% end -%>
66
- ],
67
- <% end %>
68
- <% if data["education"] %>
69
- "education": [
70
- <% data["education"].select { |x| x["publish"] }.each do |edu| -%>
71
- {
72
- "institution": <%= edu["school"].to_json %>,
73
- "area": <%= edu["topic"].to_json %>,
74
- "studyType": <%= edu["degree"].to_json %>,
75
- "startDate": "<%= edu["from"] %>",
76
- "endDate": "<%= edu["till"] %>",
77
- "gpa": "<%= edu["score"] %>"
78
- <%# "courses": [ "DB1101 - Basic SQL" ] %>
79
- },
80
- <% end -%>
81
- ],
82
- <% end -%>
83
- <% if data["awards"] -%>
84
- "awards": [
85
- <% (data["awards"] || []).each do |award| -%>
86
- {
87
- "title": <%= award["title"].to_json %>,
88
- "date": <%= award["date"] %>,
89
- "awarder": <%= award["who"].to_json %>,
90
- "summary": <%= award["summary"].to_json %>
91
- },
92
- <% end -%>
93
- ],
94
- <% end -%>
95
- <% if data["publications"] -%>
96
- "publications": [
97
- <% (data["publications"] || []).each do |pub| -%>
98
- {
99
- "name": <%= pub["title"].to_json %>,
100
- "publisher": <%= pub["publisher"].to_json %>,
101
- "releaseDate": "<%= pub["date"] %>",
102
- "website": "<%= pub["url"] %>",
103
- "summary": <%= pub["summary"].to_json %>
104
- },
105
- <% end -%>
106
- ],
107
- <% end -%>
108
- <% if data["skills"] -%>
109
- "skills": [
110
- <% (data["skills"] || []).each do |skill| -%>
111
- {
112
- "name": <%= skill["name"].to_json %>,
113
- "level": <%= skill["level"].to_json %>
114
- <%# "keywords": [...] -%>
115
- },
116
- <% end -%>
117
- ],
118
- <% end -%>
119
- <% if data["languages"] -%>
120
- "languages": [
121
- <% data["languages"]["mother_tongues"].each do |mt| -%>
122
- {
123
- "name": <%= mt["language"].to_json %>,
124
- "level": "Native speaker"
125
- },
126
- <% end -%>
127
- <% (data["languages"]["foreign"] || []).each do |lang| -%>
128
- {
129
- "name": <%= lang["language"].to_json %>,
130
- "level": <%= lang["level"].to_json %>
131
- },
132
- <% end -%>
133
- ],
134
- <% end -%>
135
- <% if data["interests"] -%>
136
- "interests": [
137
- <% (data["interests"] || []).each do |interest| -%>
138
- {
139
- "name": <%= interest["name"].to_json %>,
140
- <%# "keywords": [...] -%>
141
- },
142
- <% end -%>
143
- ],
144
- <% end -%>
145
- <% if data["references"] -%>
146
- "references": [
147
- <% (data["references"] || []).each do |reference| -%>
148
- {
149
- "name": <%= reference["name"].to_json %>,
150
- "reference": <%= reference["reference"].to_json %>
151
- },
152
- <% end -%>
153
- ]
154
- <% end %>
155
- }