my-last-cv 0.0.4 → 0.0.6
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 +5 -0
- data/lib/my_last_cv/parser.rb +103 -20
- data/lib/my_last_cv/renderer.rb +41 -6
- data/lib/my_last_cv/version.rb +1 -1
- metadata +38 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d2bc19ff6ce026645ff9fc68e65345b76a3087db661be1eac66a48379b3395e
|
4
|
+
data.tar.gz: 9edb1b606e386db51aa0272ea2ed87fe290c6273619fe5b65213430aa117663e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9f25db116d350985c4a016bfea94876b926702c606e93faf3e8daf239e1b027f89654fddc0d3495cc10746a1c723f98057b848058e2a32dbefe02a6e13ee8d6
|
7
|
+
data.tar.gz: f2802143d81a0d3a0a2fb9e8bd46f550bf093db531e9e43172d1d0746d24713251a90bdeed255034e6593e951c2c64993f5214ae14c0bb7456b27b6d14c73582
|
data/README.md
CHANGED
@@ -7,3 +7,8 @@ bundle add my-last-cv
|
|
7
7
|
bundle install
|
8
8
|
bundle exec my_last_cv sample/cv.md output/cv.pdf
|
9
9
|
```
|
10
|
+
|
11
|
+
## Custom fonts
|
12
|
+
By default, the gem looks for fonts in `./fonts` of the calling project.
|
13
|
+
You can override this with `Style.new(fonts_dir: "/path/to/fonts")`
|
14
|
+
or `MY_LAST_CV_FONTS_DIR=/path/to/fonts`.
|
data/lib/my_last_cv/parser.rb
CHANGED
@@ -5,29 +5,112 @@ module MyLastCV
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def parse
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
8
|
+
lines = @markdown.lines.map(&:chomp)
|
9
|
+
result = { sections: [] }
|
10
|
+
|
11
|
+
current_section = nil
|
12
|
+
current_element = nil
|
13
|
+
|
14
|
+
# buffer
|
15
|
+
pending = []
|
16
|
+
|
17
|
+
# helpers
|
18
|
+
flush_pending_to = lambda do |target|
|
19
|
+
return if pending.empty?
|
20
|
+
text = pending.join(" ").strip
|
21
|
+
pending.clear
|
22
|
+
return if text.empty?
|
23
|
+
target[:items] ||= []
|
24
|
+
target[:items] << { type: :paragraph, text: text }
|
25
|
+
end
|
26
|
+
|
27
|
+
flush_pending_nowhere = lambda do
|
28
|
+
return if pending.empty?
|
29
|
+
text = pending.join(" ").strip
|
30
|
+
pending.clear
|
31
|
+
return if text.empty?
|
32
|
+
result[:intro] ||= []
|
33
|
+
result[:intro] << text
|
34
|
+
end
|
35
|
+
|
36
|
+
lines.each do |raw|
|
37
|
+
line = raw.rstrip
|
38
|
+
next if line.strip.empty?
|
39
|
+
|
40
|
+
if (m = line.match(/^#\s+(.*)/)) # New header
|
41
|
+
if current_element
|
42
|
+
flush_pending_to.call(current_element)
|
43
|
+
elsif current_section
|
44
|
+
flush_pending_to.call(current_section)
|
45
|
+
else
|
46
|
+
flush_pending_nowhere.call
|
47
|
+
end
|
48
|
+
|
49
|
+
result[:name] = m[1].strip
|
50
|
+
current_section = nil
|
51
|
+
current_element = nil
|
52
|
+
|
53
|
+
elsif (m = line.match(/^(email|phone|location):\s*(.+)/i))
|
54
|
+
(result[:contact] ||= []) << m[2].strip
|
55
|
+
|
56
|
+
elsif (m = line.match(/^##\s+(.*)/)) # New section
|
57
|
+
if current_element
|
58
|
+
flush_pending_to.call(current_element)
|
59
|
+
elsif current_section
|
60
|
+
flush_pending_to.call(current_section)
|
61
|
+
else
|
62
|
+
flush_pending_nowhere.call
|
63
|
+
end
|
64
|
+
|
65
|
+
current_section = { title: m[1].strip, items: [], elements: [] }
|
66
|
+
result[:sections] << current_section
|
67
|
+
current_element = nil
|
68
|
+
|
69
|
+
elsif (m = line.match(/^###\s+(.*)/)) # New element
|
70
|
+
if current_element
|
71
|
+
flush_pending_to.call(current_element)
|
72
|
+
elsif current_section
|
73
|
+
flush_pending_to.call(current_section)
|
74
|
+
else
|
75
|
+
flush_pending_nowhere.call
|
76
|
+
end
|
77
|
+
|
78
|
+
current_section ||= { title: "Divers", items: [], elements: [] }
|
79
|
+
result[:sections] << current_section unless result[:sections].include?(current_section)
|
80
|
+
|
81
|
+
current_element = { title: m[1].strip, items: [] }
|
82
|
+
current_section[:elements] ||= []
|
83
|
+
current_section[:elements] << current_element
|
84
|
+
|
85
|
+
elsif (m = line.match(/^[-*]\s+(.*)/)) # Bullet point
|
86
|
+
item = { type: :bullet, text: m[1].strip }
|
87
|
+
if current_element
|
88
|
+
flush_pending_to.call(current_element)
|
89
|
+
current_element[:items] << item
|
90
|
+
elsif current_section
|
91
|
+
flush_pending_to.call(current_section)
|
92
|
+
current_section[:items] << item
|
93
|
+
else
|
94
|
+
current_section = { title: "Divers", items: [item], elements: [] }
|
95
|
+
result[:sections] << current_section
|
96
|
+
end
|
97
|
+
|
98
|
+
else
|
99
|
+
pending << line.strip
|
26
100
|
end
|
27
101
|
end
|
28
102
|
|
29
|
-
|
30
|
-
|
103
|
+
# End of parsing, flush any remaining pending text
|
104
|
+
if current_element
|
105
|
+
flush_pending_to.call(current_element)
|
106
|
+
elsif current_section
|
107
|
+
flush_pending_to.call(current_section)
|
108
|
+
else
|
109
|
+
flush_pending_nowhere.call
|
110
|
+
end
|
111
|
+
|
112
|
+
result[:contact] = (result[:contact] || []).join(" · ")
|
113
|
+
result
|
31
114
|
end
|
32
115
|
end
|
33
116
|
end
|
data/lib/my_last_cv/renderer.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'prawn'
|
2
|
-
require
|
2
|
+
require 'fileutils'
|
3
3
|
|
4
4
|
module MyLastCV
|
5
5
|
class Renderer
|
@@ -57,6 +57,17 @@ module MyLastCV
|
|
57
57
|
pdf.move_down 6
|
58
58
|
pdf.font(@style.body_font)
|
59
59
|
pdf.text(@parsed_cv[:contact] || '', size: @style.body_size, align: :center)
|
60
|
+
|
61
|
+
if @parsed_cv[:intro]&.any?
|
62
|
+
pdf.move_down 10
|
63
|
+
@parsed_cv[:intro].each do |p|
|
64
|
+
pdf.text(p, size: @style.body_size, leading: 2)
|
65
|
+
pdf.move_down 4
|
66
|
+
end
|
67
|
+
else
|
68
|
+
pdf.move_down 4
|
69
|
+
end
|
70
|
+
|
60
71
|
with_color(pdf, @style.accent_color) do
|
61
72
|
pdf.stroke_horizontal_rule
|
62
73
|
end
|
@@ -64,14 +75,38 @@ module MyLastCV
|
|
64
75
|
end
|
65
76
|
|
66
77
|
def render_sections(pdf)
|
67
|
-
@parsed_cv[:sections].each do |section|
|
78
|
+
(@parsed_cv[:sections] || []).each do |section|
|
68
79
|
pdf.move_down 8
|
69
80
|
pdf.font(@style.section_font)
|
70
81
|
pdf.text(section[:title], size: @style.section_size, style: :bold)
|
71
|
-
|
72
|
-
pdf
|
73
|
-
|
74
|
-
|
82
|
+
|
83
|
+
render_items(pdf, section[:items])
|
84
|
+
|
85
|
+
(section[:elements] || []).each do |el|
|
86
|
+
pdf.move_down 6
|
87
|
+
pdf.font(@style.section_font)
|
88
|
+
pdf.text(el[:title], size: (@style.section_size - 3), style: :bold)
|
89
|
+
render_items(pdf, el[:items])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def render_items(pdf, items)
|
95
|
+
return if items.nil? || items.empty?
|
96
|
+
|
97
|
+
pdf.move_down 4
|
98
|
+
pdf.font(@style.body_font)
|
99
|
+
|
100
|
+
(items || []).each do |item|
|
101
|
+
case item[:type]
|
102
|
+
when :bullet
|
103
|
+
pdf.text("• #{item[:text]}", size: @style.body_size, indent_paragraphs: 16)
|
104
|
+
when :paragraph
|
105
|
+
pdf.text(item[:text], size: @style.body_size, leading: 2)
|
106
|
+
pdf.move_down 4
|
107
|
+
else
|
108
|
+
# fallback (au cas où)
|
109
|
+
pdf.text(item.to_s, size: @style.body_size)
|
75
110
|
end
|
76
111
|
end
|
77
112
|
end
|
data/lib/my_last_cv/version.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.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxime Hanicotte
|
@@ -23,6 +23,36 @@ dependencies:
|
|
23
23
|
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '2.5'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '13.3'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '13.3'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: rspec
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.13'
|
47
|
+
type: :development
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.13'
|
54
|
+
description: MyLastCV turns a Markdown CV into a styled PDF using Prawn. Configurable
|
55
|
+
styles (fonts, sizes, margins, accent color) and project-level custom fonts support.
|
26
56
|
email:
|
27
57
|
- max_hanicotte@msn.com
|
28
58
|
executables:
|
@@ -40,7 +70,13 @@ files:
|
|
40
70
|
homepage: https://www.maxime.hanicotte.net/my-last-cv/
|
41
71
|
licenses:
|
42
72
|
- GPL-3.0-or-later
|
43
|
-
metadata:
|
73
|
+
metadata:
|
74
|
+
homepage_uri: https://www.maxime.hanicotte.net/my-last-cv/
|
75
|
+
source_code_uri: https://github.com/maxime-hanicotte/my-last-cv
|
76
|
+
changelog_uri: https://github.com/maxime-hanicotte/my_last_cv/blob/main/CHANGELOG.md
|
77
|
+
bug_tracker_uri: https://github.com/maxime-hanicotte/my_last_cv/issues
|
78
|
+
documentation_uri: https://github.com/maxime-hanicotte/my_last_cv#readme
|
79
|
+
rubygems_mfa_required: 'true'
|
44
80
|
rdoc_options: []
|
45
81
|
require_paths:
|
46
82
|
- lib
|