resme 2.0.0 → 2.1.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 +7 -2
- data/README.org +2 -2
- data/exe/resme +0 -0
- data/lib/resme/cli.rb +24 -13
- data/lib/resme/document.rb +5 -17
- data/lib/resme/document_validator.rb +166 -209
- data/lib/resme/executor.rb +34 -7
- data/lib/resme/helper.rb +13 -9
- data/lib/resme/json_resume.rb +90 -87
- data/lib/resme/version.rb +1 -1
- data/lib/resme.rb +0 -2
- data/templates/html.erb +337 -0
- data/templates/org.erb +4 -0
- data/templates/resume-bauhaus.css +354 -0
- data/templates/resume-default.css +346 -0
- data/templates/resume-futurism.css +336 -0
- data/templates/resume-kyver.css +346 -0
- data/templates/resume-modern-light.css +305 -0
- data/templates/resume-modern.css +306 -0
- data/templates/resume-shair.tech.css +309 -0
- data/templates/resume-timeline.css +372 -0
- metadata +13 -5
- data/TAGS +0 -83
data/lib/resme/executor.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Resme
|
|
4
|
+
#
|
|
5
|
+
# Execute!
|
|
6
|
+
#
|
|
4
7
|
class Executor
|
|
5
8
|
# include all formatter helpers
|
|
6
9
|
include Resme::Helper
|
|
@@ -11,12 +14,13 @@ module Resme
|
|
|
11
14
|
@options.parse
|
|
12
15
|
end
|
|
13
16
|
|
|
17
|
+
# rubocop:disable Metrics
|
|
14
18
|
def execute
|
|
15
19
|
case @options.command
|
|
16
20
|
when :init
|
|
17
21
|
resume_template = File.join __dir__, "../../templates/resume.yml"
|
|
18
22
|
puts File.read resume_template
|
|
19
|
-
|
|
23
|
+
|
|
20
24
|
when :validate
|
|
21
25
|
filename = @options.options[:filename]
|
|
22
26
|
document = Document.new(filename)
|
|
@@ -26,7 +30,7 @@ module Resme
|
|
|
26
30
|
when :sections
|
|
27
31
|
filename = @options.options[:filename]
|
|
28
32
|
keys = Document.new(filename).data.keys
|
|
29
|
-
puts keys
|
|
33
|
+
puts keys
|
|
30
34
|
|
|
31
35
|
when :build
|
|
32
36
|
filename = @options.options[:filename]
|
|
@@ -40,23 +44,41 @@ module Resme
|
|
|
40
44
|
template = File.read(template_name)
|
|
41
45
|
|
|
42
46
|
# add the json format, if specified
|
|
43
|
-
if format.to_s == "json"
|
|
47
|
+
if format.to_s.downcase == "json"
|
|
44
48
|
js = JsonResume.new Document.new(filename)
|
|
45
49
|
@json_resume = js.build
|
|
46
50
|
end
|
|
47
|
-
|
|
48
|
-
output = ERB.new(template, trim_mode: "-").result(binding)
|
|
49
51
|
|
|
52
|
+
# copy the theme and set it in data for the tempalte, if output is html
|
|
53
|
+
if format.to_s.downcase == "html"
|
|
54
|
+
css_filename = theme_css_file @options.options[:theme]
|
|
55
|
+
css_template = File.join __dir__, "../../templates/#{css_filename}"
|
|
56
|
+
FileUtils.cp css_template, css_filename
|
|
57
|
+
|
|
58
|
+
@data[:theme] = css_filename
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
output = ERB.new(template, trim_mode: "-").result(binding)
|
|
50
62
|
# it is difficult to write readable ERBs with no empty lines... we use
|
|
51
63
|
# gsub to replace multiple empty lines with \n\n in the final output
|
|
52
64
|
output.gsub!(/([\t ]*\n){3,}/, "\n\n")
|
|
53
|
-
|
|
65
|
+
|
|
66
|
+
output_filename = output_filename(format)
|
|
67
|
+
backup_and_write(output_filename, output)
|
|
68
|
+
puts "Resume generated and saved to #{output_filename}"
|
|
54
69
|
|
|
55
70
|
when :list
|
|
56
71
|
templates = File.join __dir__, "../../templates/*.erb"
|
|
57
72
|
files = Dir.glob(templates).map { |x| "#{File.basename(x)} => #{x}" }
|
|
58
73
|
puts files.join("\n")
|
|
59
74
|
|
|
75
|
+
when :themes
|
|
76
|
+
templates = File.join __dir__, "../../templates/*.css"
|
|
77
|
+
files = Dir.glob(templates).map do |x|
|
|
78
|
+
File.basename(x).gsub("resume-", "").gsub(".css", "")
|
|
79
|
+
end
|
|
80
|
+
puts files.join("\n")
|
|
81
|
+
|
|
60
82
|
when :cat
|
|
61
83
|
template = @options.options[:template]
|
|
62
84
|
template_path = File.join __dir__, "../../templates/#{template}"
|
|
@@ -70,15 +92,20 @@ module Resme
|
|
|
70
92
|
|
|
71
93
|
end
|
|
72
94
|
end
|
|
95
|
+
# rubocop:enable Metrics
|
|
73
96
|
|
|
74
97
|
private
|
|
75
98
|
|
|
99
|
+
def theme_css_file(theme_name)
|
|
100
|
+
"resume-#{theme_name}.css"
|
|
101
|
+
end
|
|
102
|
+
|
|
76
103
|
def output_filename(format)
|
|
77
104
|
"resume-#{Date.today.iso8601}.#{format}"
|
|
78
105
|
end
|
|
79
106
|
|
|
80
107
|
def backup(filename)
|
|
81
|
-
FileUtils
|
|
108
|
+
FileUtils.cp filename, "#{filename}~"
|
|
82
109
|
puts "Backup copy #{filename} created in #{filename}~."
|
|
83
110
|
end
|
|
84
111
|
|
data/lib/resme/helper.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Resme
|
|
|
14
14
|
[
|
|
15
15
|
data.dig(:basics, :first_name),
|
|
16
16
|
data.dig(:basics, :middle_name),
|
|
17
|
-
data.dig(:basics, :last_name)
|
|
17
|
+
data.dig(:basics, :last_name)
|
|
18
18
|
].compact.join(" ")
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -30,6 +30,7 @@ module Resme
|
|
|
30
30
|
# Special cases: if one line is longer than chars characters, then break at
|
|
31
31
|
# the first space after chars
|
|
32
32
|
#
|
|
33
|
+
# rubocop:disable Metrics/AbcSize
|
|
33
34
|
def reflow_a(string, line_break: 78)
|
|
34
35
|
# if the string is less than line_break chars, we are done
|
|
35
36
|
return [clean(string)] if string.length < line_break
|
|
@@ -45,7 +46,7 @@ module Resme
|
|
|
45
46
|
reflow_a(string[(index + 1)..], line_break:)
|
|
46
47
|
end
|
|
47
48
|
end
|
|
48
|
-
|
|
49
|
+
|
|
49
50
|
# here the string does not have a space between 0 and line_break
|
|
50
51
|
#
|
|
51
52
|
# In this case we try to break at the first blank after the string and
|
|
@@ -57,18 +58,19 @@ module Resme
|
|
|
57
58
|
reflow_a(string[(index + 1)..], line_break:)
|
|
58
59
|
end
|
|
59
60
|
end
|
|
60
|
-
|
|
61
|
+
|
|
61
62
|
# here string is longer than line_break and it does not have spaces
|
|
62
63
|
#
|
|
63
64
|
# The only thing left to do is returning the string as it is
|
|
64
65
|
#
|
|
65
66
|
[clean(string)]
|
|
66
67
|
end
|
|
68
|
+
# rubocop:enable Metrics/AbcSize
|
|
67
69
|
|
|
68
70
|
def blank?(char)
|
|
69
71
|
[" ", "\t", "\n"].include?(char)
|
|
70
72
|
end
|
|
71
|
-
|
|
73
|
+
|
|
72
74
|
# Reflow at +line_break+, returning a string with each line delimited by
|
|
73
75
|
# +delimiter+ (by default newline) and indented with +indent+ spaces.
|
|
74
76
|
#
|
|
@@ -148,11 +150,16 @@ module Resme
|
|
|
148
150
|
contact ? contact[:value] : nil
|
|
149
151
|
end
|
|
150
152
|
|
|
153
|
+
# break text into paragraphs and wrap in <p>
|
|
154
|
+
def html_summary(text)
|
|
155
|
+
text.split("\n\n").map { |x| "<p>#{x}</p>" }.join
|
|
156
|
+
end
|
|
157
|
+
|
|
151
158
|
#
|
|
152
159
|
# Utility functions for managing dates in the form 2015-01-01 and partial
|
|
153
160
|
# dates (e.g., 2015-05, 2015)
|
|
154
161
|
#
|
|
155
|
-
|
|
162
|
+
|
|
156
163
|
# Format the input as a date, according to format. If the input is not
|
|
157
164
|
# a date, return it as it (assuming it represents a partial date (e.g.,
|
|
158
165
|
# 2012-01, 2012
|
|
@@ -172,8 +179,6 @@ module Resme
|
|
|
172
179
|
"#{incomplete_date}-01"
|
|
173
180
|
elsif y?(incomplete_date.to_s)
|
|
174
181
|
"#{incomplete_date}-01-01"
|
|
175
|
-
else
|
|
176
|
-
nil
|
|
177
182
|
end
|
|
178
183
|
end
|
|
179
184
|
|
|
@@ -191,7 +196,7 @@ module Resme
|
|
|
191
196
|
def day(input)
|
|
192
197
|
input.is_a?(Date) ? input.strftime("%d") : input.to_s[8..9]
|
|
193
198
|
end
|
|
194
|
-
|
|
199
|
+
|
|
195
200
|
# Is the input in the form YYYY-MM(-..)
|
|
196
201
|
def y?(input)
|
|
197
202
|
input.is_a?(Date) || input.to_s.size == 4
|
|
@@ -208,4 +213,3 @@ module Resme
|
|
|
208
213
|
end
|
|
209
214
|
end
|
|
210
215
|
end
|
|
211
|
-
|
data/lib/resme/json_resume.rb
CHANGED
|
@@ -6,151 +6,154 @@ module Resme
|
|
|
6
6
|
#
|
|
7
7
|
class JsonResume
|
|
8
8
|
include Helper
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
def initialize(document)
|
|
11
11
|
@document = document
|
|
12
12
|
@data = document.data
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# rubocop:disable Metrics
|
|
15
16
|
def build
|
|
16
17
|
address = @data[:addresses]&.first || {}
|
|
17
|
-
|
|
18
|
+
education = @data[:education].select { |x| x[:publish] } || []
|
|
19
|
+
|
|
18
20
|
{
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
basics: {
|
|
22
|
+
name: full_name(@data),
|
|
23
|
+
label: @data[:basics][:title],
|
|
24
|
+
image: "",
|
|
25
|
+
email: select(@data[:contacts], label: :email),
|
|
26
|
+
phone: select(@data[:contacts], label: :phone),
|
|
27
|
+
url: select(@data[:web_presence], label: :url),
|
|
28
|
+
summary: @data[:summary],
|
|
29
|
+
location: {
|
|
30
|
+
address: address[:street],
|
|
31
|
+
postalCode: address[:postal_code].to_s,
|
|
32
|
+
city: address[:city],
|
|
33
|
+
countryCode: address[:country_code],
|
|
34
|
+
region: address[:region]
|
|
33
35
|
}.compact,
|
|
34
|
-
|
|
36
|
+
profiles: @data[:web_presence].map do |kv|
|
|
35
37
|
{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#
|
|
38
|
+
network: kv[:label],
|
|
39
|
+
username: kv[:value]
|
|
40
|
+
# url:
|
|
39
41
|
}
|
|
40
42
|
end.compact
|
|
41
43
|
}.compact,
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
work: @data[:work].map do |elem|
|
|
44
46
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
name: elem[:name],
|
|
48
|
+
position: elem[:position],
|
|
49
|
+
url: elem[:url],
|
|
50
|
+
startDate: complete_date(elem[:date] || elem[:start_date]),
|
|
51
|
+
endDate: complete_date(elem[:date] || elem[:end_date]),
|
|
52
|
+
summary: elem[:summary],
|
|
53
|
+
highlights: split_highlights(elem[:details])
|
|
52
54
|
}.compact
|
|
53
55
|
end,
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
volunteer: (@data[:volunteer] || []).map do |elem|
|
|
56
58
|
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
organization: elem[:name],
|
|
60
|
+
position: elem[:position],
|
|
61
|
+
startDate: complete_date(elem[:date] || elem[:start_date]),
|
|
62
|
+
endDate: complete_date(elem[:date] || elem[:end_date]),
|
|
63
|
+
summary: elem[:summary],
|
|
64
|
+
highlights: split_highlights(elem[:details])
|
|
63
65
|
}.compact
|
|
64
66
|
end,
|
|
65
67
|
|
|
66
|
-
|
|
68
|
+
education: education.map do |elem|
|
|
67
69
|
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
institution: elem[:school],
|
|
71
|
+
url: elem[:url],
|
|
72
|
+
area: elem[:topic],
|
|
73
|
+
studyType: elem[:degree],
|
|
74
|
+
startDate: complete_date(elem[:date] || elem[:start_date]),
|
|
75
|
+
endDate: complete_date(elem[:date] || elem[:end_date]),
|
|
76
|
+
score: elem[:score],
|
|
77
|
+
courses: []
|
|
76
78
|
}.compact
|
|
77
79
|
end,
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
awards: (@data[:awards] || []).map do |elem|
|
|
80
82
|
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
title: elem[:title],
|
|
84
|
+
date: complete_date(elem[:date]),
|
|
85
|
+
awarder: elem[:name],
|
|
86
|
+
summary: elem[:summary]
|
|
85
87
|
}.compact
|
|
86
88
|
end,
|
|
87
89
|
|
|
88
|
-
|
|
90
|
+
certificates: [],
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
publications: (@data[:publications] || []).map do |elem|
|
|
91
93
|
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
name: [elem[:title], elem[:authors]].compact.join(", "),
|
|
95
|
+
publisher: elem[:publisher],
|
|
96
|
+
releaseDate: complete_date(elem[:date]),
|
|
97
|
+
url: elem[:url],
|
|
98
|
+
summary: ""
|
|
97
99
|
}.compact
|
|
98
100
|
end,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
|
|
102
|
+
skills: (@data[:skills] || []).map do |elem|
|
|
101
103
|
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
name: elem[:name],
|
|
105
|
+
level: elem[:level],
|
|
106
|
+
keywords: split_highlights(elem[:summary])
|
|
105
107
|
}.compact
|
|
106
108
|
end,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
{
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
|
|
110
|
+
languages: (@data.dig(:languages, :mother_tongues) || []).map do |elem|
|
|
111
|
+
{
|
|
112
|
+
language: elem[:language],
|
|
113
|
+
fluency: "Native speaker"
|
|
112
114
|
}.compact
|
|
113
|
-
end + (@data.dig(:languages, :foreign) || []).map do |
|
|
114
|
-
{
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
end + (@data.dig(:languages, :foreign) || []).map do |elem|
|
|
116
|
+
{
|
|
117
|
+
language: elem[:language],
|
|
118
|
+
fluency: elem[:level]
|
|
117
119
|
}.compact
|
|
118
120
|
end,
|
|
119
121
|
|
|
120
|
-
|
|
122
|
+
interests: (@data[:interests] || []).map do |elem|
|
|
121
123
|
{
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
name: elem[:name],
|
|
125
|
+
keywords: split_highlights(elem[:summary])
|
|
124
126
|
}.compact
|
|
125
127
|
end,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
|
|
129
|
+
references: (@data[:references] || []).map do |elem|
|
|
128
130
|
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
name: elem[:name],
|
|
132
|
+
reference: elem[:reference]
|
|
131
133
|
}.compact
|
|
132
134
|
end,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
|
|
136
|
+
projects: (@data[:projects] || []).map do |elem|
|
|
135
137
|
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
name: elem[:name],
|
|
139
|
+
url: elem[:url],
|
|
140
|
+
startDate: complete_date(elem[:date] || elem[:start_date]),
|
|
141
|
+
endDate: complete_date(elem[:date] || elem[:end_date]),
|
|
142
|
+
description: elem[:summary],
|
|
143
|
+
highlights: []
|
|
142
144
|
}.compact
|
|
143
145
|
end
|
|
144
146
|
}.compact
|
|
145
147
|
end
|
|
148
|
+
# rubocop:enable Metrics
|
|
146
149
|
|
|
147
150
|
private
|
|
148
151
|
|
|
149
152
|
# make a string with an itemized list into an array of the items
|
|
150
153
|
def split_highlights(highlights)
|
|
151
154
|
(highlights || "").split(/^ *- /)
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
.map { |x| x.gsub("\n", "") }
|
|
156
|
+
.reject { |x| x == "" }
|
|
154
157
|
end
|
|
155
158
|
end
|
|
156
159
|
end
|
data/lib/resme/version.rb
CHANGED