site_maps 0.0.1.beta1

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +45 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +36 -0
  6. data/.tool-versions +1 -0
  7. data/CHANGELOG.md +8 -0
  8. data/Gemfile +18 -0
  9. data/Gemfile.lock +134 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +186 -0
  12. data/Rakefile +4 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +7 -0
  15. data/exec/site_maps +9 -0
  16. data/lib/site-maps.rb +3 -0
  17. data/lib/site_maps/adapters/adapter.rb +80 -0
  18. data/lib/site_maps/adapters/aws_sdk/config.rb +51 -0
  19. data/lib/site_maps/adapters/aws_sdk/location.rb +9 -0
  20. data/lib/site_maps/adapters/aws_sdk/storage.rb +52 -0
  21. data/lib/site_maps/adapters/aws_sdk.rb +31 -0
  22. data/lib/site_maps/adapters/file_system/config.rb +5 -0
  23. data/lib/site_maps/adapters/file_system/location.rb +35 -0
  24. data/lib/site_maps/adapters/file_system/storage.rb +61 -0
  25. data/lib/site_maps/adapters/file_system.rb +26 -0
  26. data/lib/site_maps/adapters/noop.rb +18 -0
  27. data/lib/site_maps/atomic_repository.rb +24 -0
  28. data/lib/site_maps/builder/link.rb +27 -0
  29. data/lib/site_maps/builder/normalizer.rb +48 -0
  30. data/lib/site_maps/builder/sitemap_index/item.rb +35 -0
  31. data/lib/site_maps/builder/sitemap_index.rb +40 -0
  32. data/lib/site_maps/builder/url.rb +152 -0
  33. data/lib/site_maps/builder/url_set.rb +92 -0
  34. data/lib/site_maps/cli.rb +68 -0
  35. data/lib/site_maps/configuration.rb +119 -0
  36. data/lib/site_maps/incremental_location.rb +62 -0
  37. data/lib/site_maps/notification/bus.rb +90 -0
  38. data/lib/site_maps/notification/event.rb +50 -0
  39. data/lib/site_maps/notification/publisher.rb +78 -0
  40. data/lib/site_maps/notification.rb +36 -0
  41. data/lib/site_maps/primitives/array.rb +15 -0
  42. data/lib/site_maps/primitives/output.rb +66 -0
  43. data/lib/site_maps/primitives/string.rb +43 -0
  44. data/lib/site_maps/process.rb +29 -0
  45. data/lib/site_maps/railtie.rb +18 -0
  46. data/lib/site_maps/runner/event_listener.rb +78 -0
  47. data/lib/site_maps/runner.rb +136 -0
  48. data/lib/site_maps/sitemap_builder.rb +75 -0
  49. data/lib/site_maps/sitemap_reader.rb +56 -0
  50. data/lib/site_maps/version.rb +5 -0
  51. data/lib/site_maps.rb +112 -0
  52. data/site_maps.gemspec +44 -0
  53. metadata +172 -0
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SiteMaps
4
+ module Runner::EventListener
5
+ extend Primitives::Output
6
+
7
+ module_function
8
+
9
+ def [](event_name)
10
+ method_name = Primitives::String.new(event_name).underscore.to_sym
11
+ return unless respond_to?(:"on_#{method_name}")
12
+
13
+ method(:"on_#{method_name}")
14
+ end
15
+
16
+ def on_sitemaps_runner_enqueue_process(event)
17
+ process = event[:process]
18
+ kwargs = event[:kwargs]
19
+ location = process.location(**kwargs)
20
+ print_message(
21
+ "Enqueue process %<name>s#{" at %<location>s" if location}",
22
+ name: colorize(process.name, :bold),
23
+ location: colorize(location, :lightgray)
24
+ )
25
+ if kwargs.any?
26
+ print_message("└── Keyword Arguments: {%<kwargs>s}", kwargs: kwargs.map { |k, v| "#{k}: #{v.inspect}" }.join(", "))
27
+ end
28
+ end
29
+
30
+ def on_sitemaps_runner_before_process_execution(event)
31
+ process = event[:process]
32
+ kwargs = event[:kwargs]
33
+ location = process.location(**kwargs)
34
+ print_message(
35
+ "Executing process %<name>s#{" at %<location>s" if location}",
36
+ name: colorize(process.name, :bold),
37
+ location: colorize(location, :lightgray)
38
+ )
39
+ if kwargs.any?
40
+ print_message("└── Keyword Arguments: {%<kwargs>s}", kwargs: kwargs.map { |k, v| "#{k}: #{v.inspect}" }.join(", "))
41
+ end
42
+ end
43
+
44
+ def on_sitemaps_runner_process_execution(event)
45
+ process = event[:process]
46
+ kwargs = event[:kwargs]
47
+ location = process.location(**kwargs)
48
+ print_message(
49
+ "[%<runtime>s] Executed process %<name>s#{" at %<location>s" if location}",
50
+ name: colorize(process.name, :bold),
51
+ location: colorize(location, :lightgray),
52
+ runtime: formatted_runtime(event[:runtime])
53
+ )
54
+ if kwargs.any?
55
+ print_message("└── Keyword Arguments: {%<kwargs>s}", kwargs: kwargs.map { |k, v| "#{k}: #{v.inspect}" }.join(", "))
56
+ end
57
+ end
58
+
59
+ def on_sitemaps_builder_finalize_urlset(event)
60
+ links_count = event[:links_count]
61
+ news_count = event[:news_count]
62
+ url = event[:url]
63
+ text = +"[%<runtime>s] Finalize URLSet with "
64
+ text << "%<links>d links" if links_count > 0
65
+ text << " and " if links_count > 0 && news_count > 0
66
+ text << "%<news>d news" if news_count > 0
67
+ text << " URLs at %<url>s"
68
+
69
+ print_message(
70
+ text,
71
+ links: links_count,
72
+ news: news_count,
73
+ url: colorize(url, :lightgray),
74
+ runtime: formatted_runtime(event[:runtime])
75
+ )
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SiteMaps
4
+ class Runner
5
+ attr_reader :adapter
6
+
7
+ def initialize(adapter = SiteMaps.current_adapter, max_threads: 4)
8
+ @adapter = adapter.tap(&:reset!)
9
+ @pool = Concurrent::FixedThreadPool.new(max_threads)
10
+ @execution = Concurrent::Hash.new
11
+ @failed = Concurrent::AtomicBoolean.new(false)
12
+ @errors = Concurrent::Array.new
13
+ end
14
+
15
+ def enqueue(process_name = :default, **kwargs)
16
+ process_name = process_name.to_sym
17
+ process = @adapter.processes.fetch(process_name) do
18
+ raise ArgumentError, "Process :#{process_name} not found"
19
+ end
20
+ kwargs = process.keyword_arguments(kwargs)
21
+ SiteMaps::Notification.instrument("sitemaps.runner.enqueue_process") do |payload|
22
+ payload[:process] = process
23
+ payload[:kwargs] = kwargs
24
+ if process.dynamic?
25
+ @execution[process_name] ||= Concurrent::Array.new
26
+ if @execution[process_name].any? { |_, k| k == kwargs }
27
+ raise ArgumentError, "Process :#{process_name} already enqueued with kwargs #{kwargs}"
28
+ end
29
+ @execution[process_name] << [process, kwargs]
30
+ else
31
+ if @execution.key?(process_name)
32
+ raise ArgumentError, "Process :#{process_name} already defined"
33
+ end
34
+ @execution[process_name] = Concurrent::Array.new([[process, kwargs]])
35
+ end
36
+ end
37
+ self
38
+ end
39
+
40
+ def enqueue_remaining
41
+ @adapter.processes.each_key do |process_name|
42
+ next if @execution.key?(process_name)
43
+
44
+ enqueue(process_name)
45
+ end
46
+ self
47
+ end
48
+ alias_method :enqueue_all, :enqueue_remaining
49
+
50
+ def run
51
+ may_preload_sitemap_index
52
+
53
+ futures = []
54
+ @execution.each do |_process_name, items|
55
+ items.each do |process, kwargs|
56
+ SiteMaps::Notification.publish("sitemaps.runner.before_process_execution", process: process, kwargs: kwargs)
57
+ futures << Concurrent::Future.execute(executor: pool) do
58
+ wrap_process_execution(process) do
59
+ SiteMaps::Notification.instrument("sitemaps.runner.process_execution") do |payload|
60
+ payload[:process] = process
61
+ payload[:kwargs] = kwargs
62
+ builder = SiteMaps::SitemapBuilder.new(
63
+ adapter: adapter,
64
+ location: process.location(**kwargs)
65
+ )
66
+ process.call(builder, **kwargs)
67
+ builder.finalize!
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ futures.each(&:wait)
75
+ failed.false? ? finalize! : fail_with_errors!
76
+ ensure
77
+ pool.shutdown
78
+ pool.wait_for_termination
79
+ @execution.clear
80
+ end
81
+
82
+ private
83
+
84
+ attr_reader :pool, :failed, :errors
85
+
86
+ def finalize!
87
+ adapter.repo.remaining_index_links.each do |item|
88
+ adapter.sitemap_index.add(item)
89
+ end
90
+ unless adapter.sitemap_index.empty?
91
+ raw_data = adapter.sitemap_index.to_xml
92
+ adapter.write(adapter.config.url, raw_data, last_modified: Time.now)
93
+ end
94
+ end
95
+
96
+ def fail_with_errors!
97
+ return if errors.empty?
98
+
99
+ raise errors.first.last
100
+ end
101
+
102
+ def handle_process_error(process, error)
103
+ errors << [process, error]
104
+ end
105
+
106
+ def may_preload_sitemap_index
107
+ return unless preload_sitemap_index_links?
108
+
109
+ adapter.fetch_sitemap_index_links.each do |item|
110
+ adapter.repo.preloaded_index_links.push(item)
111
+ end
112
+ end
113
+
114
+ def wrap_process_execution(process)
115
+ return if failed.true?
116
+
117
+ yield
118
+ rescue => e
119
+ handle_process_error(process, e)
120
+ failed.make_true
121
+ end
122
+
123
+ def preload_sitemap_index_links?
124
+ return false if @execution.empty?
125
+
126
+ (@adapter.processes.keys - @execution.keys).any? || # There are processes that have not been enqueued
127
+ @adapter.processes.any? { |_, process| process.dynamic? } # There are dynamic processes
128
+ end
129
+
130
+ # def single_thread?
131
+ # @pool.max_length == 1 || (
132
+ # @execution.size == 1 && @execution.first.last.size == 1
133
+ # )
134
+ # end
135
+ end
136
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SiteMaps
4
+ class SitemapBuilder
5
+ extend Forwardable
6
+
7
+ def initialize(adapter:, location: nil)
8
+ @adapter = adapter
9
+ @url_set = SiteMaps::Builder::URLSet.new
10
+ @location = location
11
+ @mutex = Mutex.new
12
+ end
13
+
14
+ def add(path, params: nil, **options)
15
+ @mutex.synchronize do
16
+ link = build_link(path, params)
17
+ url_set.add(link, **options)
18
+ rescue SiteMaps::FullSitemapError
19
+ finalize_and_start_next_urlset!
20
+ url_set.add(link, **options)
21
+ end
22
+ end
23
+
24
+ def add_sitemap_index(url, lastmod: Time.now)
25
+ sitemap_index.add(url, lastmod: lastmod)
26
+ end
27
+
28
+ def finalize!
29
+ return if url_set.finalized?
30
+ return if url_set.empty?
31
+
32
+ raw_data = url_set.finalize!
33
+
34
+ SiteMaps::Notification.instrument("sitemaps.builder.finalize_urlset") do |payload|
35
+ payload[:links_count] = url_set.links_count
36
+ payload[:news_count] = url_set.news_count
37
+ payload[:last_modified] = url_set.last_modified
38
+
39
+ if adapter.maybe_inline_urlset? && sitemap_index.empty?
40
+ payload[:url] = repo.main_url
41
+ adapter.write(repo.main_url, raw_data, last_modified: url_set.last_modified)
42
+ else
43
+ sitemap_url = repo.generate_url(location)
44
+ payload[:url] = sitemap_url
45
+ adapter.write(sitemap_url, raw_data, last_modified: url_set.last_modified)
46
+ add_sitemap_index(sitemap_url, lastmod: url_set.last_modified)
47
+ end
48
+ end
49
+ end
50
+
51
+ protected
52
+
53
+ attr_reader :url_set, :adapter, :location
54
+
55
+ def_delegators :adapter, :sitemap_index, :config, :repo
56
+
57
+ def finalize_and_start_next_urlset!
58
+ raw_data = url_set.finalize!
59
+ SiteMaps::Notification.instrument("sitemaps.builder.finalize_urlset") do |payload|
60
+ sitemap_url = repo.generate_url(location)
61
+ payload[:url] = sitemap_url
62
+ payload[:links_count] = url_set.links_count
63
+ payload[:news_count] = url_set.news_count
64
+ payload[:last_modified] = url_set.last_modified
65
+ adapter.write(sitemap_url, raw_data, last_modified: url_set.last_modified)
66
+ add_sitemap_index(sitemap_url, lastmod: url_set.last_modified)
67
+ end
68
+ @url_set = SiteMaps::Builder::URLSet.new
69
+ end
70
+
71
+ def build_link(path, params)
72
+ SiteMaps::Builder::Link.new(config.base_uri, path, params)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open-uri"
4
+
5
+ module SiteMaps
6
+ class SitemapReader
7
+ Error = Class.new(SiteMaps::Error)
8
+ FileNotFound = Class.new(Error)
9
+ MalformedFile = Class.new(Error)
10
+
11
+ def initialize(location)
12
+ @location = Pathname.new(location)
13
+ end
14
+
15
+ def read
16
+ if compressed?
17
+ Zlib::GzipReader.new(read_file).read
18
+ else
19
+ read_file.read
20
+ end
21
+ rescue Zlib::GzipFile::Error => _e
22
+ raise MalformedFile.new("The file #{@location} is not a valid Gzip file")
23
+ end
24
+
25
+ def to_doc
26
+ @doc ||= begin
27
+ require "nokogiri"
28
+ Nokogiri::XML(read)
29
+ end
30
+ rescue LoadError
31
+ raise SiteMaps::Error, "Nokogiri is required to parse the XML file"
32
+ end
33
+
34
+ protected
35
+
36
+ def read_file
37
+ if remote?
38
+ ::URI.parse(@location.to_s).open
39
+ else
40
+ ::File.open(@location, "r")
41
+ end
42
+ rescue Errno::ENOENT
43
+ raise FileNotFound.new("The file #{@location} does not exist")
44
+ rescue OpenURI::HTTPError
45
+ raise FileNotFound.new("The file #{@location} could not be opened")
46
+ end
47
+
48
+ def compressed?
49
+ @location.extname == ".gz"
50
+ end
51
+
52
+ def remote?
53
+ %r{^https?://}.match?(@location.to_s)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SiteMaps
4
+ VERSION = "0.0.1.beta1"
5
+ end
data/lib/site_maps.rb ADDED
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "site_maps/version"
4
+
5
+ require "builder"
6
+ require "concurrent-ruby"
7
+ require "date"
8
+ require "fileutils"
9
+ require "forwardable"
10
+ require "rack/utils"
11
+ require "stringio"
12
+ require "time"
13
+ require "uri"
14
+ require "zeitwerk"
15
+ require "zlib"
16
+
17
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
18
+ loader.ignore("#{__dir__}/site-maps.rb")
19
+ loader.ignore("#{__dir__}/site_maps/tasks.rb")
20
+ loader.ignore("#{__dir__}/site_maps/cli.rb")
21
+ loader.inflector.inflect "cli" => "CLI"
22
+ loader.inflector.inflect "dsl" => "DSL"
23
+ loader.inflector.inflect "url_set" => "URLSet"
24
+ loader.inflector.inflect "url" => "URL"
25
+ loader.inflector.inflect "xml" => "XML"
26
+ loader.log! if ENV["DEBUG_ZEITWERK"]
27
+ loader.setup
28
+
29
+ module SiteMaps
30
+ MAX_LENGTH = {
31
+ links: 50_000,
32
+ images: 1_000,
33
+ news: 1_000
34
+ }
35
+ MAX_FILESIZE = 50_000_000 # bytes
36
+ DEFAULT_LOGGER = Logger.new($stdout)
37
+
38
+ Error = Class.new(StandardError)
39
+ AdapterNotFound = Class.new(Error)
40
+ AdapterNotSetError = Class.new(Error)
41
+ FileNotFoundError = Class.new(Error)
42
+ FullSitemapError = Class.new(Error)
43
+ ConfigurationError = Class.new(Error)
44
+
45
+ class << self
46
+ attr_reader :current_adapter
47
+ attr_writer :logger
48
+
49
+ # @param adapter [Class, String, Symbol] The name of the adapter to use
50
+ # @param options [Hash] Options to pass to the adapter. Note that these are adapter-specific
51
+ # @param block [Proc] A block to pass to the adapter
52
+ # @return [Object] An instance of the adapter
53
+ def use(adapter, **options, &block)
54
+ adapter_class = if adapter.is_a?(Class) # && adapter < Adapters::Adapter
55
+ adapter
56
+ else
57
+ const_name = Primitives::String.new(adapter.to_s).classify
58
+ begin
59
+ Adapters.const_get(const_name)
60
+ rescue NameError
61
+ raise AdapterNotFound, "Adapter #{adapter.inspect} not found"
62
+ end
63
+ end
64
+ @current_adapter = adapter_class.new(**options, &block)
65
+ end
66
+
67
+ def config
68
+ @config ||= Configuration.new
69
+ yield(@config) if block_given?
70
+ @config
71
+ end
72
+ alias_method :configure, :config
73
+
74
+ # Load and prepare a runner with the current adapter
75
+ # Note that it won't start running until you call `#run` on the runner
76
+ #
77
+ # Example:
78
+ # SiteMaps.generate(config_file: "config/site_maps.rb", max_threads: 10)
79
+ # .enqueue_all
80
+ # .run
81
+ #
82
+ # You may also enqueue processes manually, specially those that are dynamic
83
+ #
84
+ # Example:
85
+ # SiteMaps.generate(config_file: "config/site_maps.rb", max_threads: 10)
86
+ # .enqueue(:monthly, year: 2020, month: 1)
87
+ # .enqueue(:monthly, year: 2020, month: 2)
88
+ # .enqueue_remaining # Enqueue all other non-enqueued processes
89
+ # .run
90
+ #
91
+ # @param config_file [String] The path to a configuration file
92
+ # @param options [Hash] Options to pass to the runner
93
+ # @return [Runner] An instance of the runner
94
+ def generate(config_file: nil, **options)
95
+ if config_file
96
+ @current_adapter = nil
97
+ load(config_file)
98
+ end
99
+ raise AdapterNotSetError, "No adapter set. Use SiteMaps.use to set an adapter" unless current_adapter
100
+
101
+ Runner.new(current_adapter, **options)
102
+ end
103
+
104
+ def logger
105
+ @logger ||= DEFAULT_LOGGER
106
+ end
107
+ end
108
+ end
109
+
110
+ if defined?(::Rails)
111
+ require_relative "site_maps/railtie"
112
+ end
data/site_maps.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/site_maps/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "site_maps"
7
+ spec.version = SiteMaps::VERSION
8
+ spec.authors = ["Marcos G. Zimmermann"]
9
+ spec.email = ["mgzmaster@gmail.com"]
10
+
11
+ spec.summary = <<~SUMMARY
12
+ SiteMaps simplifies the generation of sitemaps for ruby or rails applications.
13
+ SUMMARY
14
+ spec.description = <<~DESCRIPTION
15
+ SiteMaps is gem that provides a simple way to generate static sitemaps for your ruby or rails applications.
16
+ DESCRIPTION
17
+
18
+ spec.homepage = "https://github.com/marcosgz/site_maps"
19
+ spec.license = "MIT"
20
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
21
+
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes." unless spec.respond_to?(:metadata)
23
+
24
+ spec.metadata["homepage_uri"] = spec.homepage
25
+ spec.metadata["bug_tracker_uri"] = "https://github.com/marcosgz/site_maps/issues"
26
+ spec.metadata["documentation_uri"] = "https://github.com/marcosgz/site_maps"
27
+ spec.metadata["source_code_uri"] = "https://github.com/marcosgz/site_maps"
28
+
29
+ # Specify which files should be added to the gem when it is released.
30
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
32
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ end
34
+
35
+ spec.bindir = "exec"
36
+ spec.executables = spec.files.grep(%r{^exec/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+
39
+ spec.add_dependency "rack", ">= 2.0"
40
+ spec.add_dependency "zeitwerk", ">= 0"
41
+ spec.add_dependency "builder", "~> 3.0"
42
+ spec.add_dependency "concurrent-ruby", ">= 1.1"
43
+ spec.add_dependency "thor", ">= 0.0.0"
44
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: site_maps
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Marcos G. Zimmermann
8
+ autorequire:
9
+ bindir: exec
10
+ cert_chain: []
11
+ date: 2024-11-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: zeitwerk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: builder
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: thor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.0
83
+ description: 'SiteMaps is gem that provides a simple way to generate static sitemaps
84
+ for your ruby or rails applications.
85
+
86
+ '
87
+ email:
88
+ - mgzmaster@gmail.com
89
+ executables:
90
+ - site_maps
91
+ extensions: []
92
+ extra_rdoc_files: []
93
+ files:
94
+ - ".github/workflows/main.yml"
95
+ - ".gitignore"
96
+ - ".rspec"
97
+ - ".rubocop.yml"
98
+ - ".tool-versions"
99
+ - CHANGELOG.md
100
+ - Gemfile
101
+ - Gemfile.lock
102
+ - LICENSE.txt
103
+ - README.md
104
+ - Rakefile
105
+ - bin/console
106
+ - bin/setup
107
+ - exec/site_maps
108
+ - lib/site-maps.rb
109
+ - lib/site_maps.rb
110
+ - lib/site_maps/adapters/adapter.rb
111
+ - lib/site_maps/adapters/aws_sdk.rb
112
+ - lib/site_maps/adapters/aws_sdk/config.rb
113
+ - lib/site_maps/adapters/aws_sdk/location.rb
114
+ - lib/site_maps/adapters/aws_sdk/storage.rb
115
+ - lib/site_maps/adapters/file_system.rb
116
+ - lib/site_maps/adapters/file_system/config.rb
117
+ - lib/site_maps/adapters/file_system/location.rb
118
+ - lib/site_maps/adapters/file_system/storage.rb
119
+ - lib/site_maps/adapters/noop.rb
120
+ - lib/site_maps/atomic_repository.rb
121
+ - lib/site_maps/builder/link.rb
122
+ - lib/site_maps/builder/normalizer.rb
123
+ - lib/site_maps/builder/sitemap_index.rb
124
+ - lib/site_maps/builder/sitemap_index/item.rb
125
+ - lib/site_maps/builder/url.rb
126
+ - lib/site_maps/builder/url_set.rb
127
+ - lib/site_maps/cli.rb
128
+ - lib/site_maps/configuration.rb
129
+ - lib/site_maps/incremental_location.rb
130
+ - lib/site_maps/notification.rb
131
+ - lib/site_maps/notification/bus.rb
132
+ - lib/site_maps/notification/event.rb
133
+ - lib/site_maps/notification/publisher.rb
134
+ - lib/site_maps/primitives/array.rb
135
+ - lib/site_maps/primitives/output.rb
136
+ - lib/site_maps/primitives/string.rb
137
+ - lib/site_maps/process.rb
138
+ - lib/site_maps/railtie.rb
139
+ - lib/site_maps/runner.rb
140
+ - lib/site_maps/runner/event_listener.rb
141
+ - lib/site_maps/sitemap_builder.rb
142
+ - lib/site_maps/sitemap_reader.rb
143
+ - lib/site_maps/version.rb
144
+ - site_maps.gemspec
145
+ homepage: https://github.com/marcosgz/site_maps
146
+ licenses:
147
+ - MIT
148
+ metadata:
149
+ homepage_uri: https://github.com/marcosgz/site_maps
150
+ bug_tracker_uri: https://github.com/marcosgz/site_maps/issues
151
+ documentation_uri: https://github.com/marcosgz/site_maps
152
+ source_code_uri: https://github.com/marcosgz/site_maps
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: 2.7.0
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubygems_version: 3.5.21
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: SiteMaps simplifies the generation of sitemaps for ruby or rails applications.
172
+ test_files: []