jekyll 3.8.7 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +71 -62
  3. data/LICENSE +1 -1
  4. data/README.markdown +46 -17
  5. data/lib/blank_template/_config.yml +3 -0
  6. data/lib/blank_template/_layouts/default.html +12 -0
  7. data/lib/blank_template/_sass/main.scss +9 -0
  8. data/lib/blank_template/assets/css/main.scss +4 -0
  9. data/lib/blank_template/index.md +8 -0
  10. data/lib/jekyll.rb +10 -1
  11. data/lib/jekyll/cache.rb +190 -0
  12. data/lib/jekyll/cleaner.rb +5 -4
  13. data/lib/jekyll/collection.rb +82 -10
  14. data/lib/jekyll/command.rb +33 -6
  15. data/lib/jekyll/commands/build.rb +11 -20
  16. data/lib/jekyll/commands/clean.rb +2 -0
  17. data/lib/jekyll/commands/doctor.rb +15 -8
  18. data/lib/jekyll/commands/help.rb +1 -1
  19. data/lib/jekyll/commands/new.rb +37 -35
  20. data/lib/jekyll/commands/new_theme.rb +30 -28
  21. data/lib/jekyll/commands/serve.rb +55 -81
  22. data/lib/jekyll/commands/serve/live_reload_reactor.rb +6 -10
  23. data/lib/jekyll/commands/serve/servlet.rb +22 -25
  24. data/lib/jekyll/commands/serve/websockets.rb +1 -1
  25. data/lib/jekyll/configuration.rb +61 -149
  26. data/lib/jekyll/converters/identity.rb +18 -0
  27. data/lib/jekyll/converters/markdown.rb +49 -40
  28. data/lib/jekyll/converters/markdown/kramdown_parser.rb +84 -11
  29. data/lib/jekyll/converters/smartypants.rb +34 -14
  30. data/lib/jekyll/convertible.rb +30 -31
  31. data/lib/jekyll/deprecator.rb +1 -3
  32. data/lib/jekyll/document.rb +89 -61
  33. data/lib/jekyll/drops/collection_drop.rb +2 -3
  34. data/lib/jekyll/drops/document_drop.rb +14 -1
  35. data/lib/jekyll/drops/drop.rb +17 -14
  36. data/lib/jekyll/drops/excerpt_drop.rb +4 -0
  37. data/lib/jekyll/drops/page_drop.rb +18 -0
  38. data/lib/jekyll/drops/site_drop.rb +6 -5
  39. data/lib/jekyll/drops/unified_payload_drop.rb +1 -0
  40. data/lib/jekyll/drops/url_drop.rb +53 -1
  41. data/lib/jekyll/entry_filter.rb +42 -45
  42. data/lib/jekyll/excerpt.rb +45 -34
  43. data/lib/jekyll/external.rb +10 -5
  44. data/lib/jekyll/filters.rb +200 -40
  45. data/lib/jekyll/filters/date_filters.rb +6 -3
  46. data/lib/jekyll/filters/grouping_filters.rb +1 -2
  47. data/lib/jekyll/filters/url_filters.rb +46 -14
  48. data/lib/jekyll/frontmatter_defaults.rb +46 -35
  49. data/lib/jekyll/hooks.rb +4 -8
  50. data/lib/jekyll/inclusion.rb +32 -0
  51. data/lib/jekyll/liquid_extensions.rb +0 -2
  52. data/lib/jekyll/liquid_renderer.rb +31 -16
  53. data/lib/jekyll/liquid_renderer/file.rb +24 -3
  54. data/lib/jekyll/liquid_renderer/table.rb +36 -77
  55. data/lib/jekyll/log_adapter.rb +5 -1
  56. data/lib/jekyll/mime.types +53 -11
  57. data/lib/jekyll/page.rb +54 -12
  58. data/lib/jekyll/page_excerpt.rb +26 -0
  59. data/lib/jekyll/page_without_a_file.rb +0 -4
  60. data/lib/jekyll/path_manager.rb +31 -0
  61. data/lib/jekyll/plugin.rb +5 -11
  62. data/lib/jekyll/plugin_manager.rb +2 -0
  63. data/lib/jekyll/profiler.rb +58 -0
  64. data/lib/jekyll/reader.rb +42 -9
  65. data/lib/jekyll/readers/collection_reader.rb +1 -0
  66. data/lib/jekyll/readers/data_reader.rb +8 -9
  67. data/lib/jekyll/readers/layout_reader.rb +3 -12
  68. data/lib/jekyll/readers/page_reader.rb +5 -5
  69. data/lib/jekyll/readers/post_reader.rb +31 -18
  70. data/lib/jekyll/readers/static_file_reader.rb +4 -4
  71. data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
  72. data/lib/jekyll/regenerator.rb +4 -12
  73. data/lib/jekyll/renderer.rb +23 -40
  74. data/lib/jekyll/site.rb +91 -38
  75. data/lib/jekyll/static_file.rb +62 -21
  76. data/lib/jekyll/stevenson.rb +2 -3
  77. data/lib/jekyll/tags/highlight.rb +19 -51
  78. data/lib/jekyll/tags/include.rb +82 -42
  79. data/lib/jekyll/tags/link.rb +11 -7
  80. data/lib/jekyll/tags/post_url.rb +25 -21
  81. data/lib/jekyll/theme.rb +16 -18
  82. data/lib/jekyll/theme_builder.rb +91 -89
  83. data/lib/jekyll/url.rb +10 -5
  84. data/lib/jekyll/utils.rb +18 -21
  85. data/lib/jekyll/utils/ansi.rb +1 -1
  86. data/lib/jekyll/utils/exec.rb +0 -1
  87. data/lib/jekyll/utils/internet.rb +2 -4
  88. data/lib/jekyll/utils/platforms.rb +8 -8
  89. data/lib/jekyll/utils/thread_event.rb +1 -5
  90. data/lib/jekyll/utils/win_tz.rb +2 -2
  91. data/lib/jekyll/version.rb +1 -1
  92. data/lib/site_template/.gitignore +2 -0
  93. data/lib/site_template/404.html +1 -0
  94. data/lib/site_template/_config.yml +17 -5
  95. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
  96. data/lib/site_template/{about.md → about.markdown} +0 -0
  97. data/lib/site_template/{index.md → index.markdown} +0 -0
  98. data/lib/theme_template/gitignore.erb +1 -0
  99. data/lib/theme_template/theme.gemspec.erb +1 -4
  100. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -0
  101. metadata +69 -31
  102. data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
  103. data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
  104. data/lib/jekyll/utils/rouge.rb +0 -22
