resme 1.0.1 → 2.0.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 +4 -4
- data/CHANGELOG.org +15 -0
- data/CODE_OF_CONDUCT.org +16 -0
- data/LICENSE.txt +1 -1
- data/README.org +19 -129
- data/Rakefile +11 -1
- data/TAGS +83 -0
- data/exe/resme +2 -2
- data/lib/resme/cli.rb +80 -0
- data/lib/resme/document.rb +37 -0
- data/lib/resme/document_validator.rb +308 -0
- data/lib/resme/executor.rb +90 -0
- data/lib/resme/helper.rb +211 -0
- data/lib/resme/json_resume.rb +156 -0
- data/lib/resme/version.rb +1 -2
- data/lib/resme.rb +20 -5
- data/sig/resme.rbs +4 -0
- data/templates/json.erb +1 -0
- data/templates/org.erb +217 -0
- data/{lib/resme/templates → templates}/resume.yml +38 -33
- metadata +22 -53
- data/.gitignore +0 -8
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -20
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/resme/cli/command_semantics.rb +0 -198
- data/lib/resme/cli/command_syntax.rb +0 -282
- data/lib/resme/cli/resume_structure_validator.rb +0 -293
- data/lib/resme/renderer/renderer.rb +0 -134
- data/lib/resme/templates/resume.json.erb +0 -155
- data/lib/resme/templates/resume.md.erb +0 -160
- data/lib/resme/templates/resume.org.erb +0 -205
- data/resme.gemspec +0 -34
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
data/bin/console
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require "bundler/setup"
|
|
4
|
-
require "resme"
|
|
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(__FILE__)
|
data/bin/setup
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "resme/version"
|
|
4
|
-
require "readline"
|
|
5
|
-
require "fileutils"
|
|
6
|
-
require "date"
|
|
7
|
-
require "yaml"
|
|
8
|
-
require "erb"
|
|
9
|
-
require "json"
|
|
10
|
-
|
|
11
|
-
module Resme
|
|
12
|
-
# Give e meaning to commands
|
|
13
|
-
module CommandSemantics
|
|
14
|
-
APPNAME = "resme"
|
|
15
|
-
VERSION = Resme::VERSION
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
# Main App Starts Here!
|
|
19
|
-
#
|
|
20
|
-
def self.version(opts = nil, argv = [])
|
|
21
|
-
puts "#{APPNAME} version #{VERSION}"
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def self.man(opts = nil, argv = [])
|
|
25
|
-
path = File.join(File.dirname(__FILE__), "/../../../README.org")
|
|
26
|
-
file = File.open(path, "r")
|
|
27
|
-
puts file.read
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.help(opts = nil, argv = [])
|
|
31
|
-
all_commands = CommandSyntax.commands
|
|
32
|
-
|
|
33
|
-
if argv == []
|
|
34
|
-
puts "#{APPNAME} command [options] [args]\n"
|
|
35
|
-
puts "Available commands:\n"
|
|
36
|
-
all_commands.each_key do |key|
|
|
37
|
-
puts " #{all_commands[key][:options].banner}"
|
|
38
|
-
end
|
|
39
|
-
else
|
|
40
|
-
argv.map do |x|
|
|
41
|
-
puts all_commands[x.to_sym][:help]
|
|
42
|
-
puts "\n\n"
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def self.console(opts = nil, argv = [])
|
|
48
|
-
all_commands = CommandSyntax.commands
|
|
49
|
-
all_commands.delete(:console)
|
|
50
|
-
|
|
51
|
-
i = 0
|
|
52
|
-
loop do
|
|
53
|
-
string = Readline.readline("#{APPNAME}:%03d> " % i, true)
|
|
54
|
-
# as a courtesy, remove any leading appname string
|
|
55
|
-
string.gsub!(/^#{APPNAME} /, "")
|
|
56
|
-
exit 0 if %w[exit quit .].include? string
|
|
57
|
-
execute all_commands, string.split(" ")
|
|
58
|
-
i += 1
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# read-eval-print step
|
|
63
|
-
# check if argv is in any of all_commands, parse options
|
|
64
|
-
# according to the specification in all_commands and invoke
|
|
65
|
-
# a function in this class to actually do the work
|
|
66
|
-
def self.execute(all_commands, argv)
|
|
67
|
-
if argv == [] or argv[0] == "--help" or argv[0] == "-h"
|
|
68
|
-
help
|
|
69
|
-
exit 0
|
|
70
|
-
else
|
|
71
|
-
command = argv[0]
|
|
72
|
-
command_spec = all_commands[command.to_sym]
|
|
73
|
-
|
|
74
|
-
if command_spec
|
|
75
|
-
command_name = command_spec[:name]
|
|
76
|
-
option_parser = command_spec[:options]
|
|
77
|
-
|
|
78
|
-
begin
|
|
79
|
-
argv.shift # remove command name from ARGV
|
|
80
|
-
options = {}
|
|
81
|
-
parser = option_parser.parse!(into: options)
|
|
82
|
-
eval "CommandSemantics::#{command_name}(options, argv)"
|
|
83
|
-
rescue Exception => e
|
|
84
|
-
puts "#{APPNAME} error: #{e}"
|
|
85
|
-
puts "Help with \"#{APPNAME} help #{command_name}\""
|
|
86
|
-
end
|
|
87
|
-
else
|
|
88
|
-
puts "#{APPNAME} error: "#{command}" is not a valid command."
|
|
89
|
-
puts "List commands with \"#{APPNAME} help\"."
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
#
|
|
95
|
-
# APP SPECIFIC COMMANDS
|
|
96
|
-
#
|
|
97
|
-
def self.check(opts, argv)
|
|
98
|
-
begin
|
|
99
|
-
document = YAML.load_file(argv[0], permitted_classes: [Date])
|
|
100
|
-
rescue Psych::SyntaxError => ex
|
|
101
|
-
puts "The file #{argv[0]} has an invalid structure."
|
|
102
|
-
puts ex.message
|
|
103
|
-
exit 1
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
begin
|
|
107
|
-
errors = ResumeStructureValidator.validate(document)
|
|
108
|
-
rescue Exception => ex
|
|
109
|
-
puts "The files #{argv[0]} does not validate"
|
|
110
|
-
ex.entries.each do |error|
|
|
111
|
-
puts "#{error[:full_path]}: #{error[:message]}"
|
|
112
|
-
end
|
|
113
|
-
exit 1
|
|
114
|
-
end
|
|
115
|
-
puts "The file #{argv[0]} has a valid structure."
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def self.init(opts, argv)
|
|
119
|
-
output = opts[:output] || "resume.yml"
|
|
120
|
-
force = opts[:force]
|
|
121
|
-
path = File.dirname(__FILE__), "/../templates/resume.yml"
|
|
122
|
-
template = File.join(path)
|
|
123
|
-
|
|
124
|
-
# avoid catastrophe
|
|
125
|
-
if File.exist?(output) && !force
|
|
126
|
-
puts "#{APPNAME} error: file #{output} already exists."
|
|
127
|
-
puts "Use --force if you want to overwrite it."
|
|
128
|
-
else
|
|
129
|
-
content = File.read(template)
|
|
130
|
-
backup_and_write output, content
|
|
131
|
-
puts "YML resume template generated in #{output}"
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def self.list(opts, argv)
|
|
136
|
-
data = {}
|
|
137
|
-
argv.each do |file|
|
|
138
|
-
data = data.merge(YAML.load_file(file, permitted_classes: [Date]))
|
|
139
|
-
end
|
|
140
|
-
puts "Sections included in #{argv.join(", ")}:"
|
|
141
|
-
data.keys.each do |key|
|
|
142
|
-
puts "- #{key}: #{(data[key] || []).size} entries"
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def self.view(opts, argv)
|
|
147
|
-
format = opts[:to]
|
|
148
|
-
template = File.join(File.dirname(__FILE__), "/../templates/resume.#{format}.erb")
|
|
149
|
-
puts File.read template
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def self.generate(opts, argv)
|
|
153
|
-
format = opts[:to]
|
|
154
|
-
output = opts[:output] || "resume-#{Date.today}.#{format}"
|
|
155
|
-
|
|
156
|
-
if opts[:erb]
|
|
157
|
-
template = opts[:erb]
|
|
158
|
-
else
|
|
159
|
-
template = File.join(File.dirname(__FILE__), "/../templates/resume.#{format}.erb")
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
skipped_sections = opts[:skip] || []
|
|
163
|
-
|
|
164
|
-
if !File.exist?(template)
|
|
165
|
-
puts "#{APPNAME} error: format #{format} is not understood."
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
render argv, template, output, skipped_sections
|
|
169
|
-
puts "Resume generated in #{output}"
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
private_class_method def self.render(yml_files, template_name, output_name, skipped_sections)
|
|
173
|
-
data = {}
|
|
174
|
-
yml_files.each do |file|
|
|
175
|
-
data = data.merge(YAML.load_file(file, permitted_classes: [Date]))
|
|
176
|
-
end
|
|
177
|
-
skipped_sections.each do |section|
|
|
178
|
-
data.reject! { |k| k == section }
|
|
179
|
-
end
|
|
180
|
-
template = File.read(template_name)
|
|
181
|
-
output = ERB.new(template, trim_mode: "-").result(binding)
|
|
182
|
-
# it is difficult to write readable ERBs with no empty lines... we use
|
|
183
|
-
# gsub to replace multiple empty lines with \n\n in the final output
|
|
184
|
-
output.gsub!(/([\t ]*\n){3,}/, "\n\n")
|
|
185
|
-
backup_and_write output_name, output
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
private_class_method def self.backup(filename)
|
|
189
|
-
FileUtils::cp filename, filename + "~"
|
|
190
|
-
puts "Backup copy #{filename} created in #{filename}~."
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
private_class_method def self.backup_and_write(filename, content)
|
|
194
|
-
backup(filename) if File.exist?(filename)
|
|
195
|
-
File.open(filename, "w") { |f| f.puts content }
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
end
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
require "optparse"
|
|
2
|
-
|
|
3
|
-
module Resme
|
|
4
|
-
module CommandSyntax
|
|
5
|
-
# Return a hash of hashes. Each key is the name of a command and
|
|
6
|
-
# includes useful information, such as an Option object to
|
|
7
|
-
# parse options and a documentation string.
|
|
8
|
-
def self.commands
|
|
9
|
-
cmd_spec = {}
|
|
10
|
-
methods.each do |method|
|
|
11
|
-
cmd_spec = cmd_spec.merge eval(method.to_s) if method.to_s.include?("_opts")
|
|
12
|
-
end
|
|
13
|
-
cmd_spec
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def self.version_opts
|
|
17
|
-
opts = OptionParser.new do |opts|
|
|
18
|
-
opts.banner = "version # print version information"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
help = <<-EOS
|
|
22
|
-
NAME
|
|
23
|
-
#{opts.banner}
|
|
24
|
-
|
|
25
|
-
SYNOPSYS
|
|
26
|
-
#{opts.to_s}
|
|
27
|
-
|
|
28
|
-
DESCRIPTION
|
|
29
|
-
return version information
|
|
30
|
-
|
|
31
|
-
EXAMPLES
|
|
32
|
-
# resme version
|
|
33
|
-
resme version #{VERSION}
|
|
34
|
-
EOS
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
version: {
|
|
38
|
-
name: :version,
|
|
39
|
-
options: opts,
|
|
40
|
-
help: help.gsub(" ", "")
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def self.console_opts
|
|
46
|
-
opts = OptionParser.new do |opts|
|
|
47
|
-
opts.banner = "console # enter the console"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
help = <<-EOS
|
|
51
|
-
NAME
|
|
52
|
-
#{opts.banner}
|
|
53
|
-
|
|
54
|
-
SYNOPSYS
|
|
55
|
-
#{opts.to_s}
|
|
56
|
-
|
|
57
|
-
DESCRIPTION
|
|
58
|
-
Invoke a console, from which you can more easily run
|
|
59
|
-
resme commands.
|
|
60
|
-
|
|
61
|
-
EXAMPLES
|
|
62
|
-
resme console
|
|
63
|
-
resme:000> check
|
|
64
|
-
resme:001> generate -t md
|
|
65
|
-
resme:002>
|
|
66
|
-
EOS
|
|
67
|
-
|
|
68
|
-
{
|
|
69
|
-
console: {
|
|
70
|
-
name: :console,
|
|
71
|
-
options: opts,
|
|
72
|
-
help: help.gsub(" ", "")
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def self.man_opts
|
|
78
|
-
opts = OptionParser.new do |opts|
|
|
79
|
-
opts.banner = "man # print resme manual page"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
help = <<-EOS
|
|
83
|
-
NAME
|
|
84
|
-
#{opts.banner}
|
|
85
|
-
|
|
86
|
-
SYNOPSYS
|
|
87
|
-
#{opts.to_s}
|
|
88
|
-
|
|
89
|
-
DESCRIPTION
|
|
90
|
-
Print the README file of this gem
|
|
91
|
-
|
|
92
|
-
EXAMPLES
|
|
93
|
-
resme man
|
|
94
|
-
EOS
|
|
95
|
-
|
|
96
|
-
{
|
|
97
|
-
man: {
|
|
98
|
-
name: :man,
|
|
99
|
-
options: opts,
|
|
100
|
-
help: help.gsub(" ", "")
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def self.help_opts
|
|
106
|
-
opts = OptionParser.new do |opts|
|
|
107
|
-
opts.banner = "help [command] # print command usage"
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
help = <<-EOS
|
|
111
|
-
NAME
|
|
112
|
-
#{opts.banner}
|
|
113
|
-
|
|
114
|
-
SYNOPSYS
|
|
115
|
-
#{opts.to_s}
|
|
116
|
-
|
|
117
|
-
DESCRIPTION
|
|
118
|
-
Print help about a command
|
|
119
|
-
|
|
120
|
-
EXAMPLES
|
|
121
|
-
resme help
|
|
122
|
-
resme help generate
|
|
123
|
-
EOS
|
|
124
|
-
{
|
|
125
|
-
help: {
|
|
126
|
-
name: :help,
|
|
127
|
-
options: opts,
|
|
128
|
-
help: help.gsub(" ", "")
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def self.init_opts
|
|
134
|
-
opts = OptionParser.new do |opts|
|
|
135
|
-
opts.banner = "init [options] # generate an empty resume.yml file"
|
|
136
|
-
opts.on("-o", "--output FILENAME", String, "Output filename")
|
|
137
|
-
opts.on("-f", "--force", FalseClass, "Overwrite existing file (if present)")
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
help = <<-EOS
|
|
141
|
-
NAME
|
|
142
|
-
#{opts.banner}
|
|
143
|
-
|
|
144
|
-
SYNOPSYS
|
|
145
|
-
#{opts.to_s}
|
|
146
|
-
|
|
147
|
-
DESCRIPTION
|
|
148
|
-
Generate a YAML template for your resume in the current directory.
|
|
149
|
-
|
|
150
|
-
EXAMPLES
|
|
151
|
-
resme init
|
|
152
|
-
resme init -o r.yml
|
|
153
|
-
resme init -o r.yml --force
|
|
154
|
-
EOS
|
|
155
|
-
{
|
|
156
|
-
init: {
|
|
157
|
-
name: :init,
|
|
158
|
-
options: opts,
|
|
159
|
-
help: help.gsub(" ", "")
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def self.check_opts
|
|
165
|
-
opts = OptionParser.new do |opts|
|
|
166
|
-
opts.banner = "check resume.yml # Check syntax of resume.yml"
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
help = <<-EOS
|
|
170
|
-
NAME
|
|
171
|
-
#{opts.banner}
|
|
172
|
-
|
|
173
|
-
SYNOPSYS
|
|
174
|
-
#{opts.to_s}
|
|
175
|
-
|
|
176
|
-
DESCRIPTION
|
|
177
|
-
Check whether a YAML file conforms with the RESME syntax.
|
|
178
|
-
|
|
179
|
-
EXAMPLES
|
|
180
|
-
resme check file.yml
|
|
181
|
-
EOS
|
|
182
|
-
|
|
183
|
-
{
|
|
184
|
-
check: {
|
|
185
|
-
name: :check,
|
|
186
|
-
options: opts,
|
|
187
|
-
help: help.gsub(" ", "")
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
def self.list_opts
|
|
193
|
-
opts = OptionParser.new do |opts|
|
|
194
|
-
opts.banner = "list resume.yml # List main sections in resume.yml"
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
help = <<-EOS
|
|
198
|
-
NAME
|
|
199
|
-
#{opts.banner}
|
|
200
|
-
|
|
201
|
-
SYNOPSYS
|
|
202
|
-
#{opts.to_s}
|
|
203
|
-
|
|
204
|
-
DESCRIPTION
|
|
205
|
-
List main sections in resume.yml.
|
|
206
|
-
|
|
207
|
-
EXAMPLES
|
|
208
|
-
resme list file.yml
|
|
209
|
-
EOS
|
|
210
|
-
|
|
211
|
-
{
|
|
212
|
-
list: {
|
|
213
|
-
name: :list,
|
|
214
|
-
options: opts,
|
|
215
|
-
help: help.gsub(" ", "")
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def self.view_opts
|
|
221
|
-
opts = OptionParser.new do |o|
|
|
222
|
-
o.banner = "view --template FORMAT # Print template used for format"
|
|
223
|
-
o.on("-t", "--template FORMAT", String, "View template for FORMAT")
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
help = <<-EOS
|
|
227
|
-
NAME
|
|
228
|
-
#{opts.banner}
|
|
229
|
-
|
|
230
|
-
SYNOPSYS
|
|
231
|
-
#{opts.to_s}
|
|
232
|
-
|
|
233
|
-
DESCRIPTION
|
|
234
|
-
Print template used for FORMAT
|
|
235
|
-
|
|
236
|
-
EXAMPLES
|
|
237
|
-
resme view --template md
|
|
238
|
-
EOS
|
|
239
|
-
|
|
240
|
-
{
|
|
241
|
-
view: {
|
|
242
|
-
name: :view,
|
|
243
|
-
options: opts,
|
|
244
|
-
help: help.gsub(" ", "")
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def self.generate_opts
|
|
250
|
-
opts = OptionParser.new do |o|
|
|
251
|
-
o.banner = "generate [options] resume.yml ... # output resume"
|
|
252
|
-
o.on("-e", "--erb FILENAME", String, "Template to use")
|
|
253
|
-
o.on("-t", "--to FORMAT", String, "Output format")
|
|
254
|
-
o.on("-o", "--output FILENAME", String, "Output filename")
|
|
255
|
-
o.on("-s", "--skip SECTION,SECTION", Array, "Sections to skip")
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
help = <<-EOS
|
|
259
|
-
NAME
|
|
260
|
-
#{opts.banner}
|
|
261
|
-
|
|
262
|
-
SYNOPSYS
|
|
263
|
-
#{opts.to_s}
|
|
264
|
-
|
|
265
|
-
DESCRIPTION
|
|
266
|
-
Generate a resume from the YAML input files.
|
|
267
|
-
|
|
268
|
-
EXAMPLES
|
|
269
|
-
resme generate -t org resume.yml
|
|
270
|
-
resme generate -t md -o r.md section-1.yml section-2.yml
|
|
271
|
-
EOS
|
|
272
|
-
|
|
273
|
-
{
|
|
274
|
-
generate: {
|
|
275
|
-
name: :generate,
|
|
276
|
-
options: opts,
|
|
277
|
-
help: help.gsub(" ", "")
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
end
|