middleman-blog 3.4.1 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -6
  3. data/CHANGELOG.md +32 -1
  4. data/Gemfile +5 -9
  5. data/README.md +3 -2
  6. data/features/article_cli.feature +10 -1
  7. data/features/custom_collections.feature +11 -0
  8. data/features/language.feature +82 -0
  9. data/features/multiblog.feature +4 -2
  10. data/features/permalink-data.feature +12 -0
  11. data/features/summary.feature +13 -0
  12. data/features/support/env.rb +3 -0
  13. data/features/tags.feature +18 -1
  14. data/features/time_zone.feature +1 -1
  15. data/fixtures/custom-article-template-app/config.rb +3 -0
  16. data/fixtures/custom-article-template-app/my_custom_article.tt +7 -0
  17. data/fixtures/custom-article-template-app/source/index.html.erb +9 -0
  18. data/fixtures/custom-article-template-app/source/layout.erb +30 -0
  19. data/fixtures/custom-collections-sources-app/config.rb +11 -0
  20. data/fixtures/custom-collections-sources-app/source/articles/2011-01-02-another-article.html.markdown +8 -0
  21. data/fixtures/custom-collections-sources-app/source/category.html.erb +7 -0
  22. data/fixtures/custom-collections-sources-app/source/index.html.erb +5 -0
  23. data/fixtures/custom-collections-sources-app/source/layout.erb +13 -0
  24. data/fixtures/custom-collections-sources-app/source/news/2011-01-01-new-article.html.markdown +7 -0
  25. data/fixtures/language-app/config.rb +2 -0
  26. data/fixtures/language-app/locales/en.yml +4 -0
  27. data/fixtures/language-app/locales/ru.yml +4 -0
  28. data/fixtures/language-app/source/2013-09-07-english-article-with-lang-in-frontmatter.html.erb +6 -0
  29. data/fixtures/language-app/source/2013-09-07-russian-article-with-lang-in-frontmatter.html.erb +6 -0
  30. data/fixtures/language-app/source/en/2013-09-07-english-article-with-lang-in-path.html.erb +5 -0
  31. data/fixtures/language-app/source/layouts/layout.erb +8 -0
  32. data/fixtures/language-app/source/localizable/index.html.erb +5 -0
  33. data/fixtures/language-app/source/ru/2013-09-07-russian-article-with-lang-in-path.html.erb +5 -0
  34. data/fixtures/multiblog-app/source/blog1/index.html.erb +7 -0
  35. data/fixtures/permalink-data-app/config.rb +5 -0
  36. data/fixtures/permalink-data-app/source/index.html.erb +3 -0
  37. data/fixtures/permalink-data-app/source/layout.erb +14 -0
  38. data/fixtures/permalink-data-app/source/news/2011-01-01-new-article.html.markdown +7 -0
  39. data/fixtures/time-zone-app/source/blog/2013-06-24-hello.html.erb +1 -0
  40. data/lib/middleman-blog.rb +3 -8
  41. data/lib/middleman-blog/blog_article.rb +96 -60
  42. data/lib/middleman-blog/blog_data.rb +78 -76
  43. data/lib/middleman-blog/calendar_pages.rb +87 -119
  44. data/lib/middleman-blog/commands/article.rb +20 -14
  45. data/lib/middleman-blog/custom_pages.rb +30 -64
  46. data/lib/middleman-blog/extension.rb +175 -0
  47. data/lib/middleman-blog/helpers.rb +152 -0
  48. data/lib/middleman-blog/paginator.rb +127 -123
  49. data/lib/middleman-blog/tag_pages.rb +27 -45
  50. data/lib/middleman-blog/template.rb +17 -15
  51. data/lib/middleman-blog/template/config.tt +30 -33
  52. data/lib/middleman-blog/template/source/layout.erb +1 -0
  53. data/lib/middleman-blog/uri_templates.rb +58 -0
  54. data/lib/middleman-blog/version.rb +1 -1
  55. data/middleman-blog.gemspec +4 -1
  56. metadata +75 -9
  57. data/Gemfile-3.0 +0 -27
  58. data/lib/middleman-blog/extension_3_0.rb +0 -248
  59. data/lib/middleman-blog/extension_3_1.rb +0 -278
