my-last-cv 0.0.6 → 0.0.8

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: 5d2bc19ff6ce026645ff9fc68e65345b76a3087db661be1eac66a48379b3395e
4
- data.tar.gz: 9edb1b606e386db51aa0272ea2ed87fe290c6273619fe5b65213430aa117663e
3
+ metadata.gz: 031a4dc86e72946d0fb8673b77738a6cbb3d30c2404c028267a88a78b8ae1463
4
+ data.tar.gz: b2ac4623552d0ae8f597f8dd58cb9bcb481b09f201ff899335054767cfcd1620
5
5
  SHA512:
6
- metadata.gz: e9f25db116d350985c4a016bfea94876b926702c606e93faf3e8daf239e1b027f89654fddc0d3495cc10746a1c723f98057b848058e2a32dbefe02a6e13ee8d6
7
- data.tar.gz: f2802143d81a0d3a0a2fb9e8bd46f550bf093db531e9e43172d1d0746d24713251a90bdeed255034e6593e951c2c64993f5214ae14c0bb7456b27b6d14c73582
6
+ metadata.gz: bcd26c3ab542f8b2ddf18dc894351bab8c1332181609164b47e2b79ef433d83ec6298509844f20907ee91caf1a6aceea43f451e76567dd48afc457fedd74f889
7
+ data.tar.gz: d38f99b4d9fab6a4c700628282ef21cc125590d8e4a4a1ab48ad625c5ebbed132cc1c89cc1b1b5cbf306c13bf503d4fa780d0c637c425388d8c0728345706c0f
data/README.md CHANGED
@@ -1,14 +1,123 @@
1
1
  # my-last-cv
2
- A simple gem to generate beautiful CV from a markdown file
3
2
 
4
- ## How to use it?
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
+
31
+ ## Markdown format
32
+
33
+ Use YAML front matter for contact information, a level-one heading for the name,
34
+ level-two headings for sections, and level-three headings for entries within a
35
+ section:
36
+
37
+ ```markdown
38
+ ---
39
+ title: "Ruby developer"
40
+ email: "jane@example.com"
41
+ phone: "+33 6 12 34 56 78"
42
+ linkedin: "https://www.linkedin.com/in/janedoe"
43
+ github: "https://github.com/janedoe"
44
+ website: "https://janedoe.dev"
45
+ location: "Paris, France"
46
+ ---
47
+
48
+ # Jane Doe
49
+ Short professional introduction displayed below the header.
50
+
51
+ ## Experience
52
+ ### Senior Developer — Example Corp
53
+ Introductory paragraph for this role.
54
+ - Built and maintained Ruby applications.
55
+ - Mentored other developers.
56
+
57
+ ## Skills
58
+ - Ruby
59
+ - PostgreSQL
60
+ ```
61
+
62
+ Supported front-matter contact keys are `name`, `title`, `email`, `phone`,
63
+ `linkedin`, `github`, `website`, and `location`. They are rendered with icons.
64
+
65
+ Text immediately below the main heading becomes the introduction. Section and
66
+ entry content can contain paragraphs and bullet lists. A `###` entry without a
67
+ preceding `##` section is placed in a section named `Divers`.
68
+
69
+ ## Inline Markdown support
70
+
71
+ Contact fields, paragraphs, and bullet items support:
72
+
73
+ - `**bold**`
74
+ - `*italic*`
75
+ - `` `code` ``
76
+ - `[links](https://example.com)`
77
+
78
+ Escape Markdown punctuation with a backslash when it should remain literal, for
79
+ example `\*not italic\*`.
80
+
81
+ ## Ruby API and styling
82
+
83
+ ```ruby
84
+ require "my_last_cv"
85
+
86
+ style = MyLastCV::Style.new(
87
+ header_font: "Inter",
88
+ header_size: 22,
89
+ section_font: "Inter",
90
+ section_size: 12,
91
+ body_font: "Lora",
92
+ body_size: 10,
93
+ page_options: { margin: 36 },
94
+ accent_color: "1F7AE0"
95
+ )
96
+
97
+ MyLastCV.generate("cv.md", "output/cv.pdf", style: style)
98
+ ```
99
+
100
+ `MyLastCV::Style` defaults to Helvetica, sizes `18`, `12`, and `10`, a page
101
+ margin of `48`, and a black accent color (`000000`). `page_options` is passed to
102
+ `Prawn::Document`, so Prawn page settings such as `page_size` and `layout` can
103
+ also be supplied.
104
+
11
105
  ## 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`.
