middleman-blog 3.1.1 → 3.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 307641a41396030f5930374adc6ccd8016e4fcd3
4
+ data.tar.gz: 4fceaaa05d6742597a5f281192da389ab70da601
5
+ SHA512:
6
+ metadata.gz: a06536de8efae6ee8df31ec992d7f8c19b3f82506eff011050eb5ec39dd4fc0f7989bdcad6985787de2381f593ded44f5e9e564f8a38c5a0b4eddb66a0213149
7
+ data.tar.gz: bb6d528615b52afcd59c976f8d1f93fe7fadc521d989894f270db7cb45524af94686e535732d22cea399a0b7485dc9ce79f5b9ccf380c1dcc28336513dd3def8
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@ rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
4
  - 1.9.3
5
+ - 2.0.0
5
6
  - jruby-18mode
6
7
  - jruby-19mode
7
8
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ 3.2.0
2
+ ====
3
+
4
+ * The `summary` method on articles is now HTML-aware, and can be provided with
5
+ a different summary length or ellipsis string: `summary(1000, '…')`.
6
+ Nokogiri is required to use the summary.
7
+ * The `summary_generator` option now recieves the rendered article (without
8
+ layout) instead of the template source.
9
+ * Set `summary_length` to false to always use the full article as a summary.
10
+ * Future-dated articles can still be generated if `publish_future_dated` is true.
11
+ * The `summary_separator` option no longer needs to have a capturing group, or
12
+ even be a regexp.
13
+
1
14
  3.1.1
2
15
  ====
3
16
  * Correctly handle time zone, allow setting time zone with `set :time_zone`. #76
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
- source :rubygems
1
+ source 'http://rubygems.org'
2
2
 
3
- git "git://github.com/middleman/middleman.git" do
3
+ git "git://github.com/middleman/middleman.git", :branch => "master" do
4
4
  # gem "middleman"
5
5
  gem "middleman-core"
6
6
  gem "middleman-more"
@@ -9,20 +9,17 @@ end
9
9
  # Specify your gem's dependencies in middleman-blog.gemspec
10
10
  gemspec
11
11
 
12
- group :development do
13
- gem "rake", "~> 0.9.2"
14
- gem "rdoc", "~> 3.9"
15
- gem "yard", "~> 0.8.0"
16
- end
12
+ gem "rake", "~> 0.9.2"
13
+ gem "rdoc", "~> 3.9"
14
+ gem "yard", "~> 0.8.0"
15
+
16
+ gem "cucumber", "~> 1.2.0"
17
+ gem "fivemat"
18
+ gem "aruba", "~> 0.4.11"
19
+ gem "rspec", "~> 2.7"
20
+ gem "timecop", "~> 0.4.0"
21
+ gem "nokogiri"
17
22
 
18
- group :test do
19
- gem "cucumber", "~> 1.2.0"
20
- gem "fivemat"
21
- gem "aruba", "~> 0.4.11"
22
- gem "rspec", "~> 2.7"
23
- gem "timecop", "~> 0.4.0"
24
-
25
- platforms :ruby do
26
- gem "redcarpet", "~> 2.1.1"
27
- end
23
+ platforms :ruby do
24
+ gem "redcarpet", "~> 2.1.1"
28
25
  end
data/README.md CHANGED
@@ -20,7 +20,7 @@ activate :blog
20
20
 
21
21
  # Learn More
22
22
 