@@ -7,9 +7,8 @@ module Jekyll
7
7
 
8
8
  mutable false
9
9
 
10
- def_delegator :@obj, :write?, :output
11
- def_delegators :@obj, :label, :docs, :files, :directory,
12
- :relative_directory
10
+ def_delegator :@obj, :write?, :output
11
+ def_delegators :@obj, :label, :docs, :files, :directory, :relative_directory
13
12
 
14
13
  private def_delegator :@obj, :metadata, :fallback_data
15
14
 
@@ -12,7 +12,7 @@ module Jekyll
12
12
  mutable false
13
13
 
14
14
  def_delegator :@obj, :relative_path, :path
15
- def_delegators :@obj, :id, :output, :content, :to_s, :relative_path, :url
15
+ def_delegators :@obj, :id, :output, :content, :to_s, :relative_path, :url, :date
16
16
 
17
17
  private def_delegator :@obj, :data, :fallback_data
18
18
 
@@ -26,6 +26,7 @@ module Jekyll
26
26
 
27
27
  def <=>(other)
28
28
  return nil unless other.is_a? DocumentDrop
29
+
29
30
  cmp = self["date"] <=> other["date"]
30
31
  cmp = self["path"] <=> other["path"] if cmp.nil? || cmp.zero?
31
32
  cmp
@@ -63,6 +64,18 @@ module Jekyll
63
64
  result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key)
64
65
  end
