jekyll 3.9.3 → 4.4.1

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +511 -89
  3. data/LICENSE +1 -1
  4. data/README.markdown +48 -27
  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/base.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/cache.rb +186 -0
  11. data/lib/jekyll/cleaner.rb +8 -7
  12. data/lib/jekyll/collection.rb +84 -11
  13. data/lib/jekyll/command.rb +33 -6
  14. data/lib/jekyll/commands/build.rb +8 -28
  15. data/lib/jekyll/commands/clean.rb +3 -2
  16. data/lib/jekyll/commands/doctor.rb +46 -35
  17. data/lib/jekyll/commands/help.rb +1 -1
  18. data/lib/jekyll/commands/new.rb +44 -50
  19. data/lib/jekyll/commands/new_theme.rb +27 -28
  20. data/lib/jekyll/commands/serve/live_reload_reactor.rb +9 -16
  21. data/lib/jekyll/commands/serve/servlet.rb +21 -22
  22. data/lib/jekyll/commands/serve/websockets.rb +1 -1
  23. data/lib/jekyll/commands/serve.rb +75 -97
  24. data/lib/jekyll/configuration.rb +66 -158
  25. data/lib/jekyll/converters/identity.rb +18 -0
  26. data/lib/jekyll/converters/markdown/kramdown_parser.rb +83 -33
  27. data/lib/jekyll/converters/markdown.rb +49 -40
  28. data/lib/jekyll/converters/smartypants.rb +34 -14
  29. data/lib/jekyll/convertible.rb +36 -34
  30. data/lib/jekyll/deprecator.rb +2 -4
  31. data/lib/jekyll/document.rb +107 -72
  32. data/lib/jekyll/drops/collection_drop.rb +3 -4
  33. data/lib/jekyll/drops/document_drop.rb +9 -3
  34. data/lib/jekyll/drops/drop.rb +115 -33
  35. data/lib/jekyll/drops/excerpt_drop.rb +8 -0
  36. data/lib/jekyll/drops/site_drop.rb +9 -8
  37. data/lib/jekyll/drops/static_file_drop.rb +4 -4
  38. data/lib/jekyll/drops/theme_drop.rb +39 -0
  39. data/lib/jekyll/drops/unified_payload_drop.rb +7 -2
  40. data/lib/jekyll/drops/url_drop.rb +55 -3
  41. data/lib/jekyll/entry_filter.rb +42 -51
  42. data/lib/jekyll/excerpt.rb +48 -38
  43. data/lib/jekyll/external.rb +20 -19
  44. data/lib/jekyll/filters/date_filters.rb +6 -3
  45. data/lib/jekyll/filters/grouping_filters.rb +1 -2
  46. data/lib/jekyll/filters/url_filters.rb +50 -15
  47. data/lib/jekyll/filters.rb +211 -50
  48. data/lib/jekyll/frontmatter_defaults.rb +45 -36
  49. data/lib/jekyll/hooks.rb +26 -26
  50. data/lib/jekyll/inclusion.rb +32 -0
  51. data/lib/jekyll/layout.rb +12 -19
  52. data/lib/jekyll/liquid_extensions.rb +0 -2
  53. data/lib/jekyll/liquid_renderer/file.rb +24 -3
  54. data/lib/jekyll/liquid_renderer/table.rb +26 -77
  55. data/lib/jekyll/liquid_renderer.rb +31 -16
  56. data/lib/jekyll/log_adapter.rb +5 -1
  57. data/lib/jekyll/page.rb +51 -23
  58. data/lib/jekyll/page_excerpt.rb +25 -0
  59. data/lib/jekyll/page_without_a_file.rb +0 -4
  60. data/lib/jekyll/path_manager.rb +74 -0
  61. data/lib/jekyll/plugin.rb +5 -11
  62. data/lib/jekyll/plugin_manager.rb +15 -5
  63. data/lib/jekyll/profiler.rb +51 -0
  64. data/lib/jekyll/reader.rb +65 -10
  65. data/lib/jekyll/readers/collection_reader.rb +1 -0
  66. data/lib/jekyll/readers/data_reader.rb +48 -10
  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 +32 -19
  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/related_posts.rb +1 -1
  74. data/lib/jekyll/renderer.rb +34 -49
  75. data/lib/jekyll/site.rb +151 -58
  76. data/lib/jekyll/static_file.rb +64 -28
  77. data/lib/jekyll/stevenson.rb +4 -8
  78. data/lib/jekyll/tags/highlight.rb +44 -57
  79. data/lib/jekyll/tags/include.rb +114 -80
  80. data/lib/jekyll/tags/link.rb +12 -7
  81. data/lib/jekyll/tags/post_url.rb +33 -30
  82. data/lib/jekyll/theme.rb +20 -18
  83. data/lib/jekyll/theme_builder.rb +91 -89
  84. data/lib/jekyll/url.rb +18 -10
  85. data/lib/jekyll/utils/ansi.rb +2 -2
  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 +37 -52
  89. data/lib/jekyll/utils/thread_event.rb +1 -5
  90. data/lib/jekyll/utils.rb +29 -28
  91. data/lib/jekyll/version.rb +1 -1
  92. data/lib/jekyll.rb +9 -14
  93. data/lib/site_template/.gitignore +2 -0
  94. data/lib/site_template/404.html +2 -1
  95. data/lib/site_template/_config.yml +17 -5
  96. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
  97. data/lib/theme_template/README.md.erb +1 -3
  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 +150 -0
  101. data/rubocop/jekyll/no_p_allowed.rb +5 -6
  102. data/rubocop/jekyll/no_puts_allowed.rb +5 -6
  103. metadata +149 -37
  104. data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
  105. data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
  106. data/lib/jekyll/utils/rouge.rb +0 -22
  107. /data/lib/site_template/{about.md → about.markdown} +0 -0
  108. /data/lib/site_template/{index.md → index.markdown} +0 -0
