my-last-cv 0.0.5 → 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/lib/my_last_cv/parser.rb +91 -37
- data/lib/my_last_cv/renderer.rb +34 -15
- 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/lib/my_last_cv/parser.rb
CHANGED
@@ -5,58 +5,112 @@ module MyLastCV
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def parse
|
8
|
-
|
9
|
-
|
10
|
-
section_actuelle = nil
|
11
|
-
element_actuel = nil
|
8
|
+
lines = @markdown.lines.map(&:chomp)
|
9
|
+
result = { sections: [] }
|
12
10
|
|
13
|
-
|
14
|
-
|
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
|
15
38
|
next if line.strip.empty?
|
16
39
|
|
17
|
-
if (m = line.match(/^#\s+(.*)/))
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
21
48
|
|
22
|
-
|
23
|
-
|
49
|
+
result[:name] = m[1].strip
|
50
|
+
current_section = nil
|
51
|
+
current_element = nil
|
24
52
|
|
25
|
-
elsif (m = line.match(
|
26
|
-
|
27
|
-
resultat[:sections] << section_actuelle
|
28
|
-
element_actuel = nil
|
53
|
+
elsif (m = line.match(/^(email|phone|location):\s*(.+)/i))
|
54
|
+
(result[:contact] ||= []) << m[2].strip
|
29
55
|
|
30
|
-
elsif (m = line.match(
|
31
|
-
|
32
|
-
|
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
|
33
64
|
|
34
|
-
|
35
|
-
|
36
|
-
|
65
|
+
current_section = { title: m[1].strip, items: [], elements: [] }
|
66
|
+
result[:sections] << current_section
|
67
|
+
current_element = nil
|
37
68
|
|
38
|
-
elsif (m = line.match(
|
39
|
-
if
|
40
|
-
|
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)
|
41
74
|
else
|
42
|
-
|
43
|
-
resultat[:sections] << section_actuelle unless resultat[:sections].include?(section_actuelle)
|
44
|
-
section_actuelle[:items] << m[1].strip
|
75
|
+
flush_pending_nowhere.call
|
45
76
|
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
51
93
|
else
|
52
|
-
|
53
|
-
|
94
|
+
current_section = { title: "Divers", items: [item], elements: [] }
|
95
|
+
result[:sections] << current_section
|
54
96
|
end
|
97
|
+
|
98
|
+
else
|
99
|
+
pending << line.strip
|
55
100
|
end
|
56
101
|
end
|
57
102
|
|
58
|
-
|
59
|
-
|
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
|
60
114
|
end
|
61
115
|
end
|
62
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,33 +75,41 @@ 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
82
|
|
72
|
-
|
73
|
-
pdf.move_down 4
|
74
|
-
pdf.font(@style.body_font)
|
75
|
-
section[:items].each do |item|
|
76
|
-
pdf.text("• #{item}", size: @style.body_size, indent_paragraphs: 16)
|
77
|
-
end
|
78
|
-
end
|
83
|
+
render_items(pdf, section[:items])
|
79
84
|
|
80
85
|
(section[:elements] || []).each do |el|
|
81
86
|
pdf.move_down 6
|
82
87
|
pdf.font(@style.section_font)
|
83
88
|
pdf.text(el[:title], size: (@style.section_size - 3), style: :bold)
|
84
|
-
|
85
|
-
pdf.move_down 2
|
86
|
-
pdf.font(@style.body_font)
|
87
|
-
(el[:items] || []).each do |item|
|
88
|
-
pdf.text("• #{item}", size: @style.body_size, indent_paragraphs: 20)
|
89
|
-
end
|
89
|
+
render_items(pdf, el[:items])
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
93
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)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
94
113
|
|
95
114
|
def with_color(pdf, hex)
|
96
115
|
return yield if hex.to_s.strip.empty?
|
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
|