65
66
  end
67
+
68
+ def title
69
+ @obj.data["title"]
70
+ end
71
+
72
+ def categories
73
+ @obj.data["categories"]
74
+ end
75
+
76
+ def tags
77
+ @obj.data["tags"]
78
+ end
66
79
  end
67
80
  end
68
81
  end
@@ -15,11 +15,7 @@ module Jekyll
15
15
  #
16
16
  # Returns the mutability of the class
17
17
  def self.mutable(is_mutable = nil)
18
- @is_mutable = if is_mutable
19
- is_mutable
20
- else
21
- false
22
- end
18
+ @is_mutable = is_mutable || false
23
19
  end
24
20
 
25
21
  def self.mutable?
@@ -34,7 +30,6 @@ module Jekyll
34
30
  # Returns nothing
35
31
  def initialize(obj)
36
32
  @obj = obj
37
- @mutations = {} # only if mutable: true
38
33
  end
39
34
 
40
35
  # Access a method in the Drop or a field in the underlying hash data.
@@ -46,8 +41,8 @@ module Jekyll
46
41
  #
47
42
  # Returns the value for the given key, or nil if none exists
48
43
  def [](key)
49
- if self.class.mutable? && @mutations.key?(key)
50
- @mutations[key]
44
+ if self.class.mutable? && mutations.key?(key)
45
+ mutations[key]
51
46
  elsif self.class.invokable? key
52
47
  public_send key
53
48
  else
@@ -70,11 +65,12 @@ module Jekyll
70
65
  # and the key matches a method in which case it raises a
71
66
  # DropMutationException.
72
67
  def []=(key, val)
73
- if respond_to?("#{key}=")
74
- public_send("#{key}=", val)
68
+ setter = "#{key}="
69
+ if respond_to?(setter)
70
+ public_send(setter, val)
75
71
  elsif respond_to?(key.to_s)
76
72
  if self.class.mutable?
77
- @mutations[key] = val
73
+ mutations[key] = val
78
74
  else
79
75
  raise Errors::DropMutationException, "Key #{key} cannot be set in the drop."
80
76
  end
@@ -104,7 +100,8 @@ module Jekyll
104
100
  # Returns true if the given key is present
105
101
  def key?(key)
106
102
  return false if key.nil?
107
- return true if self.class.mutable? && @mutations.key?(key)
103
+ return true if self.class.mutable? && mutations.key?(key)
104
+
108
105
  respond_to?(key) || fallback_data.key?(key)
109
106
  end
110
107
 
@@ -116,7 +113,7 @@ module Jekyll
116
113
  # Returns an Array of unique keys for content for the Drop.
117
114
  def keys
118
115
  (content_methods |
119
- @mutations.keys |
116
+ mutations.keys |
120
117
  fallback_data.keys).flatten
121
118
  end
122
119
 
@@ -173,7 +170,7 @@ module Jekyll
173
170
  end
174
171
 
175
172
  def merge(other, &block)
176
- self.dup.tap do |me|
173
+ dup.tap do |me|
177
174
  if block.nil?
178
175
  me.merge!(other)
179
176
  else
@@ -207,6 +204,12 @@ module Jekyll
207
204
  return yield(key) unless block.nil?
208
205
  return default unless default.nil?
209
206
  end
207
+
208
+ private
209
+
210
+ def mutations
211
+ @mutations ||= {}
212
+ end
210
213
  end
211
214
  end
212
215
  end
@@ -7,6 +7,10 @@ module Jekyll
7
7
  @obj.doc.data["layout"]
8
8
  end
9
9
 
10
+ def date
11
+ @obj.doc.date
12
+ end
13
+
10
14
  def excerpt
11
15
  nil
12
16
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Drops
5
+ class PageDrop < Drop
6
+ extend Forwardable
7
+
8
+ mutable false
9
+
10
+ def_delegators :@obj, :content, :dir, :name, :path, :url, :excerpt
11
+ private def_delegator :@obj, :data, :fallback_data
12
+
13
+ def title
14
+ @obj.data["title"]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -13,7 +13,7 @@ module Jekyll
13
13
  private def_delegator :@obj, :config, :fallback_data