@@ -7,13 +7,13 @@ module Jekyll
7
7
 
8
8
  mutable false
9
9
 
10
- def_delegator :@obj, :site_data, :data
11
- def_delegators :@obj, :time, :pages, :static_files, :tags, :categories
10
+ delegate_method_as :site_data, :data
11
+ delegate_methods :time, :pages, :static_files, :tags, :categories
12
12
 
13
- private def_delegator :@obj, :config, :fallback_data
13
+ private delegate_method_as :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
@@ -4,11 +4,11 @@ module Jekyll
4
4
  module Drops
5
5
  class StaticFileDrop < Drop
6
6
  extend Forwardable
7
- def_delegators :@obj, :name, :extname, :modified_time, :basename
8
- def_delegator :@obj, :relative_path, :path
9
- def_delegator :@obj, :type, :collection
7
+ delegate_methods :name, :extname, :modified_time, :basename
8
+ delegate_method_as :relative_path, :path
9
+ delegate_method_as :type, :collection
10
10
 
11
- private def_delegator :@obj, :data, :fallback_data
11
+ private delegate_method_as :data, :fallback_data
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Drops
5
+ class ThemeDrop < Drop
6
+ delegate_method_as :runtime_dependencies, :dependencies
7
+
8
+ def root
9
+ @root ||= ENV["JEKYLL_ENV"] == "development" ? @obj.root : ""
10
+ end
11
+
12
+ def authors
13
+ @authors ||= gemspec.authors.join(", ")
14
+ end
15
+
16
+ def version
17
+ @version ||= gemspec.version.to_s
18
+ end
19
+
20
+ def description
21
+ @description ||= gemspec.description || gemspec.summary
22
+ end
23
+
24
+ def metadata
25
+ @metadata ||= gemspec.metadata
26
+ end
27
+
28
+ private
29
+
30
+ def gemspec
31
+ @gemspec ||= @obj.send(:gemspec)
32
+ end
33
+
34
+ def fallback_data
35
+ @fallback_data ||= {}
36
+ end
37
+ end
38
+ end
39
+ end
@@ -5,8 +5,8 @@ module Jekyll
5
5
  class UnifiedPayloadDrop < Drop
