tax_generator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.inch.yml +10 -0
- data/.reek +10 -0
- data/.rspec +1 -0
- data/.rubocop.yml +72 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +154 -0
- data/LICENSE +20 -0
- data/README.md +131 -0
- data/Rakefile +26 -0
- data/bin/tax_generator +7 -0
- data/data/input/.gitignore +25 -0
- data/data/input/destinations.xml +1073 -0
- data/data/input/taxonomy.xml +78 -0
- data/data/output/.gitignore +4 -0
- data/init.rb +1 -0
- data/lib/tax_generator/all.rb +26 -0
- data/lib/tax_generator/application.rb +125 -0
- data/lib/tax_generator/classes/destination.rb +103 -0
- data/lib/tax_generator/classes/file_creator.rb +100 -0
- data/lib/tax_generator/classes/processor.rb +270 -0
- data/lib/tax_generator/classes/taxonomy_tree.rb +97 -0
- data/lib/tax_generator/cli.rb +14 -0
- data/lib/tax_generator/helpers/application_helper.rb +154 -0
- data/lib/tax_generator/version.rb +27 -0
- data/lib/tax_generator.rb +1 -0
- data/spec/lib/tax_generator/application_spec.rb +0 -0
- data/spec/lib/tax_generator/classes/destination_spec.rb +62 -0
- data/spec/lib/tax_generator/classes/file_creator_spec.rb +96 -0
- data/spec/lib/tax_generator/classes/processor_spec.rb +30 -0
- data/spec/lib/tax_generator/classes/taxonomy_tree_spec.rb +0 -0
- data/spec/lib/tax_generator/cli_spec.rb +0 -0
- data/spec/lib/tax_generator/helpers/application_helper_spec.rb +0 -0
- data/spec/spec_helper.rb +60 -0
- data/tax_generator.gemspec +40 -0
- data/templates/static/all.css +586 -0
- data/templates/template.html.erb +91 -0
- metadata +452 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<taxonomies>
|
3
|
+
<taxonomy>
|
4
|
+
<taxonomy_name>World</taxonomy_name>
|
5
|
+
<node atlas_node_id = "355064" ethyl_content_object_id="82534" geo_id = "355064">
|
6
|
+
<node_name>Africa</node_name>
|
7
|
+
<node atlas_node_id = "355611" ethyl_content_object_id="3210" geo_id = "355611">
|
8
|
+
<node_name>South Africa</node_name>
|
9
|
+
<node atlas_node_id = "355612" ethyl_content_object_id="35474" geo_id = "355612">
|
10
|
+
<node_name>Cape Town</node_name>
|
11
|
+
<node atlas_node_id = "355613" ethyl_content_object_id="" geo_id = "355613">
|
12
|
+
<node_name>Table Mountain National Park</node_name>
|
13
|
+
</node>
|
14
|
+
</node>
|
15
|
+
<node atlas_node_id = "355614" ethyl_content_object_id="" geo_id = "355614">
|
16
|
+
<node_name>Free State</node_name>
|
17
|
+
<node atlas_node_id = "355615" ethyl_content_object_id="1000550692" geo_id = "355615">
|
18
|
+
<node_name>Bloemfontein</node_name>
|
19
|
+
</node>
|
20
|
+
</node>
|
21
|
+
<node atlas_node_id = "355616" ethyl_content_object_id="" geo_id = "355616">
|
22
|
+
<node_name>Gauteng</node_name>
|
23
|
+
<node atlas_node_id = "355617" ethyl_content_object_id="37710" geo_id = "355617">
|
24
|
+
<node_name>Johannesburg</node_name>
|
25
|
+
</node>
|
26
|
+
<node atlas_node_id = "355618" ethyl_content_object_id="1000548256" geo_id = "355618">
|
27
|
+
<node_name>Pretoria</node_name>
|
28
|
+
</node>
|
29
|
+
</node>
|
30
|
+
<node atlas_node_id = "355619" ethyl_content_object_id="" geo_id = "355619">
|
31
|
+
<node_name>KwaZulu-Natal</node_name>
|
32
|
+
<node atlas_node_id = "355620" ethyl_content_object_id="43725" geo_id = "355620">
|
33
|
+
<node_name>Durban</node_name>
|
34
|
+
</node>
|
35
|
+
<node atlas_node_id = "355621" ethyl_content_object_id="1000576780" geo_id = "355621">
|
36
|
+
<node_name>Pietermaritzburg</node_name>
|
37
|
+
</node>
|
38
|
+
</node>
|
39
|
+
<node atlas_node_id = "355622" ethyl_content_object_id="" geo_id = "355622">
|
40
|
+
<node_name>Mpumalanga</node_name>
|
41
|
+
<node atlas_node_id = "355623" ethyl_content_object_id="67561" geo_id = "355623">
|
42
|
+
<node_name>Kruger National Park</node_name>
|
43
|
+
</node>
|
44
|
+
</node>
|
45
|
+
<node atlas_node_id = "355624" ethyl_content_object_id="" geo_id = "355624">
|
46
|
+
<node_name>The Drakensberg</node_name>
|
47
|
+
<node atlas_node_id = "355625" ethyl_content_object_id="" geo_id = "355625">
|
48
|
+
<node_name>Royal Natal National Park</node_name>
|
49
|
+
</node>
|
50
|
+
</node>
|
51
|
+
<node atlas_node_id = "355626" ethyl_content_object_id="" geo_id = "355626">
|
52
|
+
<node_name>The Garden Route</node_name>
|
53
|
+
<node atlas_node_id = "355627" ethyl_content_object_id="" geo_id = "355627">
|
54
|
+
<node_name>Oudtshoorn</node_name>
|
55
|
+
</node>
|
56
|
+
<node atlas_node_id = "355628" ethyl_content_object_id="" geo_id = "355628">
|
57
|
+
<node_name>Tsitsikamma Coastal National Park</node_name>
|
58
|
+
</node>
|
59
|
+
</node>
|
60
|
+
</node>
|
61
|
+
<node atlas_node_id = "355629" ethyl_content_object_id="3263" geo_id = "355629">
|
62
|
+
<node_name>Sudan</node_name>
|
63
|
+
<node atlas_node_id = "355630" ethyl_content_object_id="" geo_id = "355630">
|
64
|
+
<node_name>Eastern Sudan</node_name>
|
65
|
+
<node atlas_node_id = "355631" ethyl_content_object_id="" geo_id = "355631">
|
66
|
+
<node_name>Port Sudan</node_name>
|
67
|
+
</node>
|
68
|
+
</node>
|
69
|
+
<node atlas_node_id = "355632" ethyl_content_object_id="" geo_id = "355632">
|
70
|
+
<node_name>Khartoum</node_name>
|
71
|
+
</node>
|
72
|
+
</node>
|
73
|
+
<node atlas_node_id = "355633" ethyl_content_object_id="3272" geo_id = "355633">
|
74
|
+
<node_name>Swaziland</node_name>
|
75
|
+
</node>
|
76
|
+
</node>
|
77
|
+
</taxonomy>
|
78
|
+
</taxonomies>
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'tax_generator'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
$stdin.sync = true # if $stdin.isatty
|
2
|
+
$stdout.sync = true # if $stdout.isatty
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
require 'bundler/setup'
|
6
|
+
require 'active_support/core_ext/object/blank'
|
7
|
+
require 'active_support/core_ext/hash/keys'
|
8
|
+
require 'active_support/core_ext/module/delegation'
|
9
|
+
|
10
|
+
require 'slop'
|
11
|
+
require 'nokogiri'
|
12
|
+
require 'tree'
|
13
|
+
require 'celluloid/autostart'
|
14
|
+
require 'celluloid/pmap'
|
15
|
+
|
16
|
+
require 'logger'
|
17
|
+
require 'fileutils'
|
18
|
+
require 'ostruct'
|
19
|
+
require 'erb'
|
20
|
+
require 'tilt'
|
21
|
+
|
22
|
+
%w(classes helpers).each do |folder_name|
|
23
|
+
Gem.find_files("tax_generator/#{folder_name}/**/*.rb").each { |path| require path }
|
24
|
+
end
|
25
|
+
require_relative './application'
|
26
|
+
require_relative './version'
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require_relative './helpers/application_helper'
|
2
|
+
module TaxGenerator
|
3
|
+
# class used run the processsor
|
4
|
+
#
|
5
|
+
# @!attribute opts
|
6
|
+
# @return [Slop::Options] the options that are used for command line access
|
7
|
+
#
|
8
|
+
class Application
|
9
|
+
include TaxGenerator::ApplicationHelper
|
10
|
+
|
11
|
+
attr_reader :opts
|
12
|
+
|
13
|
+
# method used to initialize the application, by initializing the options for command line
|
14
|
+
# access
|
15
|
+
#
|
16
|
+
#
|
17
|
+
# @return [void]
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def initialize
|
21
|
+
@opts = Slop::Options.new
|
22
|
+
@opts.banner = 'usage: tax_generator [options] ...'
|
23
|
+
end
|
24
|
+
|
25
|
+
# receives a list of options that are used to determine the input files and output and input folders
|
26
|
+
#
|
27
|
+
# @param [Hash] options the options that are used for command line access
|
28
|
+
#
|
29
|
+
# @see #execute_with_rescue
|
30
|
+
# @see TaxGenerator::Processor#new
|
31
|
+
# @see TaxGenerator::Processor#work
|
32
|
+
#
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
def run(options = {})
|
37
|
+
execute_with_rescue do
|
38
|
+
options = options.present? ? options : parse_options
|
39
|
+
processor = TaxGenerator::Processor.new(options)
|
40
|
+
processor.work
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# returns the logger used to log messages and errors
|
45
|
+
#
|
46
|
+
# @return [Logger]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def self.app_logger
|
50
|
+
@logger ||= Logger.new($stdout)
|
51
|
+
end
|
52
|
+
|
53
|
+
# returns the options list as a hash after parsing command line arguments
|
54
|
+
#
|
55
|
+
# @return [Hash]
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
def parse_options
|
59
|
+
setup_command_line_options
|
60
|
+
parser = Slop::Parser.new(@opts)
|
61
|
+
result = parser.parse(ARGV.dup)
|
62
|
+
result.to_hash
|
63
|
+
end
|
64
|
+
|
65
|
+
# sets the directory options for command line access
|
66
|
+
#
|
67
|
+
# @return [void]
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
def directory_options
|
71
|
+
@opts.separator ''
|
72
|
+
@opts.separator 'Directory options:'
|
73
|
+
@opts.string '-i', '--input_dir', 'The input directory ', default: "#{root}/data/input"
|
74
|
+
@opts.string '-o', '--output_dir', 'The ouput directory', default: "#{root}/data/output"
|
75
|
+
end
|
76
|
+
|
77
|
+
# sets the file options for command line access
|
78
|
+
#
|
79
|
+
# @return [void]
|
80
|
+
#
|
81
|
+
# @api public
|
82
|
+
def file_options
|
83
|
+
@opts.separator ''
|
84
|
+
@opts.separator 'Extra options:'
|
85
|
+
@opts.string '-t', '--taxonomy_filename', 'The taxonomy file name', default: 'taxonomy.xml'
|
86
|
+
@opts.string '-d', '--destinations_filename', 'The destinations file name', default: 'destinations.xml'
|
87
|
+
end
|
88
|
+
|
89
|
+
# sets the version of the gem available to be displayed from command line
|
90
|
+
#
|
91
|
+
# @return [void]
|
92
|
+
#
|
93
|
+
# @api public
|
94
|
+
def setup_version
|
95
|
+
@opts.on '--version', 'The destinations file name' do
|
96
|
+
puts TaxGenerator.gem_version
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# sets the help menu for command line access
|
102
|
+
#
|
103
|
+
# @return [void]
|
104
|
+
#
|
105
|
+
# @api public
|
106
|
+
def setup_help
|
107
|
+
@opts.on '--help', 'print the help' do
|
108
|
+
puts @opts
|
109
|
+
exit
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# sets the command line options
|
114
|
+
#
|
115
|
+
# @return [void]
|
116
|
+
#
|
117
|
+
# @api public
|
118
|
+
def setup_command_line_options
|
119
|
+
directory_options
|
120
|
+
file_options
|
121
|
+
setup_version
|
122
|
+
setup_help
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
2
|
+
module TaxGenerator
|
3
|
+
# class used to find xpaths from the destination node from xml
|
4
|
+
#
|
5
|
+
# @!attribute destination
|
6
|
+
# @return [Nokogiri::Element] the element from the xml document that need to be parsed
|
7
|
+
class Destination
|
8
|
+
include TaxGenerator::ApplicationHelper
|
9
|
+
|
10
|
+
delegate :xpath,
|
11
|
+
to: :destination
|
12
|
+
|
13
|
+
attr_reader :destination
|
14
|
+
|
15
|
+
# receives destination node (xml element) that need to be parsed
|
16
|
+
#
|
17
|
+
# @param [Nokogiri::Element] destination_node the element from the xml document that need to be parsed
|
18
|
+
#
|
19
|
+
# @return [void]
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
def initialize(destination_node)
|
23
|
+
@destination = destination_node
|
24
|
+
end
|
25
|
+
|
26
|
+
# returns the information about the introduction
|
27
|
+
#
|
28
|
+
# @return [Nokogiri::NodeSet]
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def introduction
|
32
|
+
xpath('.//introductory/introduction/overview')
|
33
|
+
end
|
34
|
+
|
35
|
+
# returns the information about the history
|
36
|
+
#
|
37
|
+
# @return [Nokogiri::NodeSet]
|
38
|
+
#
|
39
|
+
# @api public
|
40
|
+
def history
|
41
|
+
xpath('./history/history/history')
|
42
|
+
end
|
43
|
+
|
44
|
+
# returns the information about the practical_information
|
45
|
+
#
|
46
|
+
# @return [Nokogiri::NodeSet]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def practical_information
|
50
|
+
base = './/practical_information/health_and_safety'
|
51
|
+
xpath("#{base}/dangers_and_annoyances") + xpath("#{base}/while_youre_there") + \
|
52
|
+
xpath("#{base}/before_you_go") + xpath("#{base}/money_and_costs/money")
|
53
|
+
end
|
54
|
+
|
55
|
+
# returns the information about the transport
|
56
|
+
#
|
57
|
+
# @return [Nokogiri::NodeSet]
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
def transport
|
61
|
+
xpath('.//transport/getting_around')
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns the information about the weather
|
65
|
+
#
|
66
|
+
# @return [Nokogiri::NodeSet]
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def weather
|
70
|
+
xpath('.//weather')
|
71
|
+
end
|
72
|
+
|
73
|
+
# returns the information about the work_live_study
|
74
|
+
#
|
75
|
+
# @return [Nokogiri::NodeSet]
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
def work_live_study
|
79
|
+
xpath('.//work_live_study')
|
80
|
+
end
|
81
|
+
|
82
|
+
# returns the a hash containing all the parsed information from the xml document
|
83
|
+
# and makes sure that only elements with content not blank will be returned
|
84
|
+
#
|
85
|
+
# @see #elements_with_content
|
86
|
+
# @return [Nokogiri::NodeSet]
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
def to_hash
|
90
|
+
{
|
91
|
+
introduction: introduction,
|
92
|
+
history: history,
|
93
|
+
practical_information: practical_information,
|
94
|
+
transport: transport,
|
95
|
+
weather: weather,
|
96
|
+
work_live_study: work_live_study
|
97
|
+
}.each_with_object({}) do |(key, value), hsh|
|
98
|
+
hsh[key] = elements_with_content(value)
|
99
|
+
hsh
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
2
|
+
module TaxGenerator
|
3
|
+
# class used to create the files
|
4
|
+
#
|
5
|
+
# @!attribute processor
|
6
|
+
# @return [TaxGenerator::Processor] the manager that manages the current actor
|
7
|
+
# @!attribute job
|
8
|
+
# @return [Hash] the job that this actor received
|
9
|
+
# @!attribute job_id
|
10
|
+
# @return [String] the id of the node from the taxonomy tree
|
11
|
+
# @!attribute destination
|
12
|
+
# @return [Nokogiri::Element] the destination node from the xml document
|
13
|
+
# @!attribute taxonomy
|
14
|
+
# @return [TaxGenerator::TaxonomyTree] the taxonomy tree holding all the nodes from the taxonomy xml document
|
15
|
+
# @!attribute output_folder
|
16
|
+
# @return [String] the output folder where the new files will be created
|
17
|
+
class FileCreator
|
18
|
+
include Celluloid
|
19
|
+
include Celluloid::Logger
|
20
|
+
include TaxGenerator::ApplicationHelper
|
21
|
+
|
22
|
+
attr_reader :processor, :job, :job_id, :destination, :taxonomy, :output_folder
|
23
|
+
|
24
|
+
# returns the template file path used for generating the files
|
25
|
+
#
|
26
|
+
# @return [void]
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def template_name
|
30
|
+
File.join(root, 'templates', 'template.html.erb')
|
31
|
+
end
|
32
|
+
|
33
|
+
# processes the job received and registers itself inside the manager
|
34
|
+
# @see TaxGenerator::Processor#register_worker_for_job
|
35
|
+
# @see #process_job
|
36
|
+
#
|
37
|
+
# @param [Hash] job the job that is passed to the current actor
|
38
|
+
# @param [TaxGenerator::Processor] manager the manager that manages the actor
|
39
|
+
#
|
40
|
+
# @return [void]
|
41
|
+
#
|
42
|
+
# @api public
|
43
|
+
def work(job, manager)
|
44
|
+
job = job.stringify_keys
|
45
|
+
@job = job
|
46
|
+
@processor = manager
|
47
|
+
process_job(job)
|
48
|
+
@processor.register_worker_for_job(job, Actor.current)
|
49
|
+
end
|
50
|
+
|
51
|
+
# processes the job information by retrieving keys from the hash
|
52
|
+
#
|
53
|
+
# @param [Hash] job the job that is passed to the current actor
|
54
|
+
#
|
55
|
+
# @return [void]
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
def process_job(job)
|
59
|
+
job = job.stringify_keys
|
60
|
+
@destination = job['destination']
|
61
|
+
@job_id = job['atlas_id']
|
62
|
+
@taxonomy = job['taxonomy']
|
63
|
+
@output_folder = job['output_folder']
|
64
|
+
end
|
65
|
+
|
66
|
+
# renders the template and creates new file with the template html
|
67
|
+
#
|
68
|
+
# @return [void]
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def start_work
|
72
|
+
log_message "Generating html for destination #{@job_id}"
|
73
|
+
output = Tilt.new(template_name).render(Actor.current, fetch_atlas_details)
|
74
|
+
File.open(File.join(@output_folder, "#{@job_id}.html"), 'w') { |file| file << output }
|
75
|
+
mark_job_completed
|
76
|
+
end
|
77
|
+
|
78
|
+
# marks the job as completed after file is generated
|
79
|
+
#
|
80
|
+
# @return [void]
|
81
|
+
#
|
82
|
+
# @api public
|
83
|
+
def mark_job_completed
|
84
|
+
@processor.jobs[@job_id]['status'] = 'finished'
|
85
|
+
@processor.condition.signal('completed') if @processor.alive? && @processor.all_workers_finished?
|
86
|
+
end
|
87
|
+
|
88
|
+
# fetches the details needed to be passed to the erb template
|
89
|
+
# @see TaxGenerator::Destination#new
|
90
|
+
#
|
91
|
+
# @return [void]
|
92
|
+
#
|
93
|
+
# @api public
|
94
|
+
def fetch_atlas_details
|
95
|
+
atlas_node = @taxonomy[@job_id]
|
96
|
+
content = @destination.present? ? TaxGenerator::Destination.new(@destination).to_hash : {}
|
97
|
+
content.merge(details: atlas_node, root: root)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|