14
14
 
15
15
  def [](key)
16
- if @obj.collections.key?(key) && key != "posts"
16
+ if key != "posts" && @obj.collections.key?(key)
17
17
  @obj.collections[key].docs
18
18
  else
19
19
  super(key)
@@ -21,7 +21,7 @@ module Jekyll
21
21
  end
22
22
 
23
23
  def key?(key)
24
- (@obj.collections.key?(key) && key != "posts") || super
24
+ (key != "posts" && @obj.collections.key?(key)) || super
25
25
  end
26
26
 
27
27
  def posts
@@ -41,9 +41,9 @@ module Jekyll
41
41
  # `Site#documents` cannot be memoized so that `Site#docs_to_write` can access the
42
42
  # latest state of the attribute.
43
43
  #
44
- # Since this method will be called after `Site#pre_render` hook,
45
- # the `Site#documents` array shouldn't thereafter change and can therefore be
46
- # safely memoized to prevent additional computation of `Site#documents`.
44
+ # Since this method will be called after `Site#pre_render` hook, the `Site#documents`
45
+ # array shouldn't thereafter change and can therefore be safely memoized to prevent
46
+ # additional computation of `Site#documents`.
47
47
  def documents
48
48
  @documents ||= @obj.documents
49
49
  end
@@ -54,6 +54,7 @@ module Jekyll
54
54
  # We should remove this in 4.0 and switch to `{{ post.related_posts }}`.
55
55
  def related_posts
56
56
  return nil unless @current_document.is_a?(Jekyll::Document)
57
+
57
58
  @current_document.related_posts
58
59
  end
59
60
  attr_writer :current_document
@@ -17,6 +17,7 @@ module Jekyll
17
17
  end
18
18
 
19
19
  private
20
+
20
21
  def fallback_data
21
22
  @fallback_data ||= {}
22
23
  end
@@ -35,53 +35,105 @@ module Jekyll
35
35
  category_set.to_a.join("/")
36
36
  end
37
37
 
38
+ # Similar to output from #categories, but each category will be downcased and
39
+ # all non-alphanumeric characters of the category replaced with a hyphen.
40
+ def slugified_categories
41
+ Array(@obj.data["categories"]).each_with_object(Set.new) do |category, set|
42
+ set << Utils.slugify(category.to_s)
43
+ end.to_a.join("/")
44
+ end
45
+
46
+ # CCYY
38
47
  def year
39
48
  @obj.date.strftime("%Y")
40
49
  end
41
50
 
51
+ # MM: 01..12
42
52
  def month
43
53
  @obj.date.strftime("%m")
44
54
  end
45
55
 
56
+ # DD: 01..31
46
57
  def day
47
58
  @obj.date.strftime("%d")
48
59
  end
49
60
 
61
+ # hh: 00..23
50
62
  def hour
51
63
  @obj.date.strftime("%H")
52
64
  end
53
65
 
66
+ # mm: 00..59
54
67
  def minute
55
68
  @obj.date.strftime("%M")
56
69
  end
57
70
 
71
+ # ss: 00..59
58
72
  def second
59
73
  @obj.date.strftime("%S")
60
74
  end
61
75
 
76
+ # D: 1..31
62
77
  def i_day
63
78
  @obj.date.strftime("%-d")
64
79
  end
65
80
 
81
+ # M: 1..12
66
82
  def i_month
67
83
  @obj.date.strftime("%-m")
68
84
  end
69
85
 
86
+ # MMM: Jan..Dec
70
87
  def short_month
71
88
  @obj.date.strftime("%b")
72
89
  end
73
90
 
91
+ # MMMM: January..December
92
+ def long_month
93
+ @obj.date.strftime("%B")
94
+ end
95
+
96
+ # YY: 00..99
74
97
  def short_year
75
98
  @obj.date.strftime("%y")
76
99
  end
77
100
 
