tax_generator 0.0.1
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 +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
|