6
6
  mutable true
7
7
 
8
- attr_accessor :page, :layout, :content, :paginator
9
- attr_accessor :highlighter_prefix, :highlighter_suffix
8
+ attr_accessor :content, :page, :layout, :paginator,
9
+ :highlighter_prefix, :highlighter_suffix
10
10
 
11
11
  def jekyll
12
12
  JekyllDrop.global
@@ -16,7 +16,12 @@ module Jekyll
16
16
  @site_drop ||= SiteDrop.new(@obj)
17
17
  end
18
18
 
19
+ def theme
20
+ @theme_drop ||= ThemeDrop.new(@obj.theme) if @obj.theme
21
+ end
22
+
19
23
  private
24
+
20
25
  def fallback_data
21
26
  @fallback_data ||= {}
22
27
  end
@@ -7,8 +7,8 @@ module Jekyll
7
7
 
8
8
  mutable false
9
9
 
10
- def_delegator :@obj, :cleaned_relative_path, :path
11
- def_delegator :@obj, :output_ext, :output_ext
10
+ delegate_method :output_ext
11
+ delegate_method_as :cleaned_relative_path, :path
12
12
 
13
13
  def collection
14
14
  @obj.collection.label
@@ -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
@@ -31,12 +30,24 @@ module Jekyll
31
30
 
32
31
  def filter(entries)
33
32
  entries.reject do |e|
34
- # Reject this entry if it is a symlink.
33
+ # Reject this entry if it is just a "dot" representation.
34
+ # e.g.: '.', '..', '_movies/.', 'music/..', etc
35
+ next true if e.end_with?(".")
36
+
37
+ # Check if the current entry is explicitly included and cache the result
38
+ included = included?(e)
39
+
40
+ # Reject current entry if it is excluded but not explicitly included as well.
41
+ next true if excluded?(e) && !included
42
+
43
+ # Reject current entry if it is a symlink.
35
44
  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)
45
+
46
+ # Do not reject current entry if it is explicitly included.
47
+ next false if included
48
+
49
+ # Reject current entry if it is special or a backup file.
50
+ special?(e) || backup?(e)
40
51
  end
41
52
  end
42
53
 
@@ -46,16 +57,16 @@ module Jekyll
46
57
  end
47
58
 
48
59
  def special?(entry)
49
- SPECIAL_LEADING_CHARACTERS.include?(entry[0..0]) ||
50
- SPECIAL_LEADING_CHARACTERS.include?(File.basename(entry)[0..0])
60
+ SPECIAL_LEADING_CHAR_REGEX.match?(entry) ||
61
+ SPECIAL_LEADING_CHAR_REGEX.match?(File.basename(entry))
51
62
  end
52
63
 
53
64
  def backup?(entry)
54
- entry[-1..-1] == "~"
65
+ entry.end_with?("~")
55
66
  end
56
67
 
57
68
  def excluded?(entry)
58
- glob_include?(site.exclude, relative_to_source(entry)).tap do |excluded|
69
+ glob_include?(site.exclude - site.include, relative_to_source(entry)).tap do |excluded|
59
70
  if excluded
