resume-stylist 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31ad8a2c22c71fb69b8e476894f3d9e38555f321
4
- data.tar.gz: 1424894eccf7f0b3eff561023b742906940bbcd8
3
+ metadata.gz: 2298b819f3fe882758cdc3db17a55c2ac89496c0
4
+ data.tar.gz: 047b6d97566a5373defcc80209bca8efbde744e0
5
5
  SHA512:
6
- metadata.gz: 785c11a423a56927fd6291bd174213171abada37ae7423e5d643d5aa15493ec3593e5b59b4b37105cacb5a04da3b5ab3fce9c331599f07430036e3deeba0aee1
7
- data.tar.gz: 07433278538c665d14e132e8ce34ac46f5acb780220312785139c05a28c5ed5eab517cf312f23058590820efcbc97201430f6005e9b9db26d277e0a94d206156
6
+ metadata.gz: 9fa53127f95fb8cde42b0f56a6b29eeb2e23809b46ddd9f911ef7580d6504fa8b6cd87da507419cea93df4ab7ee04d5a9964e8589bbf215eb154d32ef348d7ed
7
+ data.tar.gz: d1da79c170544948681f7c05c69ab4fd8c8e229bb0e498148a3da57e91c59b6d9622e393a6b966bb49dd36f157e0f6eb8930249b3b458d5280a1c51881ed54e7
data/README.md CHANGED
@@ -1,39 +1,83 @@
1
1
  # Resume Stylist
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/resume-stylist`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ **Note**: Currently in very early development.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ Small framework for making CV/resume themes using [Liquid](https://github.com/Shopify/liquid/wiki/liquid-for-designers) and [Sass](http://sass-lang.com/).
6
6
 
7
7
  ## Installation
8
8
 
9
- Add this line to your application's Gemfile:
9
+ ~~~sh
10
+ $ gem install resume-stylist
11
+ ~~~
10
12
 
11
- ```ruby
12
- gem 'resume-stylist'
13
- ```
13
+ Also, since this uses PDFKit, you'll need to make sure you have `wkhtmltopdf` installed. On Arch it's as simple as running `sudo pacman -S wkhtmltopdf`, but consult their documentation for recommendations regarding other platforms: https://github.com/pdfkit/pdfkit#wkhtmltopdf
14
14
 
15
- And then execute:
15
+ ## Features
16
16
 
17
- $ bundle
17
+ Here are some cool features:
18
18
 
19
- Or install it yourself as:
20
-
21
- $ gem install resume-stylist
19
+ - Uses Liquid as the templating language
20
+ - Support for inline Sass and SCSS by using `<style type="text/sass">` and `<style type="text/scss">`
21
+ - Support for multiple Resume formats (JSON and XML currently), but you can BYOF (Bring Your Own Format)!
22
+ - Export to PDF
22
23
 
23
24
  ## Usage
24
25
 
25
- TODO: Write usage instructions here
26
+ ### Tool usage
26
27
 
27
- ## Development
28
+ Create a new theme and a JSON resume template:
28
29
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. Run `bundle exec resume-stylist` to use the gem in this directory, ignoring other installed copies of this gem.
30
+ ~~~sh
31
+ $ resume-stylist --new-theme fancy.html.liquid --new-resume john_doe.json
32
+ ~~~
30
33
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
34
+ Build your theme as a PDF:
32
35
 
33
- ## Contributing
36
+ ~~~sh
37
+ $ resume-stylist build john_doe.json john_doe.pdf
38
+ ~~~
39
+
40
+ ~~~sh
41
+ $ resume-stylist build john_doe -I json john_doe.pdf
42
+ ~~~
43
+
44
+ Run `resume-stylist --help` for more options!
45
+
46
+ ### Library usage
47
+
48
+ #### Registering a custom resume format
49
+
50
+ ~~~rb
51
+ module MyResumeFormat
52
+ def self.handles?(resume_format)
53
+ # Handle
54
+ resume_format.to_s =~ /(myformat|myf)/i
55
+ end
34
56
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/resume-stylist. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
57
+ def load!(input)
58
+ # input is the resume data
59
+ data = My::Parser.parse(input)
60
+ @data = data.to_h
61
+ end
62
+ end
63
+
64
+ ResumeStylist::Resume.register_handler MyResumeFormat
65
+ ~~~
66
+
67
+ **NOTE**: The theme expects `@data` to be a `Hash` with `String` keys.
68
+
69
+ #### Creating a resume (HTML) programmatically:
70
+
71
+ ~~~rb
72
+ resume = ResumeStylist::Resume.new(resume_source, :myformat)
73
+ theme = ResumeStylist::Theme.new(theme_source)
74
+
75
+ html = theme.render(resume.data)
76
+ ~~~
77
+
78
+ ## Contributing
36
79
 
80
+ Bug reports and pull requests are welcome on GitHub at https://github.com/omninonsense/resume-stylist. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
37
81
 
38
82
  ## License
39
83
 
@@ -1,20 +1,522 @@
1
+ ---
2
+ theme:
3
+ author:
4
+ name: Nino Miletich
5
+ url: https://github.com/omninonsense
6
+ ---
1
7
  <!DOCTYPE html>
2
8
  <html>
3
9
  <head>
4
10
  <meta charset="utf-8">
5
- <title>{{ name }}'s Resume</title>
6
-
11
+ <title>{{ basics.name }}'s Resume</title>
12
+ <meta name="description" content="{{ basics.summary }}">
13
+ <meta name="generator" content="{{ _generator.name }}/{{ _generator.version }}">
14
+ <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,800&subset=latin-ext" rel="stylesheet">
15
+ <link href="https://fonts.googleapis.com/css?family=Passion+One" rel="stylesheet">
7
16
  <!-- or type="text/sass" -->
8
17
  <style type="text/scss">
9
- .resume {
18
+ {% normalize_css inline %}
19
+
20
+ $max_width: 1200px;
21
+ #resume {
22
+ font-family: 'Open Sans', sans-serif;
23
+ color: #222;
24
+ margin: 3ex 1em;
25
+ @media screen and (min-width: $max_width){
26
+ width: 900px;
27
+ margin: 3ex auto;
28
+ }
29
+ }
30
+
31
+ small {
32
+ display: block;
33
+ }
34
+
35
+ #basics {
36
+ .picture {
37
+ $size: 128px;
38
+ display: block;
39
+ width: $size;
40
+ height: $size;
41
+ border-radius: 50%;
42
+ margin: auto;
43
+ box-shadow: 0 0 0 5px #aaa;
44
+ border: 4px solid #fff;
45
+ }
46
+
10
47
  h1 {
11
- weight: bold;
48
+ text-align: center;
49
+ font-weight: 300;
50
+
51
+ small {
52
+ color: #aaa;
53
+ font-weight: 100;
54
+ }
55
+ }
56
+
57
+ ul.contact {
58
+ text-align: center;
59
+ list-style-type: none;
60
+ padding: 0;
61
+ margin-top: 0;
62
+
63
+ li {
64
+ display: inline-block;
65
+ margin: 0 .5em;
66
+ }
67
+ }
68
+
69
+ ul.profiles {
70
+ list-style-type: none;
71
+ padding: 0;
72
+ text-align: center;
73
+
74
+ li {
75
+ display: inline-block;
76
+ margin: 0 1em;
77
+ }
78
+
79
+ .network-logo {
80
+ width: 22px;
81
+ }
82
+
83
+ a.profile {
84
+ text-decoration: none;
85
+ }
86
+
87
+ .network-logo {
88
+ vertical-align: middle;
89
+ margin-bottom: 3px;
90
+ }
91
+
92
+ .profile-facebook { color: #3C5A99; }
93
+ .profile-github { color: #000000; }
94
+ .profile-twitter { color: #66757f; }
95
+
96
+ .profile-username::before {
97
+ content: "@";
98
+ font-size: 125%;
99
+ position: relative;
100
+ bottom: -1px;
101
+ }
102
+
103
+ } /* .profiles */
104
+ } /* #basics */
105
+
106
+ /* WKHTML doesn't support flexbox properly */
107
+
108
+ .category {
109
+ /*display: flex;*/
110
+ display: table;
111
+ margin-top: 3ex;
112
+ page-break-before: auto;
113
+ page-break-inside: avoid;
114
+ page-break-after: auto;
115
+
116
+ & > div {
117
+ display: table-cell;
118
+ }
119
+
120
+ .title {
121
+ /*flex: 0 0 160px;*/
122
+ width: 160px;
123
+ text-align: right;
124
+ border-right: 1px solid #ccc;
125
+ padding: 1em;
126
+
127
+ h2 { font-weight: 100; }
128
+ }
129
+
130
+ ul.no-list {
131
+ padding: 0;
132
+ list-style-type: none;
133
+
134
+ & > li {
135
+ margin: 2em;
136
+ }
137
+
138
+ ul {
139
+ list-style-type: square;
140
+ li { margin-top: 0.75ex; }
141
+ }
142
+ }
143
+
144
+ .timespan { color: #999; }
145
+
146
+ .content {
147
+ h3 {
148
+ font-weight: 400;
149
+ margin-top: 0;
150
+ a { color: inherit; }
151
+ .company, .organisation { font-style: italic; }
152
+ }
153
+ }
154
+ } /* .category */
155
+
156
+ #skills, #interests {
157
+ h3 {
158
+ margin-bottom: 0;
159
+ margin-top: 1em;
160
+ }
161
+ }
162
+
163
+ #languages ul { margin: 2em; }
164
+
165
+ .courses, .keywords, .languages {
166
+ list-style-type: none;
167
+ padding: 0;
168
+
169
+ li {
170
+ margin: 0.75ex 0.25em;
171
+ display: inline-block;
172
+ background-color: #eee;
173
+ padding: .5ex .5em;
174
+ border-radius: 10%;
175
+ }
176
+ }
177
+
178
+
179
+ blockquote
180
+ {
181
+ border-left: 5px solid #ccc;
182
+ background-color: #eee;
183
+ margin: 0;
184
+ width: 100%;
185
+ padding: 1em;
186
+ position: relative;
187
+
188
+ p {
189
+ margin: 0;
190
+ margin-left: 1em;
191
+ }
192
+
193
+ cite {
194
+ display: block;
195
+ text-align: right;
196
+ &::before {
197
+ content: "— ";
198
+ }
199
+ }
200
+
201
+ &::before {
202
+ font-family: "Passion One", cursive;
203
+ display: block;
204
+ font-size: 500%;
205
+ color: #ccc;
206
+ height: 15px;
207
+ width: 60px;
208
+ float: left;
209
+ content: "“";
210
+ position: relative;
211
+ left: 20px;
212
+ top: -17px;
12
213
  }
13
214
  }
215
+
216
+ .flair {
217
+ color: #ccc;
218
+ text-align: right;
219
+
220
+ a {
221
+ color: #99b9d4;
222
+ }
223
+ }
224
+
14
225
  </style>
15
226
  </head>
16
- <body class="resume">
17
- <h1>{{ name }}'s Resume</h1>
18
- <!-- todo -->
227
+ <body id="resume">
228
+ <section id="basics">
229
+ {% unless basics.picture == "" %}
230
+ <div class="group">
231
+ <img class="picture" src="{{ basics.picture }}" alt="Picture of {{ basics.name }}" />
232
+ </div>
233
+ {% endunless %}
234
+ <div class="group">
235
+ <h1>{{ basics.name }}<small>{{ basics.label }}</small></h1>
236
+ <ul class="contact">
237
+ <li><a href="mailto:{{ basics.email }}" class="contact-info email">{{ basics.email }}</a></li>
238
+ <li><span class="contact-info phone">{{ basics.phone }}</span></li>
239
+ </ul>
240
+ <ul class="profiles">
241
+ {% unless basics.profiles == empty %}
242
+ {% for profile in basics.profiles %}
243
+ <li>
244
+ <a class="profile profile-{{ profile.network | downcase }}" href="{{ profile.url }}">
245
+
246
+ {% case profile.network %}
247
+ {% when "Facebook" %}
248
+ <!-- The below SVG was taken from Wikipedia. -->
249
+ <svg version="1.1" id="Facebook" class="network-logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0 0 266.893 266.895" viewBox="0 0 266.893 266.895" xml:space="preserve">
250
+ <path id="Blue_1_" fill="#3C5A99" d="M248.082,262.307c7.854,0,14.223-6.369,14.223-14.225V18.812 c0-7.857-6.368-14.224-14.223-14.224H18.812c-7.857,0-14.224,6.367-14.224,14.224v229.27c0,7.855,6.366,14.225,14.224,14.225 H248.082z"/>
251
+ <path id="f" fill="#FFFFFF" d="M182.409,262.307v-99.803h33.499l5.016-38.895h-38.515V98.777c0-11.261,3.127-18.935,19.275-18.935 l20.596-0.009V45.045c-3.562-0.474-15.788-1.533-30.012-1.533c-29.695,0-50.025,18.126-50.025,51.413v28.684h-33.585v38.895h33.585 v99.803H182.409z"/>
252
+ </svg>
253
+ {% when "GitHub" %}
254
+ <!-- The below SVG was taken from Wikipedia. -->
255
+ <svg version="1.1" id="GitHub" class="network-logo" viewbox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" xml:space="preserve">
256
+ <path d="M512 0C229.25 0 0 229.25 0 512c0 226.25 146.688 418.125 350.156 485.812 25.594 4.688 34.938-11.125 34.938-24.625 0-12.188-0.469-52.562-0.719-95.312C242 908.812 211.906 817.5 211.906 817.5c-23.312-59.125-56.844-74.875-56.844-74.875-46.531-31.75 3.53-31.125 3.53-31.125 51.406 3.562 78.47 52.75 78.47 52.75 45.688 78.25 119.875 55.625 149 42.5 4.654-33 17.904-55.625 32.5-68.375C304.906 725.438 185.344 681.5 185.344 485.312c0-55.938 19.969-101.562 52.656-137.406-5.219-13-22.844-65.094 5.062-135.562 0 0 42.938-13.75 140.812 52.5 40.812-11.406 84.594-17.031 128.125-17.219 43.5 0.188 87.312 5.875 128.188 17.281 97.688-66.312 140.688-52.5 140.688-52.5 28 70.531 10.375 122.562 5.125 135.5 32.812 35.844 52.625 81.469 52.625 137.406 0 196.688-119.75 240-233.812 252.688 18.438 15.875 34.75 47 34.75 94.75 0 68.438-0.688 123.625-0.688 140.5 0 13.625 9.312 29.562 35.25 24.562C877.438 930 1024 738.125 1024 512 1024 229.25 794.75 0 512 0z" />
257
+ </svg>
258
+ {% when "Twitter" %}
259
+ <!-- The below SVG was taken from Wikipedia. -->
260
+ <svg id="Twitter" class="network-logo" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewbox="0 0 182.26 148.12" version="1.1" xmlns:cc="http://creativecommons.org/ns#" viewBox="0 0 182.66667 150.66667" xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata id="metadata8"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs id="defs6"><clipPath id="clipPath20" clipPathUnits="userSpaceOnUse"><path id="path18" d="m0 10.012h1366.9v1110.9h-1366.9z"/></clipPath></defs><g id="g10" transform="matrix(1.3333 0 0 -1.3333 0 150.67)"><g id="g12" transform="scale(.1)"><g id="g14"><g id="g16" clip-path="url(#clipPath20)"><path id="path22" d="m1366.9 989.39c-50.27-22.309-104.33-37.387-161.05-44.18 57.89 34.723 102.34 89.679 123.28 155.15-54.18-32.15-114.18-55.47-178.09-68.04-51.13 54.49-124.02 88.55-204.68 88.55-154.89 0-280.43-125.55-280.43-280.43 0-21.988 2.457-43.398 7.258-63.91-233.08 11.68-439.72 123.36-578.04 293.01-24.141-41.4-37.969-89.567-37.969-140.97 0-97.308 49.489-183.13 124.76-233.44-45.969 1.437-89.218 14.058-127.03 35.078-0.043-1.18-0.043-2.348-0.043-3.52 0-135.9 96.68-249.22 224.96-275-23.512-6.41-48.281-9.8-73.86-9.8-18.089 0-35.628 1.711-52.781 5 35.711-111.41 139.26-192.5 262-194.77-96.058-75.23-216.96-120.04-348.36-120.04-22.621 0-44.961 1.332-66.918 3.91 124.16-79.568 271.55-125.98 429.94-125.98 515.82 0 797.86 427.31 797.86 797.93 0 12.153-0.28 24.223-0.79 36.25 54.77 39.571 102.31 88.95 139.93 145.2" fill="#55ACEE"/></g></g></g></g></svg>
261
+ {% endcase %}
262
+
263
+ <span class="profile-username">{{ profile.username }}</span>
264
+ </a>
265
+ </li>
266
+
267
+
268
+ {% endfor %}
269
+ {% endunless %}
270
+ </ul>
271
+ </div>
272
+ </section>
273
+
274
+ {% unless work == empty %}
275
+ <section id="work" class="category">
276
+ <div class="title">
277
+ <h2>Work Experience</h2>
278
+ </div>
279
+ <div class="content">
280
+ <ul class="no-list">
281
+ {% for experience in work %}
282
+ <li>
283
+ <div class="meta">
284
+ <span class="timespan">
285
+ <time datetime="{{experience.startdate}}">{{ experience.startdate | date: "%Y" }}</time>
286
+ &ndash;
287
+ {% if experience.enddate == nil %}
288
+ current
289
+ {% else %}
290
+ <time datetime="{{ experience.enddate }}">{{ experience.enddate | date: "%Y" }}</time>
291
+ {% endif %}
292
+ </span>
293
+ <h3>{{ experience.position }} at <span class="company">{% if experience.website == "" %}{{ experience.company }}{% else %}<a href="{{experience.website}}">{{ experience.company }}</a>{% endif %}</span></h3>
294
+ </div>
295
+ <p>{{ experience.summary }}</p>
296
+ {% unless experience.highlights == empty %}
297
+ <ul class="highlights">
298
+ {% for highlight in experience.highlights %}
299
+ <li>{{ highlight }}</li>
300
+ {% endfor %}
301
+ </ul>
302
+ {%endunless%}
303
+ </li>
304
+ {% endfor %}
305
+ </ul>
306
+ </div>
307
+ </section>
308
+ {% endunless %}
309
+
310
+ {% unless volunteer == empty %}
311
+ <section id="volunteer" class="category">
312
+ <div class="title">
313
+ <h2>Volunteering</h2>
314
+ </div>
315
+ <div class="content">
316
+ <ul class="no-list">
317
+ {% for experience in volunteer %}
318
+ <li>
319
+ <div class="meta">
320
+ <span class="timespan">
321
+ <time datetime="{{experience.startdate}}">{{ experience.startdate | date: "%Y" }}</time>
322
+ &ndash;
323
+ {% if experience.enddate == nil %}
324
+ current
325
+ {% else %}
326
+ <time datetime="{{ experience.enddate }}">{{ experience.enddate | date: "%Y" }}</time>
327
+ {% endif %}
328
+ </span>
329
+ <h3>{{ experience.position }} at <span class="organisation">{% if experience.website == "" %}{{ experience.organization }}{% else %}<a href="{{experience.website}}">{{ experience.organization }}</a>{% endif %}</span></h3>
330
+ </div>
331
+ <p>{{ experience.summary }}</p>
332
+ {% unless experience.highlights == empty %}
333
+ <ul class="highlights">
334
+ {% for highlight in experience.highlights %}
335
+ <li>{{ highlight }}</li>
336
+ {% endfor %}
337
+ </ul>
338
+ {%endunless%}
339
+ </li>
340
+ {% endfor %}
341
+ </ul>
342
+ </div>
343
+ </section>
344
+ {% endunless %}
345
+
346
+ {% unless education == empty %}
347
+ <section id="education" class="category">
348
+ <div class="title">
349
+ <h2>Education</h2>
350
+ </div>
351
+ <div class="content">
352
+ <ul class="no-list">
353
+ {% for edu in education %}
354
+ <li>
355
+ <span class="timespan">
356
+ <time datetime="{{edu.startdate}}">{{ edu.startdate | date: "%Y" }}</time>
357
+ &ndash;
358
+ {% if edu.enddate == nil %}
359
+ current
360
+ {% else %}
361
+ <time datetime="{{ edu.enddate }}">{{ edu.enddate | date: "%Y" }}</time>
362
+ {% endif %}
363
+ </span>
364
+ <h3>{{ edu.area }}
365
+ <small>
366
+ {{ edu.institution }}
367
+ </small>
368
+ </h3>
369
+ {% unless edu.gpa == empty %} <p><b>GPA: </b> {{ edu.gpa }}</p> {% endunless %}
370
+ {% unless edu.courses == empty %}
371
+ <ul class="courses">
372
+ {% for course in edu.courses %}
373
+ <li>{{ course }}</li>
374
+ {% endfor %}
375
+ </ul>
376
+ {%endunless%}
377
+ </li>
378
+ {% endfor %}
379
+ </ul>
380
+ </div>
381
+ </section>
382
+ {% endunless %}
383
+
384
+ {% unless skills == empty %}
385
+ <section id="skills" class="category">
386
+ <div class="title">
387
+ <h2>Skills</h2>
388
+ </div>
389
+ <div class="content">
390
+ <ul class="no-list">
391
+ {% for skill in skills %}
392
+ <li>
393
+ <h3>{{ skill.name }}<small>{{ skill.level }}</small></h3>
394
+ {% unless skill.keywords == empty %}
395
+ <ul class="keywords">
396
+ {% for keyword in skill.keywords %}
397
+ <li>{{ keyword }}</li>
398
+ {% endfor %}
399
+ </ul>
400
+ {%endunless%}
401
+ </li>
402
+ {% endfor %}
403
+ </ul>
404
+ </div>
405
+ </section>
406
+ {% endunless %}
407
+
408
+ {% unless awards == empty %}
409
+ <section id="awards" class="category">
410
+ <div class="title">
411
+ <h2>Awards</h2>
412
+ </div>
413
+ <div class="content">
414
+ <ul class="no-list">
415
+ {% for award in awards %}
416
+ <li>
417
+ <div class="meta">
418
+ <span class="timespan"><time datetime="{{ award.date }}">{{ award.date | ordinal_date }}</time></span>
419
+ <h3>{{ award.title }}<small>Awarded by <span class="awarder">{{ award.awarder }}</span></small></h3>
420
+ </div>
421
+ <p class="summary">{{ award.summary }}</p>
422
+ </li>
423
+ {% endfor %}
424
+ </ul>
425
+ </div>
426
+ </section>
427
+ {% endunless %}
428
+
429
+ {% unless publications == empty %}
430
+ <section id="publications" class="category">
431
+ <div class="title">
432
+ <h2>Publications</h2>
433
+ </div>
434
+ <div class="content">
435
+ <ul class="no-list">
436
+ {% for pub in publications %}
437
+ <li>
438
+ <div class="meta">
439
+ <span class="timespan"><time datetime="{{ pub.releasedate }}">{{ pub.releasedate | ordinal_date }}</time></span>
440
+ <h3>
441
+ {% if pub.website == empty %}
442
+ {{ pub.name }}
443
+ {% else %}
444
+ <a href="{{ pub.website }}">{{ pub.name }}</a>
445
+ {% endif %}
446
+ <small>Published by <span class="publisher">{{ pub.publisher }}</span></small>
447
+ </h3>
448
+ </div>
449
+ <p class="summary">{{ pub.summary }}</p>
450
+ </li>
451
+ {% endfor %}
452
+ </ul>
453
+ </div>
454
+ </section>
455
+ {% endunless %}
456
+
457
+ {% unless interests == empty %}
458
+ <section id="interests" class="category">
459
+ <div class="title">
460
+ <h2>Interests</h2>
461
+ </div>
462
+ <div class="content">
463
+ <ul class="no-list">
464
+ {% for interest in interests %}
465
+ <li>
466
+ <h3>{{ interest.name }}</h3>
467
+ {% unless interest.keywords == empty %}
468
+ <ul class="keywords">
469
+ {% for keyword in interest.keywords %}
470
+ <li>{{ keyword }}</li>
471
+ {% endfor %}
472
+ </ul>
473
+ {%endunless%}
474
+ </li>
475
+ {% endfor %}
476
+ </ul>
477
+ </div>
478
+ </section>
479
+ {% endunless %}
480
+
481
+ {% unless references == empty %}
482
+ <section id="references" class="category">
483
+ <div class="title">
484
+ <h2>References</h2>
485
+ </div>
486
+ <div class="content">
487
+ <ul class="no-list">
488
+ {% for reference in references %}
489
+ <li>
490
+ <blockquote>
491
+ <div class="fancy-quote"></div>
492
+ <p>{{ reference.reference }}</p>
493
+ <cite>{{ reference.name }}</cite>
494
+ </blockquote>
495
+ </li>
496
+ {% endfor %}
497
+ </ul>
498
+ </div>
499
+ </section>
500
+ {% endunless %}
501
+
502
+ {% unless languages == empty %}
503
+ <section id="languages" class="category">
504
+ <div class="title">
505
+ <h2>Languages</h2>
506
+ </div>
507
+ <div class="content">
508
+ <ul class="languages">
509
+ {% for language in languages %}
510
+ <li>{{ language.name }}<small>{{ language.level }}</small></li>
511
+ {% endfor %}
512
+ </ul>
513
+ </div>
514
+ </section>
515
+ {% endunless %}
516
+
517
+ <div class="flair">
518
+ CV generated using <a href="https://github.com/omninonsense/resume-stylist">{{ _generator.name }} v{{ _generator.version }}</a>, resume theme by <a href="{{ frontmatter.theme.author.url }}">{{ frontmatter.theme.author.name }}</a>.
519
+ </div>
520
+
19
521
  </body>
20
522
  </html>
@@ -11,31 +11,41 @@ module ResumeStylist
11
11
  return date
12
12
  end
13
13
 
14
+ def self.downcase_keys_helper(h)
15
+ case h
16
+ when Hash
17
+ h = h.dup
18
+ h.keys.each do |key|
19
+ new_key = key.downcase
20
+ val = h.delete(key)
21
+ h[new_key] = downcase_keys_helper(val)
22
+ end
23
+ when Array
24
+ return h.map {|e| downcase_keys_helper(e) }
25
+ end
26
+
27
+ return h
28
+ end
29
+
14
30
  def self.handles?(resume_format)
15
31
  resume_format.to_s.downcase == "json"
16
32
  end
17
33
 
18
34
  def load!(input)
19
- data = Yajl::Parser.parse(input, symbolize_keys: false)
20
- # data = Yajl::Parser.parse(input, symbolize_keys: true)
21
-
22
- # Copy the data data from the "basics" field into top level
23
- # and remove the basics group from the hash
24
- data["basics"].each_pair {|k, v| data[k] = v }
25
- data.delete "basics"
26
-
27
- @data = data
35
+ data = Yajl::Parser.parse(input)
28
36
 
29
37
  # Fix dates, since they're just strings now
30
- [ @data["work"], @data["volunteer"], @data["education"] ].each do |set|
38
+ [ data["work"], data["volunteer"], data["education"] ].each do |set|
31
39
  set.each do |e|
32
40
  e["startDate"] = JSONResume.date_helper(e["startDate"])
33
41
  e["endDate"] = JSONResume.date_helper(e["endDate"])
34
42
  end
35
43
  end
36
44
 
37
- @data["publications"].each{|e| e["releaseDate"] = JSONResume.date_helper(e["releaseDate"]) }
38
- @data["awards"].each{|e| e["date"] = JSONResume.date_helper(e["date"]) }
45
+ data["publications"].each {|e| e["releaseDate"] = JSONResume.date_helper(e["releaseDate"]) }
46
+ data["awards"].each {|e| e["date"] = JSONResume.date_helper(e["date"]) }
47
+
48
+ @data = JSONResume.downcase_keys_helper(data)
39
49
  end
40
50
  end
41
51
  end
@@ -14,13 +14,15 @@ module ResumeStylist
14
14
 
15
15
  def initialize(input, resume_format)
16
16
  @data = {
17
- "name" => "",
18
- "label" => "",
19
- "picture" => "",
20
- "email" => "",
21
- "phone" => "",
22
- "website" => "",
23
- "summary" => "",
17
+ "basics" => {
18
+ "name" => nil,
19
+ "label" => nil,
20
+ "picture" => nil,
21
+ "email" => nil,
22
+ "phone" => nil,
23
+ "website" => nil,
24
+ "summary" => nil
25
+ },
24
26
 
25
27
  "location" => {
26
28
  "address" => nil,
@@ -30,7 +32,7 @@ module ResumeStylist
30
32
  "region" => nil
31
33
  },
32
34
 
33
- "profiles" => [], # { network_name, username, url }
35
+ "profiles" => [], # { network, username, url }
34
36
  "work" => [], # { organisation, position, website, summary, highlights => [], startDate, endDate }
35
37
  "volunteer" => [], # { organisation, position, website, summary, highlights => [], startDate, endDate }
36
38
  "education" => [], # { institution, area, studyType, grade, courses => [], startDate, endDate }
@@ -0,0 +1,31 @@
1
+ module ResumeStylist
2
+ class NormalizeCSS < Liquid::Tag
3
+
4
+ NormalizeCSS_URI = URI("https://necolas.github.io/normalize.css/latest/normalize.css")
5
+
6
+ def initialize(tag_name, tokens, liq)
7
+ if tokens.include? "inline"
8
+ req = Net::HTTP::Get.new(NormalizeCSS_URI.request_uri)
9
+
10
+ http = Net::HTTP.new(NormalizeCSS_URI.host, NormalizeCSS_URI.port)
11
+ http.use_ssl = (NormalizeCSS_URI.scheme == "https")
12
+
13
+ response = http.request(req)
14
+
15
+ if response.code == "200"
16
+ @content = response.body
17
+ else
18
+ @content = "/*! ERROR: Request for `#{NormalizeCSS_URI}` returned #{response.code}! Please report this bug at https://github.com/omninonsense/resume-stylist/issues/new */"
19
+ end
20
+ else
21
+ @content = %Q{<link rel="stylesheet" href="#{NormalizeCSS_URI}" media="screen">}
22
+ end
23
+ end
24
+
25
+ def render(context)
26
+ @content
27
+ end
28
+ end
29
+ end
30
+
31
+ Liquid::Template.register_tag('normalize_css', ResumeStylist::NormalizeCSS)
@@ -0,0 +1,46 @@
1
+ module ResumeStylist
2
+ module OrdinalDateFilter
3
+ # safe true
4
+
5
+ # # For languages with more diverse ordinals (if such even exist)
6
+ # Ordinals = %w{
7
+ # st nd rd th th th th th th th
8
+ # th th th th th th th th th th
9
+ # st nd rd th th th th th th th
10
+ # st
11
+ # }
12
+
13
+ # For English
14
+ Ordinals = Hash.new do |h, k|
15
+ if (11..13).cover? k
16
+ h[k] = "th"
17
+ elsif 1 == (k % 10)
18
+ h[k] = "st"
19
+ elsif 2 == (k % 10)
20
+ h[k] = "nd"
21
+ elsif 3 == (k % 10)
22
+ h[k] = "rd"
23
+ else
24
+ h[k] = "th"
25
+ end
26
+ end
27
+
28
+ def ordinal_date(input)
29
+ _day = input.mday
30
+ _ordinal = Ordinals[_day]
31
+ _month = Date::MONTHNAMES[input.month]
32
+ _year = input.year
33
+
34
+ day = %Q|<span class="day">#{_day}</span>|
35
+ ordinal = %Q|<span class="ordinal">#{_ordinal}</span>|
36
+ month = %Q|<span class="month">#{_month}</span>|
37
+ year = %Q|<span class="year">#{_year}</span>|
38
+
39
+ html = "#{day}#{ordinal} #{month} #{year}"
40
+
41
+ return html
42
+ end
43
+ end
44
+ end
45
+
46
+ Liquid::Template.register_filter(ResumeStylist::OrdinalDateFilter)
@@ -13,7 +13,17 @@ module ResumeStylist
13
13
  end
