json_resume 0.1.0
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/.gitignore +18 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bin/json_resume +104 -0
- data/examples/prateek_cv.json +271 -0
- data/extras/resume_html.tar.gz +0 -0
- data/json_resume.gemspec +23 -0
- data/lib/json_resume.rb +6 -0
- data/lib/json_resume/formatter.rb +130 -0
- data/lib/json_resume/formatter_html.rb +32 -0
- data/lib/json_resume/formatter_latex.rb +45 -0
- data/lib/json_resume/formatter_md.rb +21 -0
- data/lib/json_resume/json_resume.rb +19 -0
- data/lib/json_resume/reader.rb +35 -0
- data/lib/json_resume/version.rb +3 -0
- data/spec/json_resume/formatter_html_spec.rb +95 -0
- data/spec/json_resume/formatter_latex_spec.rb +51 -0
- data/spec/json_resume/formatter_spec.rb +68 -0
- data/spec/json_resume/reader_spec.rb +33 -0
- data/spec/spec_helper.rb +6 -0
- data/templates/default_html.mustache +219 -0
- data/templates/default_md.mustache +130 -0
- data/templates/default_tex.mustache +183 -0
- metadata +106 -0
Binary file
|
data/json_resume.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'json_resume/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "json_resume"
|
8
|
+
spec.version = JsonResume::VERSION
|
9
|
+
spec.authors = ["Prateek Agarwal"]
|
10
|
+
spec.email = ["prat0318@gmail.com"]
|
11
|
+
spec.description = %q{json_resume creates pretty resume formats from a .json input file. Currently, it can cpnvert to html, tex, markdown and pdf. Customizing the template to your own need is super easy. You just need to change the mustache files for any of these formats.}
|
12
|
+
spec.summary = %q{Generates pretty resume formats out of json input file}
|
13
|
+
spec.homepage = "http://github.com/prat0318/json_resume"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = ["json_resume"]
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
data/lib/json_resume.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
#Hack to generalise call empty? on
|
2
|
+
#objects, arrays and hashes
|
3
|
+
class Object
|
4
|
+
def empty?
|
5
|
+
false
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module JsonResume
|
10
|
+
class Formatter
|
11
|
+
attr_reader :hash
|
12
|
+
|
13
|
+
def initialize(hash)
|
14
|
+
@hash = hash
|
15
|
+
|
16
|
+
#recursively defined proc
|
17
|
+
@hash_proc = Proc.new do |k,v|
|
18
|
+
v = k if v.nil? #hack to make it common for hash and array
|
19
|
+
v.delete_if(&@hash_proc) if [Hash,Array].any? { |x| v.instance_of? x }
|
20
|
+
v.empty?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_linkedin_github_url
|
25
|
+
@hash["linkedin_url"] = "http://linkedin.com/in/" + @hash["linkedin_id"] if @hash["linkedin_id"]
|
26
|
+
@hash["github_url"] = "http://github.com/" + @hash["github_id"] if @hash["github_id"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_last_marker_on_stars
|
30
|
+
return if @hash['bio_data']['stars'].nil?
|
31
|
+
@hash["bio_data"]["stars"] = {
|
32
|
+
"items" => @hash["bio_data"]["stars"].map{ |i| { "name" => i } }
|
33
|
+
}
|
34
|
+
@hash["bio_data"]["stars"]["items"][-1]["last"] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_last_marker_on_skills
|
38
|
+
return if @hash['bio_data']['skills'].nil?
|
39
|
+
@hash['bio_data']['skills']['details'].each do |item|
|
40
|
+
item['items'].map!{|x| {'name'=>x} }
|
41
|
+
item['items'][-1]['last'] = true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_last_marker_on_tools
|
46
|
+
return if @hash['bio_data']['other_projects'].nil?
|
47
|
+
@hash['bio_data']['other_projects']['items'].each do |item|
|
48
|
+
next if item['technology_used'].nil?
|
49
|
+
item['technology_used']['tools'].map!{|x| {'name' => x} }
|
50
|
+
item['technology_used']['tools'][-1]['last'] = true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_last_marker_on_field field_name
|
55
|
+
return if @hash['bio_data'][field_name].nil?
|
56
|
+
@hash['bio_data'][field_name]['items'].each do |item|
|
57
|
+
next if item['technology_used'].nil?
|
58
|
+
item['technology_used']['tools'].map!{|x| {'name' => x} }
|
59
|
+
item['technology_used']['tools'][-1]['last'] = true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def cleanse
|
64
|
+
@hash.delete_if &@hash_proc
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def format_to_output_type
|
69
|
+
format_proc = Proc.new do |k,v|
|
70
|
+
v = k if v.nil?
|
71
|
+
v.each{|x| format_proc.call(x)} if [Hash,Array].any? {|x| v.instance_of? x}
|
72
|
+
format_string v if v.instance_of? String
|
73
|
+
end
|
74
|
+
@hash.each{|x| format_proc.call(x)}
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def format_string str
|
79
|
+
raise NotImplementedError.new("format_string not impl in formatter")
|
80
|
+
end
|
81
|
+
|
82
|
+
def is_false? item
|
83
|
+
item == false || item == 'false'
|
84
|
+
end
|
85
|
+
|
86
|
+
def purge_gpa
|
87
|
+
return if @hash['bio_data']['education'].nil?
|
88
|
+
@hash["bio_data"]["education"].delete("show_gpa") if is_false?(@hash["bio_data"]["education"]["show_gpa"]) || @hash["bio_data"]["education"]["schools"].all? {|sch| sch["gpa"].nil? || sch["gpa"].empty?}
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_padding(course)
|
92
|
+
unless @hash["bio_data"].nil? || @hash["bio_data"][course].nil?
|
93
|
+
course_hash = @hash["bio_data"][course]
|
94
|
+
course_hash << {} if course_hash.size % 2 == 1
|
95
|
+
@hash["bio_data"][course] = {
|
96
|
+
"rows" => course_hash.each_slice(2).to_a.map{ |i| { "columns" => i } }
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def format
|
102
|
+
return if @hash["bio_data"].nil?
|
103
|
+
|
104
|
+
cleanse
|
105
|
+
|
106
|
+
format_to_output_type
|
107
|
+
|
108
|
+
add_last_marker_on_stars
|
109
|
+
|
110
|
+
add_last_marker_on_skills
|
111
|
+
|
112
|
+
add_last_marker_on_field 'experience'
|
113
|
+
add_last_marker_on_field 'other_projects'
|
114
|
+
|
115
|
+
purge_gpa
|
116
|
+
|
117
|
+
add_linkedin_github_url
|
118
|
+
|
119
|
+
#make odd listed courses to even
|
120
|
+
["grad_courses", "undergrad_courses"].each do |course|
|
121
|
+
add_padding(course)
|
122
|
+
end
|
123
|
+
|
124
|
+
return self
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'formatter'
|
2
|
+
|
3
|
+
module JsonResume
|
4
|
+
class FormatterHtml < Formatter
|
5
|
+
def format_link str
|
6
|
+
str.gsub! /\[(.*?)\]\((.*?)\)/, '<a href="\2">\1</a>'
|
7
|
+
end
|
8
|
+
|
9
|
+
def format_autolink str
|
10
|
+
str.gsub! /<<(\S*?)>>/, '<a href="\1">\1</a>'
|
11
|
+
end
|
12
|
+
|
13
|
+
def format_emphasis str
|
14
|
+
str.gsub! /_(.+?)_/, '<i>\1</i>'
|
15
|
+
str.gsub! /\*\*(.+?)\*\*/, '<b>\1</b>'
|
16
|
+
end
|
17
|
+
|
18
|
+
def format_string str
|
19
|
+
format_link str
|
20
|
+
format_autolink str
|
21
|
+
format_emphasis str
|
22
|
+
end
|
23
|
+
|
24
|
+
def format
|
25
|
+
super
|
26
|
+
|
27
|
+
return self
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'formatter'
|
2
|
+
|
3
|
+
module JsonResume
|
4
|
+
class FormatterLatex < Formatter
|
5
|
+
|
6
|
+
def format_link str
|
7
|
+
str.gsub! /\[(.*?)\]\((.*?)\)/, '{\color{see} \href{\2}{\1}}'
|
8
|
+
end
|
9
|
+
|
10
|
+
def format_autolink str
|
11
|
+
str.gsub! /<<(\S*?)>>/, '{\color{see} \url{\1}}'
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_emphasis str
|
15
|
+
str.gsub! /_(.+?)_/, '\textit{\1}'
|
16
|
+
str.gsub! /\*\*(.+?)\*\*/, '\textbf{\1}'
|
17
|
+
end
|
18
|
+
|
19
|
+
def format_superscripts str
|
20
|
+
str.gsub! /<sup>(.*?)<\/sup>/, '$^{\1}$'
|
21
|
+
str.gsub! /<sub>(.*?)<\/sub>/, '$_{\1}$'
|
22
|
+
end
|
23
|
+
|
24
|
+
def format_symbols str
|
25
|
+
str.gsub! /%/, '\%'
|
26
|
+
str.gsub! /_/, '\_'
|
27
|
+
end
|
28
|
+
|
29
|
+
def format_string str
|
30
|
+
format_link str
|
31
|
+
format_autolink str
|
32
|
+
format_emphasis str
|
33
|
+
format_symbols str
|
34
|
+
format_superscripts str
|
35
|
+
end
|
36
|
+
|
37
|
+
def format
|
38
|
+
super
|
39
|
+
|
40
|
+
return self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'formatter'
|
2
|
+
|
3
|
+
module JsonResume
|
4
|
+
class FormatterMd < Formatter
|
5
|
+
def format_autolink str
|
6
|
+
str.gsub! /<<(\S*?)>>/, '[\1](\1)'
|
7
|
+
end
|
8
|
+
|
9
|
+
def format_string str
|
10
|
+
format_autolink str
|
11
|
+
end
|
12
|
+
|
13
|
+
def format
|
14
|
+
super
|
15
|
+
|
16
|
+
return self
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'reader'
|
2
|
+
|
3
|
+
module JsonResume
|
4
|
+
class << self
|
5
|
+
def new(json_input, options = {})
|
6
|
+
options = options.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
7
|
+
JsonResume::Core.new(json_input, options)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Core
|
12
|
+
attr_accessor :reader
|
13
|
+
|
14
|
+
def initialize(json_input, options)
|
15
|
+
@reader = Reader.new(json_input, options)
|
16
|
+
@reader.format!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'formatter_html'
|
2
|
+
require_relative 'formatter_latex'
|
3
|
+
require_relative 'formatter_md'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module JsonResume
|
7
|
+
class Reader
|
8
|
+
attr_accessor :hash
|
9
|
+
|
10
|
+
def initialize(json_input, options)
|
11
|
+
output_type = options[:output_type] || "html" #default html, others latex, md
|
12
|
+
@json_string = case json_input
|
13
|
+
when /\.json$/i then File.read(json_input)
|
14
|
+
else json_input
|
15
|
+
end
|
16
|
+
@output_type = output_type
|
17
|
+
begin
|
18
|
+
@hash = JSON.parse(@json_string)
|
19
|
+
rescue JSON::ParserError => e
|
20
|
+
raise Exception, "Either you entered a file without .json extension or JSON string is wrong: "+e.message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def format!
|
25
|
+
formatters = {
|
26
|
+
:latex => JsonResume::FormatterLatex,
|
27
|
+
:html => JsonResume::FormatterHtml,
|
28
|
+
:markdown => JsonResume::FormatterMd,
|
29
|
+
}
|
30
|
+
type = @output_type.to_sym
|
31
|
+
@hash = formatters[type].new(@hash).format.hash
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json_resume/formatter_html'
|
3
|
+
require 'json_resume/formatter'
|
4
|
+
|
5
|
+
describe "#padder" do
|
6
|
+
it 'pads a row if items are odd' do
|
7
|
+
hash = {'bio_data' => {'test' => [
|
8
|
+
{'name'=>'sub1', 'url' => 'url1'},
|
9
|
+
{'name'=>'sub2', 'url' => 'url2'},
|
10
|
+
{'name'=>'sub3', 'url' => 'url3'}
|
11
|
+
]}
|
12
|
+
}
|
13
|
+
formatter = JsonResume::FormatterHtml.new hash
|
14
|
+
formatter.add_padding('test')
|
15
|
+
expect(formatter.hash['bio_data']['test']['rows'].size).to eq(2)
|
16
|
+
expect(formatter.hash['bio_data']['test']['rows'][-1]['columns'][-1]).to eq({})
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'doesn\'t pad a row if items are even' do
|
20
|
+
subs = [
|
21
|
+
{'name'=>'sub1', 'url' => 'url1'},
|
22
|
+
{'name'=>'sub2', 'url' => 'url2'}
|
23
|
+
]
|
24
|
+
hash = {'bio_data' => {'test' => subs}}
|
25
|
+
formatter = JsonResume::FormatterHtml.new hash
|
26
|
+
formatter.add_padding('test')
|
27
|
+
expect(formatter.hash['bio_data']['test']['rows'].size).to eq(1)
|
28
|
+
expect(formatter.hash['bio_data']['test']['rows'][0]['columns']).to eq(subs)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'ignores if data is null' do
|
32
|
+
hash = {'bio_data' => {}}
|
33
|
+
formatter = JsonResume::FormatterHtml.new hash
|
34
|
+
formatter.add_padding('test')
|
35
|
+
expect(formatter.hash['bio_data']).to eq({})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#urlformatter' do
|
40
|
+
context 'when given a link for html output' do
|
41
|
+
it 'converts link to href' do
|
42
|
+
formatter = JsonResume::FormatterHtml.new({})
|
43
|
+
str = "test [Hello](http://google.com)"
|
44
|
+
formatter.format_link str
|
45
|
+
expect(str).to eq('test <a href="http://google.com">Hello</a>')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'converts autolink to url' do
|
49
|
+
formatter = JsonResume::FormatterHtml.new({})
|
50
|
+
str = "test <<http://google.com>>"
|
51
|
+
formatter.format_autolink str
|
52
|
+
expect(str).to eq('test <a href="http://google.com">http://google.com</a>')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'converts links and autolinks to url' do
|
56
|
+
formatter = JsonResume::FormatterHtml.new({})
|
57
|
+
str = "test <<http://google.com>> [Hello](http://google.com) <<http://google.com>>"
|
58
|
+
formatter.format_string str
|
59
|
+
expect(str).to eq('test <a href="http://google.com">http://google.com</a> <a href="http://google.com">Hello</a> <a href="http://google.com">http://google.com</a>')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#emphasis_formatting" do
|
65
|
+
it 'italicizes on _text_' do
|
66
|
+
formatter = JsonResume::FormatterHtml.new({})
|
67
|
+
str = "Last word should be _italicized_"
|
68
|
+
formatter.format_emphasis str
|
69
|
+
expect(str).to eq('Last word should be <i>italicized</i>')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'bolds on **text**' do
|
73
|
+
formatter = JsonResume::FormatterHtml.new({})
|
74
|
+
str = "Last word should be **bold**"
|
75
|
+
formatter.format_emphasis str
|
76
|
+
expect(str).to eq('Last word should be <b>bold</b>')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'italicizes and bolds if given both' do
|
80
|
+
formatter = JsonResume::FormatterHtml.new({})
|
81
|
+
str = "Last word should _be **bold and italicized**_"
|
82
|
+
formatter.format_emphasis str
|
83
|
+
expect(str).to eq('Last word should <i>be <b>bold and italicized</b></i>')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#format" do
|
88
|
+
it 'calls parent format method' do
|
89
|
+
formatter = JsonResume::FormatterHtml.new({'bio_data' => {}})
|
90
|
+
expect(formatter).to receive(:cleanse).and_return(nil)
|
91
|
+
formatter.format
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json_resume/formatter_latex'
|
3
|
+
|
4
|
+
describe '#urlformatter' do
|
5
|
+
context 'when given a link for latex output' do
|
6
|
+
it 'converts link to href' do
|
7
|
+
formatter = JsonResume::FormatterLatex.new({})
|
8
|
+
str = "test [Hello](http://google.com)"
|
9
|
+
formatter.format_link str
|
10
|
+
expect(str).to eq('test {\color{see} \href{http://google.com}{Hello}}')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'converts autolink to url' do
|
14
|
+
formatter = JsonResume::FormatterLatex.new({})
|
15
|
+
str = "test <<http://google.com>>"
|
16
|
+
formatter.format_autolink str
|
17
|
+
expect(str).to eq('test {\color{see} \url{http://google.com}}')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'converts links and autolinks to url' do
|
21
|
+
formatter = JsonResume::FormatterLatex.new({})
|
22
|
+
str = "test <<http://google.com>> [Hello](http://google.com) <<http://google.com>>"
|
23
|
+
formatter.format_string str
|
24
|
+
expect(str).to eq('test {\color{see} \url{http://google.com}} {\color{see} \href{http://google.com}{Hello}} {\color{see} \url{http://google.com}}')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#emphasis_formatting" do
|
30
|
+
it 'italicizes on _text_' do
|
31
|
+
formatter = JsonResume::FormatterLatex.new({})
|
32
|
+
str = "Last word should be _italicized_"
|
33
|
+
formatter.format_emphasis str
|
34
|
+
expect(str).to eq('Last word should be \textit{italicized}')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'bolds on **text**' do
|
38
|
+
formatter = JsonResume::FormatterLatex.new({})
|
39
|
+
str = "Last word should be **bold**"
|
40
|
+
formatter.format_emphasis str
|
41
|
+
expect(str).to eq('Last word should be \textbf{bold}')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'italicizes and bolds if given both' do
|
45
|
+
formatter = JsonResume::FormatterLatex.new({})
|
46
|
+
str = "Last word should _be **bold and italicized**_"
|
47
|
+
formatter.format_emphasis str
|
48
|
+
expect(str).to eq('Last word should \textit{be \textbf{bold and italicized}}')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|