106
+
107
+ Inter and Lora are bundled with the gem. To override them, provide a directory
108
+ containing `Inter-Regular.ttf`, `Inter-Bold.ttf`, `Lora-Regular.ttf`, and
109
+ `Lora-Bold.ttf`:
110
+
111
+ ```ruby
112
+ MyLastCV::Style.new(fonts_dir: "/path/to/fonts")
113
+ ```
114
+
115
+ Alternatively, set `MY_LAST_CV_FONTS_DIR=/path/to/fonts`. Font directories are
116
+ resolved in this order: `fonts_dir`, `MY_LAST_CV_FONTS_DIR`, `./fonts`, then the
117
+ fonts bundled with the gem.
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ bundle exec rake spec
123
+ ```
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,14 @@
1
+ module MyLastCV
2
+ module Icons
3
+ MAP = {
4
+ name: "fas-user",
5
+ title: "fas-briefcase",
6
+ email: "fas-envelope",
7
+ phone: "fas-phone",
8
+ linkedin: "fab-linkedin",
9
+ github: "fab-github",
10
+ website: "fas-globe",
11
+ location: "fas-location-dot"
12
+ }.freeze
13
+ end
14
+ end
@@ -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
@@ -1,116 +1,170 @@
1
+ require 'yaml'
2
+
1
3
  module MyLastCV
2
4
  class Parser
5
+ LineHandler = Struct.new(:pattern, :method)
6
+
7
+ HANDLERS = [
8
+ LineHandler.new(/^(name|title|email|phone|linkedin|github|website|location):\s*(.+)/i, :handle_contact),
9
+ LineHandler.new(/^#\s+(.*)/, :handle_title),
10
+ LineHandler.new(/^##\s+(.*)/, :handle_section),
11
+ LineHandler.new(/^###\s+(.*)/, :handle_element),
12
+ LineHandler.new(/^[-*]\s+(.*)/, :handle_bullet)
13
+ ].freeze
14
+
15
+ CONTACT_KEYS = %w[name title email phone linkedin github website location].freeze
16
+
3
17
  def initialize(markdown)
4
18
  @markdown = markdown
5
19
  end
6
20
 
7
21
  def parse
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 }
22
+ setup_state
23
+ extract_front_matter!
24
+ @markdown.each_line do |raw|
25
+ line = raw.rstrip
26
+
27
+ stripped = line.strip
28
+ next if stripped.empty? || stripped == '---'
29
+
30
+ handler = HANDLERS.find { |h| h.pattern.match?(line) }
31
+ if handler
32
+ send(handler.method, line)
33
+ else
34
+ handle_text(line)
35
+ end
25
36
  end
26
37
 
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
38
+ finalize
39
+ @result
40
+ end
41
+
42
+ private
43
+
44
+ def setup_state
45
+ @result = { sections: [] }
46
+ @current_section = nil
47
+ @current_element = nil
48
+ @pending = []
49
+ end
50
+
51
+ def extract_front_matter!
52
+ lines = @markdown.lines
53
+ return if lines.empty?
54
+ return unless lines.first&.strip == '---'
55
+
56
+ closing_index = lines[1..]&.find_index { |l| l.strip == '---' }
57
+ return unless closing_index
58
+
59
+ closing_index += 1
60
+
61
+ yaml_content = lines[1...closing_index].join
62
+ rest = lines[(closing_index + 1)..] || []
63
+
64
+ begin
65
+ data = YAML.safe_load(yaml_content) || {}
66
+ rescue StandardError
67
+ data = {}
34
68
  end
35
69
 
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
70
+ if data.is_a?(Hash)
71
+ # Prefer explicit YAML title if present
72
+ @result[:title] = data['title'].to_s.strip unless data['title'].to_s.strip.empty?
97
73
 
98
- else
99
- pending << line.strip
74
+ CONTACT_KEYS.each do |k|
75
+ v = data[k]
76
+ next if v.nil? || v.to_s.strip.empty?
77
+ @result[:contact] ||= {}
78
+ @result[:contact][k] = v.to_s.strip
100
79
  end
101
80
  end
102
81
 
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)
82
+ @markdown = rest.join
83
+ end
84
+
85
+ def flush_pending_to(target)
86
+ return if @pending.empty?
87
+ text = @pending.join(" ").strip
88
+ @pending.clear
89
+ return if text.empty?
90
+ target[:items] ||= []
91
+ target[:items] << { type: :paragraph, text: text }
92
+ end
93
+
94
+ def flush_pending_nowhere
95
+ return if @pending.empty?
96
+ text = @pending.join(" ").strip
97
+ @pending.clear
98
+ return if text.empty?
99
+ (@result[:intro] ||= []) << text
100
+ end
101
+
102
+ def finalize
103
+ if @current_element
104
+ flush_pending_to(@current_element)
105
+ elsif @current_section
106
+ flush_pending_to(@current_section)
108
107
  else
109
- flush_pending_nowhere.call
108
+ flush_pending_nowhere
110
109
  end
110
+ end
111
+
112
+ def flush_pending_current
113
+ if @current_element
114
+ flush_pending_to(@current_element)
115
+ elsif @current_section
116
+ flush_pending_to(@current_section)
117
+ else
118
+ flush_pending_nowhere
119
+ end
120
+ end
121
+
122
+ def handle_title(line)
123
+ flush_pending_current
124
+ @result[:title] = line.sub(/^#\s+/, "").strip
125
+ @current_section = nil
126
+ @current_element = nil
127
+ end
128
+
129
+ def handle_contact(line)
130
+ key, value = line.split(":", 2)
131
+ @result[:contact] ||= {}
132
+ normalized_key = key.to_s.strip.downcase
133
+ @result[:contact][normalized_key] = value.to_s.strip
134
+ end
135
+
136
+ def handle_section(line)
137
+ flush_pending_current
138
+ @current_section = { title: line.sub(/^##\s+/, "").strip, items: [], elements: [] }
139
+ @result[:sections] << @current_section
140
+ @current_element = nil
141
+ end
142
+
143
+ def handle_element(line)
144
+ flush_pending_current
145
+ @current_section ||= { title: "Divers", items: [], elements: [] }
146
+ @result[:sections] << @current_section unless @result[:sections].include?(@current_section)
147
+ @current_element = { title: line.sub(/^###\s+/, "").strip, items: [] }
148
+ @current_section[:elements] ||= []
149
+ @current_section[:elements] << @current_element
150
+ end
151
+
152
+ def handle_bullet(line)
153
+ item = { type: :bullet, text: line.sub(/^[-*]\s+/, "").strip }
154
+ if @current_element
155
+ flush_pending_to(@current_element)
156
+ @current_element[:items] << item
157
+ elsif @current_section
158
+ flush_pending_to(@current_section)
159
+ @current_section[:items] << item
160
+ else
161
+ @current_section = { title: "Divers", items: [item], elements: [] }
162
+ @result[:sections] << @current_section
163
+ end
164
+ end
111
165
 
112
- result[:contact] = (result[:contact] || []).join(" · ")
113
- result
166
+ def handle_text(line)
167
+ @pending << line.strip
114
168
  end
115
169
  end
116
170
  end
@@ -1,5 +1,8 @@
1
1
  require 'prawn'
2
+ require 'prawn/icon'
2
3
  require 'fileutils'
4
+ require_relative 'icons'
5
+ require_relative 'inline'
3
6
 
4
7
  module MyLastCV
5
8
  class Renderer
@@ -35,7 +38,7 @@ module MyLastCV
35
38
  fonts_dir = resolved_fonts_dir
36
39
  return unless fonts_dir
37
40
 
38
- # Exemple : Inter (Regular / Bold)
41
+ # Example : Inter (Regular / Bold)
39
42
  pdf.font_families.update(
40
43
  "Inter" => {
41
44
  normal: File.join(fonts_dir, "Inter-Regular.ttf"),
@@ -49,36 +52,41 @@ module MyLastCV
49
52
  end
50
53
 
51
54
  def render_header(pdf)
52
- pdf.font(@style.header_font)
53
55
  pdf.move_down 12
54
- with_color(pdf, @style.accent_color) do
55
- pdf.text(@parsed_cv[:name] || '-', size: @style.header_size, align: :center)
56
+ pdf.font(@style.body_font)
57
+ contact = @parsed_cv[:contact] || {}
58
+ contact.each_key do |key|
59
+ icon = "<icon size=\"#{@style.body_size}\">#{MyLastCV::Icons::MAP[key.to_sym]}</icon>"
60
+ pdf.icon("#{icon} #{Inline.parse(contact[key])}", inline_format: true)
56
61
  end
62
+
57
63
  pdf.move_down 6
58
- pdf.font(@style.body_font)
59
- pdf.text(@parsed_cv[:contact] || '', size: @style.body_size, align: :center)
64
+ pdf.font(@style.header_font)
65
+ with_color(pdf, @style.accent_color) do
66
+ pdf.text(@parsed_cv[:title] || '-', size: @style.header_size, align: :center)
67
+ end
68
+
69
+ pdf.move_down 4
70
+ pdf.stroke_color(@style.accent_color)
71
+ pdf.stroke_horizontal_rule
60
72
 
61
73
  if @parsed_cv[:intro]&.any?
62
74
  pdf.move_down 10
63
75
  @parsed_cv[:intro].each do |p|
64
- pdf.text(p, size: @style.body_size, leading: 2)
65
- pdf.move_down 4
76
+ pdf.text(Inline.parse(p), size: @style.body_size, leading: 2, inline_format: true)
66
77
  end
67
- else
68
- pdf.move_down 4
69
- end
70
-
71
- with_color(pdf, @style.accent_color) do
72
- pdf.stroke_horizontal_rule
73
78
  end
74
- pdf.move_down 12
79
+ pdf.move_down 10
75
80
  end
76
81
 
77
82
  def render_sections(pdf)
78
83
  (@parsed_cv[:sections] || []).each do |section|
79
84
  pdf.move_down 8
80
85
  pdf.font(@style.section_font)
81
- pdf.text(section[:title], size: @style.section_size, style: :bold)
86
+
87
+ with_color(pdf, @style.accent_color) do
88
+ pdf.text(section[:title], size: @style.section_size, style: :bold)
89
+ end
82
90
 
83
91
  render_items(pdf, section[:items])
84
92
 
@@ -100,9 +108,9 @@ module MyLastCV
100
108
  (items || []).each do |item|
101
109
  case item[:type]
102
110
  when :bullet
103
- pdf.text("• #{item[:text]}", size: @style.body_size, indent_paragraphs: 16)
111
+ pdf.text("• #{Inline.parse(item[:text])}", size: @style.body_size, indent_paragraphs: 16, inline_format: true)
104
112
  when :paragraph
105
- pdf.text(item[:text], size: @style.body_size, leading: 2)
113
+ pdf.text(Inline.parse(item[:text]), size: @style.body_size, leading: 2, inline_format: true)
106
114
  pdf.move_down 4
107
115
  else
108
116
  # fallback (au cas où)
@@ -1,3 +1,3 @@
1
1
  module MyLastCV
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.8"
3
3
  end
data/lib/my_last_cv.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'my_last_cv/version'
2
+ require_relative 'my_last_cv/inline'
2
3
  require_relative 'my_last_cv/parser'
3
4
  require_relative 'my_last_cv/style'
4
5
  require_relative 'my_last_cv/renderer'
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.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxime Hanicotte
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '2.5'
26
+ - !ruby/object:Gem::Dependency
27
+ name: prawn-icon
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '4.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '4.1'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: rake
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -62,7 +76,13 @@ extra_rdoc_files: []
62
76
  files:
63
77
  - README.md
64
78
  - exe/my_last_cv
79
+ - fonts/Inter-Bold.ttf
80
+ - fonts/Inter-Regular.ttf
81
+ - fonts/Lora-Bold.ttf
82
+ - fonts/Lora-Regular.ttf
65
83
  - lib/my_last_cv.rb
84
+ - lib/my_last_cv/icons.rb
85
+ - lib/my_last_cv/inline.rb
66
86
  - lib/my_last_cv/parser.rb
67
87
  - lib/my_last_cv/renderer.rb
68
88
  - lib/my_last_cv/style.rb
@@ -91,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
111
  - !ruby/object:Gem::Version
92
112
  version: '0'
93
113
  requirements: []
94
- rubygems_version: 3.7.1
114
+ rubygems_version: 3.7.2
95
115
  specification_version: 4
96
116
  summary: Generate your CV from Markdown to PDF
97
117
  test_files: []