60
71
  Jekyll.logger.debug(
61
72
  "EntryFilter:",
@@ -75,50 +86,30 @@ module Jekyll
75
86
  end
76
87
 
77
88
  # --
78
- # NOTE: Pathutil#in_path? gets the realpath.
79
- # @param [<Anything>] entry the entry you want to validate.
80
- # Check if a path is outside of our given root.
89
+ # Check if given path is outside of current site's configured source directory.
81
90
  # --
82
91
  def symlink_outside_site_source?(entry)
83
- !Pathutil.new(entry).in_path?(
84
- site.in_source_dir
85
- )
92
+ !File.realpath(entry).start_with?(site.in_source_dir)
86
93
  end
87
94
 
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
-
95
+ # Check if an entry matches a specific pattern.
96
+ # Returns true if path matches against any glob pattern, else false.
97
+ def glob_include?(enumerator, entry)
98
+ entry_with_source = PathManager.join(site.source, entry)
99
+ entry_is_directory = File.directory?(entry_with_source)
100
+
101
+ enumerator.any? do |pattern|
102
+ case pattern
103
+ when String
104
+ pattern_with_source = PathManager.join(site.source, pattern)
105
+
106
+ File.fnmatch?(pattern_with_source, entry_with_source) ||
107
+ entry_with_source.start_with?(pattern_with_source) ||
108
+ (pattern_with_source == "#{entry_with_source}/" if entry_is_directory)
109
+ when Regexp
110
+ pattern.match?(entry_with_source)
103
111
  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
112
+ false
122
113
  end
123
114
  end
124
115
  end
@@ -4,14 +4,14 @@ module Jekyll
4
4
  class Excerpt
5
5
  extend Forwardable
6
6
 
7
- attr_accessor :doc
8
- attr_accessor :content, :ext
7
+ attr_accessor :content, :doc, :ext
9
8
  attr_writer :output
10
9
 
11
- def_delegators :@doc, :site, :name, :ext, :extname,
12
- :collection, :related_posts,
13
- :coffeescript_file?, :yaml_file?,
14
- :url, :next_doc, :previous_doc
10
+ def_delegators :@doc,
11
+ :site, :name, :ext, :extname,
12
+ :collection, :related_posts, :type,
13
+ :coffeescript_file?, :yaml_file?,
14
+ :url, :next_doc, :previous_doc
15
15
 
16
16
  private :coffeescript_file?, :yaml_file?
17
17
 
@@ -48,14 +48,14 @@ module Jekyll
48
48
  #
49
49
  # Returns the relative_path for the doc this excerpt belongs to with #excerpt appended
50
50
  def relative_path
51
- File.join(doc.relative_path, "#excerpt")
51
+ @relative_path ||= File.join(doc.relative_path, "#excerpt")
52
52
  end
53
53
 
54
54
  # Check if excerpt includes a string
55
55
  #
56
56
  # Returns true if the string passed in
57
57
  def include?(something)
58
- (output && output.include?(something)) || content.include?(something)
58
+ output&.include?(something) || content.include?(something)
59
59
  end
60
60
 
61
61
  # The UID for this doc (useful in feeds).
@@ -76,7 +76,7 @@ module Jekyll
76
76
 
77
77
  # Returns the shorthand String identifier of this doc.
78
78
  def inspect
79
- "<Excerpt: #{self.id}>"
79
+ "<#{self.class} id=#{id}>"
80
80
  end
81
81
 
82
82
  def output
@@ -88,6 +88,8 @@ module Jekyll
88
88
  end
89
89
 
90
90
  def render_with_liquid?
91
+ return false if data["render_with_liquid"] == false
92
+
91
93
  !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content))
92
94
  end
93
95
 
@@ -128,36 +130,47 @@ module Jekyll
128
130
  #
129
131
  # Returns excerpt String
130
132
 
131
- LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m
132
- MKDWN_LINK_REF_REGEX = %r!^ {0,3}\[[^\]]+\]:.+$!
133
+ LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m.freeze
134
+ MKDWN_LINK_REF_REGEX = %r!^ {0,3}(?:(\[[^\]]+\])(:.+))$!.freeze
133
135
 
134
136
  def extract_excerpt(doc_content)
135
137
  head, _, tail = doc_content.to_s.partition(doc.excerpt_separator)