data/Gemfile-3.0 DELETED
@@ -1,27 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in middleman-blog.gemspec
4
- gemspec
5
-
6
- gem "middleman", "~> 3.0.0"
7
-
8
- gem "rake", "~> 10.0.3", :require => false
9
- gem "yard", "~> 0.8.0", :require => false
10
-
11
- # Test tools
12
- gem "cucumber", "~> 1.3.1"
13
- gem "fivemat"
14
- gem "aruba", "~> 0.5.1"
15
- gem "rspec", "~> 2.12"
16
- gem "simplecov"
17
-
18
- gem "timecop", "~> 0.4.0"
19
- gem "nokogiri", "~> 1.5.0" # 1.6.0 requires Ruby 1.9+ but we still test on 1.8
20
- gem "kramdown"
21
-
22
- # Code Quality
23
- gem "cane", :platforms => [:mri_19, :mri_20], :require => false
24
-
25
- platforms :ruby do
26
- gem "redcarpet", "~> 2.3.0"
27
- end
@@ -1,248 +0,0 @@
1
- module Middleman
2
- module Blog
3
- class Options
4
- KEYS = [
5
- :prefix,
6
- :permalink,
7
- :sources,
8
- :taglink,
9
- :layout,
10
- :summary_separator,
11
- :summary_length,
12
- :summary_generator,
13
- :year_link,
14
- :month_link,
15
- :day_link,
16
- :default_extension,
17
- :calendar_template,
18
- :year_template,
19
- :month_template,
20
- :day_template,
21
- :tag_template,
22
- :paginate,
23
- :per_page,
24
- :page_link,
25
- :publish_future_dated,
26
- :custom_collections
27
- ]
28
-
29
- KEYS.each do |name|
30
- attr_accessor name
31
- end
32
-
33
- def initialize(options={})
34
- options.each do |k,v|
35
- self.send(:"#{k}=", v)
36
- end
37
- end
38
- end
39
-
40
- class << self
41
- def registered(app, options_hash={}, &block)
42
- require 'middleman-blog/blog_data'
43
- require 'middleman-blog/blog_article'
44
- require 'active_support/core_ext/time/zones'
45
-
46
- app.send :include, Helpers
47
-
48
- options = Options.new(options_hash)
49
- yield options if block_given?
50
-
51
- options.permalink ||= "/:year/:month/:day/:title.html"
52
- options.sources ||= ":year-:month-:day-:title.html"
53
- options.taglink ||= "tags/:tag.html"
54
- options.layout ||= "layout"
55
- options.summary_separator ||= /(READMORE)/
56
- options.summary_length ||= 250
57
- options.year_link ||= "/:year.html"
58
- options.month_link ||= "/:year/:month.html"
59
- options.day_link ||= "/:year/:month/:day.html"
60
- options.default_extension ||= ".markdown"
61
- options.paginate ||= false
62
- options.per_page ||= 10
63
- options.page_link ||= "page/:num"
64
- options.publish_future_dated ||= false
65
- options.custom_collections ||= {}
66
-
67
- # optional: :tag_template
68
- # optional: :year_template
69
- # optional: :month_template
70
- # optional: :day_template
71
- # Allow one setting to set all the calendar templates
72
- if options.calendar_template
73
- options.year_template ||= options.calendar_template
74
- options.month_template ||= options.calendar_template
75
- options.day_template ||= options.calendar_template
76
- end
77
-
78
- # If "prefix" option is specified, all other paths are relative to it.
79
- if options.prefix
80
- options.prefix = "/#{options.prefix}" unless options.prefix.start_with? '/'
81
- options.permalink = File.join(options.prefix, options.permalink)
82
- options.sources = File.join(options.prefix, options.sources)
83
- options.taglink = File.join(options.prefix, options.taglink)
84
- options.year_link = File.join(options.prefix, options.year_link)
85
- options.month_link = File.join(options.prefix, options.month_link)
86
- options.day_link = File.join(options.prefix, options.day_link)
87
-
88
- options.custom_collections.each do |key, opts|
89
- opts[:link] = File.join(options.prefix, opts[:link])
90
- end
91
- end
92
-
93
- app.after_configuration do
94
- # Make sure ActiveSupport's TimeZone stuff has something to work with,
95
- # allowing people to set their desired time zone via Time.zone or
96
- # set :time_zone
97
- Time.zone = self.time_zone if self.respond_to?(:time_zone)
98
- time_zone = Time.zone if Time.zone
99
- zone_default = Time.find_zone!(time_zone || 'UTC')
100
- unless zone_default
101
- raise 'Value assigned to time_zone not recognized.'
102
- end
103
- Time.zone_default = zone_default
104
-
105
- ignore(options.calendar_template) if options.calendar_template
106
- ignore(options.year_template) if options.year_template
107
- ignore(options.month_template) if options.month_template
108
- ignore(options.day_template) if options.day_template
109
-
110
- # Initialize blog with options
111
- blog(options)
112
-
113
- sitemap.register_resource_list_manipulator(
114
- :blog_articles,
115
- blog,
116
- false
117
- )
118
-
119
- if options.tag_template
120
- ignore options.tag_template
121
-
122
- require 'middleman-blog/tag_pages'
123
- sitemap.register_resource_list_manipulator(
124
- :blog_tags,
125
- TagPages.new(self),
126
- false
127
- )
128
- end
129
-
130
- if options.year_template ||
131
- options.month_template ||
132
- options.day_template
133
-
134
- require 'middleman-blog/calendar_pages'
135
- sitemap.register_resource_list_manipulator(
136
- :blog_calendar,
137
- CalendarPages.new(self),
138
- false
139
- )
140
- end
141
-
142
- if options.paginate
143
- require 'middleman-blog/paginator'
144
- sitemap.register_resource_list_manipulator(
145
- :blog_paginate,
146
- Paginator.new(self),
147
- false
148
- )
149
- end
150
-
151
- if options.custom_collections
152
- require 'middleman-blog/custom_pages'
153
- options.custom_collections.each do |property, options|
154
- ignore options[:template]
155
- sitemap.register_resource_list_manipulator(
156
- :"blog_#{property}",
157
- CustomPages.new(property, self),
158
- false
159
- )
160
-
161
- m = Module.new
162
- m.module_eval(%Q{
163
- def #{property}_path(value, key = nil)
164
- sitemap.find_resource_by_path(CustomPages.link(self.blog.options, :#{property}, value)).try(:url)
165
- end
166
- })
167
-
168
- self.class.send(:include, m)
169
- end
170
- end
171
- end
172
- end
173
- alias :included :registered
174
- end
175
-
176
- # Helpers for use within templates and layouts.
177
- module Helpers
178
- # Get the {BlogData} for this site.
179
- # @return [BlogData]
180
- def blog(options=nil)
181
- @_blog ||= BlogData.new(self, options)
182
- end
183
-
184
- # Determine whether the currently rendering template is a blog article.
185
- # This can be useful in layouts.
186
- # @return [Boolean]
187
- def is_blog_article?
188
- !current_article.nil?
189
- end
190
-
191
- # Get a {Resource} with mixed in {BlogArticle} methods representing the current article.
192
- # @return [Middleman::Sitemap::Resource]
193
- def current_article
194
- blog.article(current_resource.path)
195
- end
196
-
197
- # Get a path to the given tag, based on the :taglink setting.
198
- # @param [String] tag
199
- # @return [String]
200
- def tag_path(tag)
201
- sitemap.find_resource_by_path(TagPages.link(self.blog.options, tag)).try(:url)
202
- end
203
-
204
- # Get a path to the given year-based calendar page, based on the :year_link setting.
205
- # @param [Number] year
206
- # @return [String]
207
- def blog_year_path(year)
208
- sitemap.find_resource_by_path(CalendarPages.link(self.blog.options, year)).try(:url)
209
- end
210
-
211
- # Get a path to the given month-based calendar page, based on the :month_link setting.
212
- # @param [Number] year
213
- # @param [Number] month
214
- # @return [String]
215
- def blog_month_path(year, month)
216
- sitemap.find_resource_by_path(CalendarPages.link(self.blog.options, year, month)).try(:url)
217
- end
218
-
219
- # Get a path to the given day-based calendar page, based on the :day_link setting.
220
- # @param [Number] year
221
- # @param [Number] month
222
- # @param [Number] day
223
- # @return [String]
224
- def blog_day_path(year, month, day)
225
- sitemap.find_resource_by_path(CalendarPages.link(self.blog.options, year, month, day)).try(:url)
226
- end
227
-
228
-
229
- # Pagination Helpers
230
- # These are used by the template if pagination is off, to allow a single template to work
231
- # in both modes. They get overridden by the local variables if the paginator is active.
232
-
233
- # Returns true if pagination is turned on for this template; false otherwise.
234
- # @return [Boolean]
235
- def paginate; false; end
236
-
237
- # Returns the list of articles to display on this page.
238
- # @return [Array<Middleman::Sitemap::Resource>]
239
- def page_articles
240
- limit = (current_resource.metadata[:page]["per_page"] || 0) - 1
241
-
242
- # "articles" local variable is populated by Calendar and Tag page generators
243
- # If it's not set then use the complete list of articles
244
- (current_resource.metadata[:locals]["articles"] || blog.articles)[0..limit]
245
- end
246
- end
247
- end
248
- end
@@ -1,278 +0,0 @@
1
- module Middleman
2
- class BlogExtension < Extension
3
- self.supports_multiple_instances = true
4
-
5
- option :name, nil, 'Unique ID for telling multiple blogs apart'
6
- option :prefix, nil, 'Prefix to mount the blog at'
7
- option :permalink, "/:year/:month/:day/:title.html", 'HTTP path to host articles at'
8
- option :sources, ":year-:month-:day-:title.html", 'How to extract metadata from on-disk files'
9
- option :taglink, "tags/:tag.html", 'HTTP path to host tag pages at'
10
- option :layout, "layout", 'Article-specific layout'
11
- option :summary_separator, /(READMORE)/, 'How to split article summaries around a delimeter'
12
- option :summary_length, 250, 'Length of words in automatic summaries'
13
- option :summary_generator, nil, 'Block to definte how summaries are extracted'
14
- option :year_link, "/:year.html", 'HTTP path for yearly archives'
15
- option :month_link, "/:year/:month.html", 'HTTP path for monthly archives'
16
- option :day_link, "/:year/:month/:day.html", 'HTTP path for daily archives'
17
- option :default_extension, ".markdown", 'Default article extension'
18
- option :calendar_template, nil, 'Template for calendar pages'
19
- option :year_template, nil, 'Template for yearly archive pages'
20
- option :month_template, nil, 'Template for monthyl archive pages'
21
- option :day_template, nil, 'Template for daily archive pages'
22
- option :tag_template, nil, 'Template for tag archive pages'
23
- option :paginate, false, 'Whether to paginate pages'
24
- option :per_page, 10, 'Articles per page when paginating'
25
- option :page_link, "page/:num", 'HTTP path for paging'
26
- option :publish_future_dated, false, 'Whether to pubish articles dated in the future'
27
- option :custom_collections, {}, 'Hash of custom frontmatter properties to collect articles on and their options'
28
-
29
- attr_accessor :data, :uid
30
-
31
- def initialize(app, options_hash={}, &block)
32
- super
33
-
34
- @uid = options.name
35
-
36
- require 'middleman-blog/blog_data'
37
- require 'middleman-blog/blog_article'
38
- require 'active_support/core_ext/time/zones'
39
-
40
- # app.set :time_zone, 'UTC'
41
-
42
- # optional: :tag_template
43
- # optional: :year_template
44
- # optional: :month_template
45
- # optional: :day_template
46
- # Allow one setting to set all the calendar templates
47
- if options.calendar_template
48
- options.year_template ||= options.calendar_template
49
- options.month_template ||= options.calendar_template
50
- options.day_template ||= options.calendar_template
51
- end
52
-
53
- # If "prefix" option is specified, all other paths are relative to it.
54
- if options.prefix
55
- options.prefix = "/#{options.prefix}" unless options.prefix.start_with? '/'
56
- options.permalink = File.join(options.prefix, options.permalink)
57
- options.sources = File.join(options.prefix, options.sources)
58
- options.taglink = File.join(options.prefix, options.taglink)
59
- options.year_link = File.join(options.prefix, options.year_link)
60
- options.month_link = File.join(options.prefix, options.month_link)
61
- options.day_link = File.join(options.prefix, options.day_link)
62
-
63
- options.custom_collections.each do |key, opts|
64
- opts[:link] = File.join(options.prefix, opts[:link])
65
- end
66
- end
67
- end
68
-
69
- def after_configuration
70
- @uid ||= "blog#{@app.blog_instances.keys.length}"
71
-
72
- @app.ignore(options.calendar_template) if options.calendar_template
73
- @app.ignore(options.year_template) if options.year_template
74
- @app.ignore(options.month_template) if options.month_template
75
- @app.ignore(options.day_template) if options.day_template
76
-
77
- @app.blog_instances[@uid.to_sym] = self
78
-
79
- # Make sure ActiveSupport's TimeZone stuff has something to work with,
80
- # allowing people to set their desired time zone via Time.zone or
81
- # set :time_zone
82
- Time.zone = app.config[:time_zone] if app.config[:time_zone]
83
- time_zone = Time.zone if Time.zone
84
- zone_default = Time.find_zone!(time_zone || 'UTC')
85
- unless zone_default
86
- raise 'Value assigned to time_zone not recognized.'
87
- end
88
- Time.zone_default = zone_default
89
-
90
- # Initialize blog with options
91
-
92
- @data = ::Middleman::Blog::BlogData.new(@app, options, self)
93
-
94
- @app.sitemap.register_resource_list_manipulator(
95
- :"blog_#{uid}_articles",
96
- @data,
97
- false
98
- )
99
-
100
- if options.tag_template
101
- @app.ignore options.tag_template
102
-
103
- require 'middleman-blog/tag_pages'
104
- @app.sitemap.register_resource_list_manipulator(
105
- :"blog_#{uid}_tags",
106
- ::Middleman::Blog::TagPages.new(@app, self),
107
- false
108
- )
109
- end
110
-
111
- if options.year_template || options.month_template || options.day_template
112
- require 'middleman-blog/calendar_pages'
113
- @app.sitemap.register_resource_list_manipulator(
114
- :"blog_#{uid}_calendar",
115
- ::Middleman::Blog::CalendarPages.new(@app, self),
116
- false
117
- )
118
- end
119
-
120
- if options.paginate
121
- require 'middleman-blog/paginator'
122
- @app.sitemap.register_resource_list_manipulator(
123
- :"blog_#{uid}_paginate",
124
- ::Middleman::Blog::Paginator.new(@app, self),
125
- false
126
- )
127
- end
128
-
129
- if options.custom_collections
130
- require 'middleman-blog/custom_pages'
131
- register_custom_pages
132
- end
133
- end
134
-
135
- # Register any custom page collections that may be set in the config
136
- #
137
- # A custom resource list manipulator will be generated for each key in the
138
- # custom collections hash.
139
- #
140
- # The following will collect posts on the "category" frontmatter property:
141
- # ```
142
- # activate :blog do |blog|
143
- # blog.custom_collections = {
144
- # link: "/categories/:category.html",
145
- # template: "/category.html"
146
- # }
147
- # end
148
- # ```
149
- #
150
- # Category pages in the example above will use the category.html as a template file
151
- # and it will be ignored when building.
152
- def register_custom_pages
153
- options.custom_collections.each do |property, options|
154
- @app.ignore options[:template]
155
- @app.sitemap.register_resource_list_manipulator(
156
- :"blog_#{uid}_#{property}",
157
- ::Middleman::Blog::CustomPages.new(property, @app, self),
158
- false
159
- )
160
-
161
- generate_custom_helper(property)
162
- end
163
- end
164
-
165
- # Generate helpers to access the path to a custom collection.
166
- #
167
- # For example, when using a custom property called "category" to collect articles on
168
- # the method **category_path** will be generated.
169
- #
170
- # @param [Symbol] custom_property Custom property which is being used to collect articles on
171
- def generate_custom_helper(custom_property)
172
- m = Module.new
173
- m.module_eval(%Q{
174
- def #{custom_property}_path(value, key = nil)
175
- sitemap.find_resource_by_path(::Middleman::Blog::CustomPages.link(blog_controller(key).options, :#{custom_property}, value)).try(:url)
176
- end
177
- })
178
-
179
- app.class.send(:include, m)
180
- end
181
-
182
- # Helpers for use within templates and layouts.
183
- helpers do
184
- def blog_instances
185
- @blog_instances ||= {}
186
- end
187
-
188
- def blog_controller(key=nil)
189
- if !key && current_resource
190
- key = current_resource.metadata[:page]["blog"]
191
-
192
- if !key && current_resource.respond_to?(:blog_controller) && current_resource.blog_controller
193
- return current_resource.blog_controller
194
- end
195
- end
196
-
197
- # In multiblog situations, force people to specify the blog
198
- if !key && blog_instances.size > 1
199
- raise "You must either specify the blog name in calling this method or in your page frontmatter (using the 'blog' key)"
200
- end
201
-
202
- key ||= blog_instances.keys.first
203
- blog_instances[key.to_sym]
204
- end
205
-
206
- def blog(key=nil)
207
- blog_controller(key).data
208
- end
209
-
210
- # Determine whether the currently rendering template is a blog article.
211
- # This can be useful in layouts.
212
- # @return [Boolean]
213
- def is_blog_article?
214
- !current_article.nil?
215
- end
216
-
217
- # Get a {Resource} with mixed in {BlogArticle} methods representing the current article.
218
- # @return [Middleman::Sitemap::Resource]
219
- def current_article
220
- blog_instances.each do |key, blog|
221
- found = blog.data.article(current_resource.path)
222
- return found if found
223
- end
224
-
225
- nil
226
- end
227
-
228
- # Get a path to the given tag, based on the :taglink setting.
229
- # @param [String] tag
230
- # @return [String]
231
- def tag_path(tag, key=nil)
232
- sitemap.find_resource_by_path(::Middleman::Blog::TagPages.link(blog_controller(key).options, tag)).try(:url)
233
- end
234
-
235
- # Get a path to the given year-based calendar page, based on the :year_link setting.
236
- # @param [Number] year
237
- # @return [String]
238
- def blog_year_path(year, key=nil)
239
- sitemap.find_resource_by_path(::Middleman::Blog::CalendarPages.link(blog_controller(key).options, year)).try(:url)
240
- end
241
-
242
- # Get a path to the given month-based calendar page, based on the :month_link setting.
243
- # @param [Number] year
244
- # @param [Number] month
245
- # @return [String]
246
- def blog_month_path(year, month, key=nil)
247
- sitemap.find_resource_by_path(::Middleman::Blog::CalendarPages.link(blog_controller(key).options, year, month)).try(:url)
248
- end
249
-
250
- # Get a path to the given day-based calendar page, based on the :day_link setting.
251
- # @param [Number] year
252
- # @param [Number] month
253
- # @param [Number] day
254
- # @return [String]
255
- def blog_day_path(year, month, day, key=nil)
256
- sitemap.find_resource_by_path(::Middleman::Blog::CalendarPages.link(blog_controller(key).options, year, month, day)).try(:url)
257
- end
258
-
259
- # Pagination Helpers
260
- # These are used by the template if pagination is off, to allow a single template to work
261
- # in both modes. They get overridden by the local variables if the paginator is active.
262
-
263
- # Returns true if pagination is turned on for this template; false otherwise.
264
- # @return [Boolean]
265
- def paginate; false; end
266
-
267
- # Returns the list of articles to display on this page.
268
- # @return [Array<Middleman::Sitemap::Resource>]
269
- def page_articles(key=nil)
270
- limit = (current_resource.metadata[:page]["per_page"] || 0) - 1
271
-
272
- # "articles" local variable is populated by Calendar and Tag page generators
273
- # If it's not set then use the complete list of articles
274
- d = (current_resource.metadata[:locals]["articles"] || blog(key).articles)[0..limit]
275
- end
276
- end
277
- end
278
- end