my-last-cv 0.0.7 → 0.0.9
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/README.md +120 -6
- data/exe/my_last_cv +4 -4
- data/fonts/Inter-Bold.ttf +0 -0
- data/fonts/Inter-Italic.ttf +0 -0
- data/fonts/Inter-Regular.ttf +0 -0
- data/fonts/Lora-Bold.ttf +0 -0
- data/fonts/Lora-Regular.ttf +0 -0
- data/lib/my_last_cv/inline.rb +141 -0
- data/lib/my_last_cv/parser.rb +2 -1
- data/lib/my_last_cv/renderer.rb +49 -24
- data/lib/my_last_cv/version.rb +1 -1
- data/lib/my_last_cv.rb +1 -0
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 04b56bee3c092687375a967a44f81464be5f0b34fa3a453499fb4b3ac22fda06
|
|
4
|
+
data.tar.gz: dcaccb9a74c42cf24267201ddd6e95b17c434cbfb955fb8479ec3e88d76f5fab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ba6f2f816174ee03ed4f417caca9e65b8cfeec6c684b29166f687d8ca7ac0e8a090026d7f1cafc68fdac27a42cf934126fc339b3efef8e83920d5fdac7b8fd7f
|
|
7
|
+
data.tar.gz: b514c0f500dec9398744f3185295ee350d4deaf9b647a789a9f0f893d9c729716d8235c2c706571bab428785d31a0150f729582f94a8cba2c7354aadff9fed38
|
data/README.md
CHANGED
|
@@ -1,14 +1,128 @@
|
|
|
1
1
|
# my-last-cv
|
|
2
|
-
A simple gem to generate beautiful CV from a markdown file
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
A Ruby gem and command-line tool that generates a styled PDF CV from Markdown.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
Ruby 3.0 or later.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
5
11
|
```bash
|
|
6
12
|
bundle add my-last-cv
|
|
7
13
|
bundle install
|
|
8
|
-
bundle exec my_last_cv sample/cv.md output/cv.pdf
|
|
9
14
|
```
|
|
10
15
|
|
|
16
|
+
For local development, install the project's dependencies:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bundle install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Generate a CV
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bundle exec my_last_cv path/to/cv.md output/cv.pdf
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The output directory is created automatically. The CLI uses the bundled Inter and
|
|
29
|
+
Lora fonts. Start from [`sample/cv.md`](sample/cv.md) to create your document.
|
|
30
|
+
Its compact layout is designed to fit typical CVs on a single page.
|
|
31
|
+
|
|
32
|
+
## Markdown format
|
|
33
|
+
|
|
34
|
+
Use YAML front matter for contact information, a level-one heading for the name,
|
|
35
|
+
level-two headings for sections, and level-three headings for entries within a
|
|
36
|
+
section:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
---
|
|
40
|
+
title: "Ruby developer"
|
|
41
|
+
email: "jane@example.com"
|
|
42
|
+
phone: "+33 6 12 34 56 78"
|
|
43
|
+
linkedin: "https://www.linkedin.com/in/janedoe"
|
|
44
|
+
github: "https://github.com/janedoe"
|
|
45
|
+
website: "https://janedoe.dev"
|
|
46
|
+
location: "Paris, France"
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
# Jane Doe
|
|
50
|
+
Short professional introduction displayed below the header.
|
|
51
|
+
|
|
52
|
+
## Experience
|
|
53
|
+
### Senior Developer — Example Corp
|
|
54
|
+
Introductory paragraph for this role.
|
|
55
|
+
- Built and maintained Ruby applications.
|
|
56
|
+
- Mentored other developers.
|
|
57
|
+
|
|
58
|
+
## Skills
|
|
59
|
+
- Ruby
|
|
60
|
+
- PostgreSQL
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Supported front-matter contact keys are `name`, `title`, `email`, `phone`,
|
|
64
|
+
`linkedin`, `github`, `website`, and `location`. They are rendered with icons;
|
|
65
|
+
`name` and `title` are omitted from the contact list when they duplicate the
|
|
66
|
+
document heading or introduction.
|
|
67
|
+
|
|
68
|
+
Text immediately below the main heading becomes the introduction. Section and
|
|
69
|
+
entry content can contain paragraphs and bullet lists. A `###` entry without a
|
|
70
|
+
preceding `##` section is placed in a section named `Divers`.
|
|
71
|
+
|
|
72
|
+
## Inline Markdown support
|
|
73
|
+
|
|
74
|
+
Contact fields, headings, paragraphs, and bullet items support:
|
|
75
|
+
|
|
76
|
+
- `**bold**`
|
|
77
|
+
- `*italic*`
|
|
78
|
+
- `` `code` ``
|
|
79
|
+
- `[links](https://example.com)`
|
|
80
|
+
|
|
81
|
+
Escape Markdown punctuation with a backslash when it should remain literal, for
|
|
82
|
+
example `\*not italic\*`.
|
|
83
|
+
|
|
84
|
+
## Ruby API and styling
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
require "my_last_cv"
|
|
88
|
+
|
|
89
|
+
style = MyLastCV::Style.new(
|
|
90
|
+
header_font: "Inter",
|
|
91
|
+
header_size: 22,
|
|
92
|
+
section_font: "Inter",
|
|
93
|
+
section_size: 12,
|
|
94
|
+
body_font: "Lora",
|
|
95
|
+
body_size: 10,
|
|
96
|
+
page_options: { margin: 36 },
|
|
97
|
+
accent_color: "1F7AE0"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
MyLastCV.generate("cv.md", "output/cv.pdf", style: style)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`MyLastCV::Style` defaults to Helvetica, sizes `18`, `12`, and `10`, a page
|
|
104
|
+
margin of `48`, and a black accent color (`000000`). `page_options` is passed to
|
|
105
|
+
`Prawn::Document`, so Prawn page settings such as `page_size` and `layout` can
|
|
106
|
+
also be supplied.
|
|
107
|
+
|
|
11
108
|
## Custom fonts
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
109
|
+
|
|
110
|
+
Inter and Lora are bundled with the gem. To override them, provide a directory
|
|
111
|
+
containing `Inter-Regular.ttf`, `Inter-Bold.ttf`, `Lora-Regular.ttf`, and
|
|
112
|
+
`Lora-Bold.ttf`. Optional `Inter-Italic.ttf`, `Inter-BoldItalic.ttf`,
|
|
113
|
+
`Lora-Italic.ttf`, and `Lora-BoldItalic.ttf` files enable matching italic
|
|
114
|
+
styles; missing variants fall back to their regular or bold face.
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
MyLastCV::Style.new(fonts_dir: "/path/to/fonts")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Alternatively, set `MY_LAST_CV_FONTS_DIR=/path/to/fonts`. Font directories are
|
|
121
|
+
resolved in this order: `fonts_dir`, `MY_LAST_CV_FONTS_DIR`, `./fonts`, then the
|
|
122
|
+
fonts bundled with the gem.
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
bundle exec rake spec
|
|
128
|
+
```
|
data/exe/my_last_cv
CHANGED
|
@@ -12,12 +12,12 @@ input, output = ARGV
|
|
|
12
12
|
|
|
13
13
|
pro = MyLastCV::Style.new(
|
|
14
14
|
header_font: "Inter",
|
|
15
|
-
header_size:
|
|
15
|
+
header_size: 20,
|
|
16
16
|
section_font: "Inter",
|
|
17
|
-
section_size:
|
|
17
|
+
section_size: 11,
|
|
18
18
|
body_font: "Lora",
|
|
19
|
-
body_size:
|
|
20
|
-
page_options: { margin:
|
|
19
|
+
body_size: 9,
|
|
20
|
+
page_options: { margin: 30 },
|
|
21
21
|
accent_color: "1F7AE0" # blue
|
|
22
22
|
)
|
|
23
23
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/fonts/Lora-Bold.ttf
ADDED
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require 'cgi'
|
|
2
|
+
|
|
3
|
+
module MyLastCV
|
|
4
|
+
class Inline
|
|
5
|
+
LINK_COLOR = '0563C1'.freeze
|
|
6
|
+
ESCAPABLE_CHARACTERS = "`*[]()".chars.freeze
|
|
7
|
+
|
|
8
|
+
def self.parse(text)
|
|
9
|
+
new(text).parse
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(text)
|
|
13
|
+
@text = text.to_s
|
|
14
|
+
@index = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def parse
|
|
18
|
+
parse_until(nil).first
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def parse_until(stop_token)
|
|
24
|
+
output = +""
|
|
25
|
+
|
|
26
|
+
while @index < @text.length
|
|
27
|
+
if stop_token && token?(stop_token)
|
|
28
|
+
@index += stop_token.length
|
|
29
|
+
return [output, true]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
output << if escaped_character?
|
|
33
|
+
consume_escaped_character
|
|
34
|
+
elsif token?('**')
|
|
35
|
+
parse_emphasis('**', 'b')
|
|
36
|
+
elsif token?('*')
|
|
37
|
+
parse_emphasis('*', 'i')
|
|
38
|
+
elsif token?('`')
|
|
39
|
+
parse_code
|
|
40
|
+
elsif token?('[')
|
|
41
|
+
parse_link
|
|
42
|
+
else
|
|
43
|
+
consume_plain_character
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
[output, false]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def escaped_character?
|
|
51
|
+
current_character == '\\' && (next_character == '\\' || ESCAPABLE_CHARACTERS.include?(next_character))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def consume_escaped_character
|
|
55
|
+
character = next_character
|
|
56
|
+
@index += 2
|
|
57
|
+
CGI.escapeHTML(character)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def consume_plain_character
|
|
61
|
+
character = current_character
|
|
62
|
+
@index += 1
|
|
63
|
+
CGI.escapeHTML(character)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def parse_emphasis(delimiter, tag)
|
|
67
|
+
start_index = @index
|
|
68
|
+
@index += delimiter.length
|
|
69
|
+
content, closed = parse_until(delimiter)
|
|
70
|
+
|
|
71
|
+
return "<#{tag}>#{content}</#{tag}>" if closed && !content.empty?
|
|
72
|
+
|
|
73
|
+
CGI.escapeHTML(@text[start_index...@index])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def parse_code
|
|
77
|
+
start_index = @index
|
|
78
|
+
@index += 1
|
|
79
|
+
content = +""
|
|
80
|
+
|
|
81
|
+
while @index < @text.length && !token?('`')
|
|
82
|
+
content << @text[@index]
|
|
83
|
+
@index += 1
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
return CGI.escapeHTML(@text[start_index...@index]) if @index >= @text.length
|
|
87
|
+
|
|
88
|
+
@index += 1
|
|
89
|
+
"<font name=\"Courier\">#{CGI.escapeHTML(content)}</font>"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def parse_link
|
|
93
|
+
start_index = @index
|
|
94
|
+
@index += 1
|
|
95
|
+
label, closed = parse_until(']')
|
|
96
|
+
return CGI.escapeHTML(@text[start_index...@index]) unless closed
|
|
97
|
+
return CGI.escapeHTML(@text[start_index...@index]) unless token?('(')
|
|
98
|
+
|
|
99
|
+
@index += 1
|
|
100
|
+
url, closed = parse_link_destination
|
|
101
|
+
return CGI.escapeHTML(@text[start_index...@index]) unless closed
|
|
102
|
+
return CGI.escapeHTML(@text[start_index...@index]) if url.strip.empty?
|
|
103
|
+
|
|
104
|
+
%(<color rgb="#{LINK_COLOR}"><u><link href="#{CGI.escapeHTML(url)}">#{label}</link></u></color>)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def parse_link_destination
|
|
108
|
+
start_index = @index
|
|
109
|
+
depth = 0
|
|
110
|
+
|
|
111
|
+
while @index < @text.length
|
|
112
|
+
if token?('(')
|
|
113
|
+
depth += 1
|
|
114
|
+
elsif token?(')')
|
|
115
|
+
if depth.zero?
|
|
116
|
+
url = @text[start_index...@index]
|
|
117
|
+
@index += 1
|
|
118
|
+
return [url, true]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
depth -= 1
|
|
122
|
+
end
|
|
123
|
+
@index += 1
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
[@text[start_index...@index], false]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def token?(value)
|
|
130
|
+
@text[@index, value.length] == value
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def current_character
|
|
134
|
+
@text[@index]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def next_character
|
|
138
|
+
@text[@index + 1]
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
data/lib/my_last_cv/parser.rb
CHANGED
|
@@ -129,7 +129,8 @@ module MyLastCV
|
|
|
129
129
|
def handle_contact(line)
|
|
130
130
|
key, value = line.split(":", 2)
|
|
131
131
|
@result[:contact] ||= {}
|
|
132
|
-
|
|
132
|
+
normalized_key = key.to_s.strip.downcase
|
|
133
|
+
@result[:contact][normalized_key] = value.to_s.strip
|
|
133
134
|
end
|
|
134
135
|
|
|
135
136
|
def handle_section(line)
|
data/lib/my_last_cv/renderer.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'prawn'
|
|
|
2
2
|
require 'prawn/icon'
|
|
3
3
|
require 'fileutils'
|
|
4
4
|
require_relative 'icons'
|
|
5
|
+
require_relative 'inline'
|
|
5
6
|
|
|
6
7
|
module MyLastCV
|
|
7
8
|
class Renderer
|
|
@@ -37,28 +38,38 @@ module MyLastCV
|
|
|
37
38
|
fonts_dir = resolved_fonts_dir
|
|
38
39
|
return unless fonts_dir
|
|
39
40
|
|
|
40
|
-
# Example : Inter (Regular / Bold)
|
|
41
41
|
pdf.font_families.update(
|
|
42
|
-
"Inter" =>
|
|
43
|
-
|
|
44
|
-
bold: File.join(fonts_dir, "Inter-Bold.ttf")
|
|
45
|
-
},
|
|
46
|
-
"Lora" => {
|
|
47
|
-
normal: File.join(fonts_dir, "Lora-Regular.ttf"),
|
|
48
|
-
bold: File.join(fonts_dir, "Lora-Bold.ttf")
|
|
49
|
-
}
|
|
42
|
+
"Inter" => font_family_files(fonts_dir, "Inter"),
|
|
43
|
+
"Lora" => font_family_files(fonts_dir, "Lora")
|
|
50
44
|
)
|
|
51
45
|
end
|
|
52
46
|
|
|
47
|
+
def font_family_files(fonts_dir, family)
|
|
48
|
+
regular = File.join(fonts_dir, "#{family}-Regular.ttf")
|
|
49
|
+
bold = File.join(fonts_dir, "#{family}-Bold.ttf")
|
|
50
|
+
italic = File.join(fonts_dir, "#{family}-Italic.ttf")
|
|
51
|
+
bold_italic = File.join(fonts_dir, "#{family}-BoldItalic.ttf")
|
|
52
|
+
|
|
53
|
+
{
|
|
54
|
+
normal: regular,
|
|
55
|
+
bold: bold,
|
|
56
|
+
italic: File.file?(italic) ? italic : regular,
|
|
57
|
+
bold_italic: File.file?(bold_italic) ? bold_italic : bold
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
53
61
|
def render_header(pdf)
|
|
54
|
-
pdf.move_down
|
|
62
|
+
pdf.move_down 4
|
|
55
63
|
pdf.font(@style.body_font)
|
|
56
|
-
@parsed_cv[:contact]
|
|
64
|
+
contact = @parsed_cv[:contact] || {}
|
|
65
|
+
contact.each do |key, value|
|
|
66
|
+
next if redundant_contact_field?(key, value)
|
|
67
|
+
|
|
57
68
|
icon = "<icon size=\"#{@style.body_size}\">#{MyLastCV::Icons::MAP[key.to_sym]}</icon>"
|
|
58
|
-
pdf.icon("#{icon} #{
|
|
69
|
+
pdf.icon("#{icon} #{Inline.parse(value)}", inline_format: true)
|
|
59
70
|
end
|
|
60
71
|
|
|
61
|
-
pdf.move_down
|
|
72
|
+
pdf.move_down 2
|
|
62
73
|
pdf.font(@style.header_font)
|
|
63
74
|
with_color(pdf, @style.accent_color) do
|
|
64
75
|
pdf.text(@parsed_cv[:title] || '-', size: @style.header_size, align: :center)
|
|
@@ -69,29 +80,43 @@ module MyLastCV
|
|
|
69
80
|
pdf.stroke_horizontal_rule
|
|
70
81
|
|
|
71
82
|
if @parsed_cv[:intro]&.any?
|
|
72
|
-
pdf.move_down
|
|
83
|
+
pdf.move_down 4
|
|
73
84
|
@parsed_cv[:intro].each do |p|
|
|
74
|
-
pdf.text(p, size: @style.body_size, leading: 2)
|
|
85
|
+
pdf.text(Inline.parse(p), size: @style.body_size, leading: 2, inline_format: true)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
pdf.move_down 4
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def redundant_contact_field?(key, value)
|
|
92
|
+
case key
|
|
93
|
+
when "name"
|
|
94
|
+
value.to_s.strip.casecmp?(@parsed_cv[:title].to_s.strip)
|
|
95
|
+
when "title"
|
|
96
|
+
title = value.to_s.strip
|
|
97
|
+
Array(@parsed_cv[:intro]).any? do |paragraph|
|
|
98
|
+
paragraph.to_s.sub(/\A\*+/, "").start_with?(title)
|
|
75
99
|
end
|
|
100
|
+
else
|
|
101
|
+
false
|
|
76
102
|
end
|
|
77
|
-
pdf.move_down 10
|
|
78
103
|
end
|
|
79
104
|
|
|
80
105
|
def render_sections(pdf)
|
|
81
106
|
(@parsed_cv[:sections] || []).each do |section|
|
|
82
|
-
pdf.move_down
|
|
107
|
+
pdf.move_down 4
|
|
83
108
|
pdf.font(@style.section_font)
|
|
84
109
|
|
|
85
110
|
with_color(pdf, @style.accent_color) do
|
|
86
|
-
pdf.text(section[:title], size: @style.section_size, style: :bold)
|
|
111
|
+
pdf.text(Inline.parse(section[:title]), size: @style.section_size, style: :bold, inline_format: true)
|
|
87
112
|
end
|
|
88
113
|
|
|
89
114
|
render_items(pdf, section[:items])
|
|
90
115
|
|
|
91
116
|
(section[:elements] || []).each do |el|
|
|
92
|
-
pdf.move_down
|
|
117
|
+
pdf.move_down 3
|
|
93
118
|
pdf.font(@style.section_font)
|
|
94
|
-
pdf.text(el[:title], size: (@style.section_size - 3), style: :bold)
|
|
119
|
+
pdf.text(Inline.parse(el[:title]), size: (@style.section_size - 3), style: :bold, inline_format: true)
|
|
95
120
|
render_items(pdf, el[:items])
|
|
96
121
|
end
|
|
97
122
|
end
|
|
@@ -100,16 +125,16 @@ module MyLastCV
|
|
|
100
125
|
def render_items(pdf, items)
|
|
101
126
|
return if items.nil? || items.empty?
|
|
102
127
|
|
|
103
|
-
pdf.move_down
|
|
128
|
+
pdf.move_down 1
|
|
104
129
|
pdf.font(@style.body_font)
|
|
105
130
|
|
|
106
131
|
(items || []).each do |item|
|
|
107
132
|
case item[:type]
|
|
108
133
|
when :bullet
|
|
109
|
-
pdf.text("• #{item[:text]}", size: @style.body_size, indent_paragraphs: 16)
|
|
134
|
+
pdf.text("• #{Inline.parse(item[:text])}", size: @style.body_size, indent_paragraphs: 16, inline_format: true)
|
|
110
135
|
when :paragraph
|
|
111
|
-
pdf.text(item[:text], size: @style.body_size, leading: 2)
|
|
112
|
-
pdf.move_down
|
|
136
|
+
pdf.text(Inline.parse(item[:text]), size: @style.body_size, leading: 2, inline_format: true)
|
|
137
|
+
pdf.move_down 1
|
|
113
138
|
else
|
|
114
139
|
# fallback (au cas où)
|
|
115
140
|
pdf.text(item.to_s, size: @style.body_size)
|
data/lib/my_last_cv/version.rb
CHANGED
data/lib/my_last_cv.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: my-last-cv
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Maxime Hanicotte
|
|
@@ -76,8 +76,14 @@ extra_rdoc_files: []
|
|
|
76
76
|
files:
|
|
77
77
|
- README.md
|
|
78
78
|
- exe/my_last_cv
|
|
79
|
+
- fonts/Inter-Bold.ttf
|
|
80
|
+
- fonts/Inter-Italic.ttf
|
|
81
|
+
- fonts/Inter-Regular.ttf
|
|
82
|
+
- fonts/Lora-Bold.ttf
|
|
83
|
+
- fonts/Lora-Regular.ttf
|
|
79
84
|
- lib/my_last_cv.rb
|
|
80
85
|
- lib/my_last_cv/icons.rb
|
|
86
|
+
- lib/my_last_cv/inline.rb
|
|
81
87
|
- lib/my_last_cv/parser.rb
|
|
82
88
|
- lib/my_last_cv/renderer.rb
|
|
83
89
|
- lib/my_last_cv/style.rb
|
|
@@ -106,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
106
112
|
- !ruby/object:Gem::Version
|
|
107
113
|
version: '0'
|
|
108
114
|
requirements: []
|
|
109
|
-
rubygems_version: 3.7.
|
|
115
|
+
rubygems_version: 3.7.2
|
|
110
116
|
specification_version: 4
|
|
111
117
|
summary: Generate your CV from Markdown to PDF
|
|
112
118
|
test_files: []
|