101
+ # CCYYw, ISO week year
102
+ # may differ from CCYY for the first days of January and last days of December
103
+ def w_year
104
+ @obj.date.strftime("%G")
105
+ end
106
+
107
+ # WW: 01..53
108
+ # %W and %U do not comply with ISO 8601-1
109
+ def week
110
+ @obj.date.strftime("%V")
111
+ end
112
+
113
+ # d: 1..7 (Monday..Sunday)
114
+ def w_day
115
+ @obj.date.strftime("%u")
116
+ end
117
+
118
+ # dd: Mon..Sun
119
+ def short_day
120
+ @obj.date.strftime("%a")
121
+ end
122
+
123
+ # ddd: Monday..Sunday
124
+ def long_day
125
+ @obj.date.strftime("%A")
126
+ end
127
+
128
+ # DDD: 001..366
78
129
  def y_day
79
130
  @obj.date.strftime("%j")
80
131
  end
81
132
 
82
133
  private
134
+
83
135
  def fallback_data
84
- {}
136
+ @fallback_data ||= {}
85
137
  end
86
138
  end
87
139
  end
@@ -3,9 +3,8 @@
3
3
  module Jekyll
4
4
  class EntryFilter
5
5
  attr_reader :site
6
- SPECIAL_LEADING_CHARACTERS = [
7
- ".", "_", "#", "~",
8
- ].freeze
6
+
7
+ SPECIAL_LEADING_CHAR_REGEX = %r!\A#{Regexp.union([".", "_", "#", "~"])}!o.freeze
9
8
 
10
9
  def initialize(site, base_directory = nil)
11
10
  @site = site
@@ -29,16 +28,30 @@ module Jekyll
29
28
  )
30
29
  end
31
30
 
31
+ # rubocop:disable Metrics/CyclomaticComplexity
32
32
  def filter(entries)
33
33
  entries.reject do |e|
34
- # Reject this entry if it is a symlink.
34
+ # Reject this entry if it is just a "dot" representation.
35
+ # e.g.: '.', '..', '_movies/.', 'music/..', etc
36
+ next true if e.end_with?(".")
37
+
38
+ # Check if the current entry is explicitly included and cache the result
39
+ included = included?(e)
40
+
41
+ # Reject current entry if it is excluded but not explicitly included as well.
42
+ next true if excluded?(e) && !included
43
+
44
+ # Reject current entry if it is a symlink.
35
45
  next true if symlink?(e)
36
- # Do not reject this entry if it is included.
37
- next false if included?(e)
38
- # Reject this entry if it is special, a backup file, or excluded.
39
- special?(e) || backup?(e) || excluded?(e)
46
+
47
+ # Do not reject current entry if it is explicitly included.
48
+ next false if included
49
+
50
+ # Reject current entry if it is special or a backup file.
51
+ special?(e) || backup?(e)
40
52
  end
41
53
  end
54
+ # rubocop:enable Metrics/CyclomaticComplexity
42
55
 
43
56
  def included?(entry)
44
57
  glob_include?(site.include, entry) ||
@@ -46,16 +59,16 @@ module Jekyll
46
59
  end
47
60
 
48
61
  def special?(entry)
49
- SPECIAL_LEADING_CHARACTERS.include?(entry[0..0]) ||
50
- SPECIAL_LEADING_CHARACTERS.include?(File.basename(entry)[0..0])
62
+ SPECIAL_LEADING_CHAR_REGEX.match?(entry) ||
63
+ SPECIAL_LEADING_CHAR_REGEX.match?(File.basename(entry))
51
64
  end
52
65
 
53
66
  def backup?(entry)
54
- entry[-1..-1] == "~"
67
+ entry.end_with?("~")
55
68
  end
56
69
 
57
70
  def excluded?(entry)
58
- glob_include?(site.exclude, relative_to_source(entry)).tap do |excluded|
71
+ glob_include?(site.exclude - site.include, relative_to_source(entry)).tap do |excluded|
59
72
  if excluded
60
73
  Jekyll.logger.debug(
61
74
  "EntryFilter:",
@@ -85,40 +98,24 @@ module Jekyll
85
98
  )
