curriculum-generator 1.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 +7 -0
- data/.gitignore +23 -0
- data/.ruby-version +1 -0
- data/CGen.gemspec +35 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +62 -0
- data/Rakefile +3 -0
- data/bin/cgen.rb +86 -0
- data/lib/CGen.rb +27 -0
- data/lib/cgen/compiler.rb +96 -0
- data/lib/cgen/curriculum.rb +57 -0
- data/lib/cgen/data_loader/yaml_data_loader.rb +31 -0
- data/lib/cgen/data_loader.rb +6 -0
- data/lib/cgen/generator/basic_generator.rb +37 -0
- data/lib/cgen/generator/cv_column.rb +32 -0
- data/lib/cgen/generator/cv_double_item.rb +42 -0
- data/lib/cgen/generator/cv_entry.rb +33 -0
- data/lib/cgen/generator/cv_item.rb +29 -0
- data/lib/cgen/generator/cv_item_with_comment.rb +32 -0
- data/lib/cgen/generator/cv_list_double_item.rb +31 -0
- data/lib/cgen/generator/cv_list_item.rb +23 -0
- data/lib/cgen/generator/list.rb +25 -0
- data/lib/cgen/generator/macro_substitution.rb +11 -0
- data/lib/cgen/generator/specific/education.rb +95 -0
- data/lib/cgen/generator/specific/self_assessment.rb +61 -0
- data/lib/cgen/generator/specific/work_experience.rb +81 -0
- data/lib/cgen/generator.rb +10 -0
- data/lib/cgen/util/latex_to_pdf.rb +61 -0
- data/lib/cgen/util/logging.rb +27 -0
- data/lib/cgen/util/shell_command.rb +48 -0
- data/lib/cgen/util.rb +6 -0
- data/lib/cgen/version.rb +6 -0
- data/static/bundled_templates/moderncv/.gitkeep +0 -0
- data/static/bundled_templates/moderncv/deps.yml +15 -0
- data/static/bundled_templates/moderncv/main.tex +208 -0
- data/static/bundled_templates/moderncv/publications.bib +40 -0
- data/static/bundled_templates/moderncv/resources/AuthorPhoto.png +0 -0
- metadata +194 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9d188f9f8afdc19e86cada3e6707bf0cbd0d7f89
|
4
|
+
data.tar.gz: e82273c0742e3da2644db4c48508499c2de0d6a2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 965ded86275d134b62ab68dda1b54333d607ac28ac7cd7acf91f435e5c750b6381cd3a58da277894ae725f779273d5b4f27c200ce0ab4c493d7666d9396d8f1a
|
7
|
+
data.tar.gz: 4059c63ef2bc1e468bf0f9b633396a0903e0019a1b0d0c925690d904ed197f07855988049669bdf21ae8bba9f8ecc003be02a11e6fb535fea82fc3d0fba954aa
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
/.idea
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.1
|
data/CGen.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'cgen/version'
|
6
|
+
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
|
10
|
+
spec.name = 'curriculum-generator'
|
11
|
+
spec.version = CGen::VERSION
|
12
|
+
spec.authors = ['Alessandro Molari']
|
13
|
+
spec.email = ['molari.alessandro@gmail.com']
|
14
|
+
spec.summary = %q{Curriculum Vitae generator}
|
15
|
+
spec.homepage = 'http://github.com/alem0lars/cgen'
|
16
|
+
spec.license = 'Apache 2'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec)/})
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
|
26
|
+
spec.add_runtime_dependency 'hash-deep-merge'
|
27
|
+
spec.add_runtime_dependency 'monadic'
|
28
|
+
|
29
|
+
spec.add_runtime_dependency 'awesome_print'
|
30
|
+
spec.add_runtime_dependency 'colorize'
|
31
|
+
spec.add_runtime_dependency 'highline'
|
32
|
+
|
33
|
+
spec.add_runtime_dependency 'erubis'
|
34
|
+
|
35
|
+
end
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Alessandro Molari
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# CGen
|
2
|
+
|
3
|
+
CGen is the next **localized Curriculum Vitae** editor, both for hackers and end-users.
|
4
|
+
|
5
|
+
*Please note that this is still in early development stages. If you are an end-user you may want to check this project out in a couple of weeks.*
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Via homebrew
|
10
|
+
|
11
|
+
$ brew install cgen
|
12
|
+
|
13
|
+
Via rubygems
|
14
|
+
|
15
|
+
$ gem install curriculum-generator
|
16
|
+
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
CGen provides two editing modes:
|
21
|
+
1. **Hacking Mode**
|
22
|
+
2. **Normal Mode**
|
23
|
+
|
24
|
+
### Hacking Mode
|
25
|
+
|
26
|
+
This is where CGen shrines, by allowing users to **just provide the data** and let the system do the rest. This system comes with *extensibility* in mind, by providing different levels of customization:
|
27
|
+
1. **Data-level**: The first level is the most commonly used. The system automatically pulls all of your defined data. This means that there isn't anything wired-in, no names, no values, anything. Data is just data and you can use it as you want !
|
28
|
+
2. **Templates-level**: For basic customizations you can write your own (LaTeX) **templates**, or modify an existing one.
|
29
|
+
3. **Generators-level**: For more advanced customizations, you can write your own (Ruby) **generators**.
|
30
|
+
|
31
|
+
### Normal Mode
|
32
|
+
|
33
|
+
This is primarly for non-hackers. In this mode the curriculum is edited by using a GUI.
|
34
|
+
|
35
|
+
*This mode is still in development: not released yet*.
|
36
|
+
|
37
|
+
## Contributing
|
38
|
+
|
39
|
+
### Project management
|
40
|
+
|
41
|
+
#### Scrum & Trello
|
42
|
+
|
43
|
+
The project follows the **Scrum Methodology**, using Trello as the main tool.
|
44
|
+
|
45
|
+
The board is available under: [CGen Trello Board](https://trello.com/b/8er5R7dK/cgen)
|
46
|
+
|
47
|
+
#### Report bugs / Request enhancements
|
48
|
+
|
49
|
+
Create a new card in the *Product Backlog* list:
|
50
|
+
|
51
|
+
* With the *red* label for bug reporting
|
52
|
+
* With the *blue* label to request an enhancement
|
53
|
+
|
54
|
+
### Fork-Pull pattern
|
55
|
+
|
56
|
+
The project contribution is commonly done by using the so-much-famous *fork-pull pattern*:
|
57
|
+
|
58
|
+
1. Fork it ( https://github.com/[my-github-username]/cgen/fork )
|
59
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
60
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
61
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
62
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/cgen.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
require 'cgen'
|
5
|
+
|
6
|
+
|
7
|
+
# == Setup functions ===================================================================================================
|
8
|
+
|
9
|
+
def setup_opts
|
10
|
+
|
11
|
+
$tmp_pth = Pathname.new Dir.mktmpdir
|
12
|
+
$tex_out_pth = Pathname.new Dir.mktmpdir
|
13
|
+
$log_dir = $tmp_pth.join('log')
|
14
|
+
|
15
|
+
$data_pth = Pathname.new File.expand_path(ask("What's the path for the directory containing the data ? ".magenta))
|
16
|
+
$out_pth = Pathname.new File.expand_path(ask("What's the destination path ? ".magenta))
|
17
|
+
$main_tex_file_name = ask('Main TeX file name ? '.magenta) { |q| q.default = 'main.tex' }
|
18
|
+
$resources_dir_name = ask("What's the name for the directory containing the resources (relative to the directory that contains the template) ? ".magenta) { |q| q.default = 'resources' }
|
19
|
+
$template_dir_pth = Pathname.new(File.expand_path(
|
20
|
+
ask("What's the path of the template (leave empty for the default template) ? ".magenta) { |q|
|
21
|
+
q.default = File.join(File.dirname(File.dirname(__FILE__)), 'static', 'bundled_templates', 'moderncv')
|
22
|
+
}))
|
23
|
+
$template_deps_file_pth = Pathname.new(File.expand_path(
|
24
|
+
ask("What's the path for the YAML file containing the dependencies ? ".magenta) { |q|
|
25
|
+
q.default = $template_dir_pth.join('deps.yml').to_s
|
26
|
+
}))
|
27
|
+
|
28
|
+
# Ensure that the languages are correctly setup, i.e. if they aren't given use all of the available languages
|
29
|
+
$langs ||= Dir.glob($data_pth.join('*')).collect do |lang_data_pth|
|
30
|
+
File.basename(lang_data_pth).to_sym
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
# Setup the files / directories
|
36
|
+
def setup_filesystem
|
37
|
+
FileUtils.mkdir_p($out_pth)
|
38
|
+
FileUtils.mkdir_p($log_dir)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# == Utilities =========================================================================================================
|
43
|
+
|
44
|
+
def create_log_file(name)
|
45
|
+
$log_dir.join("log_#{DateTime.now.strftime('%Y.%m.%d')}_#{name}.txt")
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# == CGen entry point ==================================================================================================
|
50
|
+
|
51
|
+
puts '> Starting Curriculum'.green
|
52
|
+
|
53
|
+
setup_opts
|
54
|
+
setup_filesystem
|
55
|
+
|
56
|
+
$curriculum = CGen::Curriculum.new(
|
57
|
+
CGen::DataLoader::YamlDataLoader.new, # TODO: Let the user choose the data loader
|
58
|
+
CGen::Compiler.new($tex_out_pth),
|
59
|
+
$data_pth,
|
60
|
+
$template_dir_pth,
|
61
|
+
$langs,
|
62
|
+
File.directory?($data_pth.join('en')) ? :en : nil)
|
63
|
+
|
64
|
+
unless $curriculum.validate_deps($template_deps_file_pth)
|
65
|
+
CGen::Util::Logging.log(:fatal_error, msg: 'The dependencies are not satisfied')
|
66
|
+
end
|
67
|
+
|
68
|
+
$curriculum.compile($langs)
|
69
|
+
|
70
|
+
puts '>> Generating PDFs'.green
|
71
|
+
|
72
|
+
$langs.each do |lang|
|
73
|
+
puts '>> Generating PDF for language '.cyan + lang.to_s.light_black
|
74
|
+
|
75
|
+
input_dir = $tex_out_pth.join(lang.to_s)
|
76
|
+
out_pth = $out_pth.join(lang.to_s)
|
77
|
+
FileUtils.mkdir_p(out_pth)
|
78
|
+
|
79
|
+
latex_to_pdf = CGen::Util::LatexToPdf.new($main_tex_file_name,
|
80
|
+
input_dir,
|
81
|
+
input_dir.join($resources_dir_name).join('*').to_s,
|
82
|
+
out_pth,
|
83
|
+
create_log_file('latex_to_pdf'))
|
84
|
+
latex_to_pdf.generate
|
85
|
+
|
86
|
+
end
|
data/lib/CGen.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# The common module for all of the CGen classes
|
2
|
+
module CGen; end
|
3
|
+
|
4
|
+
|
5
|
+
# ==> Setup RubyGems and Bundler
|
6
|
+
require 'rubygems'
|
7
|
+
require 'bundler/setup'
|
8
|
+
|
9
|
+
# ==> Require the core dependencies
|
10
|
+
require 'tmpdir'
|
11
|
+
require 'pathname'
|
12
|
+
|
13
|
+
# ==> Require all of the external dependencies
|
14
|
+
require 'hash_deep_merge'
|
15
|
+
require 'monadic'
|
16
|
+
require 'awesome_print'
|
17
|
+
require 'colorize'
|
18
|
+
require 'highline/import'
|
19
|
+
require 'erubis'
|
20
|
+
|
21
|
+
# ==> Require the project stuff
|
22
|
+
require 'cgen/version'
|
23
|
+
require 'cgen/util'
|
24
|
+
require 'cgen/compiler'
|
25
|
+
require 'cgen/curriculum'
|
26
|
+
require 'cgen/data_loader'
|
27
|
+
require 'cgen/generator'
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class CGen::Compiler
|
2
|
+
|
3
|
+
def initialize(tex_out_pth)
|
4
|
+
@tex_out_pth = tex_out_pth
|
5
|
+
@generator_regex = /^generate\s*\(\s*(?<generator>[^,()]+)\s*,\s*(?<param>[^,()]+)\s*\)\s*$/i
|
6
|
+
@line_regex = /(?<re>\<=(?:(?<ctnt>(?>[^<>=]+)|\g<re>)+)\=\>)/
|
7
|
+
end
|
8
|
+
|
9
|
+
def validate_deps(deps_file_pth)
|
10
|
+
puts '>> Ensuring that the dependencies are satisfied'
|
11
|
+
|
12
|
+
# ==> Load the data from the YAML file
|
13
|
+
data = {}
|
14
|
+
File.open(deps_file_pth.to_s, 'r') { |deps_file| data.merge!(YAML::load(deps_file)) }
|
15
|
+
|
16
|
+
# ==> Validate commands are available on the system
|
17
|
+
data.has_key?('cmds') && data['cmds'].respond_to?(:all?) && data['cmds'].all? do |cmd|
|
18
|
+
CGen::Util::ShellCommand.exist?(cmd) ? true : puts(">> Command #{cmd} not found".red)
|
19
|
+
end
|
20
|
+
|
21
|
+
# ==> Validate that the required fonts are available
|
22
|
+
data.has_key?('pkgs') && data['pkgs'].respond_to?(:all?) && data['pkgs'].all? do |pkg|
|
23
|
+
`tlmgr list --only-installed | grep "i #{pkg}:"`.strip.length > 0 ? true : puts(">> Package #{pkg} not found".red)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Outputs the manual dependencies
|
27
|
+
data.has_key?('manual_deps') && data['manual_deps'].respond_to?(:each) do |manual_dep|
|
28
|
+
puts '>> Please ensure that the manual dependency is installed:'.yellow + manual_dep.to_s.light_black
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def compile(data, template_pth, lang)
|
33
|
+
puts '>> Compiling the language '.cyan + ":#{lang}".light_black
|
34
|
+
puts ' against the template '.cyan + template_pth.to_s.light_black
|
35
|
+
puts ' into the output directory '.cyan + @tex_out_pth.to_s.light_black
|
36
|
+
|
37
|
+
Dir.glob(template_pth.join('**').join('*')) do |file_pth|
|
38
|
+
if File.file?(file_pth)
|
39
|
+
rel_file_pth = file_pth.to_s.gsub(/#{template_pth}[\/]?/, '')
|
40
|
+
out_file_pth = @tex_out_pth.join(lang.to_s).join(rel_file_pth)
|
41
|
+
|
42
|
+
if File.extname(file_pth) == '.tex'
|
43
|
+
out_lines = []
|
44
|
+
|
45
|
+
File.open(file_pth, 'r').each do |line|
|
46
|
+
out_lines << line.gsub(@line_regex) do |_|
|
47
|
+
req_str = $2.strip.dup
|
48
|
+
|
49
|
+
md = @generator_regex.match(req_str)
|
50
|
+
if md
|
51
|
+
# Generate command
|
52
|
+
handle_generate(md[:generator].to_sym, md[:param], data, lang)
|
53
|
+
else
|
54
|
+
# Macro substitution
|
55
|
+
handle_generate(:macro_substitution, req_str, data, lang)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
FileUtils.mkdir_p(out_file_pth.dirname)
|
61
|
+
File.open(out_file_pth, 'w') do |tex_out_file|
|
62
|
+
tex_out_file.write(out_lines.join(''))
|
63
|
+
end
|
64
|
+
else
|
65
|
+
FileUtils.mkdir_p(out_file_pth.dirname)
|
66
|
+
FileUtils.cp_r(file_pth, out_file_pth)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def handle_generate(generator, param, data, lang)
|
73
|
+
generators = {
|
74
|
+
# Generic
|
75
|
+
cvitem: CGen::Generator::CvItem,
|
76
|
+
cventry: CGen::Generator::CvEntry,
|
77
|
+
cvitemwithcomment: CGen::Generator::CvItemWithComment,
|
78
|
+
cvdoubleitem: CGen::Generator::CvDoubleItem,
|
79
|
+
cvlistitem: CGen::Generator::CvListItem,
|
80
|
+
cvlistdoubleitem: CGen::Generator::CvListDoubleItem,
|
81
|
+
cvcolumn: CGen::Generator::CvColumn,
|
82
|
+
list: CGen::Generator::List,
|
83
|
+
# Specific
|
84
|
+
work_experience: CGen::Generator::WorkExperience,
|
85
|
+
education: CGen::Generator::Education,
|
86
|
+
self_assessment: CGen::Generator::SelfAssessment,
|
87
|
+
# Macro
|
88
|
+
macro_substitution: CGen::Generator::MacroSubstitution
|
89
|
+
}
|
90
|
+
|
91
|
+
generators.has_key?(generator) ?
|
92
|
+
generators[generator].new(param, data, lang).generate :
|
93
|
+
raise("Invalid generator: #{generator}. Expected one of: #{generators}")
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class CGen::Curriculum
|
2
|
+
|
3
|
+
attr_accessor :langs, :master_lang, :data_loader, :compiler, :data_pth
|
4
|
+
|
5
|
+
def initialize(data_loader, compiler, data_pth, template_pth, langs=[], master_lang=nil)
|
6
|
+
# Preconditions
|
7
|
+
raise 'Invalid langs. It cannot be empty' if langs.empty?
|
8
|
+
|
9
|
+
@data_loader = data_loader
|
10
|
+
@compiler = compiler
|
11
|
+
@langs = {}
|
12
|
+
# if the master language is not provided, then defaults to the first provided language
|
13
|
+
@master_lang = master_lang.nil? ? langs[0] : master_lang
|
14
|
+
|
15
|
+
@data_pth = data_pth
|
16
|
+
@template_pth = template_pth
|
17
|
+
|
18
|
+
puts '> Picking up the available languages'.green
|
19
|
+
|
20
|
+
langs.each do |lang|
|
21
|
+
lang_data_pth = @data_pth.join(lang.to_s)
|
22
|
+
|
23
|
+
inst = self
|
24
|
+
Either.chain do
|
25
|
+
bind -> { lang_data_pth.directory? }
|
26
|
+
bind -> {
|
27
|
+
lang_data = inst.data_loader.load_data(inst.data_pth, lang.to_sym, inst.master_lang.to_sym)
|
28
|
+
lang_data.is_a?(Hash) ? Success(lang_data) : Failure('lang data')
|
29
|
+
}
|
30
|
+
bind ->(lang_data) {
|
31
|
+
inst.langs[lang.to_sym] = { data: lang_data }
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_deps(template_deps_file_pth)
|
38
|
+
@compiler.validate_deps template_deps_file_pth
|
39
|
+
end
|
40
|
+
|
41
|
+
# Compile the curriculum for the provided languages
|
42
|
+
def compile(langs)
|
43
|
+
puts "> Compiling the curriculum for the languages: #{langs}".green
|
44
|
+
|
45
|
+
if langs.respond_to?(:each)
|
46
|
+
langs.each do |lang|
|
47
|
+
lang = lang.to_sym
|
48
|
+
@compiler.compile(@langs[lang][:data], @template_pth, lang)
|
49
|
+
end
|
50
|
+
elsif @langs.include? langs
|
51
|
+
@compiler.compile(@langs[lang][:data], @template_pth, langs)
|
52
|
+
else
|
53
|
+
raise 'Invalid lang'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
|
4
|
+
class CGen::DataLoader::YamlDataLoader
|
5
|
+
|
6
|
+
# Load the localized data from the directory `data_dir_pth`, following the convention that the localized data for
|
7
|
+
# a language are in a subdirectory of `data_dir_pth` named with the same name of the language.
|
8
|
+
# The target language name (which is also the subdirectory name) is `trgt_lang`, which fallbacks to the `master_lang`
|
9
|
+
def load_data(data_dir_pth, trgt_lang, master_lang)
|
10
|
+
CGen::Util::Logging.log(:loading_curriculum_data, trgt_lang: trgt_lang, master_lang: master_lang)
|
11
|
+
|
12
|
+
trgt_lang_data_dir_pth = data_dir_pth.join(trgt_lang.to_s)
|
13
|
+
master_lang_data_dir_pth = data_dir_pth.join(master_lang.to_s)
|
14
|
+
|
15
|
+
master_data = load_recursive_from_pth(trgt_lang_data_dir_pth)
|
16
|
+
trgt_data = load_recursive_from_pth(master_lang_data_dir_pth)
|
17
|
+
|
18
|
+
trgt_data.deep_merge(master_data) # return
|
19
|
+
end
|
20
|
+
|
21
|
+
# Load all of the YAML file starting from the given `base_dir_pth` and merges all of the data into an `Hash` and
|
22
|
+
# returns it
|
23
|
+
def load_recursive_from_pth(base_dir_pth)
|
24
|
+
data = {}
|
25
|
+
Dir.glob(base_dir_pth.join('**').join('*.yml')) do |yml_file_pth|
|
26
|
+
File.open(yml_file_pth, 'r') { |yml_file| data.merge!(YAML::load(yml_file)) }
|
27
|
+
end
|
28
|
+
data # return
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Abstract class for a generator. All generators should inherit from this class
|
2
|
+
class CGen::Generator::BasicGenerator
|
3
|
+
|
4
|
+
attr_accessor(:param)
|
5
|
+
attr_accessor(:data)
|
6
|
+
attr_accessor(:lang)
|
7
|
+
|
8
|
+
def initialize(param, data, lang)
|
9
|
+
@param = param
|
10
|
+
@data = data
|
11
|
+
@lang = lang
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate
|
15
|
+
raise 'Abstract class'
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_value(keys_str)
|
19
|
+
keys = keys_str.split('.').reverse
|
20
|
+
if keys.empty?
|
21
|
+
'' # return
|
22
|
+
else
|
23
|
+
data_tmp = @data.dup
|
24
|
+
until keys.empty?
|
25
|
+
key = keys.pop
|
26
|
+
data_tmp = data_tmp[key]
|
27
|
+
end
|
28
|
+
data_tmp # return
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def evaluate(input, context)
|
33
|
+
eruby = Erubis::Eruby.new(input)
|
34
|
+
eruby.evaluate(context) # return
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class CGen::Generator::CvColumn < CGen::Generator::BasicGenerator
|
2
|
+
|
3
|
+
def initialize(param, data, lang)
|
4
|
+
super(param, data, lang)
|
5
|
+
end
|
6
|
+
|
7
|
+
def generate
|
8
|
+
value = get_value(param)
|
9
|
+
unless value.is_a?(Array)
|
10
|
+
value = Array[value]
|
11
|
+
end
|
12
|
+
("\\begin{cvcolumns}" + (value.collect do |elem|
|
13
|
+
instance = self
|
14
|
+
result = Either.chain do
|
15
|
+
bind -> { elem.is_a?(Hash) }
|
16
|
+
bind -> { elem.has_key?('item_0') && elem.has_key?('item_1') }
|
17
|
+
bind -> {
|
18
|
+
instance.get_cv_list_double_item(elem['item_0'], elem['item_1'])
|
19
|
+
}
|
20
|
+
end
|
21
|
+
result.success? ? result.fetch : ''
|
22
|
+
end.join("\n")) +
|
23
|
+
"\\end{cvcolumns")
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def get_cv_list_double_item(item_0, item_1)
|
29
|
+
"\\cvcolumn{#{item_0}}{#{item_1}}"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class CGen::Generator::CvDoubleItem < CGen::Generator::BasicGenerator
|
2
|
+
|
3
|
+
def initialize(param, data, lang)
|
4
|
+
super(param, data, lang)
|
5
|
+
end
|
6
|
+
|
7
|
+
def generate
|
8
|
+
value = get_value(param)
|
9
|
+
unless value.is_a?(Array)
|
10
|
+
value = Array[value]
|
11
|
+
end
|
12
|
+
value.collect do |elem|
|
13
|
+
instance = self
|
14
|
+
result = Either.chain do
|
15
|
+
bind -> { elem.is_a?(Hash) }
|
16
|
+
bind -> {
|
17
|
+
elem.has_key?('item_0') &&
|
18
|
+
elem['item_0'].has_key?('title') &&
|
19
|
+
elem['item_0'].has_key?('content')
|
20
|
+
}
|
21
|
+
bind -> {
|
22
|
+
elem.has_key?('item_1') &&
|
23
|
+
elem['item_1'].has_key?('title') &&
|
24
|
+
elem['item_1'].has_key?('content')
|
25
|
+
}
|
26
|
+
bind -> {
|
27
|
+
instance.get_cv_double_item(elem['item_0'], elem['item_1'])
|
28
|
+
}
|
29
|
+
end
|
30
|
+
result.success? ? result.fetch : ''
|
31
|
+
end.join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def get_cv_double_item(item_0, item_1)
|
37
|
+
"\\cvdoubleitem" +
|
38
|
+
"{#{item_0['title']}}{#{item_0['content']}}" +
|
39
|
+
"{#{item_1['title']}}{#{item_1['content']}}"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class CGen::Generator::CvEntry < CGen::Generator::BasicGenerator
|
2
|
+
|
3
|
+
def initialize(param, data, lang)
|
4
|
+
super(param, data, lang)
|
5
|
+
end
|
6
|
+
|
7
|
+
def generate
|
8
|
+
value = get_value(param)
|
9
|
+
unless value.is_a?(Array)
|
10
|
+
value = Array[value]
|
11
|
+
end
|
12
|
+
instance = self
|
13
|
+
result = Either.chain do
|
14
|
+
bind -> { value.is_a?(Array) }
|
15
|
+
bind -> { instance.get_cv_entry(value) }
|
16
|
+
end
|
17
|
+
result.success? ? result.fetch : ''
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def get_cv_entry(context)
|
23
|
+
result = "\\cventry"
|
24
|
+
context.each do |elem|
|
25
|
+
result += "{#{elem}}"
|
26
|
+
end
|
27
|
+
(6 - context.size).times do
|
28
|
+
result += '{}'
|
29
|
+
end
|
30
|
+
result # return
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class CGen::Generator::CvItem < CGen::Generator::BasicGenerator
|
2
|
+
|
3
|
+
def initialize(param, data, lang)
|
4
|
+
super(param, data, lang)
|
5
|
+
end
|
6
|
+
|
7
|
+
def generate
|
8
|
+
value = get_value(param)
|
9
|
+
unless value.is_a?(Array)
|
10
|
+
value = Array[value]
|
11
|
+
end
|
12
|
+
value.collect do |elem|
|
13
|
+
instance = self
|
14
|
+
result = Either.chain do
|
15
|
+
bind -> { elem.is_a?(Hash) }
|
16
|
+
bind -> { elem.has_key?('title') && elem.has_key?('content') }
|
17
|
+
bind -> { instance.get_cv_item(elem['title'], elem['content']) }
|
18
|
+
end
|
19
|
+
result.success? ? result.fetch : ''
|
20
|
+
end.join("\n")
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def get_cv_item(title, content)
|
26
|
+
"\\cvitem{#{title}}{#{content}}"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|