138
+ return head if tail.empty?
136
139
 
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.
140
+ head = sanctify_liquid_tags(head) if head.include?("{%")
141
+ definitions = extract_markdown_link_reference_definitions(head, tail)
142
+ return head if definitions.empty?
140
143
 
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)
144
+ head << "\n\n" << definitions.join("\n")
145
+ end
148
146
 
149
- modified = true
150
- head << "\n{% end#{tag_name} %}"
151
- end
152
- print_build_warning if modified
153
- end
147
+ private
154
148
 
155
- return head if tail.empty?
149
+ # append appropriate closing tag(s) (for each Liquid block), to the `head` if the
150
+ # partitioning resulted in leaving the closing tag somewhere in the `tail` partition.
151
+ def sanctify_liquid_tags(head)
152
+ modified = false
153
+ tag_names = head.scan(LIQUID_TAG_REGEX)
154
+ tag_names.flatten!
155
+ tag_names.reverse_each do |tag_name|
156
+ next unless liquid_block?(tag_name)
157
+ next if endtag_regex_stash(tag_name).match?(head)
158
+
159
+ modified = true
160
+ head << "\n{% end#{tag_name} %}"
161
+ end
156
162
 
157
- head << "\n\n" << tail.scan(MKDWN_LINK_REF_REGEX).join("\n")
163
+ print_build_warning if modified
164
+ head
158
165
  end
159
166
 
160
- private
167
+ def extract_markdown_link_reference_definitions(head, tail)
168
+ [].tap do |definitions|
169
+ tail.scan(MKDWN_LINK_REF_REGEX).each do |segments|
170
+ definitions << segments.join if head.include?(segments[0])
171
+ end
172
+ end
173
+ end
161
174
 
162
175
  def endtag_regex_stash(tag_name)
163
176
  @endtag_regex_stash ||= {}
@@ -171,20 +184,17 @@ module Jekyll
171
184
  Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block)
172
185
  rescue NoMethodError
173
186
  Jekyll.logger.error "Error:",
174
- "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be " \
175
- "parsed."
187
+ "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed."
176
188
  raise
177
189
  end
178
190
 
179
191
  def print_build_warning
180
192
  Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!"
181
- Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator" \
182
- " #{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."
193
+ Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator " \
194
+ "#{doc.excerpt_separator.inspect}."
195
+ Jekyll.logger.warn "", "The block has been modified with the appropriate closing tag."
196
+ Jekyll.logger.warn "", "Feel free to define a custom excerpt or excerpt_separator in the"
197
+ Jekyll.logger.warn "", "document's Front Matter if the generated excerpt is unsatisfactory."
188
198
  end
189
199
  end
190
200
  end
@@ -9,6 +9,7 @@ module Jekyll
9
9
  #
10
10
  def blessed_gems
11
11
  %w(
12
+ jekyll-compose
12
13
  jekyll-docs
13
14
  jekyll-import
14
15
  )
@@ -21,13 +22,11 @@ module Jekyll
21
22
  #
22
23
  def require_if_present(names)
23
24
  Array(names).each do |name|
24
- begin
25
- require name
26
- rescue LoadError
27
- Jekyll.logger.debug "Couldn't load #{name}. Skipping."
28
- yield(name, version_constraint(name)) if block_given?
29
- false
30
- end
25
+ require name
26
+ rescue LoadError
27
+ Jekyll.logger.debug "Couldn't load #{name}. Skipping."
28
+ yield(name, version_constraint(name)) if block_given?
29
+ false
31
30
  end
32
31
  end
33
32
 
@@ -41,6 +40,7 @@ module Jekyll
41
40
  # RubyGems.
42
41
  def version_constraint(gem_name)
43
42
  return "= #{Jekyll::VERSION}" if gem_name.to_s.eql?("jekyll-docs")
43
+
44
44
  "> 0"
45
45
  end
46
46
 
@@ -53,20 +53,21 @@ module Jekyll
53
53
  #
54
54
  def require_with_graceful_fail(names)
55
55
  Array(names).each do |name|
