middleman-blog 4.0.3 → 4.2.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.
- checksums.yaml +4 -4
- data/.gitattributes +3 -0
- data/.github/workflows/ci.yml +25 -0
- data/.github/workflows/stale.yml +21 -0
- data/.gitignore +1 -3
- data/CHANGELOG.md +78 -60
- data/Gemfile +12 -26
- data/README.md +20 -30
- data/Rakefile +8 -14
- data/features/alias.feature +41 -0
- data/features/summary.feature +21 -2
- data/features/support/env.rb +2 -0
- data/features/support/time_steps.rb +9 -7
- data/features/tags.feature +4 -0
- data/fixtures/alias-app/config.rb +10 -0
- data/fixtures/alias-app/source/2024-03-14-pi-day.html.markdown +7 -0
- data/fixtures/alias-app/source/index.html +1 -0
- data/fixtures/alias-prefix-app/config.rb +11 -0
- data/fixtures/alias-prefix-app/source/blog/2024-01-15-prefix-test.html.markdown +7 -0
- data/fixtures/alias-prefix-app/source/index.html +1 -0
- data/fixtures/article-dirs-app/config-directory-indexes.rb +2 -0
- data/fixtures/article-dirs-app/config-permalink-with-dot.rb +2 -0
- data/fixtures/article-dirs-app/config.rb +2 -0
- data/fixtures/blog-sources-app/config.rb +2 -0
- data/fixtures/blog-sources-no-date-app/config.rb +2 -0
- data/fixtures/blog-sources-no-day-app/config.rb +2 -0
- data/fixtures/blog-sources-no-title-app/config.rb +2 -0
- data/fixtures/blog-sources-subdirs-app/config.rb +2 -0
- data/fixtures/calendar-and-tag-app/config-directory-indexes.rb +2 -0
- data/fixtures/calendar-and-tag-app/config.rb +2 -0
- data/fixtures/calendar-app/config-directory-indexes.rb +2 -0
- data/fixtures/calendar-app/config-only-year.rb +2 -0
- data/fixtures/calendar-app/config.rb +2 -0
- data/fixtures/calendar-multiblog-app/config.rb +2 -0
- data/fixtures/custom-article-template-app/config.rb +2 -0
- data/fixtures/custom-collections-app/config-blog-prefix.rb +2 -0
- data/fixtures/custom-collections-app/config-directory-indexes.rb +2 -0
- data/fixtures/custom-collections-app/config.rb +2 -0
- data/fixtures/custom-collections-multiblog-app/config.rb +2 -0
- data/fixtures/custom-collections-sources-app/config.rb +2 -0
- data/fixtures/custom-permalinks-app/config-directory-indexes.rb +2 -0
- data/fixtures/custom-permalinks-app/config.rb +2 -0
- data/fixtures/filename-date-app/config.rb +2 -0
- data/fixtures/future-date-app/config.rb +2 -0
- data/fixtures/indexes-app/config.rb +2 -0
- data/fixtures/lang-path-app/config.rb +2 -0
- data/fixtures/language-app/config.rb +3 -1
- data/fixtures/layouts-app/config.rb +2 -0
- data/fixtures/paginate-app/config-directory-indexes.rb +2 -0
- data/fixtures/paginate-app/config-paginate-off.rb +2 -0
- data/fixtures/paginate-app/config.rb +2 -0
- data/fixtures/paginate-multiblog-app/config.rb +2 -0
- data/fixtures/permalink-app/config.rb +2 -0
- data/fixtures/preview-app/config.rb +2 -0
- data/fixtures/published-app/config.rb +2 -0
- data/fixtures/summary-app/config.rb +2 -0
- data/fixtures/summary-app/source/layout.erb +6 -0
- data/fixtures/tags-app/config-directory-indexes.rb +2 -0
- data/fixtures/tags-app/config-filters.rb +2 -0
- data/fixtures/tags-app/config-no-tags.rb +2 -0
- data/fixtures/tags-app/config.rb +2 -0
- data/fixtures/tags-app/source/blog/2011-01-01-new-article.html.markdown +1 -1
- data/fixtures/tags-app/source/blog/2011-01-02-another-article.html.markdown +1 -0
- data/fixtures/tags-multiblog-app/config.rb +2 -0
- data/fixtures/time-zone-app/config.rb +2 -0
- data/lib/middleman-blog/alias_pages.rb +161 -0
- data/lib/middleman-blog/blog_article.rb +17 -11
- data/lib/middleman-blog/blog_data.rb +4 -8
- data/lib/middleman-blog/calendar_pages.rb +8 -6
- data/lib/middleman-blog/commands/article.rb +10 -6
- data/lib/middleman-blog/commands/article.tt +2 -2
- data/lib/middleman-blog/custom_pages.rb +3 -1
- data/lib/middleman-blog/extension.rb +32 -12
- data/lib/middleman-blog/helpers.rb +4 -2
- data/lib/middleman-blog/paginator.rb +3 -1
- data/lib/middleman-blog/tag_pages.rb +3 -1
- data/lib/middleman-blog/truncate_html.rb +21 -5
- data/lib/middleman-blog/uri_templates.rb +12 -6
- data/lib/middleman-blog/version.rb +3 -1
- data/lib/middleman-blog.rb +2 -0
- data/lib/middleman_extension.rb +2 -0
- data/middleman-blog.gemspec +15 -22
- data/spec/alias_spec.rb +116 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/uri_templates_spec.rb +14 -0
- metadata +30 -34
- data/.rubocop.yml +0 -69
- data/.travis.yml +0 -30
- data/Gemfile-4.x +0 -38
- data/fixtures/default-template-app/Gemfile +0 -6
- data/fixtures/default-template-app/config.rb +0 -35
- data/fixtures/default-template-app/source/2013-04-01-new-article.html.markdown +0 -25
- data/fixtures/default-template-app/source/about-me.html.erb +0 -0
- data/fixtures/default-template-app/source/archives.html.erb +0 -10
- data/fixtures/default-template-app/source/index.html.erb +0 -11
- data/fixtures/default-template-app/source/javascripts/_zepto.pjax.js +0 -744
- data/fixtures/default-template-app/source/javascripts/app.js +0 -11
- data/fixtures/default-template-app/source/javascripts/modernizr.js +0 -1
- data/fixtures/default-template-app/source/layouts/layout.erb +0 -62
- data/fixtures/default-template-app/source/stylesheets/app.css.scss +0 -109
- /data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +0 -0
- /data/{ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md} +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'middleman-core/cli'
|
|
2
4
|
require 'date'
|
|
3
5
|
require 'middleman-blog/uri_templates'
|
|
@@ -65,7 +67,6 @@ module Middleman
|
|
|
65
67
|
@content = options[:content] || ''
|
|
66
68
|
@date = options[:date] ? ::Time.zone.parse(options[:date]) : Time.zone.now
|
|
67
69
|
@locale = options[:locale] || (::I18n.default_locale if defined? ::I18n)
|
|
68
|
-
@slug = safe_parameterize(title)
|
|
69
70
|
@tags = options[:tags]&.split(/\s*,\s*/) || []
|
|
70
71
|
@title = title
|
|
71
72
|
|
|
@@ -77,17 +78,20 @@ module Middleman
|
|
|
77
78
|
end
|
|
78
79
|
|
|
79
80
|
blog_inst = if options[:blog]
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
app.extensions[:blog].find { |_key, instance| instance.options[:name] == options[:blog] }[ 1 ]
|
|
82
|
+
else
|
|
83
|
+
app.extensions[:blog].values.first
|
|
84
|
+
end
|
|
84
85
|
|
|
85
86
|
unless blog_inst
|
|
86
87
|
msg = 'Could not find an active blog instance'
|
|
87
|
-
msg
|
|
88
|
+
msg = "#{msg} named #{options[:blog]}" if options[:blog]
|
|
88
89
|
throw msg
|
|
89
90
|
end
|
|
90
91
|
|
|
92
|
+
# Generate slug after we have access to blog options
|
|
93
|
+
@slug = safe_parameterize(title, preserve_underscores: blog_inst.options.preserve_underscores_in_slugs)
|
|
94
|
+
|
|
91
95
|
path_template = blog_inst.data.source_template
|
|
92
96
|
params = date_to_params(@date).merge(locale: @locale.to_s, title: @slug)
|
|
93
97
|
article_path = apply_uri_template path_template, params
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'middleman-blog/uri_templates'
|
|
2
4
|
|
|
3
5
|
module Middleman
|
|
@@ -21,7 +23,7 @@ module Middleman
|
|
|
21
23
|
#
|
|
22
24
|
# @param [String] value
|
|
23
25
|
def link(value)
|
|
24
|
-
apply_uri_template @link_template, property => safe_parameterize(value)
|
|
26
|
+
apply_uri_template @link_template, property => safe_parameterize(value, preserve_underscores: @blog_controller.options.preserve_underscores_in_slugs)
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def manipulate_resource_list(resources)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'active_support/core_ext/time/zones'
|
|
2
4
|
require 'middleman-blog/blog_data'
|
|
3
5
|
require 'middleman-blog/blog_article'
|
|
@@ -39,8 +41,10 @@ module Middleman
|
|
|
39
41
|
option :publish_future_dated, false, 'Whether articles with a date in the future should be considered published'
|
|
40
42
|
option :custom_collections, {}, 'Hash of custom frontmatter properties to collect articles on and their options (link, template)'
|
|
41
43
|
option :preserve_locale, false, 'Use the global Middleman I18n.locale instead of the lang in the article\'s frontmatter'
|
|
44
|
+
option :preserve_underscores_in_slugs, false, 'Whether to preserve underscores in article slugs instead of converting them to dashes'
|
|
42
45
|
option :new_article_template, File.expand_path('commands/article.tt', __dir__), 'Path (relative to project root) to an ERb template that will be used to generate new articles from the "middleman article" command.'
|
|
43
46
|
option :default_extension, '.markdown', 'Default template extension for articles (used by "middleman article")'
|
|
47
|
+
option :aliases, [], 'Array of URL patterns that should redirect to the main permalink (e.g., [":year-:month-:day-:title.html"])'
|
|
44
48
|
|
|
45
49
|
# @return [BlogData] blog data for this blog, which has all information about the blog articles
|
|
46
50
|
attr_reader :data
|
|
@@ -60,6 +64,9 @@ module Middleman
|
|
|
60
64
|
# @return [Hash<CustomPages>] custom pages handlers for this blog, indexed by property name
|
|
61
65
|
attr_reader :custom_pages
|
|
62
66
|
|
|
67
|
+
# @return [AliasPages] alias page handler for this blog
|
|
68
|
+
attr_reader :alias_pages
|
|
69
|
+
|
|
63
70
|
# Helpers for use within templates and layouts.
|
|
64
71
|
self.defined_helpers = [Middleman::Blog::Helpers]
|
|
65
72
|
|
|
@@ -79,18 +86,23 @@ module Middleman
|
|
|
79
86
|
end
|
|
80
87
|
|
|
81
88
|
# If "prefix" option is specified, all other paths are relative to it.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
return unless options.prefix
|
|
90
|
+
|
|
91
|
+
options.prefix = "/#{options.prefix}" unless options.prefix.start_with? '/'
|
|
92
|
+
options.permalink = File.join(options.prefix, options.permalink)
|
|
93
|
+
options.sources = File.join(options.prefix, options.sources)
|
|
94
|
+
options.taglink = File.join(options.prefix, options.taglink)
|
|
95
|
+
options.year_link = File.join(options.prefix, options.year_link)
|
|
96
|
+
options.month_link = File.join(options.prefix, options.month_link)
|
|
97
|
+
options.day_link = File.join(options.prefix, options.day_link)
|
|
98
|
+
|
|
99
|
+
options.custom_collections.each_value do |opts|
|
|
100
|
+
opts[:link] = File.join(options.prefix, opts[:link])
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Apply prefix to alias patterns if specified
|
|
104
|
+
unless options.aliases.nil? || options.aliases.empty?
|
|
105
|
+
options.aliases = options.aliases.map { |alias_pattern| File.join(options.prefix, alias_pattern) }
|
|
94
106
|
end
|
|
95
107
|
end
|
|
96
108
|
|
|
@@ -113,6 +125,8 @@ module Middleman
|
|
|
113
125
|
@app.ignore(options.day_template) if options.day_template
|
|
114
126
|
@app.ignore options.tag_template if options.tag_template
|
|
115
127
|
|
|
128
|
+
ActiveSupport.to_time_preserves_timezone = :zone
|
|
129
|
+
|
|
116
130
|
# Make sure ActiveSupport's TimeZone stuff has something to work with,
|
|
117
131
|
# allowing people to set their desired time zone via Time.zone or
|
|
118
132
|
# set :time_zone
|
|
@@ -153,6 +167,12 @@ module Middleman
|
|
|
153
167
|
@app.sitemap.register_resource_list_manipulator(:"blog_#{name}_paginate", @paginator)
|
|
154
168
|
end
|
|
155
169
|
|
|
170
|
+
unless options.aliases.nil? || options.aliases.empty?
|
|
171
|
+
require 'middleman-blog/alias_pages'
|
|
172
|
+
@alias_pages = Blog::AliasPages.new(@app, self)
|
|
173
|
+
@app.sitemap.register_resource_list_manipulator(:"blog_#{name}_aliases", @alias_pages)
|
|
174
|
+
end
|
|
175
|
+
|
|
156
176
|
logger.info "== Blog Sources: #{options.sources} (:prefix + :sources)"
|
|
157
177
|
end
|
|
158
178
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Middleman
|
|
2
4
|
module Blog
|
|
3
5
|
# Blog-related helpers that are available to the Middleman application in +config.rb+ and in templates.
|
|
@@ -59,7 +61,7 @@ module Middleman
|
|
|
59
61
|
# Determine whether the currently rendering template is a {BlogArticle}.
|
|
60
62
|
# This can be useful in layouts and helpers.
|
|
61
63
|
# @return [Boolean]
|
|
62
|
-
def is_blog_article?
|
|
64
|
+
def is_blog_article?
|
|
63
65
|
!current_article.nil?
|
|
64
66
|
end
|
|
65
67
|
|
|
@@ -67,7 +69,7 @@ module Middleman
|
|
|
67
69
|
# @return [BlogArticle]
|
|
68
70
|
def current_article
|
|
69
71
|
article = current_resource
|
|
70
|
-
article if article
|
|
72
|
+
article if article.is_a?(BlogArticle)
|
|
71
73
|
end
|
|
72
74
|
|
|
73
75
|
# Get a path to the given tag page, based on the +taglink+ blog setting.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'middleman-blog/uri_templates'
|
|
2
4
|
|
|
3
5
|
module Middleman
|
|
@@ -149,7 +151,7 @@ module Middleman
|
|
|
149
151
|
else
|
|
150
152
|
page_url = apply_uri_template page_link, num: page_num
|
|
151
153
|
index_re = %r{(^|/)#{Regexp.escape(@app.config[:index_file])}$}
|
|
152
|
-
if res.path
|
|
154
|
+
if res.path&.match?(index_re)
|
|
153
155
|
res.path.sub(index_re, "\\1#{page_url}/#{@app.config[:index_file]}")
|
|
154
156
|
else
|
|
155
157
|
res.path.sub(%r{(^|/)([^/]*)\.([^/]*)$}, "\\1\\2/#{page_url}.\\3")
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'middleman-blog/uri_templates'
|
|
2
4
|
|
|
3
5
|
module Middleman
|
|
@@ -31,7 +33,7 @@ module Middleman
|
|
|
31
33
|
# @return [String] Safe Tag URL
|
|
32
34
|
##
|
|
33
35
|
def link(tag)
|
|
34
|
-
apply_uri_template @tag_link_template, tag: safe_parameterize(tag)
|
|
36
|
+
apply_uri_template @tag_link_template, tag: safe_parameterize(tag, preserve_underscores: @blog_controller.options.preserve_underscores_in_slugs)
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
##
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
begin
|
|
2
4
|
require 'nokogiri'
|
|
3
5
|
rescue LoadError
|
|
@@ -13,6 +15,20 @@ module TruncateHTML
|
|
|
13
15
|
doc.inner_html
|
|
14
16
|
end
|
|
15
17
|
|
|
18
|
+
def self.content_after_separator(text, separator)
|
|
19
|
+
text = text.encode('UTF-8') if text.respond_to?(:encode)
|
|
20
|
+
parts = text.split(separator, 2)
|
|
21
|
+
|
|
22
|
+
if parts.length >= 2
|
|
23
|
+
# Take the last part (which should be after the separator)
|
|
24
|
+
content_after = parts.last
|
|
25
|
+
doc = Nokogiri::HTML::DocumentFragment.parse content_after
|
|
26
|
+
doc.inner_html
|
|
27
|
+
else
|
|
28
|
+
text
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
16
32
|
def self.truncate_at_length(text, max_length, ellipsis = '...')
|
|
17
33
|
ellipsis_length = ellipsis.length
|
|
18
34
|
text = text.encode('UTF-8') if text.respond_to?(:encode)
|
|
@@ -48,7 +64,7 @@ module NokogiriTruncator
|
|
|
48
64
|
module TextNode
|
|
49
65
|
def truncate(max_length, ellipsis)
|
|
50
66
|
# Don't break in the middle of a word
|
|
51
|
-
trimmed_content = content.match(/(.{1,#{max_length}}
|
|
67
|
+
trimmed_content = content.match(/(.{1,#{max_length}}\w*)/m).to_s
|
|
52
68
|
trimmed_content << ellipsis if trimmed_content.length < content.length
|
|
53
69
|
|
|
54
70
|
Nokogiri::XML::Text.new(trimmed_content, parent)
|
|
@@ -63,7 +79,7 @@ module NokogiriTruncator
|
|
|
63
79
|
end
|
|
64
80
|
end
|
|
65
81
|
|
|
66
|
-
Nokogiri::HTML::DocumentFragment.
|
|
67
|
-
Nokogiri::XML::Element.
|
|
68
|
-
Nokogiri::XML::Text.
|
|
69
|
-
Nokogiri::XML::Comment.
|
|
82
|
+
Nokogiri::HTML::DocumentFragment.include NokogiriTruncator::NodeWithChildren
|
|
83
|
+
Nokogiri::XML::Element.include NokogiriTruncator::NodeWithChildren
|
|
84
|
+
Nokogiri::XML::Text.include NokogiriTruncator::TextNode
|
|
85
|
+
Nokogiri::XML::Comment.include NokogiriTruncator::CommentNode
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'addressable/template'
|
|
4
|
+
require 'active_support/all'
|
|
2
5
|
require 'middleman-core/util'
|
|
3
6
|
require 'active_support/inflector'
|
|
4
7
|
require 'active_support/inflector/transliterate'
|
|
@@ -51,13 +54,13 @@ module Middleman
|
|
|
51
54
|
# Reimplementation of this, preserves un-transliterate-able multibyte chars.
|
|
52
55
|
#
|
|
53
56
|
# @see http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize
|
|
54
|
-
def safe_parameterize(str,
|
|
57
|
+
def safe_parameterize(str, separator: '-', preserve_underscores: false)
|
|
55
58
|
# Remove ending ?
|
|
56
59
|
str = str.to_s.gsub(/\?$/, '')
|
|
57
60
|
|
|
58
61
|
# Reimplementation of http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize that preserves un-transliterate-able multibyte chars.
|
|
59
62
|
parameterized_string = ::ActiveSupport::Inflector.transliterate(str.to_s).downcase
|
|
60
|
-
parameterized_string.gsub!(/[^a-z0-9\-_
|
|
63
|
+
parameterized_string.gsub!(/[^a-z0-9\-_?]+/, separator)
|
|
61
64
|
|
|
62
65
|
# Check for multibytes and sub back in
|
|
63
66
|
parameterized_string.chars.to_a.each_with_index do |char, i|
|
|
@@ -66,17 +69,20 @@ module Middleman
|
|
|
66
69
|
parameterized_string[i] = str[i]
|
|
67
70
|
end
|
|
68
71
|
|
|
69
|
-
re_sep = ::Regexp.escape(
|
|
72
|
+
re_sep = ::Regexp.escape(separator)
|
|
70
73
|
|
|
71
74
|
# No more than one of the separator in a row.
|
|
72
|
-
parameterized_string.gsub!(/#{re_sep}{2,}/,
|
|
75
|
+
parameterized_string.gsub!(/#{re_sep}{2,}/, separator)
|
|
73
76
|
|
|
74
77
|
# Remove leading/trailing separator.
|
|
75
78
|
parameterized_string.gsub!(/^#{re_sep}|#{re_sep}$/, '')
|
|
76
|
-
|
|
79
|
+
|
|
80
|
+
# Replace all _ with - (unless preserve_underscores is true)
|
|
81
|
+
parameterized_string.tr!('_', '-') unless preserve_underscores
|
|
82
|
+
|
|
83
|
+
# Delete all ?
|
|
77
84
|
parameterized_string.delete!('?')
|
|
78
85
|
|
|
79
|
-
# Replace all ?
|
|
80
86
|
parameterized_string
|
|
81
87
|
end
|
|
82
88
|
|
data/lib/middleman-blog.rb
CHANGED
data/lib/middleman_extension.rb
CHANGED
data/middleman-blog.gemspec
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
$:.push File.expand_path( "../lib", __FILE__ )
|
|
3
|
-
require "middleman-blog/version"
|
|
1
|
+
require "./lib/middleman-blog/version"
|
|
4
2
|
|
|
5
3
|
Gem::Specification.new do | s |
|
|
6
|
-
|
|
7
|
-
s.
|
|
8
|
-
s.
|
|
9
|
-
s.
|
|
10
|
-
s.
|
|
11
|
-
s.
|
|
12
|
-
s.
|
|
13
|
-
s.
|
|
14
|
-
s.
|
|
15
|
-
s.
|
|
16
|
-
s.
|
|
17
|
-
s.
|
|
18
|
-
s.
|
|
19
|
-
s.
|
|
20
|
-
|
|
21
|
-
s.add_dependency( "middleman-core", [ ">= 4.0.0" ] )
|
|
22
|
-
s.add_dependency( "tzinfo", [ ">= 0.3.0" ] )
|
|
23
|
-
s.add_dependency( "addressable", [ "~> 2.3" ] )
|
|
24
|
-
|
|
4
|
+
s.name = "middleman-blog"
|
|
5
|
+
s.version = Middleman::Blog::VERSION
|
|
6
|
+
s.platform = Gem::Platform::RUBY
|
|
7
|
+
s.authors = [ "Thomas Reynolds", "Ben Hollis", "Ian Warner" ]
|
|
8
|
+
s.email = [ "me@tdreyno.com", "ben@benhollis.net", "ian.warner@drykiss.com" ]
|
|
9
|
+
s.homepage = "https://github.com/middleman/middleman-blog"
|
|
10
|
+
s.summary = %q{ Blog engine for Middleman }
|
|
11
|
+
s.description = %q{ Blog engine for Middleman }
|
|
12
|
+
s.license = "MIT"
|
|
13
|
+
s.files = `git ls-files -z`.split( "\0" )
|
|
14
|
+
s.test_files = `git ls-files -z -- {fixtures,features}/*`.split( "\0" )
|
|
15
|
+
s.add_dependency("middleman-core", ">= 4.0.0")
|
|
16
|
+
s.add_dependency("tzinfo", ">= 0.3.0")
|
|
17
|
+
s.add_dependency("addressable", "~> 2.3")
|
|
25
18
|
end
|
data/spec/alias_spec.rb
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require 'middleman-blog/alias_pages'
|
|
2
|
+
require 'middleman-blog/uri_templates'
|
|
3
|
+
|
|
4
|
+
describe 'Middleman::Blog::AliasPages' do
|
|
5
|
+
include Middleman::Blog::UriTemplates
|
|
6
|
+
|
|
7
|
+
let(:mock_app) { double('app') }
|
|
8
|
+
let(:mock_sitemap) { double('sitemap') }
|
|
9
|
+
let(:mock_blog_controller) { double('blog_controller') }
|
|
10
|
+
let(:mock_blog_data) { double('blog_data') }
|
|
11
|
+
let(:mock_article) { double('article') }
|
|
12
|
+
let(:mock_options) { double('options') }
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
allow(mock_app).to receive(:sitemap).and_return(mock_sitemap)
|
|
16
|
+
allow(mock_blog_controller).to receive(:data).and_return(mock_blog_data)
|
|
17
|
+
allow(mock_blog_controller).to receive(:options).and_return(mock_options)
|
|
18
|
+
allow(mock_article).to receive(:destination_path).and_return('2024/03/14/pi-day.html')
|
|
19
|
+
allow(mock_article).to receive(:date).and_return(Date.new(2024, 3, 14))
|
|
20
|
+
allow(mock_article).to receive(:slug).and_return('pi-day')
|
|
21
|
+
allow(mock_article).to receive(:lang).and_return(:en)
|
|
22
|
+
allow(mock_article).to receive(:locale).and_return(:en)
|
|
23
|
+
allow(mock_article).to receive(:metadata).and_return({ page: {} })
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe 'alias URL generation' do
|
|
27
|
+
let(:alias_patterns) { [':year-:month-:day-:title.html', ':year/:month-:day-:title'] }
|
|
28
|
+
|
|
29
|
+
before do
|
|
30
|
+
allow(mock_options).to receive(:aliases).and_return(alias_patterns)
|
|
31
|
+
allow(mock_blog_data).to receive(:articles).and_return([mock_article])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'when testing alias path generation' do
|
|
35
|
+
let(:alias_pages) { Middleman::Blog::AliasPages.new(mock_app, mock_blog_controller) }
|
|
36
|
+
|
|
37
|
+
it 'generates correct alias paths from patterns' do
|
|
38
|
+
template1 = uri_template(':year-:month-:day-:title.html')
|
|
39
|
+
template2 = uri_template(':year/:month-:day-:title')
|
|
40
|
+
|
|
41
|
+
# Test path generation directly
|
|
42
|
+
alias_path1 = alias_pages.send(:generate_alias_path, template1, mock_article)
|
|
43
|
+
alias_path2 = alias_pages.send(:generate_alias_path, template2, mock_article)
|
|
44
|
+
|
|
45
|
+
expect(alias_path1).to eq('2024-03-14-pi-day.html')
|
|
46
|
+
expect(alias_path2).to eq('2024/03-14-pi-day')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'filters out aliases that match main permalink' do
|
|
50
|
+
# Test with an alias pattern that would match the main permalink
|
|
51
|
+
template = uri_template(':year/:month/:day/:title.html')
|
|
52
|
+
|
|
53
|
+
alias_path = alias_pages.send(:generate_alias_path, template, mock_article)
|
|
54
|
+
expect(alias_path).to eq('2024/03/14/pi-day.html')
|
|
55
|
+
|
|
56
|
+
# This would be filtered out in manipulate_resource_list because it matches destination_path
|
|
57
|
+
expect(alias_path).to eq(mock_article.destination_path)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'when testing permalink options generation' do
|
|
62
|
+
let(:alias_pages) { Middleman::Blog::AliasPages.new(mock_app, mock_blog_controller) }
|
|
63
|
+
|
|
64
|
+
it 'generates correct permalink options from article data' do
|
|
65
|
+
params = alias_pages.send(:permalink_options, mock_article)
|
|
66
|
+
|
|
67
|
+
expect(params[:year]).to eq('2024')
|
|
68
|
+
expect(params[:month]).to eq('03')
|
|
69
|
+
expect(params[:day]).to eq('14')
|
|
70
|
+
expect(params[:title]).to eq('pi-day')
|
|
71
|
+
expect(params[:lang]).to eq('en')
|
|
72
|
+
expect(params[:locale]).to eq('en')
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe 'empty aliases configuration' do
|
|
78
|
+
before do
|
|
79
|
+
allow(mock_options).to receive(:aliases).and_return([])
|
|
80
|
+
allow(mock_blog_data).to receive(:articles).and_return([mock_article])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'returns original resources when aliases array is empty' do
|
|
84
|
+
alias_pages = Middleman::Blog::AliasPages.new(mock_app, mock_blog_controller)
|
|
85
|
+
resources = ['existing_resource']
|
|
86
|
+
result = alias_pages.manipulate_resource_list(resources)
|
|
87
|
+
|
|
88
|
+
# Should return the same resources since no aliases are configured
|
|
89
|
+
expect(result).to eq(resources)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe 'alias pattern handling' do
|
|
94
|
+
before do
|
|
95
|
+
allow(mock_blog_data).to receive(:articles).and_return([mock_article])
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'handles multiple alias patterns' do
|
|
99
|
+
patterns = [':year-:month-:day-:title.html', ':year/:month-:day-:title', 'archive/:title']
|
|
100
|
+
allow(mock_options).to receive(:aliases).and_return(patterns)
|
|
101
|
+
|
|
102
|
+
alias_pages = Middleman::Blog::AliasPages.new(mock_app, mock_blog_controller)
|
|
103
|
+
|
|
104
|
+
# Test that all patterns are converted to templates
|
|
105
|
+
expect(alias_pages.instance_variable_get(:@alias_templates).length).to eq(3)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'handles nil alias patterns gracefully' do
|
|
109
|
+
allow(mock_options).to receive(:aliases).and_return(nil)
|
|
110
|
+
|
|
111
|
+
expect {
|
|
112
|
+
Middleman::Blog::AliasPages.new(mock_app, mock_blog_controller)
|
|
113
|
+
}.not_to raise_error
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/uri_templates_spec.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'middleman-blog/uri_templates'
|
|
2
4
|
|
|
3
5
|
describe 'Middleman::Blog::UriTemplates' do
|
|
@@ -24,6 +26,18 @@ describe 'Middleman::Blog::UriTemplates' do
|
|
|
24
26
|
it 'can handle numbers' do
|
|
25
27
|
expect(safe_parameterize(1)).to eq '1'
|
|
26
28
|
end
|
|
29
|
+
|
|
30
|
+
it 'converts underscores to dashes by default' do
|
|
31
|
+
expect(safe_parameterize('name_of_article')).to eq 'name-of-article'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'can preserve underscores when requested' do
|
|
35
|
+
expect(safe_parameterize('name_of_article', preserve_underscores: true)).to eq 'name_of_article'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'still works with mixed content when preserving underscores' do
|
|
39
|
+
expect(safe_parameterize('Some MIXED_content', preserve_underscores: true)).to eq 'some-mixed_content'
|
|
40
|
+
end
|
|
27
41
|
end
|
|
28
42
|
|
|
29
43
|
describe 'extract_params' do
|