23
- See [the blog extension guide](http://beta.middlemanapp.com/extensions/blog/) for detailed information on configuring and using the blog extension.
23
+ See [the blog extension guide](http://middlemanapp.com/blogging/) for detailed information on configuring and using the blog extension.
24
24
 
25
25
  Up-to-date generated code documentation is available on RubyDoc:
26
26
  http://rubydoc.info/github/middleman/middleman-blog
@@ -41,7 +41,7 @@ The best way to get quick responses to your issues and swift fixes to your bugs
41
41
 
42
42
  # Build & Dependency Status
43
43
 
44
- [![Build Status](http://travis-ci.org/middleman/middleman-blog.png)](http://travis-ci.org/middleman/middleman-blog)
44
+ [![Build Status](https://travis-ci.org/middleman/middleman-blog.png)](https://travis-ci.org/middleman/middleman-blog)
45
45
 
46
46
  # How to Run Cucumber Tests
47
47
 
@@ -52,7 +52,7 @@ The best way to get quick responses to your issues and swift fixes to your bugs
52
52
 
53
53
  # Donate
54
54
 
55
- [![Click here to lend your support to Middleman](https://www.pledgie.com/campaigns/15807.png)](http://www.pledgie.com/campaigns/15807)
55
+ Please, [help support the Middleman team with a donation](https://spb.io/s/4dXbHBorC3).
56
56
 
57
57
  # License
58
58
 
@@ -34,3 +34,23 @@ Feature: Future-dated blog articles
34
34
  Then I should see "This is a future-dated article"
35
35
  When I go to "/2012/06/19/future-article/example.txt"
36
36
  Then I should see "Example Text"
37
+
38
+ Scenario: Future-dated articles show up when publish_future_dated is true
39
+ Given a fixture app "future-date-app"
40
+ And a file named "config.rb" with:
41
+ """
42
+ set :environment, :production
43
+ Time.zone = "Pacific Time (US & Canada)"
44
+ activate :blog do |blog|
45
+ blog.sources = "blog/:year-:month-:day-:title.html"
46
+ blog.publish_future_dated = true
47
+ end
48
+ """
49
+ Given the date is 2012-06-18
50
+ And the Server is running at "future-date-app"
51
+ When I go to "/2011/01/01/new-article.html"
52
+ Then I should see "Newer Article Content"
53
+ When I go to "/2012/06/19/future-article.html"
54
+ Then I should see "This is a future-dated article"
55
+ When I go to "/2012/06/19/future-article/example.txt"
56
+ Then I should see "Example Text"
@@ -19,8 +19,8 @@ module Middleman
19
19
  content = super(opts, locs, &block)
20
20
 
21
21
  unless opts[:keep_separator]
22
- if content =~ app.blog.options.summary_separator
23
- content.sub!($1, "")
22
+ if content.match(app.blog.options.summary_separator)
23
+ content.sub!(app.blog.options.summary_separator, "")
24
24
  end
25
25
  end
26
26
 
@@ -34,9 +34,16 @@ module Middleman
34
34
  end
35
35
 
36
36
  # Whether or not this article has been published
37
+ #
38
+ # An article is considered published in the following scenarios:
39
+ #
40
+ # 1. frontmatter does not set published to false and either
41
+ # 2. published_future_dated is true or
42
+ # 3. article date is after the current time
37
43
  # @return [Boolean]
38
44
  def published?
39
- data["published"] != false and date <= Time.current
45
+ (data["published"] != false) and
46
+ (app.blog.options.publish_future_dated || date <= Time.current)
40
47
  end
41
48
 
42
49
  # The body of this article, in HTML. This is for
@@ -52,29 +59,36 @@ module Middleman
52
59
  # everything before the summary separator (set via :summary_separator
53
60
  # and defaulting to "READMORE") or the first :summary_length
54
61
  # characters of the post.
62
+ #
63
+ # :summary_generator can be set to a Proc in order to provide
64
+ # custom summary generation. The Proc is provided a parameter
65
+ # which is the rendered content of the article (without layout), the
66
+ # desired length to trim the summary to, and the ellipsis string to use.
67
+ #
68
+ # @param [Number] length How many characters to trim the summary to.
69
+ # @param [Number] length The ellipsis string to use when content is trimmed.
55
70
  # @return [String]
56
- def summary
57
- @_summary ||= begin
58
- source = app.template_data_for_file(source_file).dup
59
-
60
- summary_source = if app.blog.options.summary_generator
61
- app.blog.options.summary_generator.call(self, source)
62
- else
63
- default_summary_generator(source)
64
- end
65
-
66
- md = metadata.dup
67
- locs = md[:locals]
68
- opts = md[:options].merge({:template_body => summary_source})
69
- app.render_individual_file(source_file, locs, opts)
71
+ def summary(length=app.blog.options.summary_length, ellipsis='...')
72
+ rendered = render(:layout => false, :keep_separator => true)
73
+
74
+ if app.blog.options.summary_separator && rendered.match(app.blog.options.summary_separator)
75
+ rendered.split(app.blog.options.summary_separator).first
76
+ elsif app.blog.options.summary_generator
77
+ app.blog.options.summary_generator.call(self, rendered, length, ellipsis)
78
+ else
79
+ default_summary_generator(rendered, length, ellipsis)
70
80
  end
71
81
  end
72
82
 
73
- def default_summary_generator(source)
74
- if source =~ app.blog.options.summary_separator
75
- source.split(app.blog.options.summary_separator).first
83
+ def default_summary_generator(rendered, length, ellipsis)
84
+ require 'middleman-blog/truncate_html'
85
+
86
+ if rendered =~ app.blog.options.summary_separator
87
+ rendered.split(app.blog.options.summary_separator).first
88
+ elsif length
89
+ TruncateHTML.truncate_html(rendered, length, ellipsis)
76
90
  else
77
- source.match(/(.{1,#{app.blog.options.summary_length}}.*?)(\n|\Z)/m).to_s
91
+ rendered
78
92
  end
79
93
  end
80
94
 
@@ -33,7 +33,7 @@ module Middleman
33
33
  if shared_instance.respond_to? :blog
34
34
  @title = title
35
35
  @slug = title.parameterize
36
- @date = options[:date] ? DateTime.parse(options[:date]) : DateTime.now
36
+ @date = options[:date] ? Time.zone.parse(options[:date]) : Time.zone.now
37
37
 
38
38
  article_path = shared_instance.blog.options.sources.
39
39
  sub(':year', @date.year.to_s).
@@ -21,7 +21,8 @@ module Middleman
21
21
  :tag_template,
22
22
  :paginate,
23
23
  :per_page,
24
- :page_link
24
+ :page_link,
25
+ :publish_future_dated
25
26
  ]
26
27
 
27
28
  KEYS.each do |name|
@@ -48,19 +49,20 @@ module Middleman
48
49
  options = Options.new(options_hash)
49
50
  yield options if block_given?
50
51
 
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"
52
+ options.permalink ||= "/:year/:month/:day/:title.html"
53
+ options.sources ||= ":year-:month-:day-:title.html"
54
+ options.taglink ||= "tags/:tag.html"
55
+ options.layout ||= "layout"
56
+ options.summary_separator ||= /(READMORE)/
57
+ options.summary_length ||= 250
58
+ options.year_link ||= "/:year.html"
59
+ options.month_link ||= "/:year/:month.html"
60
+ options.day_link ||= "/:year/:month/:day.html"
61
+ options.default_extension ||= ".markdown"
62
+ options.paginate ||= false
63
+ options.per_page ||= 10
64
+ options.page_link ||= "page/:num"
65
+ options.publish_future_dated ||= false
64
66
 
65
67
  # optional: :tag_template
66
68
  # optional: :year_template
@@ -16,7 +16,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
16
16
  xml.published article.date.to_time.iso8601
17
17
  xml.updated article.date.to_time.iso8601
18
18
  xml.author { xml.name "Article Author" }
19
- xml.summary article.summary, "type" => "html"
19
+ # xml.summary article.summary, "type" => "html"
20
20
  xml.content article.body, "type" => "html"
21
21
  end
22
22
  end
@@ -12,7 +12,9 @@ per_page: 10
12
12
 
13
13
  <% page_articles.each_with_index do |article, i| %>
14
14
  <h2><%= link_to article.title, article %> <span><%= article.date.strftime('%b %e') %></span></h2>
15
- <p><%= article.summary %></p>
15
+ <!-- use article.summary(250) if you have Nokogiri available to show just
16
+ the first 250 characters -->
17
+ <%= article.body %>
16
18
  <% end %>
17
19
 
18
20
  <% if paginate %>
@@ -14,21 +14,21 @@
14
14
  <h2>Recent Articles</h2>
15
15
  <ol>
16
16
  <% blog.articles[0...10].each do |article| %>
17
- <li><a href="<%= article.url %>"><%= article.title %></a> <span><%= article.date.strftime('%b %e') %></span></li>
17
+ <li><%= link_to article.title, article %> <span><%= article.date.strftime('%b %e') %></span></li>
18
18
  <% end %>
19
19
  </ol>
20
20
 
21
21
  <h2>Tags</h2>
22
22
  <ol>
23
23
  <% blog.tags.each do |tag, articles| %>
24
- <li><a href="<%= tag_path tag %>"><%= tag %> (<%= articles.size %>)</a></li>
24
+ <li><%= link_to tag, tag_path(tag) %> (<%= articles.size %>)</a></li>
25
25
  <% end %>
26
26
  </ol>
27
27
 
28
28
  <h2>By Year</h2>
29
29
  <ol>
30
30
  <% blog.articles.group_by {|a| a.date.year }.each do |year, articles| %>
31
- <li><a href="<%= blog_year_path year %>"><%= year %> (<%= articles.size %>)</a></li>
31
+ <li><%= link_to year, blog_year_path(year) %> (<%= articles.size %>)</a></li>
32
32
  <% end %>
33
33
  </ol>
34
34
  </aside>
@@ -0,0 +1,53 @@
1
+ begin
2
+ require "nokogiri"
3
+ rescue LoadError
4
+ raise "Nokogiri is required for blog post summaries. Add 'nokogiri' to your Gemfile."
5
+ end
6
+
7
+ # Taken and modified from http://madebydna.com/all/code/2010/06/04/ruby-helper-to-cleanly-truncate-html.html
8
+ # MIT license
9
+ module TruncateHTML
10
+ def self.truncate_html(text, max_length, ellipsis = "...")
11
+ ellipsis_length = ellipsis.length
12
+ doc = Nokogiri::HTML::DocumentFragment.parse text
13
+ content_length = doc.inner_text.length
14
+ actual_length = max_length - ellipsis_length
15
+ if content_length > actual_length
16
+ doc.truncate(actual_length, ellipsis).inner_html
17
+ else
18
+ text
19
+ end
20
+ end
21
+ end
22
+
23
+ module NokogiriTruncator
24
+ module NodeWithChildren
25
+ def truncate(max_length, ellipsis)
26
+ return self if inner_text.length <= max_length
27
+ truncated_node = self.dup
28
+ truncated_node.children.remove
29
+
30
+ self.children.each do |node|
31
+ remaining_length = max_length - truncated_node.inner_text.length
32
+ break if remaining_length <= 0
33
+ truncated_node.add_child node.truncate(remaining_length, ellipsis)
34
+ end
35
+ truncated_node
36
+ end
37
+ end
38
+
39
+ module TextNode
40
+ def truncate(max_length, ellipsis)
41
+ # Don't break in the middle of a word
42
+ trimmed_content = content.match(/(.{1,#{max_length}}[\w]*)/m).to_s
43
+ trimmed_content << ellipsis if trimmed_content.length < content.length
44
+
45
+ Nokogiri::XML::Text.new(trimmed_content, parent)
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ Nokogiri::HTML::DocumentFragment.send(:include, NokogiriTruncator::NodeWithChildren)
52
+ Nokogiri::XML::Element.send(:include, NokogiriTruncator::NodeWithChildren)
53
+ Nokogiri::XML::Text.send(:include, NokogiriTruncator::TextNode)
@@ -1,5 +1,5 @@
1
1
  module Middleman
2
2
  module Blog
3
- VERSION = "3.1.1"
3
+ VERSION = "3.2.0"
4
4
  end
5
5
  end
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.test_files = `git ls-files -z -- {fixtures,features}/*`.split("\0")
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_dependency("middleman-core", ["~> 3.0.1"])
21
+ s.add_dependency("middleman-core", ["~> 3.0"])
22
22
  s.add_dependency("maruku", ["~> 0.6.0"])
23
23
  s.add_dependency("tzinfo", ["~> 0.3.0"])
24
24
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: middleman-blog
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
5
- prerelease:
4
+ version: 3.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Thomas Reynolds
@@ -10,28 +9,25 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2012-09-21 00:00:00.000000000 Z
12
+ date: 2013-03-11 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: middleman-core
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
18
  - - ~>
21
19
  - !ruby/object:Gem::Version
22
- version: 3.0.1
20
+ version: '3.0'
23
21
  type: :runtime
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
25
  - - ~>
29
26
  - !ruby/object:Gem::Version
30
- version: 3.0.1
27
+ version: '3.0'
31
28
  - !ruby/object:Gem::Dependency
32
29
  name: maruku
33
30
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
31
  requirements:
36
32
  - - ~>
37
33
  - !ruby/object:Gem::Version
@@ -39,7 +35,6 @@ dependencies:
39
35
  type: :runtime
40
36
  prerelease: false
41
37
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
38
  requirements:
44
39
  - - ~>
45
40
  - !ruby/object:Gem::Version
@@ -47,7 +42,6 @@ dependencies:
47
42
  - !ruby/object:Gem::Dependency
48
43
  name: tzinfo
49
44
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
45
  requirements:
52
46
  - - ~>
53
47
  - !ruby/object:Gem::Version
@@ -55,7 +49,6 @@ dependencies:
55
49
  type: :runtime
56
50
  prerelease: false
57
51
  version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
52
  requirements:
60
53
  - - ~>
61
54
  - !ruby/object:Gem::Version
@@ -202,38 +195,32 @@ files:
202
195
  - lib/middleman-blog/template/source/index.html.erb
203
196
  - lib/middleman-blog/template/source/layout.erb
204
197
  - lib/middleman-blog/template/source/tag.html.erb
198
+ - lib/middleman-blog/truncate_html.rb
205
199
  - lib/middleman-blog/version.rb
206
200
  - lib/middleman_extension.rb
207
201
  - middleman-blog.gemspec
208
202
  homepage: https://github.com/middleman/middleman-blog
209
203
  licenses: []
204
+ metadata: {}
210
205
  post_install_message:
211
206
  rdoc_options: []
212
207
  require_paths:
213
208
  - lib
214
209
  required_ruby_version: !ruby/object:Gem::Requirement
215
- none: false
216
210
  requirements:
217
- - - ! '>='
211
+ - - '>='
218
212
  - !ruby/object:Gem::Version
219
213
  version: '0'
220
- segments:
221
- - 0
222
- hash: -3637459157260692446
223
214
  required_rubygems_version: !ruby/object:Gem::Requirement
224
- none: false
225
215
  requirements:
226
- - - ! '>='
216
+ - - '>='
227
217
  - !ruby/object:Gem::Version
228
218
  version: '0'
229
- segments:
230
- - 0
231
- hash: -3637459157260692446
232
219
  requirements: []
233
220
  rubyforge_project: middleman-blog
234
- rubygems_version: 1.8.24
221
+ rubygems_version: 2.0.0
235
222
  signing_key:
236
- specification_version: 3
223
+ specification_version: 4
237
224
  summary: A blog foundation using Middleman
238
225
  test_files:
239
226
  - features/article_cli.feature