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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94c3e91fc809c66ce9bff0a797dbc4701562502617080a3dfc1980ff72d6d7a8
4
- data.tar.gz: 0d92a8897223468db3de303b7a23e312873cc2da76d3b0976e2f642e7863e442
3
+ metadata.gz: 5d2bc19ff6ce026645ff9fc68e65345b76a3087db661be1eac66a48379b3395e
4
+ data.tar.gz: 9edb1b606e386db51aa0272ea2ed87fe290c6273619fe5b65213430aa117663e
5
5
  SHA512:
6
- metadata.gz: cdfc99a9a7ae9d9145c643df109dedb8f9c02860e1d2d92c859a4d28a55a82bb8aff49e5d1fd478683b1e8d98f952d43d88a243749c12691f39a31489c000c4d
7
- data.tar.gz: b8970a939e5ff4f47640dc3021cb743e4794e58a96d41db4c74ce4ed75949cc4481fd274d7b9a708a2c3badb8d257fe5982308f7b3fa931b1329cfb9d260fb20
6
+ metadata.gz: e9f25db116d350985c4a016bfea94876b926702c606e93faf3e8daf239e1b027f89654fddc0d3495cc10746a1c723f98057b848058e2a32dbefe02a6e13ee8d6
7
+ data.tar.gz: f2802143d81a0d3a0a2fb9e8bd46f550bf093db531e9e43172d1d0746d24713251a90bdeed255034e6593e951c2c64993f5214ae14c0bb7456b27b6d14c73582
@@ -5,58 +5,112 @@ module MyLastCV
5
5
  end
6
6
 
7
7
  def parse
8
- lignes = @markdown.lines.map(&:chomp)
9
- resultat = { sections: [] }
10
- section_actuelle = nil
11
- element_actuel = nil
8
+ lines = @markdown.lines.map(&:chomp)
9
+ result = { sections: [] }
12
10
 
13
- lignes.each do |ligne|
14
- line = ligne
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
- resultat[:name] = m[1].strip
19
- section_actuelle = nil
20
- element_actuel = nil
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
- elsif (m = line.match(/^(email|phone|location):\s*(.+)/i))
23
- (resultat[:contact] ||= []) << m[2].strip
49
+ result[:name] = m[1].strip
50
+ current_section = nil
51
+ current_element = nil
24
52
 
25
- elsif (m = line.match(/^##\s+(.*)/))
26
- section_actuelle = { title: m[1].strip, items: [], elements: [] }
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(/^###\s+(.*)/))
31
- section_actuelle ||= { title: "Divers", items: [], elements: [] }
32
- resultat[:sections] << section_actuelle unless resultat[:sections].include?(section_actuelle)
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
- element_actuel = { title: m[1].strip, items: [] }
35
- section_actuelle[:elements] ||= []
36
- section_actuelle[:elements] << element_actuel
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(/^[-*]\s+(.*)/))
39
- if element_actuel
40
- element_actuel[:items] << m[1].strip
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
- section_actuelle ||= { title: "Divers", items: [], elements: [] }
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
- else
47
- if element_actuel && !element_actuel[:items].empty?
48
- element_actuel[:items][-1] += " " + line.strip
49
- elsif section_actuelle && !section_actuelle[:items].empty?
50
- section_actuelle[:items][-1] += " " + line.strip
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
- section_actuelle ||= { title: "Divers", items: [], elements: [] }
53
- section_actuelle[:items] << line.strip
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
- resultat[:contact] = (resultat[:contact] || []).join(" · ")
59
- resultat
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
@@ -1,5 +1,5 @@
1
1
  require 'prawn'
2
- require "fileutils"
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
- unless section[:items].nil? || section[:items].empty?
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?
@@ -1,3 +1,3 @@
1
1
  module MyLastCV
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
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.5
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