multiformat-cv2 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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +34 -0
- data/bin/multiformatcv +20 -0
- data/lib/multiformatcv.rb +60 -0
- data/lib/multiformatcv/contact.rb +32 -0
- data/lib/multiformatcv/job.rb +42 -0
- data/lib/multiformatcv/personal.rb +26 -0
- data/lib/multiformatcv/project.rb +60 -0
- data/lib/multiformatcv/resume.rb +127 -0
- data/lib/multiformatcv/templates/cv.html.erb +66 -0
- data/lib/multiformatcv/templates/cv.tex.erb +66 -0
- data/lib/multiformatcv/version.rb +4 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ea0b2f804d7fb2f5343f838661479add46a24a796fb87bff6ca464233bf9d88a
|
4
|
+
data.tar.gz: 469da0d9732299829d39f1837767cbf27eab1af019ea826a62d5d24139297f27
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ea427348ba5d91c7458e2edbdcb7a0e847cf5d57880ee35706726dee23321fda0d87e783057ab6c5960b11e5d4ced7bcb19dc18affe726ee4c15841f3b9ae8b
|
7
|
+
data.tar.gz: 9d4c3f21ca9cd0977eaa23cc88f290523f35aef2b1a6f172e9b996671d0da9960d7342c57d602418ea3c7c1c705f8ac98b66f33b27cb41810ddb831861248716
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2004-2019 David Heinemeier Hansson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Multiformat CV
|
2
|
+
|
3
|
+
Multi-format CV generator from YAML files and ERB templates.
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
```bash
|
8
|
+
$ gem install multiformat-cv
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Taking this repository's `sample` directory as a starting point, we can
|
14
|
+
generate the CV as follows:
|
15
|
+
|
16
|
+
```bash
|
17
|
+
$ tree
|
18
|
+
.
|
19
|
+
├── data
|
20
|
+
│ ├── contact.yml
|
21
|
+
│ ├── jobs.yml
|
22
|
+
│ └── personal.yml
|
23
|
+
└── onepager
|
24
|
+
├── cv.css
|
25
|
+
└── cv.html.erb
|
26
|
+
|
27
|
+
2 directories, 5 files
|
28
|
+
$ multiformatcv -d sample/data -s sample/onepager -o sample/onepager/cv.html
|
29
|
+
$ open sample/onepager/cv.html
|
30
|
+
```
|
31
|
+
|
32
|
+
Which, after being printed from the browser, would look something like this:
|
33
|
+
|
34
|
+

|
data/bin/multiformatcv
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "multiformatcv"
|
5
|
+
require "mercenary"
|
6
|
+
|
7
|
+
Mercenary.program(:multiformatcv) do |p|
|
8
|
+
p.version MultiformatCV::VERSION
|
9
|
+
p.description "Generate your CV in different formats"
|
10
|
+
p.syntax "multiformatcv <format> [-d './data'] [-t <directory>] [-o <file>]"
|
11
|
+
|
12
|
+
p.option "format", "-f FORMAT", "--format FORMAT", "Output format", String
|
13
|
+
p.option "data_dir", "-d DIR", "--data DIR", "YAML data files directory", String
|
14
|
+
p.option "templates", "-s DIR", "--templates DIR", "Templates directory, MUST contain cv.<format>.erb file", String
|
15
|
+
p.option "output", "-o FILE", "--outpu FILEt", "Output where to write result, defaults to STDOUT", String
|
16
|
+
|
17
|
+
p.action do |args, options|
|
18
|
+
MultiformatCV::generate(options)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'erubi'
|
3
|
+
|
4
|
+
module MultiformatCV
|
5
|
+
|
6
|
+
# YAML files that will be read from the specified directory
|
7
|
+
YML_FILES = %w( contact jobs personal )
|
8
|
+
|
9
|
+
# Parse yaml files located at data directory
|
10
|
+
#
|
11
|
+
# @param [Hash] opts Options to specify format and templates source
|
12
|
+
# @option opts [String] 'data_dir' Directory where the YAML files are located.
|
13
|
+
# @option opts [Symbol] 'format' One of [ :html, :tex ]
|
14
|
+
# @option opts [Symbol] 'output' Output file
|
15
|
+
# @option opts [String] 'templates' Directory where templates are located,
|
16
|
+
# expected template files are `cv.#{ format }.erb`
|
17
|
+
#
|
18
|
+
# @return [MultiformatCV::Resume] Resume with parsed data
|
19
|
+
# @see https://www.rubydoc.info/gems/erubi/1.8.0 Erubi documentation
|
20
|
+
# @see Erubi::Engine
|
21
|
+
|
22
|
+
def self.generate(opts = {})
|
23
|
+
opts['format'] ||= 'html'
|
24
|
+
opts['data_dir'] ||= 'data'
|
25
|
+
opts['templates'] ||= default_template_path
|
26
|
+
opts['output'] ||= nil
|
27
|
+
|
28
|
+
template = File.read("#{ opts['templates'] }/cv.#{ opts['format'] }.erb")
|
29
|
+
resume = Resume.new
|
30
|
+
yml = nil
|
31
|
+
|
32
|
+
YML_FILES.each do |f|
|
33
|
+
yml = YAML.load_file("#{ opts['data_dir'] }/#{ f }.yml")
|
34
|
+
if yml then
|
35
|
+
resume.send("add_#{ f }", yml[f])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
resume.rendered = eval Erubi::Engine.new(template).src
|
40
|
+
|
41
|
+
if opts['output'] then
|
42
|
+
File.open(opts['output'], 'w') { |f| f.write(resume.rendered) }
|
43
|
+
end
|
44
|
+
|
45
|
+
resume
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def self.default_template_path
|
51
|
+
File.expand_path('../../sample/onepager', __FILE__)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
require 'multiformatcv/contact'
|
56
|
+
require 'multiformatcv/job'
|
57
|
+
require 'multiformatcv/personal'
|
58
|
+
require 'multiformatcv/project'
|
59
|
+
require 'multiformatcv/resume'
|
60
|
+
require 'multiformatcv/version'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class MultiformatCV::Contact
|
2
|
+
attr_accessor :name,
|
3
|
+
:title,
|
4
|
+
:phone,
|
5
|
+
:email
|
6
|
+
|
7
|
+
# Hash of links
|
8
|
+
#
|
9
|
+
# == Example:
|
10
|
+
# links = { github: 'https://www.github.com/john.doe/personal-dashboard' }
|
11
|
+
attr_accessor :links
|
12
|
+
|
13
|
+
# Create Contact instance
|
14
|
+
#
|
15
|
+
# == Example:
|
16
|
+
# contact = MultiformatCV::Contact.new(title: 'Accountant', name: 'John Doe')
|
17
|
+
#
|
18
|
+
# @param [Hash] h Instance initializer; keys *MUST* be strings
|
19
|
+
# @option h [String] 'name'
|
20
|
+
# @option h [String] 'title'
|
21
|
+
# @option h [String] 'email'
|
22
|
+
# @option h [String] 'phone'
|
23
|
+
# @option h [Hash<String, String>] 'links'
|
24
|
+
|
25
|
+
def initialize(h = {})
|
26
|
+
@name = h['name']
|
27
|
+
@title = h['title']
|
28
|
+
@email = h['email']
|
29
|
+
@phone = h['phone']
|
30
|
+
@links = h['links']
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class MultiformatCV::Job
|
2
|
+
attr_accessor :position,
|
3
|
+
:company,
|
4
|
+
:start_date,
|
5
|
+
:end_date,
|
6
|
+
:summary
|
7
|
+
|
8
|
+
# List of projects that you worked on during this job
|
9
|
+
# @return [Array<MultiformatCV::Project>]
|
10
|
+
attr_accessor :projects
|
11
|
+
|
12
|
+
# Create Job instance
|
13
|
+
#
|
14
|
+
# == Example:
|
15
|
+
# job = MultiformatCV::Job.new(position: 'Accountant', company: 'Accountants Inc.')
|
16
|
+
#
|
17
|
+
# @param [Hash] h Instance initializer; keys *MUST* be strings
|
18
|
+
# @option h [String] 'position'
|
19
|
+
# @option h [String] 'company'
|
20
|
+
# @option h [String] 'start_date'
|
21
|
+
# @option h [String] 'end_date'
|
22
|
+
# @option h [String] 'summary'
|
23
|
+
# @option h [Array<Hash>] 'projects' List of hashes that will be used to
|
24
|
+
# initialize new MultiformatCV::Porject entries
|
25
|
+
#
|
26
|
+
# @see MultiformatCV::Project
|
27
|
+
|
28
|
+
def initialize(h = {})
|
29
|
+
@position = h['position']
|
30
|
+
@company = h['company']
|
31
|
+
@start_date = h['start_date']
|
32
|
+
@end_date = h['end_date']
|
33
|
+
@summary = h['summary']
|
34
|
+
@projects = []
|
35
|
+
|
36
|
+
if h['projects']
|
37
|
+
h['projects'].each do |p|
|
38
|
+
@projects << MultiformatCV::Project.new(p)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class MultiformatCV::Personal
|
2
|
+
attr_accessor :summary
|
3
|
+
|
4
|
+
# List of personal projects
|
5
|
+
# @return [Array<MultiformatCV::Project>]
|
6
|
+
attr_accessor :projects
|
7
|
+
|
8
|
+
# Create Personal information instance
|
9
|
+
#
|
10
|
+
# == Example:
|
11
|
+
# personal = MultiformatCV::Personal.new(summary: 'Volunteer at...', projects: [])
|
12
|
+
#
|
13
|
+
# @param [Hash] h Instance initializer; keys *MUST* be strings
|
14
|
+
# @option h [String] 'summary'
|
15
|
+
# @option h [Array<Hash>] 'projects' List of hashes that will be used to
|
16
|
+
# initialize new MultiformatCV::Porject entries
|
17
|
+
#
|
18
|
+
# @see MultiformatCV::Project
|
19
|
+
|
20
|
+
def initialize(h = {})
|
21
|
+
@summary = h['summary']
|
22
|
+
@projects = []
|
23
|
+
|
24
|
+
h['projects'].each { |p| @projects << MultiformatCV::Project.new(p) }
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class MultiformatCV::Project
|
2
|
+
attr_accessor :name,
|
3
|
+
:position,
|
4
|
+
:summary,
|
5
|
+
:tasks,
|
6
|
+
:skills
|
7
|
+
|
8
|
+
# Repository URL for the project
|
9
|
+
attr_accessor :repo
|
10
|
+
|
11
|
+
# Page or site URL for the project
|
12
|
+
attr_accessor :url
|
13
|
+
|
14
|
+
# Create Project instance
|
15
|
+
#
|
16
|
+
# == Example:
|
17
|
+
# project = MultiformatCV::Project.new(name: 'Life Solver (TM)', summary: '...', ...)
|
18
|
+
#
|
19
|
+
# @param [Hash] h Instance initializer; keys *MUST* be strings
|
20
|
+
# @option h [String] 'name'
|
21
|
+
# @option h [String] 'position'
|
22
|
+
# @option h [String] 'start_date'
|
23
|
+
# @option h [String] 'end_date'
|
24
|
+
# @option h [String] 'repo' Repository URL
|
25
|
+
# @option h [String] 'url' URL for the project
|
26
|
+
# @option h [String] 'summary' Project description, goals, etc.
|
27
|
+
# @option h [Array<String>] 'tasks' Tasks done for the project
|
28
|
+
# @option h [Array<String>] 'skills' skills used in the project
|
29
|
+
|
30
|
+
def initialize(h = {})
|
31
|
+
@name = h['name']
|
32
|
+
@position = h['position']
|
33
|
+
@start_date = h['start_date']
|
34
|
+
@end_date = h['end_date']
|
35
|
+
@repo = h['repo']
|
36
|
+
@summary = h['summary']
|
37
|
+
@url = h['url']
|
38
|
+
@tasks = []
|
39
|
+
@skills = []
|
40
|
+
|
41
|
+
h['tasks'].each { |t| @tasks << t } if h['tasks']
|
42
|
+
h['skills'].each { |t| @skills << t } if h['skills']
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [DateTime] Date or nil
|
46
|
+
def end_date
|
47
|
+
if @end_date and @end_date != ''
|
48
|
+
return DateTime.parse(@end_date)
|
49
|
+
end
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [DateTime] Date or nil
|
54
|
+
def start_date
|
55
|
+
if @start_date and @start_date != ''
|
56
|
+
return DateTime.parse(@start_date)
|
57
|
+
end
|
58
|
+
return nil
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class MultiformatCV::Resume
|
4
|
+
# Contact information
|
5
|
+
# @return [MultiformatCV::Contact]
|
6
|
+
attr_accessor :contact
|
7
|
+
|
8
|
+
# List of jobs
|
9
|
+
# @return [Array<MultiformatCV::Job>]
|
10
|
+
attr_accessor :jobs
|
11
|
+
|
12
|
+
# List of skills
|
13
|
+
# @key skill name
|
14
|
+
# @value time duration in months
|
15
|
+
# @return [Hash]
|
16
|
+
attr_accessor :skills
|
17
|
+
|
18
|
+
# Personal accomplishments and projects
|
19
|
+
# @return [MultiformatCV::Personal]
|
20
|
+
attr_accessor :personal
|
21
|
+
|
22
|
+
# Rendered templates with CV data
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :rendered
|
25
|
+
|
26
|
+
# Initialize Resume
|
27
|
+
#
|
28
|
+
# @param [Hash] h Options
|
29
|
+
# @option h [Array<MultiformatCV::Contact>] 'contact' Contact information
|
30
|
+
# @option h [Array<MultiformatCV::Job>] 'jobs' Jobs list
|
31
|
+
# @option h [Array<MultiformatCV::Personal>] 'personal' Personal information
|
32
|
+
|
33
|
+
def initialize(h = {})
|
34
|
+
@contact = MultiformatCV::Contact.new(h['contact'] || []) if h['contact']
|
35
|
+
@jobs = []
|
36
|
+
@skills = {}
|
37
|
+
@personal = MultiformatCV::Personal.new(h['personal'] || []) if h['personal']
|
38
|
+
|
39
|
+
h['jobs'].each { |j| @jobs << MultiformatCV::Job.new(j) } if h['jobs']
|
40
|
+
|
41
|
+
estimate_skills_experience_duration! if jobs.length > 0
|
42
|
+
end
|
43
|
+
|
44
|
+
# Set contact information
|
45
|
+
# @param [Hash] h Hash used to initialize new MultiformatCV::Contact
|
46
|
+
# @see MultiformatCV::Contact
|
47
|
+
|
48
|
+
def add_contact(h = {})
|
49
|
+
@contact = MultiformatCV::Contact.new(h)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add list of job entries to @jobs list
|
53
|
+
#
|
54
|
+
# @param [Array<Hash>] arr List of hashes that will be used to initialize new
|
55
|
+
# MultiformatCV::Job entries
|
56
|
+
#
|
57
|
+
# @see MultiformatCV::Job
|
58
|
+
|
59
|
+
def add_jobs(arr = [])
|
60
|
+
arr.each { |j| @jobs << MultiformatCV::Job.new(j) }
|
61
|
+
estimate_skills_experience_duration!
|
62
|
+
end
|
63
|
+
|
64
|
+
# Set personal information
|
65
|
+
# @param [Hash] h Hash used to initialize new MultiformatCV::Personal
|
66
|
+
# @see MultiformatCV::Personal
|
67
|
+
|
68
|
+
def add_personal(h = {})
|
69
|
+
@personal = MultiformatCV::Personal.new(h)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# A skill can be shared among projects, so we need to **NOT** count the
|
75
|
+
# same skill more than once if it appears in more than one.
|
76
|
+
#
|
77
|
+
# We do a naive calculation of _assuming_ if a skill has the same
|
78
|
+
# duration in more than one project, then we count it only once.
|
79
|
+
#
|
80
|
+
# **NOTE**: the way dates are parsed, if they don't specify the day,
|
81
|
+
# start of the month assumed; if they don't specify month, start of the
|
82
|
+
# year is assumed.
|
83
|
+
#
|
84
|
+
# For example, this approach will give approximate results when
|
85
|
+
# `skill1` was used from January 'til March in `project1` and from
|
86
|
+
# June 'til August in `project2`, giving a total of 4 months
|
87
|
+
# assuming dates are:
|
88
|
+
#
|
89
|
+
# * 2020-01-01 -> 2020-03-01: 2 months
|
90
|
+
# * 2020-06-01 -> 2020-08-01: 2 months
|
91
|
+
|
92
|
+
def estimate_skills_experience_duration!
|
93
|
+
jobs.each do |job|
|
94
|
+
job_skills = {}
|
95
|
+
default_start_date = job.start_date
|
96
|
+
default_end_date = job.end_date || Time.now # present/current job
|
97
|
+
|
98
|
+
job.projects.each do |proj|
|
99
|
+
start_date = proj.start_date || default_start_date
|
100
|
+
end_date = proj.end_date || default_end_date
|
101
|
+
|
102
|
+
proj.skills.each do |s|
|
103
|
+
job_skills[s] ||= []
|
104
|
+
job_skills[s] << diff_in_months(start_date.to_time, end_date.to_time)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# we assume that if the same skill has the same duration twice for the
|
109
|
+
# same job, the projects were developed in parallel so we count the skill
|
110
|
+
# only once
|
111
|
+
job_skills.each { |s, arr| job_skills[s] = arr.uniq.sum }
|
112
|
+
skills.merge!(job_skills) { |k, oldval, newval| oldval + newval }
|
113
|
+
end
|
114
|
+
|
115
|
+
skills
|
116
|
+
end
|
117
|
+
|
118
|
+
# Generic (30-day) month duration in seconds
|
119
|
+
ONE_MONTH = 3600 * 24 * 30
|
120
|
+
|
121
|
+
# @param [Time] t1
|
122
|
+
# @param [Time] t2
|
123
|
+
# @return [Integer] Difference in months between dates
|
124
|
+
def diff_in_months(t1, t2)
|
125
|
+
((t1 - t2) / ONE_MONTH).abs.round
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
5
|
+
<title><%= "#{ resume.contact.name } - #{ resume.contact.title }" %></title>
|
6
|
+
<style>
|
7
|
+
html {
|
8
|
+
font: normal 16px/20px sans-serif, serif;
|
9
|
+
max-width: 90%;
|
10
|
+
margin: 2rem auto;
|
11
|
+
}
|
12
|
+
h1 { font-size: 1.6rem; line-height: 1.8rem; color: #000; }
|
13
|
+
h2 { font-size: 1.5rem; line-height: 1.7rem; color: #222; }
|
14
|
+
h3 { font-size: 1.4rem; line-height: 1.6rem; color: #444; }
|
15
|
+
h4 { font-size: 1.3rem; line-height: 1.5rem; color: #555; }
|
16
|
+
h5 { font-size: 1.2rem; line-height: 1.4rem; color: #666; }
|
17
|
+
h6 { font-size: 1.1rem; line-height: 1.3rem; color: #777; }
|
18
|
+
.text-right { text-align: right; }
|
19
|
+
|
20
|
+
.job {
|
21
|
+
border-bottom: 1px solid #666;
|
22
|
+
}
|
23
|
+
.project {}
|
24
|
+
</style>
|
25
|
+
</head>
|
26
|
+
<body>
|
27
|
+
<header>
|
28
|
+
<h1><%= "#{ resume.contact.name } - #{ resume.contact.title }" %></h1>
|
29
|
+
<div class="text-right">
|
30
|
+
<a href="mailto:<%= resume.contact.email %>" class="email"><%= resume.contact.email %></a><br>
|
31
|
+
<a href="tel:<%= resume.contact.phone %>" class="phone"><%= resume.contact.phone %></a>
|
32
|
+
</div>
|
33
|
+
</header>
|
34
|
+
|
35
|
+
<section id="jobs">
|
36
|
+
<h2>Work Experience</h2>
|
37
|
+
<% resume.jobs.each do |job| %>
|
38
|
+
<article class="job">
|
39
|
+
<header>
|
40
|
+
<h3><%= "#{ job.position } — #{ job.company }" %></h3>
|
41
|
+
</header>
|
42
|
+
<p><%= job.summary.chomp %></p>
|
43
|
+
<% job.projects.each do |project| %>
|
44
|
+
<article class="project">
|
45
|
+
<h4><%= project.name %></h4>
|
46
|
+
|
47
|
+
<h5>Skills</h5>
|
48
|
+
<ul class="skills">
|
49
|
+
<% project.skills.each do |tech| %>
|
50
|
+
<li><%= tech %></li>
|
51
|
+
<% end %>
|
52
|
+
</ul>
|
53
|
+
|
54
|
+
<h5>Tasks</h5>
|
55
|
+
<ul class="tasks">
|
56
|
+
<% project.tasks.each do |task| %>
|
57
|
+
<li><%= task %></li>
|
58
|
+
<% end %>
|
59
|
+
</ul>
|
60
|
+
</article>
|
61
|
+
<% end %>
|
62
|
+
</article>
|
63
|
+
<% end %>
|
64
|
+
</section>
|
65
|
+
</body>
|
66
|
+
</html>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
\documentclass{article}
|
2
|
+
|
3
|
+
\title{<%= resume.contact.name %>}
|
4
|
+
\author{<%= resume.contact.name %>}
|
5
|
+
|
6
|
+
\begin{document}
|
7
|
+
|
8
|
+
\maketitle
|
9
|
+
|
10
|
+
\section{\centerline{Proffesional Experience}}
|
11
|
+
|
12
|
+
\vspace{8pt}
|
13
|
+
|
14
|
+
<% resume.jobs.each do |job| %>
|
15
|
+
|
16
|
+
\subsection{<%= job.company %> -- <%= job.position %>}
|
17
|
+
\hfill <%= job.start_date %> -- <%= job.end_date or 'present' %>
|
18
|
+
|
19
|
+
<%- if job.summary %><%= job.summary %><% end -%>
|
20
|
+
|
21
|
+
<% job.projects.each do |project| %>
|
22
|
+
\subsubsection{<%= project.name %>}
|
23
|
+
|
24
|
+
<%- if project.summary %><%= project.summary %><% end -%>
|
25
|
+
|
26
|
+
|
27
|
+
\noindent Skills
|
28
|
+
|
29
|
+
\begin{itemize}
|
30
|
+
<% project.skills.each do |tech| %>
|
31
|
+
\item <%= tech %>
|
32
|
+
<% end %>
|
33
|
+
\end{itemize}
|
34
|
+
|
35
|
+
\noindent Tasks
|
36
|
+
|
37
|
+
\begin{itemize}
|
38
|
+
<% project.tasks.each do |task| %>
|
39
|
+
\item <%= task %>
|
40
|
+
<% end %>
|
41
|
+
\end{itemize}
|
42
|
+
<% end %>
|
43
|
+
<% end %>
|
44
|
+
|
45
|
+
\section{\centerline{Personal Projects}}
|
46
|
+
|
47
|
+
\vspace{8pt}
|
48
|
+
|
49
|
+
<%- if resume.personal and resume.personal.summary %>
|
50
|
+
<%= resume.personal.summary %>
|
51
|
+
<% end -%>
|
52
|
+
|
53
|
+
<% resume.personal.projects.each do |project| %>
|
54
|
+
\subsubsection{<%= project.name %>}
|
55
|
+
|
56
|
+
<%- if project.summary %><%= project.summary %><% end -%>
|
57
|
+
|
58
|
+
\noindent Skills
|
59
|
+
|
60
|
+
\begin{itemize}
|
61
|
+
<% project.skills.each do |tech| %>
|
62
|
+
\item <%= tech %>
|
63
|
+
<% end %>
|
64
|
+
\end{itemize}
|
65
|
+
<% end %>
|
66
|
+
\end{document}
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: multiformat-cv2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- juankman94
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: erubi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mercenary
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.3
|
41
|
+
description: Multi-format CV generator from YAML files
|
42
|
+
email: juan.carlos@hey.com
|
43
|
+
executables:
|
44
|
+
- multiformatcv
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- MIT-LICENSE
|
49
|
+
- README.md
|
50
|
+
- bin/multiformatcv
|
51
|
+
- lib/multiformatcv.rb
|
52
|
+
- lib/multiformatcv/contact.rb
|
53
|
+
- lib/multiformatcv/job.rb
|
54
|
+
- lib/multiformatcv/personal.rb
|
55
|
+
- lib/multiformatcv/project.rb
|
56
|
+
- lib/multiformatcv/resume.rb
|
57
|
+
- lib/multiformatcv/templates/cv.html.erb
|
58
|
+
- lib/multiformatcv/templates/cv.tex.erb
|
59
|
+
- lib/multiformatcv/version.rb
|
60
|
+
homepage: https://www.gitlab.com/juankman94/multiformat-cv
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubygems_version: 3.1.2
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Generate your CV in different formats
|
83
|
+
test_files: []
|