86
99
  end
87
100
 
88
- # --
89
- # Check if an entry matches a specific pattern and return true,false.
90
- # Returns true if path matches against any glob pattern.
91
- # --
92
- def glob_include?(enum, entry)
93
- entry_path = Pathutil.new(site.in_source_dir).join(entry)
94
- enum.any? do |exp|
95
- # Users who send a Regexp knows what they want to
96
- # exclude, so let them send a Regexp to exclude files,
97
- # we will not bother caring if it works or not, it's
98
- # on them at this point.
99
-
100
- if exp.is_a?(Regexp)
101
- entry_path =~ exp
102
-
101
+ # Check if an entry matches a specific pattern.
102
+ # Returns true if path matches against any glob pattern, else false.
103
+ def glob_include?(enumerator, entry)
104
+ entry_with_source = PathManager.join(site.source, entry)
105
+ entry_is_directory = File.directory?(entry_with_source)
106
+
107
+ enumerator.any? do |pattern|
108
+ case pattern
109
+ when String
110
+ pattern_with_source = PathManager.join(site.source, pattern)
111
+
112
+ File.fnmatch?(pattern_with_source, entry_with_source) ||
113
+ entry_with_source.start_with?(pattern_with_source) ||
114
+ (pattern_with_source == "#{entry_with_source}/" if entry_is_directory)
115
+ when Regexp
116
+ pattern.match?(entry_with_source)
103
117
  else
104
- item = Pathutil.new(site.in_source_dir).join(exp)
105
-
106
- # If it's a directory they want to exclude, AKA
107
- # ends with a "/" then we will go on to check and
108
- # see if the entry falls within that path and
109
- # exclude it if that's the case.
110
-
111
- if entry.end_with?("/")
112
- entry_path.in_path?(
113
- item
114
- )
115
-
116
- else
117
- File.fnmatch?(item, entry_path) ||
118
- entry_path.to_path.start_with?(
119
- item
120
- )
121
- end
118
+ false
122
119
  end
123
120
  end
124
121
  end
@@ -8,10 +8,11 @@ module Jekyll
8
8
  attr_accessor :content, :ext
9
9
  attr_writer :output
10
10
 
11
- def_delegators :@doc, :site, :name, :ext, :extname,
12
- :collection, :related_posts,
13
- :coffeescript_file?, :yaml_file?,
14
- :url, :next_doc, :previous_doc
11
+ def_delegators :@doc,
12
+ :site, :name, :ext, :extname,
13
+ :collection, :related_posts, :type,
14
+ :coffeescript_file?, :yaml_file?,
15
+ :url, :next_doc, :previous_doc
15
16
 
16
17
  private :coffeescript_file?, :yaml_file?
17
18
 
@@ -48,14 +49,14 @@ module Jekyll
48
49
  #
49
50
  # Returns the relative_path for the doc this excerpt belongs to with #excerpt appended
50
51
  def relative_path
51
- File.join(doc.relative_path, "#excerpt")
52
+ @relative_path ||= File.join(doc.relative_path, "#excerpt")
52
53
  end
53
54
 
54
55
  # Check if excerpt includes a string
55
56
  #
56
57
  # Returns true if the string passed in
57
58
  def include?(something)
58
- (output && output.include?(something)) || content.include?(something)
59
+ output&.include?(something) || content.include?(something)
59
60
  end
60
61
 
61
62
  # The UID for this doc (useful in feeds).
@@ -76,7 +77,7 @@ module Jekyll
76
77
 
77
78
  # Returns the shorthand String identifier of this doc.
78
79
  def inspect
79
- "<Excerpt: #{self.id}>"
80
+ "<#{self.class} id=#{id}>"
80
81
  end
81
82
 
82
83
  def output
@@ -88,6 +89,8 @@ module Jekyll
88
89
  end
89
90
 
90
91
  def render_with_liquid?
92
+ return false if data["render_with_liquid"] == false
93
+
91
94
  !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content))
92
95
  end
93
96
 