56
- begin
57
- Jekyll.logger.debug "Requiring:", name.to_s
58
- require name
59
- rescue LoadError => e
60
- Jekyll.logger.error "Dependency Error:", <<-MSG
61
- Yikes! It looks like you don't have #{name} or one of its dependencies installed.
62
- In order to use Jekyll as currently configured, you'll need to install this gem.
56
+ Jekyll.logger.debug "Requiring:", name.to_s
57
+ require name
58
+ rescue LoadError => e
59
+ Jekyll.logger.error "Dependency Error:", <<~MSG
60
+ Yikes! It looks like you don't have #{name} or one of its dependencies installed.
61
+ In order to use Jekyll as currently configured, you'll need to install this gem.
62
+
63
+ If you've run Jekyll with `bundle exec`, ensure that you have included the #{name}
64
+ gem in your Gemfile as well.
63
65
 
64
- The full error message from Ruby is: '#{e.message}'
66
+ The full error message from Ruby is: '#{e.message}'
65
67
 
66
- If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/!
67
- MSG
68
- raise Jekyll::Errors::MissingDependencyException, name
69
- end
68
+ If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/!
69
+ MSG
70
+ raise Jekyll::Errors::MissingDependencyException, name
70
71
  end
71
72
  end
72
73
  end
@@ -45,6 +45,7 @@ module Jekyll
45
45
  # Returns the formatted String.
46
46
  def date_to_xmlschema(date)
47
47
  return date if date.to_s.empty?
48
+
48
49
  time(date).xmlschema
49
50
  end
50
51
 
@@ -60,10 +61,12 @@ module Jekyll
60
61
  # Returns the formatted String.
61
62
  def date_to_rfc822(date)
62
63
  return date if date.to_s.empty?
64
+
63
65
  time(date).rfc822
64
66
  end
65
67
 
66
68
  private
69
+
67
70
  # month_type: Notations that evaluate to 'Month' via `Time#strftime` ("%b", "%B")
68
71
  # type: nil (default) or "ordinal"
69
72
  # style: nil (default) or "US"
@@ -71,17 +74,18 @@ module Jekyll
71
74
  # Returns a stringified date or the empty input.
72
75
  def stringify_date(date, month_type, type = nil, style = nil)
73
76
  return date if date.to_s.empty?
77
+
74
78
  time = time(date)
75
79
  if type == "ordinal"
76
80
  day = time.day
77
81
  ordinal_day = "#{day}#{ordinal(day)}"
78
82
  return time.strftime("#{month_type} #{ordinal_day}, %Y") if style == "US"
83
+
79
84
  return time.strftime("#{ordinal_day} #{month_type} %Y")
80
85
  end
81
86
  time.strftime("%d #{month_type} %Y")
82
87
  end
83
88
 
84
- private
85
89
  def ordinal(number)
86
90
  return "th" if (11..13).cover?(number)
87
91
 
@@ -93,12 +97,11 @@ module Jekyll
93
97
  end
94
98
  end
95
99
 
96
- private
97
100
  def time(input)
98
101
  date = Liquid::Utils.to_date(input)
99
102
  unless date.respond_to?(:to_time)
100
103
  raise Errors::InvalidDateError,
101
- "Invalid Date: '#{input.inspect}' is not a valid datetime."
104
+ "Invalid Date: '#{input.inspect}' is not a valid datetime."
102
105
  end
103
106
  date.to_time.dup.localtime
104
107
  end
@@ -41,16 +41,15 @@ module Jekyll
41
41
  end
42
42
 
43
43
  private
44
+
44
45
  def parse_expression(str)
45
46
  Liquid::Variable.new(str, Liquid::ParseContext.new)
46
47
  end
47
48
 
48
- private
49
49
  def groupable?(element)
50
50
  element.respond_to?(:group_by)
51
51
  end
52
52
 
53
- private
54
53
  def grouped_array(groups)
55
54
  groups.each_with_object([]) do |item, array|
56
55
  array << {