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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.inch.yml +10 -0
  4. data/.reek +10 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +72 -0
  7. data/Gemfile +3 -0
  8. data/Gemfile.lock +154 -0
  9. data/LICENSE +20 -0
  10. data/README.md +131 -0
  11. data/Rakefile +26 -0
  12. data/bin/tax_generator +7 -0
  13. data/data/input/.gitignore +25 -0
  14. data/data/input/destinations.xml +1073 -0
  15. data/data/input/taxonomy.xml +78 -0
  16. data/data/output/.gitignore +4 -0
  17. data/init.rb +1 -0
  18. data/lib/tax_generator/all.rb +26 -0
  19. data/lib/tax_generator/application.rb +125 -0
  20. data/lib/tax_generator/classes/destination.rb +103 -0
  21. data/lib/tax_generator/classes/file_creator.rb +100 -0
  22. data/lib/tax_generator/classes/processor.rb +270 -0
  23. data/lib/tax_generator/classes/taxonomy_tree.rb +97 -0
  24. data/lib/tax_generator/cli.rb +14 -0
  25. data/lib/tax_generator/helpers/application_helper.rb +154 -0
  26. data/lib/tax_generator/version.rb +27 -0
  27. data/lib/tax_generator.rb +1 -0
  28. data/spec/lib/tax_generator/application_spec.rb +0 -0
  29. data/spec/lib/tax_generator/classes/destination_spec.rb +62 -0
  30. data/spec/lib/tax_generator/classes/file_creator_spec.rb +96 -0
  31. data/spec/lib/tax_generator/classes/processor_spec.rb +30 -0
  32. data/spec/lib/tax_generator/classes/taxonomy_tree_spec.rb +0 -0
  33. data/spec/lib/tax_generator/cli_spec.rb +0 -0
  34. data/spec/lib/tax_generator/helpers/application_helper_spec.rb +0 -0
  35. data/spec/spec_helper.rb +60 -0
  36. data/tax_generator.gemspec +40 -0
  37. data/templates/static/all.css +586 -0
  38. data/templates/template.html.erb +91 -0
  39. 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>
@@ -0,0 +1,4 @@
1
+ # Ignore everything in this directory
2
+ *
3
+ # Except this file
4
+ !.gitignore
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