middleman-sitemap-xml-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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 39126624d004b40536c5f31beb3f23fa8fe821ad
4
+ data.tar.gz: 0b9325923fc546edb658fdc6bd2b0a3bf14346d3
5
+ SHA512:
6
+ metadata.gz: 82829eda0cd378195d7cb5e5df2ce21a5c61502803c9f682c6cb0772c3b90d2b21d95b95a9df7ebde0fbeab4c39c82465b06581a55e032a38ad3aee0cfba4dc0
7
+ data.tar.gz: 57e007bebf44470378ca5af854e2b810136d15221b64285b037389860be421120ef8d87a541103316c5c62bc83c5feadb39762f346bb13f959c81dccebd2d6fe
@@ -0,0 +1,10 @@
1
+ # Ignore bundler lock file
2
+ Gemfile.lock
3
+
4
+ # Ignore pkg folder
5
+ pkg
6
+
7
+ .bundle
8
+ tmp
9
+ spec/reports
10
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in middleman-search_engine_sitemap.gemspec
4
+ gemspec
@@ -0,0 +1,24 @@
1
+ The MIT License (MIT)
2
+
3
+ (c) 2016 AT-AT
4
+
5
+ Original:
6
+ Copyright (c) 2014 Pete Nicholls
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
@@ -0,0 +1,197 @@
1
+ # Middleman-Sitemap-Xml-Generator
2
+
3
+
4
+ This extension is a forked and slightly extended version of [Middleman Search Engine Sitemap by Pete Nicholls](https://github.com/Aupajo/middleman-search_engine_sitemap).
5
+
6
+ Note that this extension has been forked from the release [tagged as v1.3.0](https://github.com/Aupajo/middleman-search_engine_sitemap/releases/tag/v1.3.0) to support Middleman-v3.
7
+
8
+ Please refer to [the original](https://github.com/Aupajo/middleman-search_engine_sitemap) if you want to get the latest release or a version for Middleman-v4.
9
+
10
+
11
+ ### Why forked from v1.3.0?
12
+
13
+ Because I'm not be planning to use Middleman-v4 yet. 8-)
14
+
15
+
16
+ ## Installation
17
+
18
+ Add the following line to the Gemfile of your Middleman project:
19
+
20
+ ```ruby
21
+ gem 'middleman-sitemap-xml-generator'
22
+ ```
23
+
24
+ Then as usual, run:
25
+
26
+ ```sh
27
+ bundle install
28
+ ```
29
+
30
+
31
+ ## Usage
32
+
33
+ To activate and configure this extension, add the following configuration block to Middleman's config.rb:
34
+
35
+ ```ruby
36
+ set :url_root, 'http://example.com'
37
+ activate :sitemap_xml_generator
38
+ ```
39
+
40
+
41
+ ### Options
42
+
43
+ | Option | Default | Description
44
+ | --- | --- | ---
45
+ | default_changefreq | 'monthly' | Default page priority
46
+ | default_priority | 0.5 | Default page priority
47
+ | sitemap_xml_path | 'sitemap.xml' | Path to the sitemap.xml
48
+ | exclude_attr | 'hide_from_sitemap' | Attribute in `Frontmatter` to exclude from the sitemap
49
+ | process_url | nil | Callable object(responds to #call) to process a URL
50
+ | process_changefreq | nil | Callable object to determine a changefreq
51
+ | process_priority | nil | Callable object to determine a priority
52
+ | exclude_if | ->(resource) { false } | Callable object to exclude from the sitemap
53
+ | extra_ext | [] | Extensions allowed to be in the sitemap<br>(needed prefixed "dot")
54
+ | discard_ext | [] | Extensions removed from "loc" tag<br>(needed prefixed "dot")
55
+
56
+
57
+ ## Determination of "changefreq" and "priority"
58
+
59
+ A value of `changefreq` and `priority` in the sitemap.xml is determined in the following priority.
60
+
61
+ 1. **(Higher)** `Frontmatter` attributes in each file
62
+
63
+ ```yaml
64
+ ---
65
+ changefreq: daily
66
+ priority: 1.0
67
+ ---
68
+ ```
69
+
70
+ 1. Processing in a `process_changefreq` and a `process_priority` option
71
+
72
+ ```ruby
73
+ activate :sitemap_xml_generator do |f|
74
+ f.process_changefreq = ->(path, default) {
75
+ path.end_with?('.foo') ? 'yearly' : default
76
+ }
77
+ f.process_priority = ->(path, default) {
78
+ path.end_with?('.foo') ? 0.9 : default
79
+ }
80
+ end
81
+ ```
82
+
83
+ | Argument | Description
84
+ | --- | ---
85
+ | path | A path prefixed "/" from **Web** root. e.g. `/foo.html`
86
+ | default | The same value as `default_changefreq` or `default_priority`
87
+
88
+ 1. **(Lower)** A value in a `default_changefreq` and a `default_priority` option
89
+
90
+
91
+ ## Excluding pages
92
+
93
+
94
+ ### Specify in Frontmatter
95
+
96
+ You can add a `hide_from_sitemap` attribute to `Frontmatter` in the page which is omitted from the sitemap.xml:
97
+
98
+ ```yaml
99
+ ---
100
+ hide_from_sitemap: true
101
+ ---
102
+ ```
103
+
104
+ If you would like to use a different `Frontmatter` attribute, you can specify it in a `exclude_attr` option:
105
+
106
+ ```ruby
107
+ activate :sitemap_xml_generator do |f|
108
+ f.exclude_attr = 'invisible'
109
+ end
110
+ ```
111
+
112
+ Then you can omit a page the following way:
113
+
114
+ ```yaml
115
+ ---
116
+ invisible: true
117
+ ---
118
+ ```
119
+
120
+
121
+ ### Use custom processor
122
+
123
+ You can also use a `exclude_if` option to exclude pages based on conditions you want:
124
+
125
+ ```ruby
126
+ # Exclude all pages which have a date that's after today
127
+ activate :sitemap_xml_generator do |f|
128
+ f.exclude_if = ->(resource) {
129
+ resource.data.date && resource.data.date > Date.today
130
+ }
131
+ end
132
+ ```
133
+
134
+ | Argument | Description
135
+ | --- | ---
136
+ | resource | A resource object (`Middleman::Sitemap::Resource`)
137
+
138
+
139
+ ## Processing a URL in "loc" tag
140
+
141
+ You can use a `process_url` option to process a URL in "loc" tag in each page in the sitemap.xml:
142
+
143
+ ```ruby
144
+ # This Proc removes a trailing slash from a URL in all "loc" tag.
145
+ activate :sitemap_xml_generator do |f|
146
+ f.process_url = ->(url) { url.chomp('/') }
147
+ end
148
+ ```
149
+
150
+ | Argument | Description
151
+ | --- | ---
152
+ | url | The URL of each page
153
+
154
+
155
+ ## Adding file in addition to HTML
156
+
157
+ Only HTML file is added to the sitemap.xml with the default setting.
158
+
159
+ You can use a `extra_ext` option to add any file to the sitemap.xml:
160
+
161
+ ```ruby
162
+ # This setting adds every file suffixed ".foo" to the sitemap.xml.
163
+ activate :sitemap_xml_generator do |f|
164
+ f.extra_ext = ['.foo'] # prefixed dot is required.
165
+ end
166
+ ```
167
+
168
+
169
+ ## Excluding a content extension
170
+
171
+ You can use a `discard_ext` option to exclude a content extension from a address in "loc" tag in the sitemap.xml:
172
+
173
+ ```ruby
174
+ # This setting removes suffixed ".foo" from "loc" tag in the sitemap.xml.
175
+ activate :sitemap_xml_generator do |f|
176
+ f.discard_ext = ['.foo'] # prefixed dot is required.
177
+ end
178
+ ```
179
+
180
+ Note that this process is executed before the process designated in a `process_url` option.
181
+
182
+
183
+ ## Workaround for the template reference issue
184
+
185
+ This extension deals with that [issue](https://github.com/Aupajo/middleman-search_engine_sitemap/issues/5) by [this workaround](https://github.com/Aupajo/middleman-search_engine_sitemap/issues/2#issuecomment-46701165).
186
+
187
+
188
+ ## Thanks
189
+
190
+ All ideas, logics, hints and prizes belong to the original author, Pete Nicholls.
191
+
192
+ And all mistakes belong to me.
193
+
194
+
195
+ ## License
196
+
197
+ (c) 2016 AT-AT. MIT Licensed, see [LICENSE](LICENSE.md) for details.
@@ -0,0 +1,7 @@
1
+ require "bundler/setup"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ require 'middleman-core'
2
+
3
+ ::Middleman::Extensions.register(:sitemap_xml_generator) do
4
+ require 'middleman-sitemap-xml-generator/extension'
5
+ ::Middleman::SitemapXmlGenerator::Extension
6
+ end
@@ -0,0 +1,168 @@
1
+ module Middleman
2
+ module SitemapXmlGenerator
3
+ class Extension < ::Middleman::Extension
4
+ option :default_changefreq, 'monthly', 'Default page priority'
5
+ option :default_priority, 0.5, 'Default page priority'
6
+ option :sitemap_xml_path, 'sitemap.xml', 'Path to the sitemap.xml'
7
+ option :exclude_attr, 'hide_from_sitemap', 'Attribute in Frontmatter to exclude from sitemap'
8
+ option :process_url, nil, 'Callable object(responds to #call) to process a URL'
9
+ option :process_changefreq, nil, 'Callable object to determine a changefreq'
10
+ option :process_priority, nil, 'Callable object to determine a priority'
11
+ option :exclude_if, ->(resource) { false }, 'Callable object to exclude from the sitemap'
12
+ option :extra_ext, [], 'Extensions allowed to be in the sitemap(needed prefixed "dot")'
13
+ option :discard_ext, [], 'Extensions removed from "loc" in the sitemap(needed prefixed "dot")'
14
+
15
+ TEMPLATES_DIR = File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
16
+
17
+
18
+ def initialize(app, options_hash={}, &block)
19
+ super
20
+
21
+ require 'builder'
22
+ end
23
+
24
+
25
+ public
26
+
27
+
28
+ #
29
+ # Hooks
30
+ #
31
+
32
+ def after_configuration
33
+ register_extension_templates
34
+ prepare_extra_ext_opt
35
+ prepare_discard_ext_opt
36
+ watch_vendor_directory
37
+ end
38
+
39
+ def manipulate_resource_list(resources)
40
+ resources << sitemap_resource
41
+ end
42
+
43
+
44
+ #
45
+ # Helpers
46
+ #
47
+
48
+ def resource_in_sitemap?(resource)
49
+ is_page?(resource) && not_excluded?(resource)
50
+ end
51
+
52
+ def process_changefreq(path)
53
+ default = options.default_changefreq
54
+ options.process_changefreq ? options.process_changefreq.call(path, default) : default
55
+ end
56
+
57
+ def process_priority(path)
58
+ default = options.default_priority
59
+ options.process_priority ? options.process_priority.call(path, default) : default
60
+ end
61
+
62
+ def process_url(path)
63
+ path = process_extension path
64
+ options.process_url ? options.process_url.call(path) : path
65
+ end
66
+
67
+ helpers do
68
+ def resources_for_sitemap
69
+ sitemap.resources.select do |resource|
70
+ extensions[:sitemap_xml_generator].resource_in_sitemap?(resource)
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ #
77
+ # Internals
78
+ #
79
+
80
+ private
81
+
82
+ def allowed_ext?(resource)
83
+ options.extra_ext.include? File.extname(resource.path)
84
+ end
85
+
86
+ def filter_valid_extension(value)
87
+ [value].flatten.select { |ext| ext.match /^\.[^.]+/ }
88
+ end
89
+
90
+ def generate_processor(method_name)
91
+ self.class.instance_method(method_name.to_sym).bind(self)
92
+ end
93
+
94
+ def is_page?(resource)
95
+ resource.path.end_with?(page_ext) || allowed_ext?(resource)
96
+ end
97
+
98
+ def not_excluded?(resource)
99
+ !resource.ignored? \
100
+ && !resource.data[options.exclude_attr] && !options.exclude_if.call(resource)
101
+ end
102
+
103
+ def page_ext
104
+ File.extname(app.index_file)
105
+ end
106
+
107
+ def prepare_extra_ext_opt
108
+ options.extra_ext = filter_valid_extension options.extra_ext
109
+ end
110
+
111
+ def prepare_discard_ext_opt
112
+ options.discard_ext = filter_valid_extension options.discard_ext
113
+ end
114
+
115
+ def process_extension(path)
116
+ target_ext = File.extname path
117
+ if options.discard_ext.include?(target_ext)
118
+ path = File.join(File.dirname(path), File.basename(path, target_ext))
119
+ end
120
+ path
121
+ end
122
+
123
+ def register_extension_templates
124
+ # We call reload_path to register the templates directory with Middleman.
125
+ # The path given to app.files must be relative to the Middleman site's root.
126
+ templates_dir_relative_from_root = \
127
+ Pathname(TEMPLATES_DIR).relative_path_from(Pathname(app.root))
128
+ app.files.reload_path(templates_dir_relative_from_root)
129
+ end
130
+
131
+ def sitemap_locals
132
+ {
133
+ url_proc: generate_processor(:process_url),
134
+ changefreq_proc: generate_processor(:process_changefreq),
135
+ priority_proc: generate_processor(:process_priority)
136
+ }
137
+ end
138
+
139
+ def sitemap_resource
140
+ source_file = template('sitemap.xml.builder')
141
+
142
+ ::Middleman::Sitemap::Resource.new(app.sitemap, sitemap_xml_path, source_file).tap do |res|
143
+ res.add_metadata(options: { layout: false }, locals: sitemap_locals)
144
+ end
145
+ end
146
+
147
+ def sitemap_xml_path
148
+ options.sitemap_xml_path
149
+ end
150
+
151
+ def template(path)
152
+ full_path = File.join(TEMPLATES_DIR, path)
153
+ raise "Template #{full_path} not found" if !File.exist?(full_path)
154
+ full_path
155
+ end
156
+
157
+ # Workaround for the template reference issue. See below:
158
+ # https://github.com/Aupajo/middleman-search_engine_sitemap/issues/5
159
+ # https://github.com/Aupajo/middleman-search_engine_sitemap/issues/2#issuecomment-46701165
160
+ def watch_vendor_directory
161
+ app.config[:file_watcher_ignore] = (app.config[:file_watcher_ignore].reject do |regexp|
162
+ regexp == /^vendor(\/|$)/
163
+ end)
164
+ end
165
+
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,11 @@
1
+ xml.instruct!
2
+ xml.urlset 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9' do
3
+ resources_for_sitemap.each do |page|
4
+ xml.url do
5
+ xml.loc url_proc.call(File.join(url_root, page.url))
6
+ xml.lastmod(File.mtime(page.source_file).iso8601) if page.source_file
7
+ xml.changefreq page.data.changefreq || changefreq_proc.call(page.url)
8
+ xml.priority page.data.priority || priority_proc.call(page.url)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module Middleman
2
+ module SitemapXmlGenerator
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require 'middleman-sitemap-xml-generator'
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $:.unshift(lib) unless $:.include?(lib)
4
+ require 'middleman-sitemap-xml-generator/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'middleman-sitemap-xml-generator'
8
+ s.version = Middleman::SitemapXmlGenerator::VERSION
9
+ s.authors = ['AT-AT']
10
+ s.email = ['dec.alpha21264@gmail.com']
11
+ s.homepage = 'https://github.com/AT-AT/middleman-sitemap-xml-generator'
12
+ s.summary = %q{Adds a sitemap.xml file to your Middleman site for search engines.}
13
+ s.description = %q{Adds a sitemap.xml file to your Middleman site for search engines.}
14
+ s.license = 'MIT'
15
+ s.files = `git ls-files -z`.split("\0")
16
+ s.test_files = `git ls-files -- {test,spec,features,fixtures}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ # The version of middleman-core your extension depends on
21
+ s.add_runtime_dependency 'middleman-core', '~> 3.4.1'
22
+ s.add_runtime_dependency 'builder'
23
+
24
+ # Additional dependencies
25
+ s.add_development_dependency 'bundler', '~> 1.5'
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency 'rspec'
28
+ s.add_development_dependency 'nokogiri', '1.6.3'
29
+ end
@@ -0,0 +1,116 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3
+ targetNamespace="http://www.sitemaps.org/schemas/sitemap/0.9"
4
+ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
5
+ elementFormDefault="qualified">
6
+ <xsd:annotation>
7
+ <xsd:documentation>
8
+ XML Schema for Sitemap files.
9
+ Last Modifed 2008-03-26
10
+ </xsd:documentation>
11
+ </xsd:annotation>
12
+
13
+ <xsd:element name="urlset">
14
+ <xsd:annotation>
15
+ <xsd:documentation>
16
+ Container for a set of up to 50,000 document elements.
17
+ This is the root element of the XML file.
18
+ </xsd:documentation>
19
+ </xsd:annotation>
20
+ <xsd:complexType>
21
+ <xsd:sequence>
22
+ <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="strict"/>
23
+ <xsd:element name="url" type="tUrl" maxOccurs="unbounded"/>
24
+ </xsd:sequence>
25
+ </xsd:complexType>
26
+ </xsd:element>
27
+
28
+ <xsd:complexType name="tUrl">
29
+ <xsd:annotation>
30
+ <xsd:documentation>
31
+ Container for the data needed to describe a document to crawl.
32
+ </xsd:documentation>
33
+ </xsd:annotation>
34
+ <xsd:sequence>
35
+ <xsd:element name="loc" type="tLoc"/>
36
+ <xsd:element name="lastmod" type="tLastmod" minOccurs="0"/>
37
+ <xsd:element name="changefreq" type="tChangeFreq" minOccurs="0"/>
38
+ <xsd:element name="priority" type="tPriority" minOccurs="0"/>
39
+ <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="strict"/>
40
+ </xsd:sequence>
41
+ </xsd:complexType>
42
+
43
+ <xsd:simpleType name="tLoc">
44
+ <xsd:annotation>
45
+ <xsd:documentation>
46
+ REQUIRED: The location URI of a document.
47
+ The URI must conform to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt).
48
+ </xsd:documentation>
49
+ </xsd:annotation>
50
+ <xsd:restriction base="xsd:anyURI">
51
+ <xsd:minLength value="12"/>
52
+ <xsd:maxLength value="2048"/>
53
+ </xsd:restriction>
54
+ </xsd:simpleType>
55
+
56
+ <xsd:simpleType name="tLastmod">
57
+ <xsd:annotation>
58
+ <xsd:documentation>
59
+ OPTIONAL: The date the document was last modified. The date must conform
60
+ to the W3C DATETIME format (http://www.w3.org/TR/NOTE-datetime).
61
+ Example: 2005-05-10
62
+ Lastmod may also contain a timestamp.
63
+ Example: 2005-05-10T17:33:30+08:00
64
+ </xsd:documentation>
65
+ </xsd:annotation>
66
+ <xsd:union>
67
+ <xsd:simpleType>
68
+ <xsd:restriction base="xsd:date"/>
69
+ </xsd:simpleType>
70
+ <xsd:simpleType>
71
+ <xsd:restriction base="xsd:dateTime"/>
72
+ </xsd:simpleType>
73
+ </xsd:union>
74
+ </xsd:simpleType>
75
+
76
+ <xsd:simpleType name="tChangeFreq">
77
+ <xsd:annotation>
78
+ <xsd:documentation>
79
+ OPTIONAL: Indicates how frequently the content at a particular URL is
80
+ likely to change. The value "always" should be used to describe
81
+ documents that change each time they are accessed. The value "never"
82
+ should be used to describe archived URLs. Please note that web
83
+ crawlers may not necessarily crawl pages marked "always" more often.
84
+ Consider this element as a friendly suggestion and not a command.
85
+ </xsd:documentation>
86
+ </xsd:annotation>
87
+ <xsd:restriction base="xsd:string">
88
+ <xsd:enumeration value="always"/>
89
+ <xsd:enumeration value="hourly"/>
90
+ <xsd:enumeration value="daily"/>
91
+ <xsd:enumeration value="weekly"/>
92
+ <xsd:enumeration value="monthly"/>
93
+ <xsd:enumeration value="yearly"/>
94
+ <xsd:enumeration value="never"/>
95
+ </xsd:restriction>
96
+ </xsd:simpleType>
97
+
98
+ <xsd:simpleType name="tPriority">
99
+ <xsd:annotation>
100
+ <xsd:documentation>
101
+ OPTIONAL: The priority of a particular URL relative to other pages
102
+ on the same site. The value for this element is a number between
103
+ 0.0 and 1.0 where 0.0 identifies the lowest priority page(s).
104
+ The default priority of a page is 0.5. Priority is used to select
105
+ between pages on your site. Setting a priority of 1.0 for all URLs
106
+ will not help you, as the relative priority of pages on your site
107
+ is what will be considered.
108
+ </xsd:documentation>
109
+ </xsd:annotation>
110
+ <xsd:restriction base="xsd:decimal">
111
+ <xsd:minInclusive value="0.0"/>
112
+ <xsd:maxInclusive value="1.0"/>
113
+ </xsd:restriction>
114
+ </xsd:simpleType>
115
+
116
+ </xsd:schema>
@@ -0,0 +1,3 @@
1
+ ---
2
+ priority: 0.2
3
+ ---
@@ -0,0 +1,2 @@
1
+ ---
2
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ changefreq: daily
3
+ priority: 0.2
4
+ ---
@@ -0,0 +1,3 @@
1
+ ---
2
+ changefreq: daily
3
+ ---
File without changes
@@ -0,0 +1,3 @@
1
+ ---
2
+ ignored_by_proc: true
3
+ ---
@@ -0,0 +1,3 @@
1
+ ---
2
+ hide_from_sitemap: true
3
+ ---
File without changes
@@ -0,0 +1 @@
1
+ Layout
@@ -0,0 +1,4 @@
1
+ ---
2
+ changefreq: daily
3
+ priority: 0.2
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ changefreq: daily
3
+ priority: 0.2
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ changefreq: daily
3
+ priority: 0.2
4
+ ---
@@ -0,0 +1,2 @@
1
+ ---
2
+ ---
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+ require 'nokogiri'
3
+ require 'pathname'
4
+
5
+ describe "Generate sitemap.xml", :feature do
6
+ include XmlHelpers
7
+
8
+ it "produces a valid sitemap" do
9
+ run_site 'dummy' do
10
+ set :url_root, 'http://example.com'
11
+ activate :sitemap_xml_generator
12
+
13
+ ignore '/ignored.html'
14
+ end
15
+
16
+ visit '/sitemap.xml'
17
+
18
+ schema = Pathname(__dir__) + '../../sitemap.xsd'
19
+ doc = Nokogiri::XML(last_response.body)
20
+ expect(doc).to validate_against_schema(schema)
21
+
22
+ expect(doc).to contain_node('url').with_children(
23
+ 'loc' => 'http://example.com/home.html',
24
+ 'priority' => '0.5',
25
+ 'changefreq' => 'monthly'
26
+ )
27
+
28
+ expect(doc).to contain_node('url').with_children(
29
+ 'loc' => 'http://example.com/about.html',
30
+ 'priority' => '0.2',
31
+ 'changefreq' => 'monthly'
32
+ )
33
+
34
+ expect(doc).to contain_node('url').with_children(
35
+ 'loc' => 'http://example.com/blog.html',
36
+ 'priority' => '0.5',
37
+ 'changefreq' => 'daily'
38
+ )
39
+
40
+ expect(doc.to_s).not_to include('http://example.com/ignored.html')
41
+ expect(doc.to_s).not_to include('http://example.com/ignored-in-frontmatter.html')
42
+ end
43
+
44
+ it "works with directory indexes" do
45
+ run_site 'dummy' do
46
+ set :url_root, 'http://example.com'
47
+ activate :directory_indexes
48
+ activate :sitemap_xml_generator
49
+
50
+ ignore '/ignored.html'
51
+ end
52
+
53
+ visit '/sitemap.xml'
54
+ doc = Nokogiri::XML(last_response.body)
55
+
56
+ expect(doc).to contain_node('url').with_children(
57
+ 'loc' => 'http://example.com/home/',
58
+ 'priority' => '0.5',
59
+ 'changefreq' => 'monthly'
60
+ )
61
+
62
+ expect(doc).to contain_node('url').with_children(
63
+ 'loc' => 'http://example.com/about/',
64
+ 'priority' => '0.2',
65
+ 'changefreq' => 'monthly'
66
+ )
67
+
68
+ expect(doc).to contain_node('url').with_children(
69
+ 'loc' => 'http://example.com/blog/',
70
+ 'priority' => '0.5',
71
+ 'changefreq' => 'daily'
72
+ )
73
+
74
+ expect(doc.to_s).not_to include('http://example.com/ignored/')
75
+ expect(doc.to_s).not_to include('http://example.com/ignored-in-frontmatter/')
76
+ end
77
+
78
+ it "supports custom URL processing" do
79
+ run_site 'dummy' do
80
+ set :url_root, 'http://example.com'
81
+ activate :directory_indexes
82
+ activate :sitemap_xml_generator, process_url: ->(url) { url.upcase }
83
+ end
84
+
85
+ visit '/sitemap.xml'
86
+ doc = Nokogiri::XML(last_response.body)
87
+
88
+ expect(doc).to contain_node('url').with_children(
89
+ 'loc' => 'HTTP://EXAMPLE.COM/HOME/',
90
+ 'priority' => '0.5',
91
+ 'changefreq' => 'monthly'
92
+ )
93
+ end
94
+
95
+ it "ignores resources based on exclude_if result" do
96
+ run_site 'dummy' do
97
+ set :url_root, 'http://example.com'
98
+ activate :sitemap_xml_generator,
99
+ exclude_if: ->(resource) { resource.data.ignored_by_proc }
100
+
101
+ ignore '/ignored.html'
102
+ end
103
+
104
+ visit '/sitemap.xml'
105
+ doc = Nokogiri::XML(last_response.body)
106
+
107
+ expect(doc.to_s).not_to include('http://example.com/ignored-by-proc.html')
108
+ end
109
+
110
+ it "allows resources having a extension which is designated in the option" do
111
+ run_site 'dummy' do
112
+ set :url_root, 'http://example.com'
113
+ activate :sitemap_xml_generator,
114
+ extra_ext: ['.foo', 'bar']
115
+ end
116
+
117
+ visit '/sitemap.xml'
118
+ doc = Nokogiri::XML(last_response.body)
119
+
120
+ expect(doc).to contain_node('url').with_children(
121
+ 'loc' => 'http://example.com/allowed-extra-ext.foo',
122
+ 'priority' => '0.2',
123
+ 'changefreq' => 'daily'
124
+ )
125
+
126
+ expect(doc.to_s).not_to include('http://example.com/allowed-extra-ext.bar')
127
+ end
128
+
129
+ it "removes designated extention from resources" do
130
+ run_site 'dummy' do
131
+ set :url_root, 'http://example.com'
132
+ activate :sitemap_xml_generator,
133
+ extra_ext: ['.foo', '.bar'],
134
+ discard_ext: ['.html', '.foo', 'bar']
135
+ end
136
+
137
+ visit '/sitemap.xml'
138
+ doc = Nokogiri::XML(last_response.body)
139
+
140
+ expect(doc).to contain_node('url').with_children(
141
+ 'loc' => 'http://example.com/removed-ext',
142
+ 'priority' => '0.2',
143
+ 'changefreq' => 'daily'
144
+ )
145
+
146
+ expect(doc).to contain_node('url').with_children(
147
+ 'loc' => 'http://example.com/removed-extra-ext',
148
+ 'priority' => '0.2',
149
+ 'changefreq' => 'daily'
150
+ )
151
+
152
+ expect(doc).to contain_node('url').with_children(
153
+ 'loc' => 'http://example.com/removed-ext-remained.bar',
154
+ 'priority' => '0.2',
155
+ 'changefreq' => 'daily'
156
+ )
157
+ end
158
+
159
+ it "set values by procs" do
160
+ run_site 'dummy' do
161
+ set :url_root, 'http://example.com'
162
+ activate :sitemap_xml_generator,
163
+ extra_ext: ['.foo'],
164
+ process_changefreq: ->(path, default){
165
+ path.end_with?('.foo') ? 'yearly' : default
166
+ },
167
+ process_priority: ->(path, default){
168
+ path.end_with?('.foo') ? 0.9 : default
169
+ }
170
+ end
171
+
172
+ visit '/sitemap.xml'
173
+ doc = Nokogiri::XML(last_response.body)
174
+
175
+ expect(doc).to contain_node('url').with_children(
176
+ 'loc' => 'http://example.com/values_by_proc.foo',
177
+ 'priority' => '0.9',
178
+ 'changefreq' => 'yearly'
179
+ )
180
+ end
181
+
182
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspec'
2
+
3
+ $LOAD_PATH << File.expand_path("../../lib", __FILE__)
4
+
5
+ # Include support files
6
+ support_files_pattern = File.expand_path('../support/**/*.rb', __FILE__)
7
+ Dir.glob(support_files_pattern).each { |f| require f }
8
+
9
+ RSpec.configure do |config|
10
+ config.include MiddlemanServerHelpers, :feature
11
+ end
@@ -0,0 +1,41 @@
1
+ require 'middleman/rack'
2
+ require 'rack/test'
3
+
4
+ module MiddlemanServerHelpers
5
+ include Rack::Test::Methods
6
+
7
+ def app
8
+ @app.call
9
+ end
10
+
11
+ def visit(path)
12
+ get(path)
13
+ raise last_response.errors if !last_response.errors.empty?
14
+ end
15
+
16
+ def find_on_page(string)
17
+ expect(last_response.body).to include(string)
18
+ end
19
+
20
+ def run_site(path, &block)
21
+ setup_environment(path)
22
+
23
+ @app = lambda do
24
+ instance = Middleman::Application.server.inst do
25
+ # Require the extension after the server has booted, as would typically happen.
26
+ require File.expand_path('../../../lib/middleman_extension', __FILE__)
27
+
28
+ instance_exec(&block)
29
+ end
30
+
31
+ instance.class.to_rack_app
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def setup_environment(path)
38
+ ENV['MM_ROOT'] = File.expand_path("../../#{path}", __FILE__)
39
+ ENV['TEST'] = "true"
40
+ end
41
+ end
@@ -0,0 +1,49 @@
1
+ module XmlHelpers
2
+ extend RSpec::Matchers::DSL
3
+
4
+ matcher :validate_against_schema do |schema|
5
+ match do |actual|
6
+ xsd = Nokogiri::XML::Schema(schema.read)
7
+ @validation_errors = xsd.validate(actual)
8
+ @validation_errors.empty?
9
+ end
10
+
11
+ failure_message do |actual|
12
+ num_errors = @validation_errors.length
13
+ error_count = "#{num_errors} error#{'s' if num_errors > 1}"
14
+
15
+ "expected XML to validate against #{schema}, got #{error_count}:\n" +
16
+ @validation_errors.each_with_index.map do |error, i|
17
+ " #{i + 1}. #{error}"
18
+ end.join("\n")
19
+ end
20
+ end
21
+
22
+ matcher :contain_node do |name|
23
+ match do |doc|
24
+ if @attributes
25
+ doc.css(name).detect do |node|
26
+ @attributes.all? { |k, v| node.css(k).text == v }
27
+ end
28
+ else
29
+ doc.at_css(name)
30
+ end
31
+ end
32
+
33
+ chain :with_children do |attributes|
34
+ @attributes = attributes
35
+ end
36
+
37
+ failure_message do |doc|
38
+ expected_xml = "<#{name}>\n"
39
+
40
+ if @attributes
41
+ @attributes.each { |k,v| expected_xml << " <#{k}>#{v}</#{k}>\n" }
42
+ end
43
+
44
+ expected_xml << "</#{name}>"
45
+
46
+ "expected XML to contain:\n\n#{expected_xml}\n\ninstead got:\n\n#{doc.to_s}"
47
+ end
48
+ end
49
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: middleman-sitemap-xml-generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - AT-AT
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: middleman-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: builder
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: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: nokogiri
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.6.3
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.6.3
97
+ description: Adds a sitemap.xml file to your Middleman site for search engines.
98
+ email:
99
+ - dec.alpha21264@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - Gemfile
106
+ - LICENSE.md
107
+ - README.md
108
+ - Rakefile
109
+ - lib/middleman-sitemap-xml-generator.rb
110
+ - lib/middleman-sitemap-xml-generator/extension.rb
111
+ - lib/middleman-sitemap-xml-generator/templates/sitemap.xml.builder
112
+ - lib/middleman-sitemap-xml-generator/version.rb
113
+ - lib/middleman_extension.rb
114
+ - middleman-sitemap-xml-generator.gemspec
115
+ - sitemap.xsd
116
+ - spec/dummy/source/about.html
117
+ - spec/dummy/source/allowed-extra-ext.bar
118
+ - spec/dummy/source/allowed-extra-ext.foo
119
+ - spec/dummy/source/blog.html
120
+ - spec/dummy/source/home.html
121
+ - spec/dummy/source/ignored-by-proc.html
122
+ - spec/dummy/source/ignored-in-frontmatter.html
123
+ - spec/dummy/source/ignored.html
124
+ - spec/dummy/source/layouts/layout.erb
125
+ - spec/dummy/source/removed-ext-remained.bar
126
+ - spec/dummy/source/removed-ext.html
127
+ - spec/dummy/source/removed-extra-ext.foo
128
+ - spec/dummy/source/values_by_proc.foo
129
+ - spec/features/sitemap_feature_spec.rb
130
+ - spec/spec_helper.rb
131
+ - spec/support/middleman_server_helpers.rb
132
+ - spec/support/xml_helpers.rb
133
+ homepage: https://github.com/AT-AT/middleman-sitemap-xml-generator
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.5.1
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Adds a sitemap.xml file to your Middleman site for search engines.
157
+ test_files:
158
+ - spec/dummy/source/about.html
159
+ - spec/dummy/source/allowed-extra-ext.bar
160
+ - spec/dummy/source/allowed-extra-ext.foo
161
+ - spec/dummy/source/blog.html
162
+ - spec/dummy/source/home.html
163
+ - spec/dummy/source/ignored-by-proc.html
164
+ - spec/dummy/source/ignored-in-frontmatter.html
165
+ - spec/dummy/source/ignored.html
166
+ - spec/dummy/source/layouts/layout.erb
167
+ - spec/dummy/source/removed-ext-remained.bar
168
+ - spec/dummy/source/removed-ext.html
169
+ - spec/dummy/source/removed-extra-ext.foo
170
+ - spec/dummy/source/values_by_proc.foo
171
+ - spec/features/sitemap_feature_spec.rb
172
+ - spec/spec_helper.rb
173
+ - spec/support/middleman_server_helpers.rb
174
+ - spec/support/xml_helpers.rb