14
14
 
15
15
  def render(resume_data)
16
- @resume = @template.render(resume_data)
16
+ meta_data = {
17
+ "frontmatter" => @frontmatter,
18
+
19
+ "_generator" => {
20
+ "name" => "resume-stylist",
21
+ "version" => ResumeStylist::VERSION
22
+ }
23
+
24
+ }
25
+ ctx = resume_data.merge(meta_data)
26
+ @resume = @template.render(ctx)
17
27
  post_process!
18
28
 
19
29
  @resume
@@ -47,3 +57,6 @@ module ResumeStylist
47
57
  end
48
58
  end
49
59
  end
60
+
61
+ require "resume-stylist/theme/normalize_css"
62
+ require "resume-stylist/theme/ordinal_date"
@@ -1,3 +1,3 @@
1
1
  module ResumeStylist
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -3,6 +3,9 @@ require "oga"
3
3
  require "liquid"
4
4
  require "sass"
5
5
  require "date"
6
+ require 'net/http'
7
+ require 'uri'
8
+ require 'English'
6
9
 
7
10
  require "resume-stylist/version"
8
11
  require "resume-stylist/resume"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resume-stylist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nino Miletich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-16 00:00:00.000000000 Z
11
+ date: 2016-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -137,8 +137,6 @@ files:
137
137
  - LICENSE.txt
138
138
  - README.md
139
139
  - Rakefile
140
- - bin/console
141
- - bin/setup
142
140
  - data/resume-stylist/templates/resume.json
143
141
  - data/resume-stylist/templates/theme.html.liquid
144
142
  - exe/resume-stylist
@@ -147,6 +145,8 @@ files:
147
145
  - lib/resume-stylist/resume/json.rb
148
146
  - lib/resume-stylist/resume/xml.rb
149
147
  - lib/resume-stylist/theme.rb
148
+ - lib/resume-stylist/theme/normalize_css.rb
149
+ - lib/resume-stylist/theme/ordinal_date.rb
150
150
  - lib/resume-stylist/version.rb
151
151
  - resume-stylist.gemspec
152
152
  homepage: https://github.com/omninonsense/resume-stylist
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "resume-stylist"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
data/bin/setup DELETED
@@ -1,7 +0,0 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here