@@ -128,36 +131,47 @@ module Jekyll
128
131
  #
129
132
  # Returns excerpt String
130
133
 
131
- LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m
132
- MKDWN_LINK_REF_REGEX = %r!^ {0,3}\[[^\]]+\]:.+$!
134
+ LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m.freeze
135
+ MKDWN_LINK_REF_REGEX = %r!^ {0,3}(?:(\[[^\]]+\])(:.+))$!.freeze
133
136
 
134
137
  def extract_excerpt(doc_content)
135
138
  head, _, tail = doc_content.to_s.partition(doc.excerpt_separator)
139
+ return head if tail.empty?
136
140
 
137
- # append appropriate closing tag(s) (for each Liquid block), to the `head`
138
- # if the partitioning resulted in leaving the closing tag somewhere
139
- # in the `tail` partition.
141
+ head = sanctify_liquid_tags(head) if head.include?("{%")
142
+ definitions = extract_markdown_link_reference_defintions(head, tail)
143
+ return head if definitions.empty?
140
144
 
141
- if head.include?("{%")
142
- modified = false
143
- tag_names = head.scan(LIQUID_TAG_REGEX)
144
- tag_names.flatten!
145
- tag_names.reverse_each do |tag_name|
146
- next unless liquid_block?(tag_name)
147
- next if head =~ endtag_regex_stash(tag_name)
145
+ head << "\n\n" << definitions.join("\n")
146
+ end
148
147
 
149
- modified = true
150
- head << "\n{% end#{tag_name} %}"
151
- end
152
- print_build_warning if modified
153
- end
148
+ private
154
149
 
155
- return head if tail.empty?
150
+ # append appropriate closing tag(s) (for each Liquid block), to the `head` if the
151
+ # partitioning resulted in leaving the closing tag somewhere in the `tail` partition.
152
+ def sanctify_liquid_tags(head)
153
+ modified = false
154
+ tag_names = head.scan(LIQUID_TAG_REGEX)
155
+ tag_names.flatten!
156
+ tag_names.reverse_each do |tag_name|
157
+ next unless liquid_block?(tag_name)
158
+ next if endtag_regex_stash(tag_name).match?(head)
159
+
160
+ modified = true
161
+ head << "\n{% end#{tag_name} %}"
162
+ end
156
163
 
157
- head << "\n\n" << tail.scan(MKDWN_LINK_REF_REGEX).join("\n")
164
+ print_build_warning if modified
165
+ head
158
166
  end
159
167
 
160
- private
168
+ def extract_markdown_link_reference_defintions(head, tail)
169
+ [].tap do |definitions|
170
+ tail.scan(MKDWN_LINK_REF_REGEX).each do |segments|
171
+ definitions << segments.join if head.include?(segments[0])
172
+ end
173
+ end
174
+ end
161
175
 
162
176
  def endtag_regex_stash(tag_name)
163
177
  @endtag_regex_stash ||= {}
@@ -171,8 +185,7 @@ module Jekyll
171
185
  Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block)
172
186
  rescue NoMethodError
173
187
  Jekyll.logger.error "Error:",
174
- "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be " \
175
- "parsed."
188
+ "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed."
176
189
  raise
177
190
  end
178
191
 
@@ -180,11 +193,9 @@ module Jekyll
180
193
  Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!"
181
194
  Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator" \
182
195
  " #{doc.excerpt_separator.inspect}. "
183
- Jekyll.logger.warn "", "The block has been modified with the appropriate" \
184
- " closing tag."
185
- Jekyll.logger.warn "", "Feel free to define a custom excerpt or" \
186
- " excerpt_separator in the document's front matter" \
187
- " if the generated excerpt is unsatisfactory."
196
+ Jekyll.logger.warn "", "The block has been modified with the appropriate closing tag."
197
+ Jekyll.logger.warn "", "Feel free to define a custom excerpt or excerpt_separator in the"
198
+ Jekyll.logger.warn "", "document's Front Matter if the generated excerpt is unsatisfactory."
188
199
  end
189
200
  end
190
201
  end